<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/nvsoft/cef"
	"github.com/nvsoft/win"
	"os"
	"syscall"
	"unsafe"
	"goapp/config"
)

const (
	ICON_MAIN       = 100
	nguiWindowClass = `\o/ NGui_Window_Class \o/`
)

var (
	hInstance win.HINSTANCE
	manifest  config.Manifest
)

var wndProc = syscall.NewCallback(WndProc)

func init() {
	hInstance := win.GetModuleHandle(nil)
	if hInstance == 0 {
		panic("GetModuleHandle")
	}

	MustRegisterWindowClass(nguiWindowClass)

	manifest.Load()
}

func main() {
	cef.ExecuteProcess(unsafe.Pointer(hInstance))

	settings := cef.Settings{}
	//settings.SingleProcess = 1                     // 单进程模式
	settings.CachePath = manifest.CachePath()      // Set to empty to disable
	settings.LogSeverity = cef.LOGSEVERITY_DEFAULT // LOGSEVERITY_VERBOSE
	//settings.LocalesDirPath = releasePath + "/locales"
	settings.Locale = manifest.Locale() //"zh-CN"
	settings.BrowserSubprocessPath = manifest.BrowserSubprocessPath()
	//settings.RemoteDebuggingPort = 7000
	cef.Initialize(settings)

	renderWindow := createMainWindow()
	go func() {
		createBrowser(renderWindow, "about:blank") // http://www.baidu.com/
	}()

	//go func() {
	//	working()
	//}()

	cef.RunMessageLoop()
	cef.Shutdown()
	os.Exit(0)
}

func createMainWindow() win.HWND {
	var dwExStyle, dwStyle uint32 = 0, 0

	dwStyle = win.WS_OVERLAPPEDWINDOW

	if !manifest.FormFixed() {
		dwStyle |= win.WS_SIZEBOX
	}

	// 获取屏幕宽度和高度
	var x, y int32
	var width, height int32

	width = manifest.Width()
	height = manifest.Height()
	x = (win.GetSystemMetrics(win.SM_CXSCREEN) - width) / 2
	y = (win.GetSystemMetrics(win.SM_CYSCREEN)-height)/2 - 2

	renderWindow := win.CreateWindowEx(
		dwExStyle,
		syscall.StringToUTF16Ptr(nguiWindowClass),
		nil,
		dwStyle, //|win.WS_CLIPSIBLINGS,
		x,       //win.CW_USEDEFAULT,
		y,       //win.CW_USEDEFAULT,
		width,   //win.CW_USEDEFAULT,
		height,  //win.CW_USEDEFAULT,
		0,       //hwndParent
		0,
		0, //hInstance
		nil)
	if renderWindow == 0 {
		//err := errors.New("CreateWindowEx")
		return win.HWND(0)
	}

	win.MoveWindow(renderWindow, x, y, width, height, false)

	fmt.Printf("CreateWindow x=%v, y=%v, width=%v, height=%v\n", x, y, width, height)

	return renderWindow
}

func createBrowser(renderWindow win.HWND, url string) {
	//browser := cef.CreateBrowser(unsafe.Pointer(hwnd), &browserSettings, url, false)
	browserSettings := cef.BrowserSettings{}
	cef.CreateBrowser(unsafe.Pointer(renderWindow), &browserSettings, url, false)

	//m_dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP |
	//		WS_VISIBLE;
	cef.WindowResized(unsafe.Pointer(renderWindow))

	win.ShowWindow(renderWindow, win.SW_SHOW) //win.SW_SHOW
	win.UpdateWindow(renderWindow)

	//cef.WindowResized(unsafe.Pointer(renderWindow))
	// It should be enough to call WindowResized after 10ms,
	// though to be sure let's extend it to 100ms.
	//time.AfterFunc(time.Millisecond*100, func() {
	//	cef.WindowResized(unsafe.Pointer(renderWindow))
	//})
}

func WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) (result uintptr) {
	switch msg {
	case win.WM_CREATE:
		result = win.DefWindowProc(hwnd, msg, wParam, lParam)
	case win.WM_SIZE:
		// 最小化时不能调整Cef窗体，否则恢复时界面一片空白
		if wParam == win.SIZE_RESTORED || wParam == win.SIZE_MAXIMIZED {
			cef.WindowResized(unsafe.Pointer(hwnd))
		}
	case win.WM_CLOSE:
		win.DestroyWindow(hwnd)
	case win.WM_DESTROY:
		cef.QuitMessageLoop()
	default:
		result = win.DefWindowProc(hwnd, msg, wParam, lParam)
	}
	return
}

func MustRegisterWindowClass(className string) {
	hInstance := win.GetModuleHandle(nil)
	if hInstance == 0 {
		panic("GetModuleHandle")
	}
	hIcon := win.LoadIcon(hInstance, (*uint16)(unsafe.Pointer(uintptr(ICON_MAIN))))
	//hIcon, _ := NewIconFromResource(hInstance, ICON_MAIN)
	if hIcon == 0 {
		panic("LoadIcon")
	}

	hCursor := win.LoadCursor(0, (*uint16)(unsafe.Pointer(uintptr(win.IDC_ARROW))))
	if hCursor == 0 {
		panic("LoadCursor")
	}

	var wc win.WNDCLASSEX
	wc.CbSize = uint32(unsafe.Sizeof(wc))
	wc.LpfnWndProc = wndProc
	wc.HInstance = hInstance
	wc.HIcon = hIcon
	wc.HCursor = hCursor
	wc.HbrBackground = win.COLOR_WINDOW + 1 //COLOR_BTNFACE
	wc.LpszClassName = syscall.StringToUTF16Ptr(className)

	if atom := win.RegisterClassEx(&wc); atom == 0 {
		panic("RegisterClassEx")
	}
}

func NewIconFromResource(instance win.HINSTANCE, resId uint16) (ico win.HICON, err error) {
	if ico = win.LoadIcon(instance, win.MAKEINTRESOURCE(uintptr(resId))); ico == 0 {
		err = errors.New(fmt.Sprintf("Cannot load icon from resource with id %v", resId))
	}

	return ico, err
}
<commit_msg>Modify<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/nvsoft/cef"
	"github.com/nvsoft/win"
	"os"
	"syscall"
	"unsafe"
	"github.com/nvsoft/goapp/config"
)

const (
	ICON_MAIN       = 100
	nguiWindowClass = `\o/ NGui_Window_Class \o/`
)

var (
	hInstance win.HINSTANCE
	manifest  config.Manifest
)

var wndProc = syscall.NewCallback(WndProc)

func init() {
	hInstance := win.GetModuleHandle(nil)
	if hInstance == 0 {
		panic("GetModuleHandle")
	}

	MustRegisterWindowClass(nguiWindowClass)

	manifest.Load()
}

func main() {
	cef.ExecuteProcess(unsafe.Pointer(hInstance))

	settings := cef.Settings{}
	//settings.SingleProcess = 1                     // 单进程模式
	settings.CachePath = manifest.CachePath()      // Set to empty to disable
	settings.LogSeverity = cef.LOGSEVERITY_DEFAULT // LOGSEVERITY_VERBOSE
	//settings.LocalesDirPath = releasePath + "/locales"
	settings.Locale = manifest.Locale() //"zh-CN"
	settings.BrowserSubprocessPath = manifest.BrowserSubprocessPath()
	//settings.RemoteDebuggingPort = 7000
	cef.Initialize(settings)

	renderWindow := createMainWindow()
	go func() {
		createBrowser(renderWindow, manifest.FirstPage()) // http://www.baidu.com/
	}()

	//go func() {
	//	working()
	//}()

	cef.RunMessageLoop()
	cef.Shutdown()
	os.Exit(0)
}

func createMainWindow() win.HWND {
	var dwExStyle, dwStyle uint32 = 0, 0

	dwStyle = win.WS_OVERLAPPEDWINDOW

	if !manifest.FormFixed() {
		dwStyle |= win.WS_SIZEBOX
	}

	// 获取屏幕宽度和高度
	var x, y int32
	var width, height int32

	width = manifest.Width()
	height = manifest.Height()
	x = (win.GetSystemMetrics(win.SM_CXSCREEN) - width) / 2
	y = (win.GetSystemMetrics(win.SM_CYSCREEN)-height)/2 - 2

	renderWindow := win.CreateWindowEx(
		dwExStyle,
		syscall.StringToUTF16Ptr(nguiWindowClass),
		nil,
		dwStyle, //|win.WS_CLIPSIBLINGS,
		x,       //win.CW_USEDEFAULT,
		y,       //win.CW_USEDEFAULT,
		width,   //win.CW_USEDEFAULT,
		height,  //win.CW_USEDEFAULT,
		0,       //hwndParent
		0,
		0, //hInstance
		nil)
	if renderWindow == 0 {
		//err := errors.New("CreateWindowEx")
		return win.HWND(0)
	}

	win.MoveWindow(renderWindow, x, y, width, height, false)

	fmt.Printf("CreateWindow x=%v, y=%v, width=%v, height=%v\n", x, y, width, height)

	return renderWindow
}

func createBrowser(renderWindow win.HWND, url string) {
	//browser := cef.CreateBrowser(unsafe.Pointer(hwnd), &browserSettings, url, false)
	browserSettings := cef.BrowserSettings{}
	cef.CreateBrowser(unsafe.Pointer(renderWindow), &browserSettings, url, false)

	//m_dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP |
	//		WS_VISIBLE;
	cef.WindowResized(unsafe.Pointer(renderWindow))

	win.ShowWindow(renderWindow, win.SW_SHOW) //win.SW_SHOW
	win.UpdateWindow(renderWindow)

	//cef.WindowResized(unsafe.Pointer(renderWindow))
	// It should be enough to call WindowResized after 10ms,
	// though to be sure let's extend it to 100ms.
	//time.AfterFunc(time.Millisecond*100, func() {
	//	cef.WindowResized(unsafe.Pointer(renderWindow))
	//})
}

func WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) (result uintptr) {
	switch msg {
	case win.WM_CREATE:
		result = win.DefWindowProc(hwnd, msg, wParam, lParam)
	case win.WM_SIZE:
		// 最小化时不能调整Cef窗体，否则恢复时界面一片空白
		if wParam == win.SIZE_RESTORED || wParam == win.SIZE_MAXIMIZED {
			cef.WindowResized(unsafe.Pointer(hwnd))
		}
	case win.WM_CLOSE:
		win.DestroyWindow(hwnd)
	case win.WM_DESTROY:
		cef.QuitMessageLoop()
	default:
		result = win.DefWindowProc(hwnd, msg, wParam, lParam)
	}
	return
}

func MustRegisterWindowClass(className string) {
	hInstance := win.GetModuleHandle(nil)
	if hInstance == 0 {
		panic("GetModuleHandle")
	}
	hIcon := win.LoadIcon(hInstance, (*uint16)(unsafe.Pointer(uintptr(ICON_MAIN))))
	//hIcon, _ := NewIconFromResource(hInstance, ICON_MAIN)
	if hIcon == 0 {
		panic("LoadIcon")
	}

	hCursor := win.LoadCursor(0, (*uint16)(unsafe.Pointer(uintptr(win.IDC_ARROW))))
	if hCursor == 0 {
		panic("LoadCursor")
	}

	var wc win.WNDCLASSEX
	wc.CbSize = uint32(unsafe.Sizeof(wc))
	wc.LpfnWndProc = wndProc
	wc.HInstance = hInstance
	wc.HIcon = hIcon
	wc.HCursor = hCursor
	wc.HbrBackground = win.COLOR_WINDOW + 1 //COLOR_BTNFACE
	wc.LpszClassName = syscall.StringToUTF16Ptr(className)

	if atom := win.RegisterClassEx(&wc); atom == 0 {
		panic("RegisterClassEx")
	}
}

func NewIconFromResource(instance win.HINSTANCE, resId uint16) (ico win.HICON, err error) {
	if ico = win.LoadIcon(instance, win.MAKEINTRESOURCE(uintptr(resId))); ico == 0 {
		err = errors.New(fmt.Sprintf("Cannot load icon from resource with id %v", resId))
	}

	return ico, err
}
<|endoftext|>


<commit_before>package gorel

import (
	"testing"
	//"fmt"
	//"strconv"
)

func TestVisit(t *testing.T) {
	//	binary := new(Equality)
	//	l := new(Literal)
	//	l.value = "leftb"
	//	binary.left = l
	//
	//	r := new(Literal)
	//	r.value = "rightb"
	//	binary.right = r
	//
	//	p := new(Literal)
	//	p.value = "p"
	//	u := new(Not)
	//	u.expression = p
	//	join := new(InnerJoin)
	//	join.left = binary
	//	join.right = u
	//
	//	v := new(MySQL)
	//	//v.Visit(*join)
	//	s := join.Visit(v)
	//	fmt.Println(s)
}

func TestVisitNodes(t *testing.T) {
	//	v := new(ToSql)
	//	s := v.VisitNodes(nil)
	//
	//	if s != "" {
	//		t.Errorf("invalid visit nodes")
	//	}
	//
	//	nodes := make([]Node, 3)
	//	s = v.VisitNodes(nodes)
	//	if s != "" {
	//		t.Errorf("handle nil nodes")
	//	}
	//	//t.Log("Pending")
	//t.Errorf("1Pending")
}
//func TestTable(t *testing.T) {
//	conn := GetConnection()
//	table := conn.Table("users")
//	if table.name != "users" {
//		t.Errorf("Error wrong table name")
//	}
//
//	if len(table.columns) != 2 {
//		t.Errorf("invalid column number")
//	}
//
//	if table.columns["id"].name != "id" {
//		t.Errorf("invalid id column")
//	}
//
//	if table.columns["username"].name != "username" {
//		t.Errorf("invalid username column")
//	}
//
//	table = table.where_string("id = 1")
//
//	if table.wheres[0].ToSql() != "(id = 1)" {
//		t.Errorf("invalid where")
//	}
//
//	var sql = table.execute()
//
//	if sql != "SELECT * FROM users WHERE (id = 1)" {
//		t.Errorf("invalid sql")
//	}
//
//	table = table.where_string("username = 'testuser'")
//
//	if table.wheres[1].ToSql() != "(username = 'testuser')" {
//		t.Errorf("invalid where")
//	}
//
//	sql = table.execute()
//
//	if sql != "SELECT * FROM users WHERE (id = 1) AND (username = 'testuser')" {
//		t.Errorf("invalid sql")
//	}
//
//}
//
//func TestEquality(t *testing.T) {
//	conn := GetConnection()
//	table := conn.Table("users")
//	table = table.where(table.columns["id"].eq(9))
//	sql := table.execute()
//
//	if sql != "SELECT * FROM users WHERE (`users`.`id` = 9)" {
//		t.Errorf("invalid sql")
//	}
//}
//
//
//func TestGreaterThan(t *testing.T) {
//	conn := GetConnection()
//	table := conn.Table("users")
//	table = table.where(table.columns["id"].gt(9))
//	sql := table.execute()
//
//	if sql != "SELECT * FROM users WHERE (`users`.`id` > 9)" {
//		t.Errorf("invalid sql")
//	}
//}
//
//func TestLessThan(t *testing.T) {
//	conn := GetConnection()
//	table := conn.Table("users")
//	table = table.where(table.columns["id"].lt(9))
//	sql := table.execute()
//
//	if sql != "SELECT * FROM users WHERE (`users`.`id` < 9)" {
//		t.Errorf("invalid sql")
//	}
//}
<commit_msg>removed unnecessary test<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 AlexRuzin (stan.ruzin@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package govfs

import (
    "testing"
    "time"
    "os"
)

const FS_DATABASE_FILE string = "test_db"

func TestIOSanity(t *testing.T) {
    out("[+] Running Standard I/O Sanity Test...")

    /* Remove the test database if it exists */
    if _, err := os.Stat(FS_DATABASE_FILE); os.IsExist(err) {
        os.Remove(FS_DATABASE_FILE)
    }

    var raw_fs_file *string
    *raw_fs_file = FS_DATABASE_FILE
    var header = create_db(raw_fs_file)
    if header == nil {
        drive_fail("TEST1: Failed to obtain header", t)
    }
    out("[+] Test 1 PASS")

    // The root file "/" must at least exist
    if file, err := header.create("/"); file != nil && err == nil {
        drive_fail("TEST2: Failed to return root handle", t)
    }
    out("[+] Test 2 PASS")

    /*
     * Try to delete the root file "/"
     */
    if header.delete("/") == nil {
        drive_fail("TEST3: Cannot delete root -- critical", t)
    }
    out("[+] Test 3 PASS")

    /*
     * Attempt to write to a nonexistant file
     */
    var data = []byte{ 1, 2 }
    if header.write("/folder5/folder5/file5", data) == nil {
        drive_fail("TEST4: Cannot write to a nonexistant file", t)
    }
    out("[+] Test 4 PASS")

    /*
     * Create empty file file9
     */
    if file, err := header.create("/folder5/folder4/folder2/file9"); file == nil || err != nil {
        drive_fail("TEST4.1: file9 cannot be created", t)
    }
    out("[+] Test 4.1 PASS")

    /*
     * Attempt to create a new file0
     */
    if file, err := header.create("/folder0/folder0/file0"); file == nil || err != nil {
        drive_fail("TEST5.0: file0 cannot be created", t)
    }
    out("[+] Test 5.0 PASS")

    /*
     * Attempt to create a new file0, this will fail since it should already exist
     */
    if file, err := header.create("/folder0/folder0/file0"); file != nil && err == nil {
        drive_fail("TEST5.1: file0 cannot be created twice", t)
    }
    out("[+] Test 5.1 PASS")

    /*
     * Write some data into file0
     */
    data = []byte{ 1, 2, 3, 4 }
    if header.write("/folder0/folder0/file0", data) == nil {
        drive_fail("TEST6: Failed to write data in file0", t)
    }
    out("[+] Test 6 PASS")

    /*
     * Check that the size of file0 is 4
     */
    if k, _ := header.get_file_size("/folder0/folder0/file0"); k != uint(len(data)) {
        drive_fail("TEST6.1: The size of data does not match", t)
    }
    out("[+] Test 6.1 PASS")

    /*
     * Attempt to create a new file3
     */
    if file, err := header.create("/folder1/folder0/file3"); file == nil || err != nil {
        drive_fail("TEST7: file3 cannot be created", t)
    }
    out("[+] Test 7 PASS")

    /*
     * Write some data into file3
     */
    var data2 = []byte{ 1, 2, 3, 4, 5, 6, 7 }
    if header.write("/folder1/folder0/file3", data2) == nil {
        drive_fail("TEST8: Failed to write data in file3", t)
    }
    out("[+] Test 8 PASS")

    /*
     * Write some data into file3
     */
    if header.write("/folder1/folder0/file3", data2) == nil{
        drive_fail("TEST8.1: Failed to write data in file3", t)
    }
    out("[+] Test 8.1 PASS")

    /*
     * Read the written data from file0 and compare
     */
    output_data, _ := header.read("/folder0/folder0/file0")
    if output_data == nil || len(output_data) != len(data) || header.t_size - 7 /* len(file3) */ != uint(len(data)) {
        drive_fail("TEST9: Failed to read data from file0", t)
    }
    out("[+] Test 9 PASS")

    /*
     * Read the written data from file3 and compare
     */
    output_data, _ = header.read("/folder1/folder0/file3")
    if output_data == nil || len(output_data) != len(data2) || header.t_size - 4 /* len(file0) */ != uint(len(data2)) {
        drive_fail("TEST10: Failed to read data from file3", t)
    }
    out("[+] Test 10 PASS")

    /*
     * Write other data to file0
     */
    data = []byte{ 1, 2, 3 }
    if header.write("/folder0/folder0/file0", data) == nil {
        drive_fail("TEST11: Failed to write data in file1", t)
    }
    out("[+] Test 11 PASS")

    /*
     * Read the new data from file0
     */
    output_data, _ = header.read("/folder0/folder0/file0")
    if output_data == nil || len(output_data) != len(data) {
        drive_fail("TEST12: Failed to read data from file1", t)
    }
    out("[+] Test 12 PASS")

    /*
     * Attempt to create a new file5. This will be a blank file
     */
    if file, err := header.create("/folder2/file7"); file == nil || err != nil {
        drive_fail("TEST13: file3 cannot be created", t)
    }
    out("[+] Test 13 PASS")

    /*
     * Delete file0 -- complete this
     */
    // FIXME/ADDME

    /*
     * Create just a folder
     */
    if file, err := header.create("/folder2/file5/"); file == nil || err != nil {
        drive_fail("TEST15: folder file5 cannot be created", t)
    }
    out("[+] Test 15 PASS")

    /*
     * Print out files
     */
    file_list := header.get_file_list()
    for _, e := range file_list {
        out(e)
    }

    /*
     * Unmount/commit database to file
     */
    if header.unmount_db() == nil {
        drive_fail("TEST16: Failed to commit database", t)
    }
    out("[+] Test 16 PASS")

    time.Sleep(10000)
}

func TestFSReader(t *testing.T) {
    /*
     * Read in FS_DATABASE_FILE and do basic tests
     */

}

func drive_fail(output string, t *testing.T) {
    t.Errorf(output)
    t.FailNow()
}
<commit_msg>Fixed the test files to compensate for the new 'errors' handling<commit_after>/*
 * Copyright (c) 2017 AlexRuzin (stan.ruzin@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package govfs

import (
    "testing"
    "time"
    "os"
)

const FS_DATABASE_FILE string = "test_db"

func TestIOSanity(t *testing.T) {
    out("[+] Running Standard I/O Sanity Test...")

    /* Remove the test database if it exists */
    if _, err := os.Stat(FS_DATABASE_FILE); os.IsExist(err) {
        os.Remove(FS_DATABASE_FILE)
    }

    var raw_fs_file string
    raw_fs_file = FS_DATABASE_FILE
    var header = create_db(&raw_fs_file)
    if header == nil {
        drive_fail("TEST1: Failed to obtain header", t)
    }
    out("[+] Test 1 PASS")

    // The root file "/" must at least exist
    if file, err := header.create("/"); file != nil && err == nil {
        drive_fail("TEST2: Failed to return root handle", t)
    }
    out("[+] Test 2 PASS")

    /*
     * Try to delete the root file "/"
     */
    if header.delete("/") == nil {
        drive_fail("TEST3: Cannot delete root -- critical", t)
    }
    out("[+] Test 3 PASS")

    /*
     * Attempt to write to a nonexistant file
     */
    var data = []byte{ 1, 2 }
    if header.write("/folder5/folder5/file5", data) == nil {
        drive_fail("TEST4: Cannot write to a nonexistant file", t)
    }
    out("[+] Test 4 PASS")

    /*
     * Create empty file file9
     */
    if file, err := header.create("/folder5/folder4/folder2/file9"); file == nil || err != nil {
        drive_fail("TEST4.1: file9 cannot be created", t)
    }
    out("[+] Test 4.1 PASS")

    /*
     * Attempt to create a new file0
     */
    if file, err := header.create("/folder0/folder0/file0"); file == nil || err != nil {
        drive_fail("TEST5.0: file0 cannot be created", t)
    }
    out("[+] Test 5.0 PASS")

    /*
     * Attempt to create a new file0, this will fail since it should already exist
     */
    if file, err := header.create("/folder0/folder0/file0"); file != nil && err == nil {
        drive_fail("TEST5.1: file0 cannot be created twice", t)
    }
    out("[+] Test 5.1 PASS")

    /*
     * Write some data into file0
     */
    data = []byte{ 1, 2, 3, 4 }
    if header.write("/folder0/folder0/file0", data) != nil {
        drive_fail("TEST6: Failed to write data in file0", t)
    }
    out("[+] Test 6 PASS")

    /*
     * Check that the size of file0 is 4
     */
    if k, _ := header.get_file_size("/folder0/folder0/file0"); k != uint(len(data)) {
        drive_fail("TEST6.1: The size of data does not match", t)
    }
    out("[+] Test 6.1 PASS")

    /*
     * Attempt to create a new file3
     */
    if file, err := header.create("/folder1/folder0/file3"); file == nil || err != nil {
        drive_fail("TEST7: file3 cannot be created", t)
    }
    out("[+] Test 7 PASS")

    /*
     * Write some data into file3
     */
    var data2 = []byte{ 1, 2, 3, 4, 5, 6, 7 }
    if header.write("/folder1/folder0/file3", data2) != nil {
        drive_fail("TEST8: Failed to write data in file3", t)
    }
    out("[+] Test 8 PASS")

    /*
     * Write some data into file3
     */
    if header.write("/folder1/folder0/file3", data2) != nil {
        drive_fail("TEST8.1: Failed to write data in file3", t)
    }
    out("[+] Test 8.1 PASS")

    /*
     * Read the written data from file0 and compare
     */
    output_data, _ := header.read("/folder0/folder0/file0")
    if output_data == nil || len(output_data) != len(data) || header.t_size - 7 /* len(file3) */ != uint(len(data)) {
        drive_fail("TEST9: Failed to read data from file0", t)
    }
    out("[+] Test 9 PASS")

    /*
     * Read the written data from file3 and compare
     */
    output_data, _ = header.read("/folder1/folder0/file3")
    if output_data == nil || len(output_data) != len(data2) || header.t_size - 4 /* len(file0) */ != uint(len(data2)) {
        drive_fail("TEST10: Failed to read data from file3", t)
    }
    out("[+] Test 10 PASS")

    /*
     * Write other data to file0
     */
    data = []byte{ 1, 2, 3 }
    if header.write("/folder0/folder0/file0", data) != nil {
        drive_fail("TEST11: Failed to write data in file1", t)
    }
    out("[+] Test 11 PASS")

    /*
     * Read the new data from file0
     */
    output_data, _ = header.read("/folder0/folder0/file0")
    if output_data == nil || len(output_data) != len(data) {
        drive_fail("TEST12: Failed to read data from file1", t)
    }
    out("[+] Test 12 PASS")

    /*
     * Attempt to create a new file5. This will be a blank file
     */
    if file, err := header.create("/folder2/file7"); file == nil || err != nil {
        drive_fail("TEST13: file3 cannot be created", t)
    }
    out("[+] Test 13 PASS")

    /*
     * Delete file0 -- complete this
     */
    // FIXME/ADDME

    /*
     * Create just a folder
     */
    if file, err := header.create("/folder2/file5/"); file == nil || err != nil {
        drive_fail("TEST15: folder file5 cannot be created", t)
    }
    out("[+] Test 15 PASS")

    /*
     * Print out files
     */
    file_list := header.get_file_list()
    for _, e := range file_list {
        out(e)
    }

    /*
     * Unmount/commit database to file
     */
    if header.unmount_db() == nil {
        drive_fail("TEST16: Failed to commit database", t)
    }
    out("[+] Test 16 PASS")

    time.Sleep(10000)
}

func TestFSReader(t *testing.T) {
    /*
     * Read in FS_DATABASE_FILE and do basic tests
     */

}

func drive_fail(output string, t *testing.T) {
    t.Errorf(output)
    t.FailNow()
}
<|endoftext|>


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

package sdb

import (
	"fmt"
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/exp/sdb/conn"
	"github.com/jacobsa/aws/time"
	"net/url"
	"regexp"
)

// A regexp for valid domain names.
//
// Reference:
//     http://goo.gl/Kkbnf
var domainNameRe = regexp.MustCompile(`^[-a-zA-Z0-9_.]{3,255}$`)

// The name of an item within a SimpleDB domain. Item names must be UTF-8
// strings no longer than 1024 bytes. They must contain only characters that
// are valid in XML 1.0 documents, as defined by Section 2.2 of the XML 1.0
// spec. (Note that this is a more restrictive condition than imposed by
// SimpleDB itself, and is done for the sake of Go's XML 1.0 parser.)
//
// For more info:
//
//     http://goo.gl/Fkjnz
//     http://goo.gl/csem8
//
type ItemName string

// An attribute is a (name, value) pair possessed by an item. Items contain
// sets of attributes; they may contain multiple attributes with the same name,
// but not with the same (name, value) pair.
//
// Attribute names and values share the same restrictions as those on item
// names.
type Attribute struct {
	Name  string
	Value string
}

// SimpleDB represents an authenticated connection to a particular endpoint the
// SimpleDB service.
type SimpleDB interface {
	// Ensure that the domain with the specified name exists, then return it.
	OpenDomain(name string) (Domain, error)

	// Remove the supplied domain from the DB. Any domains previously opened with
	// this domain's name will no longer be valid. It is not an error to call
	// this method for a domain that has already been deleted.
	DeleteDomain(d Domain) error

	// Retrieve a set of items and their attributes based on a query string.
	//
	// constistentRead specifies whether completely fresh data is needed or not.
	//
	// If the selected result set is too large, a "next token" will be returned.
	// It can be passed to the Select method to resume where the previous result
	// set left off. For the initial query, use nil.
	//
	// For more info:
	//
	//     http://goo.gl/GTsSZ
	//
	Select(
		query string,
		constistentRead bool,
		nextToken []byte) (res map[ItemName][]Attribute, tok []byte, err error)
}

// Return a SimpleDB connection tied to the given region, using the sipplied
// access key to authenticate requests.
func NewSimpleDB(region Region, key aws.AccessKey) (db SimpleDB, err error) {
	// Open an appropriate HTTP connection.
	endpoint := &url.URL{
		Scheme: "https",
		Host: string(region),
	}

	httpConn, err := conn.NewHttpConn(endpoint)
	if err != nil {
		err = fmt.Errorf("Opening HTTP connection: %v", err)
		return
	}

	// Create a request signer.
	signer, err := conn.NewSigner(key, endpoint.Host)
	if err != nil {
		err = fmt.Errorf("Creating signer: %v", err)
		return
	}

	// Create a connection to the server.
	c, err := conn.NewConn(key, httpConn, signer, time.RealClock())
	if err != nil {
		err = fmt.Errorf("Creating connection: %v", err)
		return
	}

	return newSimpleDB(c)
}

// Create a SimpleDB with the supplied underlying connection.
func newSimpleDB(c conn.Conn) (SimpleDB, error) {
	return &simpleDB{c}, nil
}

type simpleDB struct {
	c conn.Conn
}

func (db *simpleDB) OpenDomain(name string) (d Domain, err error) {
	// Make sure the requested name is legal.
	if !domainNameRe.MatchString(name) {
		err = fmt.Errorf("Illegal domain name: %s", name)
		return
	}

	// Build a request.
	req := conn.Request{}
	req["DomainName"] = name

	// Call the connection.
	if _, err = db.c.SendRequest(req); err != nil {
		err = fmt.Errorf("SendRequest: %v", err)
		return
	}

	// Create the object.
	return newDomain(name, db.c)
}

func (db *simpleDB) DeleteDomain(d Domain) (err error) {
	err = fmt.Errorf("TODO")
	return
}
<commit_msg>Implemented DeleteDomain.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sdb

import (
	"fmt"
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/exp/sdb/conn"
	"github.com/jacobsa/aws/time"
	"net/url"
	"regexp"
)

// A regexp for valid domain names.
//
// Reference:
//     http://goo.gl/Kkbnf
var domainNameRe = regexp.MustCompile(`^[-a-zA-Z0-9_.]{3,255}$`)

// The name of an item within a SimpleDB domain. Item names must be UTF-8
// strings no longer than 1024 bytes. They must contain only characters that
// are valid in XML 1.0 documents, as defined by Section 2.2 of the XML 1.0
// spec. (Note that this is a more restrictive condition than imposed by
// SimpleDB itself, and is done for the sake of Go's XML 1.0 parser.)
//
// For more info:
//
//     http://goo.gl/Fkjnz
//     http://goo.gl/csem8
//
type ItemName string

// An attribute is a (name, value) pair possessed by an item. Items contain
// sets of attributes; they may contain multiple attributes with the same name,
// but not with the same (name, value) pair.
//
// Attribute names and values share the same restrictions as those on item
// names.
type Attribute struct {
	Name  string
	Value string
}

// SimpleDB represents an authenticated connection to a particular endpoint the
// SimpleDB service.
type SimpleDB interface {
	// Ensure that the domain with the specified name exists, then return it.
	OpenDomain(name string) (Domain, error)

	// Remove the supplied domain from the DB. Any domains previously opened with
	// this domain's name will no longer be valid. It is not an error to call
	// this method for a domain that has already been deleted.
	DeleteDomain(d Domain) error

	// Retrieve a set of items and their attributes based on a query string.
	//
	// constistentRead specifies whether completely fresh data is needed or not.
	//
	// If the selected result set is too large, a "next token" will be returned.
	// It can be passed to the Select method to resume where the previous result
	// set left off. For the initial query, use nil.
	//
	// For more info:
	//
	//     http://goo.gl/GTsSZ
	//
	Select(
		query string,
		constistentRead bool,
		nextToken []byte) (res map[ItemName][]Attribute, tok []byte, err error)
}

// Return a SimpleDB connection tied to the given region, using the sipplied
// access key to authenticate requests.
func NewSimpleDB(region Region, key aws.AccessKey) (db SimpleDB, err error) {
	// Open an appropriate HTTP connection.
	endpoint := &url.URL{
		Scheme: "https",
		Host: string(region),
	}

	httpConn, err := conn.NewHttpConn(endpoint)
	if err != nil {
		err = fmt.Errorf("Opening HTTP connection: %v", err)
		return
	}

	// Create a request signer.
	signer, err := conn.NewSigner(key, endpoint.Host)
	if err != nil {
		err = fmt.Errorf("Creating signer: %v", err)
		return
	}

	// Create a connection to the server.
	c, err := conn.NewConn(key, httpConn, signer, time.RealClock())
	if err != nil {
		err = fmt.Errorf("Creating connection: %v", err)
		return
	}

	return newSimpleDB(c)
}

// Create a SimpleDB with the supplied underlying connection.
func newSimpleDB(c conn.Conn) (SimpleDB, error) {
	return &simpleDB{c}, nil
}

type simpleDB struct {
	c conn.Conn
}

func (db *simpleDB) OpenDomain(name string) (d Domain, err error) {
	// Make sure the requested name is legal.
	if !domainNameRe.MatchString(name) {
		err = fmt.Errorf("Illegal domain name: %s", name)
		return
	}

	// Build a request.
	req := conn.Request{}
	req["DomainName"] = name

	// Call the connection.
	if _, err = db.c.SendRequest(req); err != nil {
		err = fmt.Errorf("SendRequest: %v", err)
		return
	}

	// Create the object.
	return newDomain(name, db.c)
}

func (db *simpleDB) DeleteDomain(d Domain) (err error) {
	// Build a request.
	req := conn.Request{}
	req["DomainName"] = d.Name()

	// Call the connection.
	if _, err = db.c.SendRequest(req); err != nil {
		err = fmt.Errorf("SendRequest: %v", err)
		return
	}

	return
}
<|endoftext|>


<commit_before>package data

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"strings"
)

type Builder interface {
	Build(raw []byte) (interface{}, *DataError)
}

type TypeBuilder struct{}

func NewTypeBuilder() Builder {
	return &TypeBuilder{}
}

func (this *TypeBuilder) Build(raw []byte) (interface{}, *DataError) {

	const (
		type_field        = "type"
		basal_type        = "basal"
		device_event_type = "deviceevent"
	)

	var data map[string]interface{}

	//d := json.NewDecoder(strings.NewReader(string(raw))).Decode(v)
	//d.UseNumber()

	if err := json.NewDecoder(strings.NewReader(string(raw))).Decode(&data); err != nil {
		log.Println("error doing an unmarshal", err.Error())
		e := NewDataError(data)
		e.AppendError(errors.New(fmt.Sprintf("sorry but we do anything with %s", string(raw))))
		return nil, e
	}

	if data[type_field] != nil {

		if strings.ToLower(data[type_field].(string)) == basal_type {
			return BuildBasal(data)
		} else if strings.ToLower(data[type_field].(string)) == device_event_type {
			return BuildDeviceEvent(data)
		}
		e := NewDataError(data)
		e.AppendError(errors.New(fmt.Sprintf("we can't deal with `type`=%s", data[type_field].(string))))
		return nil, e
	}

	e := NewDataError(data)
	e.AppendError(errors.New("there is no match for that type"))

	return nil, e

}
<commit_msg>cleanup<commit_after>package data

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"strings"
)

type Builder interface {
	Build(raw []byte) (interface{}, *DataError)
}

type TypeBuilder struct{}

func NewTypeBuilder() Builder {
	return &TypeBuilder{}
}

func (this *TypeBuilder) Build(raw []byte) (interface{}, *DataError) {

	const (
		type_field        = "type"
		basal_type        = "basal"
		device_event_type = "deviceevent"
	)

	var data map[string]interface{}

	if err := json.NewDecoder(strings.NewReader(string(raw))).Decode(&data); err != nil {
		log.Println("error doing an unmarshal", err.Error())
		e := NewDataError(data)
		e.AppendError(errors.New(fmt.Sprintf("sorry but we do anything with %s", string(raw))))
		return nil, e
	}

	if data[type_field] != nil {

		if strings.ToLower(data[type_field].(string)) == basal_type {
			return BuildBasal(data)
		} else if strings.ToLower(data[type_field].(string)) == device_event_type {
			return BuildDeviceEvent(data)
		}
		e := NewDataError(data)
		e.AppendError(errors.New(fmt.Sprintf("we can't deal with `type`=%s", data[type_field].(string))))
		return nil, e
	}

	e := NewDataError(data)
	e.AppendError(errors.New("there is no match for that type"))

	return nil, e

}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/terraform"
	"google.golang.org/api/compute/v1"
)

func TestAccComputeImage_withLicense(t *testing.T) {
	t.Parallel()

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeImageDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccComputeImage_license("image-test-" + randString(t, 10)),
			},
			{
				ResourceName:      "google_compute_image.foobar",
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccComputeImage_update(t *testing.T) {
	t.Parallel()

	var image compute.Image

	name := "image-test-" + randString(t, 10)
	// Only labels supports an update
	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeImageDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccComputeImage_basic(name),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeImageExists(
						t, "google_compute_image.foobar", &image),
					testAccCheckComputeImageContainsLabel(&image, "my-label", "my-label-value"),
					testAccCheckComputeImageContainsLabel(&image, "empty-label", ""),
					testAccCheckComputeImageHasComputedFingerprint(&image, "google_compute_image.foobar"),
				),
			},
			{
				Config: testAccComputeImage_update(name),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeImageExists(
						t, "google_compute_image.foobar", &image),
					testAccCheckComputeImageDoesNotContainLabel(&image, "my-label"),
					testAccCheckComputeImageContainsLabel(&image, "empty-label", "oh-look-theres-a-label-now"),
					testAccCheckComputeImageContainsLabel(&image, "new-field", "only-shows-up-when-updated"),
					testAccCheckComputeImageHasComputedFingerprint(&image, "google_compute_image.foobar"),
				),
			},
			{
				ResourceName:            "google_compute_image.foobar",
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"raw_disk"},
			},
		},
	})
}

func TestAccComputeImage_basedondisk(t *testing.T) {
	t.Parallel()

	var image compute.Image

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeImageDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccComputeImage_basedondisk(randString(t, 10), randString(t, 10)),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeImageExists(
						t, "google_compute_image.foobar", &image),
					testAccCheckComputeImageHasSourceDisk(&image),
				),
			},
			{
				ResourceName:      "google_compute_image.foobar",
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckComputeImageExists(t *testing.T, n string, image *compute.Image) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.Attributes["name"] == "" {
			return fmt.Errorf("No name is set")
		}

		config := googleProviderConfig(t)

		found, err := config.clientCompute.Images.Get(
			config.Project, rs.Primary.Attributes["name"]).Do()
		if err != nil {
			return err
		}

		if found.Name != rs.Primary.Attributes["name"] {
			return fmt.Errorf("Image not found")
		}

		*image = *found

		return nil
	}
}

func TestAccComputeImage_resolveImage(t *testing.T) {
	t.Parallel()

	var image compute.Image
	rand := randString(t, 10)
	name := fmt.Sprintf("test-image-%s", rand)
	fam := fmt.Sprintf("test-image-family-%s", rand)

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeImageDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccComputeImage_resolving(name, fam),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeImageExists(
						t, "google_compute_image.foobar", &image),
					testAccCheckComputeImageResolution(t, "google_compute_image.foobar"),
				),
			},
		},
	})
}

func testAccCheckComputeImageResolution(t *testing.T, n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		config := googleProviderConfig(t)
		project := config.Project

		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Resource not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}
		if rs.Primary.Attributes["name"] == "" {
			return fmt.Errorf("No image name is set")
		}
		if rs.Primary.Attributes["family"] == "" {
			return fmt.Errorf("No image family is set")
		}
		if rs.Primary.Attributes["self_link"] == "" {
			return fmt.Errorf("No self_link is set")
		}

		name := rs.Primary.Attributes["name"]
		family := rs.Primary.Attributes["family"]
		link := rs.Primary.Attributes["self_link"]

		latestDebian, err := config.clientCompute.Images.GetFromFamily("debian-cloud", "debian-9").Do()
		if err != nil {
			return fmt.Errorf("Error retrieving latest debian: %s", err)
		}

		images := map[string]string{
			"family/" + latestDebian.Family:                            "projects/debian-cloud/global/images/family/" + latestDebian.Family,
			"projects/debian-cloud/global/images/" + latestDebian.Name: "projects/debian-cloud/global/images/" + latestDebian.Name,
			latestDebian.Family:                                        "projects/debian-cloud/global/images/family/" + latestDebian.Family,
			latestDebian.Name:                                          "projects/debian-cloud/global/images/" + latestDebian.Name,
			latestDebian.SelfLink:                                      latestDebian.SelfLink,

			"global/images/" + name:          "global/images/" + name,
			"global/images/family/" + family: "global/images/family/" + family,
			name:                             "global/images/" + name,
			family:                           "global/images/family/" + family,
			"family/" + family:               "global/images/family/" + family,
			project + "/" + name:             "projects/" + project + "/global/images/" + name,
			project + "/" + family:           "projects/" + project + "/global/images/family/" + family,
			link:                             link,
		}

		for input, expectation := range images {
			result, err := resolveImage(config, project, input)
			if err != nil {
				return fmt.Errorf("Error resolving input %s to image: %+v\n", input, err)
			}
			if result != expectation {
				return fmt.Errorf("Expected input '%s' to resolve to '%s', it resolved to '%s' instead.\n", input, expectation, result)
			}
		}
		return nil
	}
}

func testAccCheckComputeImageContainsLabel(image *compute.Image, key string, value string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		v, ok := image.Labels[key]
		if !ok {
			return fmt.Errorf("Expected label with key '%s' not found", key)
		}
		if v != value {
			return fmt.Errorf("Incorrect label value for key '%s': expected '%s' but found '%s'", key, value, v)
		}
		return nil
	}
}

func testAccCheckComputeImageDoesNotContainLabel(image *compute.Image, key string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if v, ok := image.Labels[key]; ok {
			return fmt.Errorf("Expected no label for key '%s' but found one with value '%s'", key, v)
		}

		return nil
	}
}

func testAccCheckComputeImageHasComputedFingerprint(image *compute.Image, resource string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		// First ensure we actually have a fingerprint
		if image.LabelFingerprint == "" {
			return fmt.Errorf("No fingerprint set in API read result")
		}

		state := s.RootModule().Resources[resource]
		if state == nil {
			return fmt.Errorf("Unable to find resource named %s in resources", resource)
		}

		storedFingerprint := state.Primary.Attributes["label_fingerprint"]
		if storedFingerprint != image.LabelFingerprint {
			return fmt.Errorf("Stored fingerprint doesn't match fingerprint found on server; stored '%s', server '%s'",
				storedFingerprint, image.LabelFingerprint)
		}

		return nil
	}
}

func testAccCheckComputeImageHasSourceDisk(image *compute.Image) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if image.SourceType == "" {
			return fmt.Errorf("No source disk")
		}
		return nil
	}
}

func testAccComputeImage_resolving(name, family string) string {
	return fmt.Sprintf(`
data "google_compute_image" "my_image" {
  family  = "debian-9"
  project = "debian-cloud"
}

resource "google_compute_disk" "foobar" {
  name  = "%s"
  zone  = "us-central1-a"
  image = data.google_compute_image.my_image.self_link
}

resource "google_compute_image" "foobar" {
  name        = "%s"
  family      = "%s"
  source_disk = google_compute_disk.foobar.self_link
}
`, name, name, family)
}

func testAccComputeImage_basic(name string) string {
	return fmt.Sprintf(`
resource "google_compute_image" "foobar" {
  name        = "%s"
  description = "description-test"
  family      = "family-test"
  raw_disk {
    source = "https://storage.googleapis.com/bosh-cpi-artifacts/bosh-stemcell-3262.4-google-kvm-ubuntu-trusty-go_agent-raw.tar.gz"
  }
  labels = {
    my-label    = "my-label-value"
    empty-label = ""
  }
}
`, name)
}

func testAccComputeImage_license(name string) string {
	return fmt.Sprintf(`
data "google_compute_image" "my_image" {
  family  = "debian-9"
  project = "debian-cloud"
}

resource "google_compute_disk" "foobar" {
  name  = "disk-test-%s"
  zone  = "us-central1-a"
  image = data.google_compute_image.my_image.self_link
}

resource "google_compute_image" "foobar" {
  name        = "%s"
  description = "description-test"
  source_disk = google_compute_disk.foobar.self_link

  labels = {
    my-label    = "my-label-value"
    empty-label = ""
  }
  licenses = [
    "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/licenses/debian-9-stretch",
  ]
}
`, name, name)
}

func testAccComputeImage_update(name string) string {
	return fmt.Sprintf(`
resource "google_compute_image" "foobar" {
  name        = "%s"
  description = "description-test"
  family      = "family-test"
  raw_disk {
    source = "https://storage.googleapis.com/bosh-cpi-artifacts/bosh-stemcell-3262.4-google-kvm-ubuntu-trusty-go_agent-raw.tar.gz"
  }
  labels = {
    empty-label = "oh-look-theres-a-label-now"
    new-field   = "only-shows-up-when-updated"
  }
}
`, name)
}

func testAccComputeImage_basedondisk(diskName, imageName string) string {
	return fmt.Sprintf(`
data "google_compute_image" "my_image" {
  family  = "debian-9"
  project = "debian-cloud"
}

resource "google_compute_disk" "foobar" {
  name  = "disk-test-%s"
  zone  = "us-central1-a"
  image = data.google_compute_image.my_image.self_link
}

resource "google_compute_image" "foobar" {
  name        = "image-test-%s"
  source_disk = google_compute_disk.foobar.self_link
}
`, diskName, imageName)
}
<commit_msg>Remove fingerprint check from Image test (#3773)<commit_after>package google

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/terraform"
	"google.golang.org/api/compute/v1"
)

func TestAccComputeImage_withLicense(t *testing.T) {
	t.Parallel()

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeImageDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccComputeImage_license("image-test-" + randString(t, 10)),
			},
			{
				ResourceName:      "google_compute_image.foobar",
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccComputeImage_update(t *testing.T) {
	t.Parallel()

	var image compute.Image

	name := "image-test-" + randString(t, 10)
	// Only labels supports an update
	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeImageDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccComputeImage_basic(name),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeImageExists(
						t, "google_compute_image.foobar", &image),
					testAccCheckComputeImageContainsLabel(&image, "my-label", "my-label-value"),
					testAccCheckComputeImageContainsLabel(&image, "empty-label", ""),
				),
			},
			{
				Config: testAccComputeImage_update(name),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeImageExists(
						t, "google_compute_image.foobar", &image),
					testAccCheckComputeImageDoesNotContainLabel(&image, "my-label"),
					testAccCheckComputeImageContainsLabel(&image, "empty-label", "oh-look-theres-a-label-now"),
					testAccCheckComputeImageContainsLabel(&image, "new-field", "only-shows-up-when-updated"),
				),
			},
			{
				ResourceName:            "google_compute_image.foobar",
				ImportState:             true,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"raw_disk"},
			},
		},
	})
}

func TestAccComputeImage_basedondisk(t *testing.T) {
	t.Parallel()

	var image compute.Image

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeImageDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccComputeImage_basedondisk(randString(t, 10), randString(t, 10)),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeImageExists(
						t, "google_compute_image.foobar", &image),
					testAccCheckComputeImageHasSourceDisk(&image),
				),
			},
			{
				ResourceName:      "google_compute_image.foobar",
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckComputeImageExists(t *testing.T, n string, image *compute.Image) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.Attributes["name"] == "" {
			return fmt.Errorf("No name is set")
		}

		config := googleProviderConfig(t)

		found, err := config.clientCompute.Images.Get(
			config.Project, rs.Primary.Attributes["name"]).Do()
		if err != nil {
			return err
		}

		if found.Name != rs.Primary.Attributes["name"] {
			return fmt.Errorf("Image not found")
		}

		*image = *found

		return nil
	}
}

func TestAccComputeImage_resolveImage(t *testing.T) {
	t.Parallel()

	var image compute.Image
	rand := randString(t, 10)
	name := fmt.Sprintf("test-image-%s", rand)
	fam := fmt.Sprintf("test-image-family-%s", rand)

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeImageDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccComputeImage_resolving(name, fam),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeImageExists(
						t, "google_compute_image.foobar", &image),
					testAccCheckComputeImageResolution(t, "google_compute_image.foobar"),
				),
			},
		},
	})
}

func testAccCheckComputeImageResolution(t *testing.T, n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		config := googleProviderConfig(t)
		project := config.Project

		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Resource not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}
		if rs.Primary.Attributes["name"] == "" {
			return fmt.Errorf("No image name is set")
		}
		if rs.Primary.Attributes["family"] == "" {
			return fmt.Errorf("No image family is set")
		}
		if rs.Primary.Attributes["self_link"] == "" {
			return fmt.Errorf("No self_link is set")
		}

		name := rs.Primary.Attributes["name"]
		family := rs.Primary.Attributes["family"]
		link := rs.Primary.Attributes["self_link"]

		latestDebian, err := config.clientCompute.Images.GetFromFamily("debian-cloud", "debian-9").Do()
		if err != nil {
			return fmt.Errorf("Error retrieving latest debian: %s", err)
		}

		images := map[string]string{
			"family/" + latestDebian.Family:                            "projects/debian-cloud/global/images/family/" + latestDebian.Family,
			"projects/debian-cloud/global/images/" + latestDebian.Name: "projects/debian-cloud/global/images/" + latestDebian.Name,
			latestDebian.Family:                                        "projects/debian-cloud/global/images/family/" + latestDebian.Family,
			latestDebian.Name:                                          "projects/debian-cloud/global/images/" + latestDebian.Name,
			latestDebian.SelfLink:                                      latestDebian.SelfLink,

			"global/images/" + name:          "global/images/" + name,
			"global/images/family/" + family: "global/images/family/" + family,
			name:                             "global/images/" + name,
			family:                           "global/images/family/" + family,
			"family/" + family:               "global/images/family/" + family,
			project + "/" + name:             "projects/" + project + "/global/images/" + name,
			project + "/" + family:           "projects/" + project + "/global/images/family/" + family,
			link:                             link,
		}

		for input, expectation := range images {
			result, err := resolveImage(config, project, input)
			if err != nil {
				return fmt.Errorf("Error resolving input %s to image: %+v\n", input, err)
			}
			if result != expectation {
				return fmt.Errorf("Expected input '%s' to resolve to '%s', it resolved to '%s' instead.\n", input, expectation, result)
			}
		}
		return nil
	}
}

func testAccCheckComputeImageContainsLabel(image *compute.Image, key string, value string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		v, ok := image.Labels[key]
		if !ok {
			return fmt.Errorf("Expected label with key '%s' not found", key)
		}
		if v != value {
			return fmt.Errorf("Incorrect label value for key '%s': expected '%s' but found '%s'", key, value, v)
		}
		return nil
	}
}

func testAccCheckComputeImageDoesNotContainLabel(image *compute.Image, key string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if v, ok := image.Labels[key]; ok {
			return fmt.Errorf("Expected no label for key '%s' but found one with value '%s'", key, v)
		}

		return nil
	}
}

func testAccCheckComputeImageHasSourceDisk(image *compute.Image) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if image.SourceType == "" {
			return fmt.Errorf("No source disk")
		}
		return nil
	}
}

func testAccComputeImage_resolving(name, family string) string {
	return fmt.Sprintf(`
data "google_compute_image" "my_image" {
  family  = "debian-9"
  project = "debian-cloud"
}

resource "google_compute_disk" "foobar" {
  name  = "%s"
  zone  = "us-central1-a"
  image = data.google_compute_image.my_image.self_link
}

resource "google_compute_image" "foobar" {
  name        = "%s"
  family      = "%s"
  source_disk = google_compute_disk.foobar.self_link
}
`, name, name, family)
}

func testAccComputeImage_basic(name string) string {
	return fmt.Sprintf(`
resource "google_compute_image" "foobar" {
  name        = "%s"
  description = "description-test"
  family      = "family-test"
  raw_disk {
    source = "https://storage.googleapis.com/bosh-cpi-artifacts/bosh-stemcell-3262.4-google-kvm-ubuntu-trusty-go_agent-raw.tar.gz"
  }
  labels = {
    my-label    = "my-label-value"
    empty-label = ""
  }
}
`, name)
}

func testAccComputeImage_license(name string) string {
	return fmt.Sprintf(`
data "google_compute_image" "my_image" {
  family  = "debian-9"
  project = "debian-cloud"
}

resource "google_compute_disk" "foobar" {
  name  = "disk-test-%s"
  zone  = "us-central1-a"
  image = data.google_compute_image.my_image.self_link
}

resource "google_compute_image" "foobar" {
  name        = "%s"
  description = "description-test"
  source_disk = google_compute_disk.foobar.self_link

  labels = {
    my-label    = "my-label-value"
    empty-label = ""
  }
  licenses = [
    "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/licenses/debian-9-stretch",
  ]
}
`, name, name)
}

func testAccComputeImage_update(name string) string {
	return fmt.Sprintf(`
resource "google_compute_image" "foobar" {
  name        = "%s"
  description = "description-test"
  family      = "family-test"
  raw_disk {
    source = "https://storage.googleapis.com/bosh-cpi-artifacts/bosh-stemcell-3262.4-google-kvm-ubuntu-trusty-go_agent-raw.tar.gz"
  }
  labels = {
    empty-label = "oh-look-theres-a-label-now"
    new-field   = "only-shows-up-when-updated"
  }
}
`, name)
}

func testAccComputeImage_basedondisk(diskName, imageName string) string {
	return fmt.Sprintf(`
data "google_compute_image" "my_image" {
  family  = "debian-9"
  project = "debian-cloud"
}

resource "google_compute_disk" "foobar" {
  name  = "disk-test-%s"
  zone  = "us-central1-a"
  image = data.google_compute_image.my_image.self_link
}

resource "google_compute_image" "foobar" {
  name        = "image-test-%s"
  source_disk = google_compute_disk.foobar.self_link
}
`, diskName, imageName)
}
<|endoftext|>


<commit_before>package memstore

import (
	"sync"

	"github.com/pressly/chainstore/lrumgr"
)

type memStore struct {
	sync.Mutex
	data map[string][]byte
}

func New(capacity int64) *lrumgr.LruManager {
	memStore := &memStore{data: make(map[string][]byte, 1000)}
	store := lrumgr.New(capacity, memStore)
	return store
}

func (s *memStore) Open() (err error)  { return }
func (s *memStore) Close() (err error) { return }

func (s *memStore) Put(key string, val []byte) (err error) {
	s.Lock()
	s.data[key] = val
	s.Unlock()
	return nil
}

func (s *memStore) Get(key string) ([]byte, error) {
	s.Lock()
	val := s.data[key]
	s.Unlock()
	return val, nil
}

func (s *memStore) Del(key string) (err error) {
	s.Lock()
	delete(s.data, key)
	s.Unlock()
	return
}
<commit_msg>RWMutex in chainstore<commit_after>package memstore

import (
	"sync"

	"github.com/pressly/chainstore/lrumgr"
)

type memStore struct {
	sync.RWMutex
	data map[string][]byte
}

func New(capacity int64) *lrumgr.LruManager {
	memStore := &memStore{data: make(map[string][]byte, 1000)}
	store := lrumgr.New(capacity, memStore)
	return store
}

func (s *memStore) Open() (err error)  { return }
func (s *memStore) Close() (err error) { return }

func (s *memStore) Put(key string, val []byte) (err error) {
	s.Lock()
	s.data[key] = val
	s.Unlock()
	return nil
}

func (s *memStore) Get(key string) ([]byte, error) {
	s.RLock()
	val := s.data[key]
	s.RUnlock()
	return val, nil
}

func (s *memStore) Del(key string) (err error) {
	s.Lock()
	delete(s.data, key)
	s.Unlock()
	return
}
<|endoftext|>


<commit_before>// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// Package gredis provides convenient client for redis server.
//
// Redis Client.
//
// Redis Commands Official: https://redis.io/commands
//
// Redis Chinese Documentation: http://redisdoc.com/
package gredis

import (
	"fmt"
	"github.com/gogf/gf/util/gconv"
	"time"

	"github.com/gogf/gf/container/gmap"
	"github.com/gogf/gf/container/gvar"
	"github.com/gomodule/redigo/redis"
)

// Redis client.
type Redis struct {
	pool   *redis.Pool // Underlying connection pool.
	group  string      // Configuration group.
	config Config      // Configuration.
}

// Redis connection.
type Conn struct {
	redis.Conn
}

// Redis configuration.
type Config struct {
	Host            string
	Port            int
	Db              int
	Pass            string        // Password for AUTH.
	MaxIdle         int           // Maximum number of connections allowed to be idle (default is 10)
	MaxActive       int           // Maximum number of connections limit (default is 0 means no limit).
	IdleTimeout     time.Duration // Maximum idle time for connection (default is 10 seconds, not allowed to be set to 0)
	MaxConnLifetime time.Duration // Maximum lifetime of the connection (default is 30 seconds, not allowed to be set to 0)
	ConnectTimeout  time.Duration // Dial connection timeout.
	TLS				bool		  // Specifies the config to use when a TLS connection is dialed.
	TLSSkipVerify	bool		  // Disables server name verification when connecting over TLS
}

// Pool statistics.
type PoolStats struct {
	redis.PoolStats
}

const (
	gDEFAULT_POOL_IDLE_TIMEOUT  = 10 * time.Second
	gDEFAULT_POOL_CONN_TIMEOUT  = 10 * time.Second
	gDEFAULT_POOL_MAX_IDLE      = 10
	gDEFAULT_POOL_MAX_ACTIVE    = 100
	gDEFAULT_POOL_MAX_LIFE_TIME = 30 * time.Second
)

var (
	// Pool map.
	pools = gmap.NewStrAnyMap(true)
)

// New creates a redis client object with given configuration.
// Redis client maintains a connection pool automatically.
func New(config Config) *Redis {
	// The MaxIdle is the most important attribute of the connection pool.
	// Only if this attribute is set, the created connections from client
	// can not exceed the limit of the server.
	if config.MaxIdle == 0 {
		config.MaxIdle = gDEFAULT_POOL_MAX_IDLE
	}
	// This value SHOULD NOT exceed the connection limit of redis server.
	if config.MaxActive == 0 {
		config.MaxActive = gDEFAULT_POOL_MAX_ACTIVE
	}
	if config.IdleTimeout == 0 {
		config.IdleTimeout = gDEFAULT_POOL_IDLE_TIMEOUT
	}
	if config.ConnectTimeout == 0 {
		config.ConnectTimeout = gDEFAULT_POOL_CONN_TIMEOUT
	}
	if config.MaxConnLifetime == 0 {
		config.MaxConnLifetime = gDEFAULT_POOL_MAX_LIFE_TIME
	}
	return &Redis{
		config: config,
		pool: pools.GetOrSetFuncLock(fmt.Sprintf("%v", config), func() interface{} {
			return &redis.Pool{
				Wait:            true,
				IdleTimeout:     config.IdleTimeout,
				MaxActive:       config.MaxActive,
				MaxIdle:         config.MaxIdle,
				MaxConnLifetime: config.MaxConnLifetime,
				Dial: func() (redis.Conn, error) {
					c, err := redis.Dial(
						"tcp",
						fmt.Sprintf("%s:%d", config.Host, config.Port),
						redis.DialConnectTimeout(config.ConnectTimeout),
						redis.DialUseTLS(config.TLS),
						redis.DialTLSSkipVerify(config.TLSSkipVerify),
					)
					if err != nil {
						return nil, err
					}
					// AUTH
					if len(config.Pass) > 0 {
						if _, err := c.Do("AUTH", config.Pass); err != nil {
							return nil, err
						}
					}
					// DB
					if _, err := c.Do("SELECT", config.Db); err != nil {
						return nil, err
					}
					return c, nil
				},
				// After the conn is taken from the connection pool, to test if the connection is available,
				// If error is returned then it closes the connection object and recreate a new connection.
				TestOnBorrow: func(c redis.Conn, t time.Time) error {
					_, err := c.Do("PING")
					return err
				},
			}
		}).(*redis.Pool),
	}
}

// NewFromStr creates a redis client object with given configuration string.
// Redis client maintains a connection pool automatically.
// The parameter <str> like:
// 127.0.0.1:6379,0
// 127.0.0.1:6379,0,password
func NewFromStr(str string) (*Redis, error) {
	config, err := ConfigFromStr(str)
	if err != nil {
		return nil, err
	}
	return New(config), nil
}

// Close closes the redis connection pool,
// it will release all connections reserved by this pool.
// It is not necessary to call Close manually.
func (r *Redis) Close() error {
	if r.group != "" {
		// If it is an instance object,
		// it needs to remove it from the instance Map.
		instances.Remove(r.group)
	}
	pools.Remove(fmt.Sprintf("%v", r.config))
	return r.pool.Close()
}

// Conn returns a raw underlying connection object,
// which expose more methods to communicate with server.
// **You should call Close function manually if you do not use this connection any further.**
func (r *Redis) Conn() *Conn {
	return &Conn{r.pool.Get()}
}

// Alias of Conn, see Conn.
func (r *Redis) GetConn() *Conn {
	return r.Conn()
}

// SetMaxIdle sets the maximum number of idle connections in the pool.
func (r *Redis) SetMaxIdle(value int) {
	r.pool.MaxIdle = value
}

// SetMaxActive sets the maximum number of connections allocated by the pool at a given time.
// When zero, there is no limit on the number of connections in the pool.
//
// Note that if the pool is at the MaxActive limit, then all the operations will wait for
// a connection to be returned to the pool before returning.
func (r *Redis) SetMaxActive(value int) {
	r.pool.MaxActive = value
}

// SetIdleTimeout sets the IdleTimeout attribute of the connection pool.
// It closes connections after remaining idle for this duration. If the value
// is zero, then idle connections are not closed. Applications should set
// the timeout to a value less than the server's timeout.
func (r *Redis) SetIdleTimeout(value time.Duration) {
	r.pool.IdleTimeout = value
}

// SetMaxConnLifetime sets the MaxConnLifetime attribute of the connection pool.
// It closes connections older than this duration. If the value is zero, then
// the pool does not close connections based on age.
func (r *Redis) SetMaxConnLifetime(value time.Duration) {
	r.pool.MaxConnLifetime = value
}

// Stats returns pool's statistics.
func (r *Redis) Stats() *PoolStats {
	return &PoolStats{r.pool.Stats()}
}

// Do sends a command to the server and returns the received reply.
// Do automatically get a connection from pool, and close it when the reply received.
// It does not really "close" the connection, but drops it back to the connection pool.
func (r *Redis) Do(command string, args ...interface{}) (interface{}, error) {
	conn := &Conn{r.pool.Get()}
	defer conn.Close()
	return conn.Do(command, args...)
}

// DoVar returns value from Do as gvar.Var.
func (r *Redis) DoVar(command string, args ...interface{}) (*gvar.Var, error) {
	v, err := r.Do(command, args...)
	if result, ok := v.([]byte); ok {
		return gvar.New(gconv.UnsafeBytesToStr(result)), err
	}
	// It treats all returned slice as string slice.
	if result, ok := v.([]interface{}); ok {
		return gvar.New(gconv.Strings(result)), err
	}
	return gvar.New(v), err
}
<commit_msg>format code<commit_after>// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// Package gredis provides convenient client for redis server.
//
// Redis Client.
//
// Redis Commands Official: https://redis.io/commands
//
// Redis Chinese Documentation: http://redisdoc.com/
package gredis

import (
	"fmt"
	"github.com/gogf/gf/util/gconv"
	"time"

	"github.com/gogf/gf/container/gmap"
	"github.com/gogf/gf/container/gvar"
	"github.com/gomodule/redigo/redis"
)

// Redis client.
type Redis struct {
	pool   *redis.Pool // Underlying connection pool.
	group  string      // Configuration group.
	config Config      // Configuration.
}

// Redis connection.
type Conn struct {
	redis.Conn
}

// Redis configuration.
type Config struct {
	Host            string
	Port            int
	Db              int
	Pass            string        // Password for AUTH.
	MaxIdle         int           // Maximum number of connections allowed to be idle (default is 10)
	MaxActive       int           // Maximum number of connections limit (default is 0 means no limit).
	IdleTimeout     time.Duration // Maximum idle time for connection (default is 10 seconds, not allowed to be set to 0)
	MaxConnLifetime time.Duration // Maximum lifetime of the connection (default is 30 seconds, not allowed to be set to 0)
	ConnectTimeout  time.Duration // Dial connection timeout.
	TLS             bool          // Specifies the config to use when a TLS connection is dialed.
	TLSSkipVerify   bool          // Disables server name verification when connecting over TLS
}

// Pool statistics.
type PoolStats struct {
	redis.PoolStats
}

const (
	gDEFAULT_POOL_IDLE_TIMEOUT  = 10 * time.Second
	gDEFAULT_POOL_CONN_TIMEOUT  = 10 * time.Second
	gDEFAULT_POOL_MAX_IDLE      = 10
	gDEFAULT_POOL_MAX_ACTIVE    = 100
	gDEFAULT_POOL_MAX_LIFE_TIME = 30 * time.Second
)

var (
	// Pool map.
	pools = gmap.NewStrAnyMap(true)
)

// New creates a redis client object with given configuration.
// Redis client maintains a connection pool automatically.
func New(config Config) *Redis {
	// The MaxIdle is the most important attribute of the connection pool.
	// Only if this attribute is set, the created connections from client
	// can not exceed the limit of the server.
	if config.MaxIdle == 0 {
		config.MaxIdle = gDEFAULT_POOL_MAX_IDLE
	}
	// This value SHOULD NOT exceed the connection limit of redis server.
	if config.MaxActive == 0 {
		config.MaxActive = gDEFAULT_POOL_MAX_ACTIVE
	}
	if config.IdleTimeout == 0 {
		config.IdleTimeout = gDEFAULT_POOL_IDLE_TIMEOUT
	}
	if config.ConnectTimeout == 0 {
		config.ConnectTimeout = gDEFAULT_POOL_CONN_TIMEOUT
	}
	if config.MaxConnLifetime == 0 {
		config.MaxConnLifetime = gDEFAULT_POOL_MAX_LIFE_TIME
	}
	return &Redis{
		config: config,
		pool: pools.GetOrSetFuncLock(fmt.Sprintf("%v", config), func() interface{} {
			return &redis.Pool{
				Wait:            true,
				IdleTimeout:     config.IdleTimeout,
				MaxActive:       config.MaxActive,
				MaxIdle:         config.MaxIdle,
				MaxConnLifetime: config.MaxConnLifetime,
				Dial: func() (redis.Conn, error) {
					c, err := redis.Dial(
						"tcp",
						fmt.Sprintf("%s:%d", config.Host, config.Port),
						redis.DialConnectTimeout(config.ConnectTimeout),
						redis.DialUseTLS(config.TLS),
						redis.DialTLSSkipVerify(config.TLSSkipVerify),
					)
					if err != nil {
						return nil, err
					}
					// AUTH
					if len(config.Pass) > 0 {
						if _, err := c.Do("AUTH", config.Pass); err != nil {
							return nil, err
						}
					}
					// DB
					if _, err := c.Do("SELECT", config.Db); err != nil {
						return nil, err
					}
					return c, nil
				},
				// After the conn is taken from the connection pool, to test if the connection is available,
				// If error is returned then it closes the connection object and recreate a new connection.
				TestOnBorrow: func(c redis.Conn, t time.Time) error {
					_, err := c.Do("PING")
					return err
				},
			}
		}).(*redis.Pool),
	}
}

// NewFromStr creates a redis client object with given configuration string.
// Redis client maintains a connection pool automatically.
// The parameter <str> like:
// 127.0.0.1:6379,0
// 127.0.0.1:6379,0,password
func NewFromStr(str string) (*Redis, error) {
	config, err := ConfigFromStr(str)
	if err != nil {
		return nil, err
	}
	return New(config), nil
}

// Close closes the redis connection pool,
// it will release all connections reserved by this pool.
// It is not necessary to call Close manually.
func (r *Redis) Close() error {
	if r.group != "" {
		// If it is an instance object,
		// it needs to remove it from the instance Map.
		instances.Remove(r.group)
	}
	pools.Remove(fmt.Sprintf("%v", r.config))
	return r.pool.Close()
}

// Conn returns a raw underlying connection object,
// which expose more methods to communicate with server.
// **You should call Close function manually if you do not use this connection any further.**
func (r *Redis) Conn() *Conn {
	return &Conn{r.pool.Get()}
}

// Alias of Conn, see Conn.
func (r *Redis) GetConn() *Conn {
	return r.Conn()
}

// SetMaxIdle sets the maximum number of idle connections in the pool.
func (r *Redis) SetMaxIdle(value int) {
	r.pool.MaxIdle = value
}

// SetMaxActive sets the maximum number of connections allocated by the pool at a given time.
// When zero, there is no limit on the number of connections in the pool.
//
// Note that if the pool is at the MaxActive limit, then all the operations will wait for
// a connection to be returned to the pool before returning.
func (r *Redis) SetMaxActive(value int) {
	r.pool.MaxActive = value
}

// SetIdleTimeout sets the IdleTimeout attribute of the connection pool.
// It closes connections after remaining idle for this duration. If the value
// is zero, then idle connections are not closed. Applications should set
// the timeout to a value less than the server's timeout.
func (r *Redis) SetIdleTimeout(value time.Duration) {
	r.pool.IdleTimeout = value
}

// SetMaxConnLifetime sets the MaxConnLifetime attribute of the connection pool.
// It closes connections older than this duration. If the value is zero, then
// the pool does not close connections based on age.
func (r *Redis) SetMaxConnLifetime(value time.Duration) {
	r.pool.MaxConnLifetime = value
}

// Stats returns pool's statistics.
func (r *Redis) Stats() *PoolStats {
	return &PoolStats{r.pool.Stats()}
}

// Do sends a command to the server and returns the received reply.
// Do automatically get a connection from pool, and close it when the reply received.
// It does not really "close" the connection, but drops it back to the connection pool.
func (r *Redis) Do(command string, args ...interface{}) (interface{}, error) {
	conn := &Conn{r.pool.Get()}
	defer conn.Close()
	return conn.Do(command, args...)
}

// DoVar returns value from Do as gvar.Var.
func (r *Redis) DoVar(command string, args ...interface{}) (*gvar.Var, error) {
	v, err := r.Do(command, args...)
	if result, ok := v.([]byte); ok {
		return gvar.New(gconv.UnsafeBytesToStr(result)), err
	}
	// It treats all returned slice as string slice.
	if result, ok := v.([]interface{}); ok {
		return gvar.New(gconv.Strings(result)), err
	}
	return gvar.New(v), err
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Paul R. Tagliamonte, 2015
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE. */

package dictd

/* server.go - infrastructure code for the dictd server
 *
 * In particular, this file contains a few interfaces and commonly used
 * structs for message passing, as well as generic routing code. */

import (
	"errors"
)

/* Command is the encapsulation for a user's request of the Server. */
type Command struct {
	Command string
	Params  []string
}

/* Definition is the encapsulation of a response for a given Entry. */
type Definition struct {
	Word             string
	Definition       string
	DictDatabase     Database
	DictDatabaseName string
}

/* Database is an interface for external Database "Backends" to implement. */
type Database interface {

	/* Method to handle incoming `MATCH` commands. */
	Match(name string, query string, strat string) []*Definition

	/* Method to handle incoming `DEFINE` commands. */
	Define(name string, query string) []*Definition

	/* Method to handle incoming `SHOW INFO` commands. */
	Info(name string) string

	/* Method to return a one-line Description of the Database. */
	Description(name string) string
}

/* Server encapsulation.
 *
 * This contains a bundle of useful helpers, as well as a few data structures
 * to handle registered Databases and Commands. */
type Server struct {
	Name      string
	Info      string
	databases map[string]Database
	commands  map[string]func(*Session, Command)
}

/* Define a word against the server, according to fun rules! */
func (this *Server) Define(
	database string,
	query string,
) ([]*Definition, error) {

	switch database {
	case "!":
		for database, databaseBackend := range this.databases {
			defs := databaseBackend.Define(database, query)
			if defs != nil && len(defs) != 0 {
				return defs, nil
			}
		}
		return make([]*Definition, 0), nil
	case "*":
		var allDefs = make([]*Definition, 0)
		for database, databaseBackend := range this.databases {
			defs := databaseBackend.Define(database, query)
			allDefs = append(allDefs, defs...)
		}
		return allDefs, nil
	}

	db := this.GetDatabase(database)
	if db == nil {
		return nil, errors.New("No such database")
	}
	return db.Define(database, query), nil
}

/* Register dict.Database `database` under `name`. */
func (this *Server) RegisterDatabase(database Database, name string) {
	this.databases[name] = database
}

/* Get dict.Database that has been registered under `name`. */
func (this *Server) GetDatabase(name string) Database {
	if value, ok := this.databases[name]; ok {
		return value
	}
	return nil
}

/* Register a Command `handler` under name `name`. */
func (this *Server) RegisterHandler(
	name string,
	handler func(*Session, Command),
) {
	this.commands[name] = handler
}

/* Get a Command handler for the given dict.Command `command` */
func (this *Server) GetHandler(command *Command) func(*Session, Command) {
	name := command.Command

	if value, ok := this.commands[name]; ok {
		return value
	}
	return nil
}

/* Create a new server by name `name`. */
func NewServer(name string) Server {
	server := Server{
		Name:      name,
		Info:      "",
		commands:  map[string]func(*Session, Command){},
		databases: map[string]Database{},
	}
	registerDefaultHandlers(&server)
	return server
}
<commit_msg>Comment the Define routine<commit_after>/**
 * Copyright (c) Paul R. Tagliamonte, 2015
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE. */

package dictd

/* server.go - infrastructure code for the dictd server
 *
 * In particular, this file contains a few interfaces and commonly used
 * structs for message passing, as well as generic routing code. */

import (
	"errors"
)

/* Command is the encapsulation for a user's request of the Server. */
type Command struct {
	Command string
	Params  []string
}

/* Definition is the encapsulation of a response for a given Entry. */
type Definition struct {
	Word             string
	Definition       string
	DictDatabase     Database
	DictDatabaseName string
}

/* Database is an interface for external Database "Backends" to implement. */
type Database interface {

	/* Method to handle incoming `MATCH` commands. */
	Match(name string, query string, strat string) []*Definition

	/* Method to handle incoming `DEFINE` commands. */
	Define(name string, query string) []*Definition

	/* Method to handle incoming `SHOW INFO` commands. */
	Info(name string) string

	/* Method to return a one-line Description of the Database. */
	Description(name string) string
}

/* Server encapsulation.
 *
 * This contains a bundle of useful helpers, as well as a few data structures
 * to handle registered Databases and Commands. */
type Server struct {
	Name      string
	Info      string
	databases map[string]Database
	commands  map[string]func(*Session, Command)
}

/* Define a word against the server, according to fun rules! */
func (this *Server) Define(
	database string,
	query string,
) ([]*Definition, error) {

	/* Right, so we've been asked to figure out what a word is.
	 * The RFC has special handling based on the database name,
	 * so we're going to go ahead and figure out what we should
	 * be doing here. */

	switch database {
	case "!":
		/* The RFC states that we search all Databases for entries, and
		 * if we hit, we should return all Definitions for the given word
		 * for that Database. */
		for database, databaseBackend := range this.databases {
			defs := databaseBackend.Define(database, query)
			if defs != nil && len(defs) != 0 {
				return defs, nil
			}
		}
		return make([]*Definition, 0), nil

	case "*":
		/* The RFC states that we search all Databases for entries, and
		 * return *all* Definitions for the given word for all Databases. */
		var allDefs = make([]*Definition, 0)
		for database, databaseBackend := range this.databases {
			defs := databaseBackend.Define(database, query)
			allDefs = append(allDefs, defs...)
		}
		return allDefs, nil
	}

	/* Otherwise, let's go with the boring usual behavior -- try to get
	 * the database, and return defs for that one DB. */
	db := this.GetDatabase(database)
	if db == nil {
		return nil, errors.New("No such database")
	}
	return db.Define(database, query), nil
}

/* Register dict.Database `database` under `name`. */
func (this *Server) RegisterDatabase(database Database, name string) {
	this.databases[name] = database
}

/* Get dict.Database that has been registered under `name`. */
func (this *Server) GetDatabase(name string) Database {
	if value, ok := this.databases[name]; ok {
		return value
	}
	return nil
}

/* Register a Command `handler` under name `name`. */
func (this *Server) RegisterHandler(
	name string,
	handler func(*Session, Command),
) {
	this.commands[name] = handler
}

/* Get a Command handler for the given dict.Command `command` */
func (this *Server) GetHandler(command *Command) func(*Session, Command) {
	name := command.Command

	if value, ok := this.commands[name]; ok {
		return value
	}
	return nil
}

/* Create a new server by name `name`. */
func NewServer(name string) Server {
	server := Server{
		Name:      name,
		Info:      "",
		commands:  map[string]func(*Session, Command){},
		databases: map[string]Database{},
	}
	registerDefaultHandlers(&server)
	return server
}
<|endoftext|>


<commit_before>package main

import (
	//	"fmt"
	"container/list"
	"github.com/nsf/termbox-go"
	"github.com/simulatedsimian/go_sandbox/geom"
	"reflect"
	"unicode"
)

func printAt(x, y int, s string, fg, bg termbox.Attribute) {
	for _, r := range s {
		termbox.SetCell(x, y, r, fg, bg)
		x++
	}
}

func printAtDef(x, y int, s string) {
	printAt(x, y, s, termbox.ColorDefault, termbox.ColorDefault)
}

func clearRect(rect geom.Rectangle, c rune, fg, bg termbox.Attribute) {
	w, h := termbox.Size()
	sz := geom.RectangleFromSize(geom.Coord{w, h})

	toClear, ok := geom.RectangleIntersection(rect, sz)
	if ok {
		for y := toClear.Min.Y; y < toClear.Max.Y; y++ {
			for x := toClear.Min.X; x < toClear.Max.X; x++ {
				termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
			}
		}
	}
}

func clearRectDef(rect geom.Rectangle) {
	clearRect(rect, '.', termbox.ColorDefault, termbox.ColorDefault)
}

type DisplayElement interface {
	GiveFocus() bool
	HandleInput(k termbox.Key, r rune)
	Draw()
}

type DisplayList struct {
	list       []DisplayElement
	focusIndex int
}

func (dl *DisplayList) AddElement(elem DisplayElement) {
	dl.list = append(dl.list, elem)
}

func (dl *DisplayList) Draw() {
	w, h := termbox.Size()
	clearRectDef(geom.RectangleFromSize(geom.Coord{w, h}))

	for _, elem := range dl.list {
		elem.Draw()
	}
}

func (dl *DisplayList) NextFocus() {
	if dl.list != nil && len(dl.list) > 0 {
		for {
			dl.focusIndex++
			if dl.focusIndex >= len(dl.list) {
				dl.focusIndex = 0
			}

			if dl.list[dl.focusIndex].GiveFocus() {
				break
			}
		}
	}
}

func (dl *DisplayList) PrevFocus() {
	if dl.list != nil && len(dl.list) > 0 {
		for {
			dl.focusIndex--
			if dl.focusIndex < 0 {
				dl.focusIndex = len(dl.list)
			}

			if dl.list[dl.focusIndex].GiveFocus() {
				break
			}
		}
	}
}

func (dl *DisplayList) HandleInput(k termbox.Key, r rune) {

	if dl.list != nil && len(dl.list) > 0 {
		if k == termbox.KeyTab {
			dl.NextFocus()
		} else {
			dl.list[dl.focusIndex].HandleInput(k, r)
		}
	}
}

type InputHandler func(inp string)

type TextInputField struct {
	x, y       int
	inp        []rune
	cursorLoc  int
	inpHandler InputHandler
	hasFocus   bool
	history    *list.List
	histPos    *list.Element
}

func MakeTextInputField(x, y int, inpHandler InputHandler) *TextInputField {
	return &TextInputField{x, y, nil, 0, inpHandler, false, list.New(), nil}
}

func (t *TextInputField) HandleInput(k termbox.Key, r rune) {
	if k == termbox.KeyEnter {
		t.inp = TrimRunes(t.inp, unicode.IsSpace)
		if len(t.inp) > 0 {
			if t.histPos != nil && reflect.DeepEqual(t.histPos.Value, t.inp) {
				t.history.MoveToBack(t.histPos)
			} else {
				t.history.PushBack(t.inp)
			}
			t.histPos = nil

			t.inpHandler(string(t.inp))
			t.inp = nil
			t.cursorLoc = 0
		}
	}

	if k == termbox.KeyEsc {
		t.inp = nil
		t.cursorLoc = 0
	}

	if k == termbox.KeyArrowLeft {
		if t.cursorLoc > 0 {
			t.cursorLoc--
		}
	}

	if k == termbox.KeyArrowRight {
		if t.cursorLoc < len(t.inp) {
			t.cursorLoc++
		}
	}

	if k == termbox.KeyArrowUp {
		if t.history.Len() > 0 {
			if t.histPos == nil {
				t.histPos = t.history.Back()
			} else {
				t.histPos = t.histPos.Prev()
				if t.histPos == nil {
					t.histPos = t.history.Front()
				}
			}
			t.inp = CloneRuneSlice(t.histPos.Value.([]rune))
			t.cursorLoc = len(t.inp)
		}
	}

	if k == termbox.KeyArrowDown {
		if t.history.Len() > 0 {
			if t.histPos != nil {
				t.histPos = t.histPos.Next()
			}

			t.inp = nil
			if t.histPos != nil {
				t.inp = append(t.inp, t.histPos.Value.([]rune)...)
			}
			t.cursorLoc = len(t.inp)
		}
	}

	if r > ' ' {
		t.inp = InsertRuneAt(t.inp, r, t.cursorLoc)
		t.cursorLoc++
	}

	if k == 32 {
		t.inp = InsertRuneAt(t.inp, ' ', t.cursorLoc)
		t.cursorLoc++
	}

	if t.cursorLoc > 0 && len(t.inp) > 0 && (k == termbox.KeyBackspace || k == termbox.KeyBackspace2) {
		t.inp = DeleteRuneAt(t.inp, t.cursorLoc-1)
		t.cursorLoc--
	}

	termbox.SetCursor(t.x+t.cursorLoc, t.y)
	//	printAtDef(t.x, t.y+1, fmt.Sprintf("%v, %v               ", k, r))
}

func (t *TextInputField) Draw() {
	printAtDef(t.x, t.y, string(t.inp)+" ")
}

func (t *TextInputField) GiveFocus() bool {
	termbox.SetCursor(t.x, t.y)
	return true
}

type StaticText struct {
	x, y int
	text string
}

func (t *StaticText) HandleInput(k termbox.Key, r rune) {
}

func (t *StaticText) Draw() {
	printAtDef(t.x, t.y, t.text)
}

func (t *StaticText) GiveFocus() bool {
	return false
}

type ScrollingTextOutput struct {
	x, y int
	w, h int
	text []string
}

func (t *ScrollingTextOutput) HandleInput(k termbox.Key, r rune) {
}

func (t *ScrollingTextOutput) Write(p []byte) (n int, err error) {
	return len(p), nil
}

func (t *ScrollingTextOutput) WriteLine(l string) {
	t.text = append(t.text, l)
}

func (t *ScrollingTextOutput) Draw() {
	clearRectDef(geom.RectangleFromPosSize(geom.Coord{t.x, t.y}, geom.Coord{t.w, t.h}))

	start := 0

	if len(t.text) > t.h {
		start = len(t.text) - t.h
	}

	y := t.y
	for l := start; l < len(t.text); l++ {
		printAtDef(t.x, y, t.text[l])
		y++
	}
}

func (t *ScrollingTextOutput) GiveFocus() bool {
	return false
}
<commit_msg>added more editing keys<commit_after>package main

import (
	//	"fmt"
	"container/list"
	"github.com/nsf/termbox-go"
	"github.com/simulatedsimian/go_sandbox/geom"
	"reflect"
	"unicode"
)

func printAt(x, y int, s string, fg, bg termbox.Attribute) {
	for _, r := range s {
		termbox.SetCell(x, y, r, fg, bg)
		x++
	}
}

func printAtDef(x, y int, s string) {
	printAt(x, y, s, termbox.ColorDefault, termbox.ColorDefault)
}

func clearRect(rect geom.Rectangle, c rune, fg, bg termbox.Attribute) {
	w, h := termbox.Size()
	sz := geom.RectangleFromSize(geom.Coord{w, h})

	toClear, ok := geom.RectangleIntersection(rect, sz)
	if ok {
		for y := toClear.Min.Y; y < toClear.Max.Y; y++ {
			for x := toClear.Min.X; x < toClear.Max.X; x++ {
				termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
			}
		}
	}
}

func clearRectDef(rect geom.Rectangle) {
	clearRect(rect, '.', termbox.ColorDefault, termbox.ColorDefault)
}

type DisplayElement interface {
	GiveFocus() bool
	HandleInput(k termbox.Key, r rune)
	Draw()
}

type DisplayList struct {
	list       []DisplayElement
	focusIndex int
}

func (dl *DisplayList) AddElement(elem DisplayElement) {
	dl.list = append(dl.list, elem)
}

func (dl *DisplayList) Draw() {
	w, h := termbox.Size()
	clearRectDef(geom.RectangleFromSize(geom.Coord{w, h}))

	for _, elem := range dl.list {
		elem.Draw()
	}
}

func (dl *DisplayList) NextFocus() {
	if dl.list != nil && len(dl.list) > 0 {
		for {
			dl.focusIndex++
			if dl.focusIndex >= len(dl.list) {
				dl.focusIndex = 0
			}

			if dl.list[dl.focusIndex].GiveFocus() {
				break
			}
		}
	}
}

func (dl *DisplayList) PrevFocus() {
	if dl.list != nil && len(dl.list) > 0 {
		for {
			dl.focusIndex--
			if dl.focusIndex < 0 {
				dl.focusIndex = len(dl.list)
			}

			if dl.list[dl.focusIndex].GiveFocus() {
				break
			}
		}
	}
}

func (dl *DisplayList) HandleInput(k termbox.Key, r rune) {

	if dl.list != nil && len(dl.list) > 0 {
		if k == termbox.KeyTab {
			dl.NextFocus()
		} else {
			dl.list[dl.focusIndex].HandleInput(k, r)
		}
	}
}

type InputHandler func(inp string)

type TextInputField struct {
	x, y       int
	inp        []rune
	cursorLoc  int
	inpHandler InputHandler
	hasFocus   bool
	history    *list.List
	histPos    *list.Element
}

func MakeTextInputField(x, y int, inpHandler InputHandler) *TextInputField {
	return &TextInputField{x, y, nil, 0, inpHandler, false, list.New(), nil}
}

func (t *TextInputField) HandleInput(k termbox.Key, r rune) {
	if k == termbox.KeyEnter {
		t.inp = TrimRunes(t.inp, unicode.IsSpace)
		if len(t.inp) > 0 {
			if t.histPos != nil && reflect.DeepEqual(t.histPos.Value, t.inp) {
				t.history.MoveToBack(t.histPos)
			} else {
				t.history.PushBack(t.inp)
			}
			t.histPos = nil

			t.inpHandler(string(t.inp))
			t.inp = nil
			t.cursorLoc = 0
		}
	}

	if k == termbox.KeyEsc {
		t.inp = nil
		t.cursorLoc = 0
	}

	if k == termbox.KeyArrowLeft {
		if t.cursorLoc > 0 {
			t.cursorLoc--
		}
	}

	if k == termbox.KeyArrowRight {
		if t.cursorLoc < len(t.inp) {
			t.cursorLoc++
		}
	}

	if k == termbox.KeyArrowUp {
		if t.history.Len() > 0 {
			if t.histPos == nil {
				t.histPos = t.history.Back()
			} else {
				t.histPos = t.histPos.Prev()
				if t.histPos == nil {
					t.histPos = t.history.Front()
				}
			}
			t.inp = CloneRuneSlice(t.histPos.Value.([]rune))
			t.cursorLoc = len(t.inp)
		}
	}

	if k == termbox.KeyArrowDown {
		if t.history.Len() > 0 {
			if t.histPos != nil {
				t.histPos = t.histPos.Next()
			}

			t.inp = nil
			if t.histPos != nil {
				t.inp = append(t.inp, t.histPos.Value.([]rune)...)
			}
			t.cursorLoc = len(t.inp)
		}
	}

	if r > ' ' {
		t.inp = InsertRuneAt(t.inp, r, t.cursorLoc)
		t.cursorLoc++
	}

	if k == 32 {
		t.inp = InsertRuneAt(t.inp, ' ', t.cursorLoc)
		t.cursorLoc++
	}

	if t.cursorLoc > 0 && len(t.inp) > 0 && (k == termbox.KeyBackspace || k == termbox.KeyBackspace2) {
		t.inp = DeleteRuneAt(t.inp, t.cursorLoc-1)
		t.cursorLoc--
	}

	if k == termbox.KeyDelete && t.cursorLoc < len(t.inp) {
		t.inp = DeleteRuneAt(t.inp, t.cursorLoc)
	}

	if k == termbox.KeyHome {
		t.cursorLoc = 0
	}

	if k == termbox.KeyEnd {
		t.cursorLoc = len(t.inp)
	}

	termbox.SetCursor(t.x+t.cursorLoc, t.y)
	//	printAtDef(t.x, t.y+1, fmt.Sprintf("%v, %v               ", k, r))
}

func (t *TextInputField) Draw() {
	printAtDef(t.x, t.y, string(t.inp)+" ")
}

func (t *TextInputField) GiveFocus() bool {
	termbox.SetCursor(t.x, t.y)
	return true
}

type StaticText struct {
	x, y int
	text string
}

func (t *StaticText) HandleInput(k termbox.Key, r rune) {
}

func (t *StaticText) Draw() {
	printAtDef(t.x, t.y, t.text)
}

func (t *StaticText) GiveFocus() bool {
	return false
}

type ScrollingTextOutput struct {
	x, y int
	w, h int
	text []string
}

func (t *ScrollingTextOutput) HandleInput(k termbox.Key, r rune) {
}

func (t *ScrollingTextOutput) Write(p []byte) (n int, err error) {
	return len(p), nil
}

func (t *ScrollingTextOutput) WriteLine(l string) {
	t.text = append(t.text, l)
}

func (t *ScrollingTextOutput) Draw() {
	clearRectDef(geom.RectangleFromPosSize(geom.Coord{t.x, t.y}, geom.Coord{t.w, t.h}))

	start := 0

	if len(t.text) > t.h {
		start = len(t.text) - t.h
	}

	y := t.y
	for l := start; l < len(t.text); l++ {
		printAtDef(t.x, y, t.text[l])
		y++
	}
}

func (t *ScrollingTextOutput) GiveFocus() bool {
	return false
}
<|endoftext|>