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

package suffixarray

import (
	"bytes"
	"math/rand"
	"regexp"
	"sort"
	"strings"
	"testing"
)

type testCase struct {
	name     string   // name of test case
	source   string   // source to index
	patterns []string // patterns to lookup
}

var testCases = []testCase{
	{
		"empty string",
		"",
		[]string{
			"",
			"foo",
			"(foo)",
			".*",
			"a*",
		},
	},

	{
		"all a's",
		"aaaaaaaaaa", // 10 a's
		[]string{
			"",
			"a",
			"aa",
			"aaa",
			"aaaa",
			"aaaaa",
			"aaaaaa",
			"aaaaaaa",
			"aaaaaaaa",
			"aaaaaaaaa",
			"aaaaaaaaaa",
			"aaaaaaaaaaa", // 11 a's
			".",
			".*",
			"a+",
			"aa+",
			"aaaa[b]?",
			"aaa*",
		},
	},

	{
		"abc",
		"abc",
		[]string{
			"a",
			"b",
			"c",
			"ab",
			"bc",
			"abc",
			"a.c",
			"a(b|c)",
			"abc?",
		},
	},

	{
		"barbara*3",
		"barbarabarbarabarbara",
		[]string{
			"a",
			"bar",
			"rab",
			"arab",
			"barbar",
			"bara?bar",
		},
	},

	{
		"typing drill",
		"Now is the time for all good men to come to the aid of their country.",
		[]string{
			"Now",
			"the time",
			"to come the aid",
			"is the time for all good men to come to the aid of their",
			"to (come|the)?",
		},
	},

	{
		"godoc simulation",
		"package main\n\nimport(\n    \"rand\"\n    ",
		[]string{},
	},
}

// find all occurrences of s in source; report at most n occurrences
func find(src, s string, n int) []int {
	var res []int
	if s != "" && n != 0 {
		// find at most n occurrences of s in src
		for i := -1; n < 0 || len(res) < n; {
			j := strings.Index(src[i+1:], s)
			if j < 0 {
				break
			}
			i += j + 1
			res = append(res, i)
		}
	}
	return res
}

func testLookup(t *testing.T, tc *testCase, x *Index, s string, n int) {
	res := x.Lookup([]byte(s), n)
	exp := find(tc.source, s, n)

	// check that the lengths match
	if len(res) != len(exp) {
		t.Errorf("test %q, lookup %q (n = %d): expected %d results; got %d", tc.name, s, n, len(exp), len(res))
	}

	// if n >= 0 the number of results is limited --- unless n >= all results,
	// we may obtain different positions from the Index and from find (because
	// Index may not find the results in the same order as find) => in general
	// we cannot simply check that the res and exp lists are equal

	// check that each result is in fact a correct match and there are no duplicates
	sort.Ints(res)
	for i, r := range res {
		if r < 0 || len(tc.source) <= r {
			t.Errorf("test %q, lookup %q, result %d (n = %d): index %d out of range [0, %d[", tc.name, s, i, n, r, len(tc.source))
		} else if !strings.HasPrefix(tc.source[r:], s) {
			t.Errorf("test %q, lookup %q, result %d (n = %d): index %d not a match", tc.name, s, i, n, r)
		}
		if i > 0 && res[i-1] == r {
			t.Errorf("test %q, lookup %q, result %d (n = %d): found duplicate index %d", tc.name, s, i, n, r)
		}
	}

	if n < 0 {
		// all results computed - sorted res and exp must be equal
		for i, r := range res {
			e := exp[i]
			if r != e {
				t.Errorf("test %q, lookup %q, result %d: expected index %d; got %d", tc.name, s, i, e, r)
			}
		}
	}
}

func testFindAllIndex(t *testing.T, tc *testCase, x *Index, rx *regexp.Regexp, n int) {
	res := x.FindAllIndex(rx, n)
	exp := rx.FindAllStringIndex(tc.source, n)

	// check that the lengths match
	if len(res) != len(exp) {
		t.Errorf("test %q, FindAllIndex %q (n = %d): expected %d results; got %d", tc.name, rx, n, len(exp), len(res))
	}

	// if n >= 0 the number of results is limited --- unless n >= all results,
	// we may obtain different positions from the Index and from regexp (because
	// Index may not find the results in the same order as regexp) => in general
	// we cannot simply check that the res and exp lists are equal

	// check that each result is in fact a correct match and the result is sorted
	for i, r := range res {
		if r[0] < 0 || r[0] > r[1] || len(tc.source) < r[1] {
			t.Errorf("test %q, FindAllIndex %q, result %d (n == %d): illegal match [%d, %d]", tc.name, rx, i, n, r[0], r[1])
		} else if !rx.MatchString(tc.source[r[0]:r[1]]) {
			t.Errorf("test %q, FindAllIndex %q, result %d (n = %d): [%d, %d] not a match", tc.name, rx, i, n, r[0], r[1])
		}
	}

	if n < 0 {
		// all results computed - sorted res and exp must be equal
		for i, r := range res {
			e := exp[i]
			if r[0] != e[0] || r[1] != e[1] {
				t.Errorf("test %q, FindAllIndex %q, result %d: expected match [%d, %d]; got [%d, %d]",
					tc.name, rx, i, e[0], e[1], r[0], r[1])
			}
		}
	}
}

func testLookups(t *testing.T, tc *testCase, x *Index, n int) {
	for _, pat := range tc.patterns {
		testLookup(t, tc, x, pat, n)
		if rx, err := regexp.Compile(pat); err == nil {
			testFindAllIndex(t, tc, x, rx, n)
		}
	}
}

// index is used to hide the sort.Interface
type index Index

func (x *index) Len() int           { return len(x.sa) }
func (x *index) Less(i, j int) bool { return bytes.Compare(x.at(i), x.at(j)) < 0 }
func (x *index) Swap(i, j int)      { x.sa[i], x.sa[j] = x.sa[j], x.sa[i] }
func (a *index) at(i int) []byte    { return a.data[a.sa[i]:] }

func testConstruction(t *testing.T, tc *testCase, x *Index) {
	if !sort.IsSorted((*index)(x)) {
		t.Errorf("failed testConstruction %s", tc.name)
	}
}

func equal(x, y *Index) bool {
	if !bytes.Equal(x.data, y.data) {
		return false
	}
	for i, j := range x.sa {
		if j != y.sa[i] {
			return false
		}
	}
	return true
}

// returns the serialized index size
func testSaveRestore(t *testing.T, tc *testCase, x *Index) int {
	var buf bytes.Buffer
	if err := x.Write(&buf); err != nil {
		t.Errorf("failed writing index %s (%s)", tc.name, err)
	}
	size := buf.Len()
	var y Index
	if err := y.Read(&buf); err != nil {
		t.Errorf("failed reading index %s (%s)", tc.name, err)
	}
	if !equal(x, &y) {
		t.Errorf("restored index doesn't match saved index %s", tc.name)
	}
	return size
}

func TestIndex(t *testing.T) {
	for _, tc := range testCases {
		x := New([]byte(tc.source))
		testConstruction(t, &tc, x)
		testSaveRestore(t, &tc, x)
		testLookups(t, &tc, x, 0)
		testLookups(t, &tc, x, 1)
		testLookups(t, &tc, x, 10)
		testLookups(t, &tc, x, 2e9)
		testLookups(t, &tc, x, -1)
	}
}

// Of all possible inputs, the random bytes have the least amount of substring
// repetition, and the repeated bytes have the most. For most algorithms,
// the running time of every input will be between these two.
func benchmarkNew(b *testing.B, random bool) {
	b.StopTimer()
	data := make([]byte, 1e6)
	if random {
		for i := range data {
			data[i] = byte(rand.Intn(256))
		}
	}
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		New(data)
	}
}

func BenchmarkNewIndexRandom(b *testing.B) {
	benchmarkNew(b, true)
}
func BenchmarkNewIndexRepeat(b *testing.B) {
	benchmarkNew(b, false)
}

func BenchmarkSaveRestore(b *testing.B) {
	b.StopTimer()
	r := rand.New(rand.NewSource(0x5a77a1)) // guarantee always same sequence
	data := make([]byte, 10<<20)            // 10MB of data to index
	for i := range data {
		data[i] = byte(r.Intn(256))
	}
	x := New(data)
	size := testSaveRestore(nil, nil, x)       // verify correctness
	buf := bytes.NewBuffer(make([]byte, size)) // avoid growing
	b.SetBytes(int64(size))
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x.Write(buf)
		var y Index
		y.Read(buf)
	}
}
<commit_msg>index/suffixarray: reduce size of a benchmark A single iteration of BenchmarkSaveRestore runs for 5 seconds on my freebsd machine. 5 seconds looks like too long for a single iteration. This is the only benchmark that times out on freebsd-amd64-race builder.<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package suffixarray

import (
	"bytes"
	"math/rand"
	"regexp"
	"sort"
	"strings"
	"testing"
)

type testCase struct {
	name     string   // name of test case
	source   string   // source to index
	patterns []string // patterns to lookup
}

var testCases = []testCase{
	{
		"empty string",
		"",
		[]string{
			"",
			"foo",
			"(foo)",
			".*",
			"a*",
		},
	},

	{
		"all a's",
		"aaaaaaaaaa", // 10 a's
		[]string{
			"",
			"a",
			"aa",
			"aaa",
			"aaaa",
			"aaaaa",
			"aaaaaa",
			"aaaaaaa",
			"aaaaaaaa",
			"aaaaaaaaa",
			"aaaaaaaaaa",
			"aaaaaaaaaaa", // 11 a's
			".",
			".*",
			"a+",
			"aa+",
			"aaaa[b]?",
			"aaa*",
		},
	},

	{
		"abc",
		"abc",
		[]string{
			"a",
			"b",
			"c",
			"ab",
			"bc",
			"abc",
			"a.c",
			"a(b|c)",
			"abc?",
		},
	},

	{
		"barbara*3",
		"barbarabarbarabarbara",
		[]string{
			"a",
			"bar",
			"rab",
			"arab",
			"barbar",
			"bara?bar",
		},
	},

	{
		"typing drill",
		"Now is the time for all good men to come to the aid of their country.",
		[]string{
			"Now",
			"the time",
			"to come the aid",
			"is the time for all good men to come to the aid of their",
			"to (come|the)?",
		},
	},

	{
		"godoc simulation",
		"package main\n\nimport(\n    \"rand\"\n    ",
		[]string{},
	},
}

// find all occurrences of s in source; report at most n occurrences
func find(src, s string, n int) []int {
	var res []int
	if s != "" && n != 0 {
		// find at most n occurrences of s in src
		for i := -1; n < 0 || len(res) < n; {
			j := strings.Index(src[i+1:], s)
			if j < 0 {
				break
			}
			i += j + 1
			res = append(res, i)
		}
	}
	return res
}

func testLookup(t *testing.T, tc *testCase, x *Index, s string, n int) {
	res := x.Lookup([]byte(s), n)
	exp := find(tc.source, s, n)

	// check that the lengths match
	if len(res) != len(exp) {
		t.Errorf("test %q, lookup %q (n = %d): expected %d results; got %d", tc.name, s, n, len(exp), len(res))
	}

	// if n >= 0 the number of results is limited --- unless n >= all results,
	// we may obtain different positions from the Index and from find (because
	// Index may not find the results in the same order as find) => in general
	// we cannot simply check that the res and exp lists are equal

	// check that each result is in fact a correct match and there are no duplicates
	sort.Ints(res)
	for i, r := range res {
		if r < 0 || len(tc.source) <= r {
			t.Errorf("test %q, lookup %q, result %d (n = %d): index %d out of range [0, %d[", tc.name, s, i, n, r, len(tc.source))
		} else if !strings.HasPrefix(tc.source[r:], s) {
			t.Errorf("test %q, lookup %q, result %d (n = %d): index %d not a match", tc.name, s, i, n, r)
		}
		if i > 0 && res[i-1] == r {
			t.Errorf("test %q, lookup %q, result %d (n = %d): found duplicate index %d", tc.name, s, i, n, r)
		}
	}

	if n < 0 {
		// all results computed - sorted res and exp must be equal
		for i, r := range res {
			e := exp[i]
			if r != e {
				t.Errorf("test %q, lookup %q, result %d: expected index %d; got %d", tc.name, s, i, e, r)
			}
		}
	}
}

func testFindAllIndex(t *testing.T, tc *testCase, x *Index, rx *regexp.Regexp, n int) {
	res := x.FindAllIndex(rx, n)
	exp := rx.FindAllStringIndex(tc.source, n)

	// check that the lengths match
	if len(res) != len(exp) {
		t.Errorf("test %q, FindAllIndex %q (n = %d): expected %d results; got %d", tc.name, rx, n, len(exp), len(res))
	}

	// if n >= 0 the number of results is limited --- unless n >= all results,
	// we may obtain different positions from the Index and from regexp (because
	// Index may not find the results in the same order as regexp) => in general
	// we cannot simply check that the res and exp lists are equal

	// check that each result is in fact a correct match and the result is sorted
	for i, r := range res {
		if r[0] < 0 || r[0] > r[1] || len(tc.source) < r[1] {
			t.Errorf("test %q, FindAllIndex %q, result %d (n == %d): illegal match [%d, %d]", tc.name, rx, i, n, r[0], r[1])
		} else if !rx.MatchString(tc.source[r[0]:r[1]]) {
			t.Errorf("test %q, FindAllIndex %q, result %d (n = %d): [%d, %d] not a match", tc.name, rx, i, n, r[0], r[1])
		}
	}

	if n < 0 {
		// all results computed - sorted res and exp must be equal
		for i, r := range res {
			e := exp[i]
			if r[0] != e[0] || r[1] != e[1] {
				t.Errorf("test %q, FindAllIndex %q, result %d: expected match [%d, %d]; got [%d, %d]",
					tc.name, rx, i, e[0], e[1], r[0], r[1])
			}
		}
	}
}

func testLookups(t *testing.T, tc *testCase, x *Index, n int) {
	for _, pat := range tc.patterns {
		testLookup(t, tc, x, pat, n)
		if rx, err := regexp.Compile(pat); err == nil {
			testFindAllIndex(t, tc, x, rx, n)
		}
	}
}

// index is used to hide the sort.Interface
type index Index

func (x *index) Len() int           { return len(x.sa) }
func (x *index) Less(i, j int) bool { return bytes.Compare(x.at(i), x.at(j)) < 0 }
func (x *index) Swap(i, j int)      { x.sa[i], x.sa[j] = x.sa[j], x.sa[i] }
func (a *index) at(i int) []byte    { return a.data[a.sa[i]:] }

func testConstruction(t *testing.T, tc *testCase, x *Index) {
	if !sort.IsSorted((*index)(x)) {
		t.Errorf("failed testConstruction %s", tc.name)
	}
}

func equal(x, y *Index) bool {
	if !bytes.Equal(x.data, y.data) {
		return false
	}
	for i, j := range x.sa {
		if j != y.sa[i] {
			return false
		}
	}
	return true
}

// returns the serialized index size
func testSaveRestore(t *testing.T, tc *testCase, x *Index) int {
	var buf bytes.Buffer
	if err := x.Write(&buf); err != nil {
		t.Errorf("failed writing index %s (%s)", tc.name, err)
	}
	size := buf.Len()
	var y Index
	if err := y.Read(&buf); err != nil {
		t.Errorf("failed reading index %s (%s)", tc.name, err)
	}
	if !equal(x, &y) {
		t.Errorf("restored index doesn't match saved index %s", tc.name)
	}
	return size
}

func TestIndex(t *testing.T) {
	for _, tc := range testCases {
		x := New([]byte(tc.source))
		testConstruction(t, &tc, x)
		testSaveRestore(t, &tc, x)
		testLookups(t, &tc, x, 0)
		testLookups(t, &tc, x, 1)
		testLookups(t, &tc, x, 10)
		testLookups(t, &tc, x, 2e9)
		testLookups(t, &tc, x, -1)
	}
}

// Of all possible inputs, the random bytes have the least amount of substring
// repetition, and the repeated bytes have the most. For most algorithms,
// the running time of every input will be between these two.
func benchmarkNew(b *testing.B, random bool) {
	b.StopTimer()
	data := make([]byte, 1e6)
	if random {
		for i := range data {
			data[i] = byte(rand.Intn(256))
		}
	}
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		New(data)
	}
}

func BenchmarkNewIndexRandom(b *testing.B) {
	benchmarkNew(b, true)
}
func BenchmarkNewIndexRepeat(b *testing.B) {
	benchmarkNew(b, false)
}

func BenchmarkSaveRestore(b *testing.B) {
	b.StopTimer()
	r := rand.New(rand.NewSource(0x5a77a1)) // guarantee always same sequence
	data := make([]byte, 1<<20)             // 1MB of data to index
	for i := range data {
		data[i] = byte(r.Intn(256))
	}
	x := New(data)
	size := testSaveRestore(nil, nil, x)       // verify correctness
	buf := bytes.NewBuffer(make([]byte, size)) // avoid growing
	b.SetBytes(int64(size))
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		x.Write(buf)
		var y Index
		y.Read(buf)
	}
}
<|endoftext|>


<commit_before>/*
   Copyright 2012 the go.wde authors

   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 win

import (
	"fmt"
	"github.com/AllenDang/w32"
	"github.com/skelterjohn/go.wde"
)

/*
TODO:
 F10 loses focus
 left alt loses focus
<	(left from z), code 226. Coded as ',' in xgb for some reason.
		// Some that are not found in wde constants
		// Hardcoded to be compatible with xgb
		19:	"Pause",
		93:	"Menu",
		145:	"Scroll_Lock",
		186:	"dead_diaeresis",	// ¨
		192:	"odiaresis",			// ö
		220:	"section",				// §
		221:	"aring",					// å
		222:	"adiaresis",			// ä
*/

func keyFromVirtualKeyCode(vk uintptr) string {
	switch vk {
	case w32.VK_LBUTTON:
	case w32.VK_RBUTTON:
	case w32.VK_CANCEL:
	case w32.VK_MBUTTON:
	case w32.VK_XBUTTON1:
	case w32.VK_XBUTTON2:
	case w32.VK_BACK:
		return wde.KeyBackspace
	case w32.VK_TAB:
		return wde.KeyTab
	case w32.VK_CLEAR:
	case w32.VK_RETURN:
		return wde.KeyReturn
	case w32.VK_SHIFT:
		return wde.KeyLeftShift
	case w32.VK_CONTROL:
		return wde.KeyLeftControl
	case w32.VK_MENU:
		return wde.KeyLeftAlt
	case w32.VK_PAUSE:
	case w32.VK_CAPITAL:
		return wde.KeyCapsLock
	case w32.VK_HANGUL:
	case w32.VK_JUNJA:
	case w32.VK_FINAL:
	case w32.VK_KANJI:
	case w32.VK_ESCAPE:
		return wde.KeyEscape
	case w32.VK_CONVERT:
	case w32.VK_NONCONVERT:
	case w32.VK_ACCEPT:
	case w32.VK_MODECHANGE:
	case w32.VK_SPACE:
		return wde.KeySpace
	case w32.VK_PRIOR:
		return wde.KeyPrior
	case w32.VK_NEXT:
		return wde.KeyNext
	case w32.VK_END:
		return wde.KeyEnd
	case w32.VK_HOME:
		return wde.KeyHome
	case w32.VK_LEFT:
		return wde.KeyLeftArrow
	case w32.VK_UP:
		return wde.KeyUpArrow
	case w32.VK_RIGHT:
		return wde.KeyRightArrow
	case w32.VK_DOWN:
		return wde.KeyDownArrow
	case w32.VK_SELECT:
	case w32.VK_PRINT:
	case w32.VK_EXECUTE:
	case w32.VK_SNAPSHOT:
	case w32.VK_INSERT:
		return wde.KeyInsert
	case w32.VK_DELETE:
		return wde.KeyDelete
	case w32.VK_HELP:
	case w32.VK_LWIN:
		return wde.KeyLeftSuper
	case w32.VK_RWIN:
		return wde.KeyRightSuper
	case w32.VK_APPS:
	case w32.VK_SLEEP:
	case w32.VK_NUMPAD0:
		return wde.Key0
	case w32.VK_NUMPAD1:
		return wde.Key1
	case w32.VK_NUMPAD2:
		return wde.Key2
	case w32.VK_NUMPAD3:
		return wde.Key3
	case w32.VK_NUMPAD4:
		return wde.Key4
	case w32.VK_NUMPAD5:
		return wde.Key5
	case w32.VK_NUMPAD6:
		return wde.Key6
	case w32.VK_NUMPAD7:
		return wde.Key7
	case w32.VK_NUMPAD8:
		return wde.Key8
	case w32.VK_NUMPAD9:
		return wde.Key9
	case w32.VK_MULTIPLY:
		return wde.KeyPadStar
	case w32.VK_ADD:
		return wde.KeyPadPlus
	case w32.VK_SEPARATOR:
	case w32.VK_SUBTRACT:
		return wde.KeyPadMinus
	case w32.VK_DECIMAL:
		return wde.KeyPadDot
	case w32.VK_DIVIDE:
		return wde.KeyPadSlash
	case w32.VK_F1:
		return wde.KeyF1
	case w32.VK_F2:
		return wde.KeyF2
	case w32.VK_F3:
		return wde.KeyF3
	case w32.VK_F4:
		return wde.KeyF4
	case w32.VK_F5:
		return wde.KeyF5
	case w32.VK_F6:
		return wde.KeyF5
	case w32.VK_F7:
		return wde.KeyF7
	case w32.VK_F8:
		return wde.KeyF8
	case w32.VK_F9:
		return wde.KeyF9
	case w32.VK_F10:
		return wde.KeyF10
	case w32.VK_F11:
		return wde.KeyF11
	case w32.VK_F12:
		return wde.KeyF12
	case w32.VK_F13:
		return wde.KeyF13
	case w32.VK_F14:
		return wde.KeyF14
	case w32.VK_F15:
		return wde.KeyF15
	case w32.VK_F16:
		return wde.KeyF16
	case w32.VK_F17:
	case w32.VK_F18:
	case w32.VK_F19:
	case w32.VK_F20:
	case w32.VK_F21:
	case w32.VK_F22:
	case w32.VK_F23:
	case w32.VK_F24:
	case w32.VK_NUMLOCK:
		return wde.KeyNumlock
	case w32.VK_SCROLL:
	case w32.VK_LSHIFT:
		return wde.KeyLeftShift
	case w32.VK_RSHIFT:
		return wde.KeyRightShift
	case w32.VK_LCONTROL:
		return wde.KeyLeftShift
	case w32.VK_RCONTROL:
		return wde.KeyRightShift
	case w32.VK_LMENU:
		return wde.KeyLeftAlt
	case w32.VK_RMENU:
		return wde.KeyRightAlt
	case w32.VK_BROWSER_BACK:
	case w32.VK_BROWSER_FORWARD:
	case w32.VK_BROWSER_REFRESH:
	case w32.VK_BROWSER_STOP:
	case w32.VK_BROWSER_SEARCH:
	case w32.VK_BROWSER_FAVORITES:
	case w32.VK_BROWSER_HOME:
	case w32.VK_VOLUME_MUTE:
	case w32.VK_VOLUME_DOWN:
	case w32.VK_VOLUME_UP:
	case w32.VK_MEDIA_NEXT_TRACK:
	case w32.VK_MEDIA_PREV_TRACK:
	case w32.VK_MEDIA_STOP:
	case w32.VK_MEDIA_PLAY_PAUSE:
	case w32.VK_LAUNCH_MAIL:
	case w32.VK_LAUNCH_MEDIA_SELECT:
	case w32.VK_LAUNCH_APP1:
	case w32.VK_LAUNCH_APP2:
	case w32.VK_OEM_1:
		return wde.KeySemicolon
	case w32.VK_OEM_PLUS:
		return wde.KeyEqual
	case w32.VK_OEM_COMMA:
		return wde.KeyComma
	case w32.VK_OEM_MINUS:
		return wde.KeyMinus
	case w32.VK_OEM_PERIOD:
		return wde.KeyPeriod
	case w32.VK_OEM_2:
		return wde.KeySlash
	case w32.VK_OEM_3:
		return wde.KeyBackTick
	case w32.VK_OEM_4:
		return wde.KeyLeftBracket
	case w32.VK_OEM_5:
		return wde.KeyBackslash
	case w32.VK_OEM_6:
		return wde.KeyRightBracket
	case w32.VK_OEM_7:
		return wde.KeyQuote
	case w32.VK_OEM_8:
	case w32.VK_OEM_AX:
	case w32.VK_OEM_102:
	case w32.VK_ICO_HELP:
	case w32.VK_ICO_00:
	case w32.VK_PROCESSKEY:
	case w32.VK_ICO_CLEAR:
	case w32.VK_OEM_RESET:
	case w32.VK_OEM_JUMP:
	case w32.VK_OEM_PA1:
	case w32.VK_OEM_PA2:
	case w32.VK_OEM_PA3:
	case w32.VK_OEM_WSCTRL:
	case w32.VK_OEM_CUSEL:
	case w32.VK_OEM_ATTN:
	case w32.VK_OEM_FINISH:
	case w32.VK_OEM_COPY:
	case w32.VK_OEM_AUTO:
	case w32.VK_OEM_ENLW:
	case w32.VK_OEM_BACKTAB:
	case w32.VK_ATTN:
	case w32.VK_CRSEL:
	case w32.VK_EXSEL:
	case w32.VK_EREOF:
	case w32.VK_PLAY:
	case w32.VK_ZOOM:
	case w32.VK_NONAME:
	case w32.VK_PA1:
	case w32.VK_OEM_CLEAR:

	}
	return fmt.Sprintf("%c", vk)
}
<commit_msg>win: polish off keymapping code<commit_after>/*
   Copyright 2012 the go.wde authors

   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 win

import (
	"fmt"
	"github.com/AllenDang/w32"
	"github.com/skelterjohn/go.wde"
)

func keyFromVirtualKeyCode(vk uintptr) string {
	if vk >= '0' && vk <= 'Z' {
		/* alphanumeric range (windows doesn't use 0x3a-0x40) */
		return fmt.Sprintf("%c", vk)
	}
	switch vk {
	case w32.VK_BACK:
		return wde.KeyBackspace
	case w32.VK_TAB:
		return wde.KeyTab
	case w32.VK_RETURN:
		return wde.KeyReturn
	case w32.VK_SHIFT:
		return wde.KeyLeftShift
	case w32.VK_CONTROL:
		return wde.KeyLeftControl
	case w32.VK_MENU:
		return wde.KeyLeftAlt
	case w32.VK_CAPITAL:
		return wde.KeyCapsLock
	case w32.VK_ESCAPE:
		return wde.KeyEscape
	case w32.VK_SPACE:
		return wde.KeySpace
	case w32.VK_PRIOR:
		return wde.KeyPrior
	case w32.VK_NEXT:
		return wde.KeyNext
	case w32.VK_END:
		return wde.KeyEnd
	case w32.VK_HOME:
		return wde.KeyHome
	case w32.VK_LEFT:
		return wde.KeyLeftArrow
	case w32.VK_UP:
		return wde.KeyUpArrow
	case w32.VK_RIGHT:
		return wde.KeyRightArrow
	case w32.VK_DOWN:
		return wde.KeyDownArrow
	case w32.VK_INSERT:
		return wde.KeyInsert
	case w32.VK_DELETE:
		return wde.KeyDelete
	case w32.VK_LWIN:
		return wde.KeyLeftSuper
	case w32.VK_RWIN:
		return wde.KeyRightSuper
	case w32.VK_NUMPAD0:
		return wde.Key0
	case w32.VK_NUMPAD1:
		return wde.Key1
	case w32.VK_NUMPAD2:
		return wde.Key2
	case w32.VK_NUMPAD3:
		return wde.Key3
	case w32.VK_NUMPAD4:
		return wde.Key4
	case w32.VK_NUMPAD5:
		return wde.Key5
	case w32.VK_NUMPAD6:
		return wde.Key6
	case w32.VK_NUMPAD7:
		return wde.Key7
	case w32.VK_NUMPAD8:
		return wde.Key8
	case w32.VK_NUMPAD9:
		return wde.Key9
	case w32.VK_MULTIPLY:
		return wde.KeyPadStar
	case w32.VK_ADD:
		return wde.KeyPadPlus
	case w32.VK_SUBTRACT:
		return wde.KeyPadMinus
	case w32.VK_DECIMAL:
		return wde.KeyPadDot
	case w32.VK_DIVIDE:
		return wde.KeyPadSlash
	case w32.VK_F1:
		return wde.KeyF1
	case w32.VK_F2:
		return wde.KeyF2
	case w32.VK_F3:
		return wde.KeyF3
	case w32.VK_F4:
		return wde.KeyF4
	case w32.VK_F5:
		return wde.KeyF5
	case w32.VK_F6:
		return wde.KeyF5
	case w32.VK_F7:
		return wde.KeyF7
	case w32.VK_F8:
		return wde.KeyF8
	case w32.VK_F9:
		return wde.KeyF9
	case w32.VK_F10:
		return wde.KeyF10
	case w32.VK_F11:
		return wde.KeyF11
	case w32.VK_F12:
		return wde.KeyF12
	case w32.VK_F13:
		return wde.KeyF13
	case w32.VK_F14:
		return wde.KeyF14
	case w32.VK_F15:
		return wde.KeyF15
	case w32.VK_F16:
		return wde.KeyF16
	case w32.VK_NUMLOCK:
		return wde.KeyNumlock
	case w32.VK_LSHIFT:
		return wde.KeyLeftShift
	case w32.VK_RSHIFT:
		return wde.KeyRightShift
	case w32.VK_LCONTROL:
		return wde.KeyLeftShift
	case w32.VK_RCONTROL:
		return wde.KeyRightShift
	case w32.VK_LMENU:
		return wde.KeyLeftAlt
	case w32.VK_RMENU:
		return wde.KeyRightAlt
	case w32.VK_OEM_1:
		return wde.KeySemicolon
	case w32.VK_OEM_PLUS:
		return wde.KeyEqual
	case w32.VK_OEM_COMMA:
		return wde.KeyComma
	case w32.VK_OEM_MINUS:
		return wde.KeyMinus
	case w32.VK_OEM_PERIOD:
		return wde.KeyPeriod
	case w32.VK_OEM_2:
		return wde.KeySlash
	case w32.VK_OEM_3:
		return wde.KeyBackTick
	case w32.VK_OEM_4:
		return wde.KeyLeftBracket
	case w32.VK_OEM_5:
		return wde.KeyBackslash
	case w32.VK_OEM_6:
		return wde.KeyRightBracket
	case w32.VK_OEM_7:
		return wde.KeyQuote

	// the rest lack wde constants. the first few are xgb compatible
	case w32.VK_PAUSE:
		return "Pause"
	case w32.VK_APPS:
		return "Menu"
	case w32.VK_SCROLL:
		return "Scroll_Lock"

	// the rest fallthrough to the default format "vk-0xff"
	case w32.VK_LBUTTON:
	case w32.VK_RBUTTON:
	case w32.VK_CANCEL:
	case w32.VK_MBUTTON:
	case w32.VK_XBUTTON1:
	case w32.VK_XBUTTON2:
	case w32.VK_CLEAR:
	case w32.VK_HANGUL:
	case w32.VK_JUNJA:
	case w32.VK_FINAL:
	case w32.VK_KANJI:
	case w32.VK_CONVERT:
	case w32.VK_NONCONVERT:
	case w32.VK_ACCEPT:
	case w32.VK_MODECHANGE:
	case w32.VK_SELECT:
	case w32.VK_PRINT:
	case w32.VK_EXECUTE:
	case w32.VK_SNAPSHOT:
	case w32.VK_HELP:
	case w32.VK_SLEEP:
	case w32.VK_SEPARATOR:
	case w32.VK_F17:
	case w32.VK_F18:
	case w32.VK_F19:
	case w32.VK_F20:
	case w32.VK_F21:
	case w32.VK_F22:
	case w32.VK_F23:
	case w32.VK_F24:
	case w32.VK_BROWSER_BACK:
	case w32.VK_BROWSER_FORWARD:
	case w32.VK_BROWSER_REFRESH:
	case w32.VK_BROWSER_STOP:
	case w32.VK_BROWSER_SEARCH:
	case w32.VK_BROWSER_FAVORITES:
	case w32.VK_BROWSER_HOME:
	case w32.VK_VOLUME_MUTE:
	case w32.VK_VOLUME_DOWN:
	case w32.VK_VOLUME_UP:
	case w32.VK_MEDIA_NEXT_TRACK:
	case w32.VK_MEDIA_PREV_TRACK:
	case w32.VK_MEDIA_STOP:
	case w32.VK_MEDIA_PLAY_PAUSE:
	case w32.VK_LAUNCH_MAIL:
	case w32.VK_LAUNCH_MEDIA_SELECT:
	case w32.VK_LAUNCH_APP1:
	case w32.VK_LAUNCH_APP2:
	case w32.VK_OEM_8:
	case w32.VK_OEM_AX:
	case w32.VK_OEM_102:
	case w32.VK_ICO_HELP:
	case w32.VK_ICO_00:
	case w32.VK_PROCESSKEY:
	case w32.VK_ICO_CLEAR:
	case w32.VK_OEM_RESET:
	case w32.VK_OEM_JUMP:
	case w32.VK_OEM_PA1:
	case w32.VK_OEM_PA2:
	case w32.VK_OEM_PA3:
	case w32.VK_OEM_WSCTRL:
	case w32.VK_OEM_CUSEL:
	case w32.VK_OEM_ATTN:
	case w32.VK_OEM_FINISH:
	case w32.VK_OEM_COPY:
	case w32.VK_OEM_AUTO:
	case w32.VK_OEM_ENLW:
	case w32.VK_OEM_BACKTAB:
	case w32.VK_ATTN:
	case w32.VK_CRSEL:
	case w32.VK_EXSEL:
	case w32.VK_EREOF:
	case w32.VK_PLAY:
	case w32.VK_ZOOM:
	case w32.VK_NONAME:
	case w32.VK_PA1:
	case w32.VK_OEM_CLEAR:
	}
	return fmt.Sprintf("vk-0x%02x", vk)
}
<|endoftext|>


<commit_before>// Title：顾问通话详情列表
//
// Description:
//
// Author:black
//
// Createtime:2013-09-26 15:50
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-09-26 15:50 black 创建文档
package server

import (
	"fmt"
	"github.com/hjqhezgh/commonlib"
	"github.com/hjqhezgh/lessgo"
	"math"
	"net/http"
	"strconv"
	"text/template"
)

//顾问分页数据服务
func ConsultantPhoneDetailListAction(w http.ResponseWriter, r *http.Request) {

	m := make(map[string]interface{})

	employee := lessgo.GetCurrentEmployee(r)

	if employee.UserId == "" {
		lessgo.Log.Warn("用户未登陆")
		m["success"] = false
		m["code"] = 100
		m["msg"] = "用户未登陆"
		commonlib.OutputJson(w, m, " ")
		return
	}

	err := r.ParseForm()

	if err != nil {
		m["success"] = false
		m["code"] = 100
		m["msg"] = "出现错误，请联系IT部门，错误信息:" + err.Error()
		commonlib.OutputJson(w, m, " ")
		return
	}

	pageNoString := r.FormValue("page")
	pageNo := 1
	if pageNoString != "" {
		pageNo, err = strconv.Atoi(pageNoString)
		if err != nil {
			pageNo = 1
			lessgo.Log.Warn("错误的pageNo:", pageNo)
		}
	}

	pageSizeString := r.FormValue("rows")
	pageSize := 10
	if pageSizeString != "" {
		pageSize, err = strconv.Atoi(pageSizeString)
		if err != nil {
			lessgo.Log.Warn("错误的pageSize:", pageSize)
		}
	}

	eid := r.FormValue("eid")
	year := r.FormValue("year-eq")
	month := r.FormValue("month-eq")
	week := r.FormValue("week-eq")
	startTime := r.FormValue("start_time-eq")

	st := ""
	et := ""
	flag := true

	if startTime != "" {
		st = startTime + " 00:00:00"
		et = startTime + " 23:59:59"
	} else {
		if week != "" && month != "" && year != "" {
			st, et, flag = lessgo.FindRangeTimeDim("", "", year+month+week)
		} else if month != "" && year != "" {
			st, et, flag = lessgo.FindRangeTimeDim("", year+month, "")
		} else if year != "" {
			st, et, flag = lessgo.FindRangeTimeDim(year, "", "")
		}
	}

	params := []interface{}{}

	sql := "select a.aid,case a.remotephone when c.father_phone then c.father when c.mother_phone then c.mother  else '未知客户' end as c_name,a.remotephone,e.really_name,a.start_time,a.seconds,a.inout,a.is_upload_finish,a.note,c.id,a.filename,a.cid from audio a left join consumer c on (a.remotephone=c.mother_phone and c.mother_phone!='' and c.mother_phone is not null ) or (a.remotephone=c.father_phone and c.father_phone!='' and  c.father_phone is not null) left join employee e on e.phone_in_center=a.localphone where a.remotephone !='' and a.remotephone is not null and e.user_id=? "

	params = append(params, eid)

	if flag {
		if st != "" && et != "" {
			sql += " and a.start_time >= ? and a.start_time<= ?"
			params = append(params, st)
			params = append(params, et)
		}
	} else { //找不到相应的时间区间
		sql += " and a.start_time >= ? and a.start_time<= ?"
		params = append(params, "2000-01-01 00:00:00")
		params = append(params, "2000-01-01 00:00:01")
	}

	countSql := ""

	countSql = "select count(1) from (" + sql + ") num"

	lessgo.Log.Debug(countSql)

	db := lessgo.GetMySQL()
	defer db.Close()

	rows, err := db.Query(countSql, params...)

	if err != nil {
		lessgo.Log.Warn(err.Error())
		m["success"] = false
		m["code"] = 100
		m["msg"] = "系统发生错误，请联系IT部门"
		commonlib.OutputJson(w, m, " ")
		return
	}

	totalNum := 0

	if rows.Next() {
		err := rows.Scan(&totalNum)

		if err != nil {
			lessgo.Log.Warn(err.Error())
			m["success"] = false
			m["code"] = 100
			m["msg"] = "系统发生错误，请联系IT部门"
			commonlib.OutputJson(w, m, " ")
			return
		}
	}

	totalPage := int(math.Ceil(float64(totalNum) / float64(pageSize)))

	currPageNo := pageNo

	if currPageNo > totalPage {
		currPageNo = totalPage
	}

	sql += " order by a.start_time desc  limit ?,?"

	lessgo.Log.Debug(sql)

	params = append(params, (currPageNo-1)*pageSize)
	params = append(params, pageSize)

	rows, err = db.Query(sql, params...)

	if err != nil {
		lessgo.Log.Warn(err.Error())
		m["success"] = false
		m["code"] = 100
		m["msg"] = "系统发生错误，请联系IT部门"
		commonlib.OutputJson(w, m, " ")
		return
	}

	objects := []interface{}{}

	for rows.Next() {

		model := new(lessgo.Model)

		fillObjects := []interface{}{}

		fillObjects = append(fillObjects, &model.Id)

		for i := 0; i < 11; i++ {
			prop := new(lessgo.Prop)
			prop.Name = fmt.Sprint(i)
			prop.Value = ""
			fillObjects = append(fillObjects, &prop.Value)
			model.Props = append(model.Props, prop)
		}

		err = commonlib.PutRecord(rows, fillObjects...)

		if err != nil {
			lessgo.Log.Warn(err.Error())
			m["success"] = false
			m["code"] = 100
			m["msg"] = "系统发生错误，请联系IT部门"
			commonlib.OutputJson(w, m, " ")
			return
		}

		objects = append(objects, model)
	}

	pageData := commonlib.BulidTraditionPage(currPageNo, pageSize, totalNum, objects)

	m["PageData"] = pageData
	m["DataLength"] = len(pageData.Datas) - 1
	if len(pageData.Datas) > 0 {
		m["FieldLength"] = len(pageData.Datas[0].(*lessgo.Model).Props) - 1
	}

	commonlib.RenderTemplate(w, r, "entity_page.json", m, template.FuncMap{"getPropValue": lessgo.GetPropValue, "compareInt": lessgo.CompareInt, "dealJsonString": lessgo.DealJsonString}, "../lessgo/template/entity_page.json")

}
<commit_msg>顾问电话详情，排序问题，使得最新电话能够置顶<commit_after>// Title：顾问通话详情列表
//
// Description:
//
// Author:black
//
// Createtime:2013-09-26 15:50
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-09-26 15:50 black 创建文档
package server

import (
	"fmt"
	"github.com/hjqhezgh/commonlib"
	"github.com/hjqhezgh/lessgo"
	"math"
	"net/http"
	"strconv"
	"text/template"
)

//顾问分页数据服务
func ConsultantPhoneDetailListAction(w http.ResponseWriter, r *http.Request) {

	m := make(map[string]interface{})

	employee := lessgo.GetCurrentEmployee(r)

	if employee.UserId == "" {
		lessgo.Log.Warn("用户未登陆")
		m["success"] = false
		m["code"] = 100
		m["msg"] = "用户未登陆"
		commonlib.OutputJson(w, m, " ")
		return
	}

	err := r.ParseForm()

	if err != nil {
		m["success"] = false
		m["code"] = 100
		m["msg"] = "出现错误，请联系IT部门，错误信息:" + err.Error()
		commonlib.OutputJson(w, m, " ")
		return
	}

	pageNoString := r.FormValue("page")
	pageNo := 1
	if pageNoString != "" {
		pageNo, err = strconv.Atoi(pageNoString)
		if err != nil {
			pageNo = 1
			lessgo.Log.Warn("错误的pageNo:", pageNo)
		}
	}

	pageSizeString := r.FormValue("rows")
	pageSize := 10
	if pageSizeString != "" {
		pageSize, err = strconv.Atoi(pageSizeString)
		if err != nil {
			lessgo.Log.Warn("错误的pageSize:", pageSize)
		}
	}

	eid := r.FormValue("eid")
	year := r.FormValue("year-eq")
	month := r.FormValue("month-eq")
	week := r.FormValue("week-eq")
	startTime := r.FormValue("start_time-eq")

	st := ""
	et := ""
	flag := true

	if startTime != "" {
		st = startTime + " 00:00:00"
		et = startTime + " 23:59:59"
	} else {
		if week != "" && month != "" && year != "" {
			st, et, flag = lessgo.FindRangeTimeDim("", "", year+month+week)
		} else if month != "" && year != "" {
			st, et, flag = lessgo.FindRangeTimeDim("", year+month, "")
		} else if year != "" {
			st, et, flag = lessgo.FindRangeTimeDim(year, "", "")
		}
	}

	params := []interface{}{}

	sql := "select a.aid,case a.remotephone when c.father_phone then c.father when c.mother_phone then c.mother  else '未知客户' end as c_name,a.remotephone,e.really_name,a.start_time,a.seconds,a.inout,a.is_upload_finish,a.note,c.id,a.filename,a.cid from audio a left join consumer c on (a.remotephone=c.mother_phone and c.mother_phone!='' and c.mother_phone is not null ) or (a.remotephone=c.father_phone and c.father_phone!='' and  c.father_phone is not null) left join employee e on e.phone_in_center=a.localphone where a.remotephone !='' and a.remotephone is not null and e.user_id=? "

	params = append(params, eid)

	if flag {
		if st != "" && et != "" {
			sql += " and a.start_time >= ? and a.start_time<= ?"
			params = append(params, st)
			params = append(params, et)
		}
	} else { //找不到相应的时间区间
		sql += " and a.start_time >= ? and a.start_time<= ?"
		params = append(params, "2000-01-01 00:00:00")
		params = append(params, "2000-01-01 00:00:01")
	}

	countSql := ""

	countSql = "select count(1) from (" + sql + ") num"

	lessgo.Log.Debug(countSql)

	db := lessgo.GetMySQL()
	defer db.Close()

	rows, err := db.Query(countSql, params...)

	if err != nil {
		lessgo.Log.Warn(err.Error())
		m["success"] = false
		m["code"] = 100
		m["msg"] = "系统发生错误，请联系IT部门"
		commonlib.OutputJson(w, m, " ")
		return
	}

	totalNum := 0

	if rows.Next() {
		err := rows.Scan(&totalNum)

		if err != nil {
			lessgo.Log.Warn(err.Error())
			m["success"] = false
			m["code"] = 100
			m["msg"] = "系统发生错误，请联系IT部门"
			commonlib.OutputJson(w, m, " ")
			return
		}
	}

	totalPage := int(math.Ceil(float64(totalNum) / float64(pageSize)))

	currPageNo := pageNo

	if currPageNo > totalPage {
		currPageNo = totalPage
	}

	sql += " order by a.aid desc limit ?,?"

	lessgo.Log.Debug(sql)

	params = append(params, (currPageNo-1)*pageSize)
	params = append(params, pageSize)

	rows, err = db.Query(sql, params...)

	if err != nil {
		lessgo.Log.Warn(err.Error())
		m["success"] = false
		m["code"] = 100
		m["msg"] = "系统发生错误，请联系IT部门"
		commonlib.OutputJson(w, m, " ")
		return
	}

	objects := []interface{}{}

	for rows.Next() {

		model := new(lessgo.Model)

		fillObjects := []interface{}{}

		fillObjects = append(fillObjects, &model.Id)

		for i := 0; i < 11; i++ {
			prop := new(lessgo.Prop)
			prop.Name = fmt.Sprint(i)
			prop.Value = ""
			fillObjects = append(fillObjects, &prop.Value)
			model.Props = append(model.Props, prop)
		}

		err = commonlib.PutRecord(rows, fillObjects...)

		if err != nil {
			lessgo.Log.Warn(err.Error())
			m["success"] = false
			m["code"] = 100
			m["msg"] = "系统发生错误，请联系IT部门"
			commonlib.OutputJson(w, m, " ")
			return
		}

		objects = append(objects, model)
	}

	pageData := commonlib.BulidTraditionPage(currPageNo, pageSize, totalNum, objects)

	m["PageData"] = pageData
	m["DataLength"] = len(pageData.Datas) - 1
	if len(pageData.Datas) > 0 {
		m["FieldLength"] = len(pageData.Datas[0].(*lessgo.Model).Props) - 1
	}

	commonlib.RenderTemplate(w, r, "entity_page.json", m, template.FuncMap{"getPropValue": lessgo.GetPropValue, "compareInt": lessgo.CompareInt, "dealJsonString": lessgo.DealJsonString}, "../lessgo/template/entity_page.json")

}
<|endoftext|>


<commit_before>package build

import (
	"strings"

	icmd "github.com/docker/docker/pkg/testutil/cmd"
)

// WithDockerfile creates / returns a CmdOperator to set the Dockerfile for a build operation
func WithDockerfile(dockerfile string) func(*icmd.Cmd) func() {
	return func(cmd *icmd.Cmd) func() {
		cmd.Command = append(cmd.Command, "-")
		cmd.Stdin = strings.NewReader(dockerfile)
		return nil
	}
}

// WithoutCache makes the build ignore cache
func WithoutCache(cmd *icmd.Cmd) func() {
	cmd.Command = append(cmd.Command, "--no-cache")
	return nil
}

// WithContextPath set the build context path
func WithContextPath(path string) func(*icmd.Cmd) func() {
	// WithContextPath sets the build context path
	return func(cmd *icmd.Cmd) func() {
		cmd.Command = append(cmd.Command, path)
		return nil
	}
}
<commit_msg>remove redundant comments in test build.go<commit_after>package build

import (
	"strings"

	icmd "github.com/docker/docker/pkg/testutil/cmd"
)

// WithDockerfile creates / returns a CmdOperator to set the Dockerfile for a build operation
func WithDockerfile(dockerfile string) func(*icmd.Cmd) func() {
	return func(cmd *icmd.Cmd) func() {
		cmd.Command = append(cmd.Command, "-")
		cmd.Stdin = strings.NewReader(dockerfile)
		return nil
	}
}

// WithoutCache makes the build ignore cache
func WithoutCache(cmd *icmd.Cmd) func() {
	cmd.Command = append(cmd.Command, "--no-cache")
	return nil
}

// WithContextPath sets the build context path
func WithContextPath(path string) func(*icmd.Cmd) func() {
	return func(cmd *icmd.Cmd) func() {
		cmd.Command = append(cmd.Command, path)
		return nil
	}
}
<|endoftext|>


<commit_before>package monitor

import (
	"encoding/json"
	"fmt"
	"net/url"
	"reflect"
	"strings"
	"time"
)

const (
	NameSpaceQceDocker = "qce/docker"
	NameSpaceQceCvm    = "qce/cvm"

	QCloudMonitorAPITimeTemplate = "2006-01-02 15:04:05"
)

type QCloudMonitorAPITime struct {
	time.Time
}

func (qmat *QCloudMonitorAPITime) EncodeStructWithPrefix(prefix string, val reflect.Value, v *url.Values) error {
	ret := fmt.Sprintf("%d-%d-%d %d:%d:%d", qmat.Year(), qmat.Month(), qmat.Day(), qmat.Hour(), qmat.Minute(), qmat.Second())
	v.Set(strings.TrimLeft(prefix, "."), ret)
	return nil
}

func (qmat *QCloudMonitorAPITime) MarshalJSON() ([]byte, error) {

	return []byte(
		fmt.Sprintf(
			"%d-%d-%d %d:%d:%d",
			qmat.Year(),
			qmat.Month(),
			qmat.Day(),
			qmat.Hour(),
			qmat.Minute(),
			qmat.Second()),
	), nil
}

func (qmat *QCloudMonitorAPITime) UnmarshalJSON(b []byte) error {
	var tmp string
	if err := json.Unmarshal(b, &tmp); err != nil {
		return nil
	}

	t, err := time.Parse(QCloudMonitorAPITimeTemplate, tmp)
	if err != nil {
		return err
	}
	qmat.Time = t

	return nil
}

type Response struct {
	Code     int    `json:"code"`
	Message  string `json:"message"`
	CodeDesc string `json:"codeDesc"`
}

type GetMonitorDataArgs struct {
	Namespace  string                `qcloud_arg:"namespace"`
	MetricName string                `qcloud_arg:"metricName"`
	Dimensions []Dimension           `qcloud_arg:"dimensions"`
	Period     *int                  `qcloud_arg:"period,omitempty"`
	StartTime  *QCloudMonitorAPITime `qcloud_arg:"startTime,omitempty"`
	EndTime    *QCloudMonitorAPITime `qcloud_arg:"endTime,omitempty"`
}

type Dimension struct {
	Name  string `qcloud_arg:"name"`
	Value string `qcloud_arg:"value"`
}

type GetMonitorDataResponse struct {
	StartTime  QCloudMonitorAPITime `json:"startTime"`
	EndTime    QCloudMonitorAPITime `json:"endTime"`
	MetricName string               `json:"metricName"`
	Period     int                  `json:"period"`
	DataPoints []float64            `json:"dataPoints"`
}

type BatchGetMonitorDataArgs struct {
	Namespace  string                `qcloud_arg:"namespace"`
	MetricName string                `qcloud_arg:"metricName"`
	Batch      []Batch               `qcloud_arg:"batch"`
	Period     *int                  `qcloud_arg:"period,omitempty"`
	StartTime  *QCloudMonitorAPITime `qcloud_arg:"startTime,omitempty"`
	EndTime    *QCloudMonitorAPITime `qcloud_arg:"endTime,omitempty"`
}

type Batch struct {
	Dimensions []Dimension `qcloud_arg:"dimensions"`
}

type BatchGetMonitorDataResponse struct {
	StartTime  QCloudMonitorAPITime `json:"startTime"`
	EndTime    QCloudMonitorAPITime `json:"endTime"`
	MetricName string               `json:"metricName"`
	Period     int                  `json:"period"`
	DataPoints map[string][]float64 `json:"dataPoints"`
}

func (client *Client) GetMonitorData(args *GetMonitorDataArgs) (*GetMonitorDataResponse, error) {
	response := &GetMonitorDataResponse{}
	err := client.Invoke("GetMonitorData", args, response)
	if err != nil {
		return &GetMonitorDataResponse{}, err
	}
	return response, nil
}

func (client *Client) BatchGetMonitorData(args *BatchGetMonitorDataArgs) (*BatchGetMonitorDataResponse, error) {
	response := &BatchGetMonitorDataResponse{}
	err := client.Invoke("GetMonitorData", args, response)
	if err != nil {
		return &BatchGetMonitorDataResponse{}, err
	}
	return response, nil
}
<commit_msg>change data point type from float64 to *float64<commit_after>package monitor

import (
	"encoding/json"
	"fmt"
	"net/url"
	"reflect"
	"strings"
	"time"
)

const (
	NameSpaceQceDocker = "qce/docker"
	NameSpaceQceCvm    = "qce/cvm"

	QCloudMonitorAPITimeTemplate = "2006-01-02 15:04:05"
)

type QCloudMonitorAPITime struct {
	time.Time
}

func (qmat *QCloudMonitorAPITime) EncodeStructWithPrefix(prefix string, val reflect.Value, v *url.Values) error {
	ret := fmt.Sprintf("%d-%d-%d %d:%d:%d", qmat.Year(), qmat.Month(), qmat.Day(), qmat.Hour(), qmat.Minute(), qmat.Second())
	v.Set(strings.TrimLeft(prefix, "."), ret)
	return nil
}

func (qmat *QCloudMonitorAPITime) MarshalJSON() ([]byte, error) {

	return []byte(
		fmt.Sprintf(
			"%d-%d-%d %d:%d:%d",
			qmat.Year(),
			qmat.Month(),
			qmat.Day(),
			qmat.Hour(),
			qmat.Minute(),
			qmat.Second()),
	), nil
}

func (qmat *QCloudMonitorAPITime) UnmarshalJSON(b []byte) error {
	var tmp string
	if err := json.Unmarshal(b, &tmp); err != nil {
		return nil
	}

	t, err := time.Parse(QCloudMonitorAPITimeTemplate, tmp)
	if err != nil {
		return err
	}
	qmat.Time = t

	return nil
}

type Response struct {
	Code     int    `json:"code"`
	Message  string `json:"message"`
	CodeDesc string `json:"codeDesc"`
}

type GetMonitorDataArgs struct {
	Namespace  string                `qcloud_arg:"namespace"`
	MetricName string                `qcloud_arg:"metricName"`
	Dimensions []Dimension           `qcloud_arg:"dimensions"`
	Period     *int                  `qcloud_arg:"period,omitempty"`
	StartTime  *QCloudMonitorAPITime `qcloud_arg:"startTime,omitempty"`
	EndTime    *QCloudMonitorAPITime `qcloud_arg:"endTime,omitempty"`
}

type Dimension struct {
	Name  string `qcloud_arg:"name"`
	Value string `qcloud_arg:"value"`
}

type GetMonitorDataResponse struct {
	StartTime  QCloudMonitorAPITime `json:"startTime"`
	EndTime    QCloudMonitorAPITime `json:"endTime"`
	MetricName string               `json:"metricName"`
	Period     int                  `json:"period"`
	DataPoints []*float64            `json:"dataPoints"`
}

type BatchGetMonitorDataArgs struct {
	Namespace  string                `qcloud_arg:"namespace"`
	MetricName string                `qcloud_arg:"metricName"`
	Batch      []Batch               `qcloud_arg:"batch"`
	Period     *int                  `qcloud_arg:"period,omitempty"`
	StartTime  *QCloudMonitorAPITime `qcloud_arg:"startTime,omitempty"`
	EndTime    *QCloudMonitorAPITime `qcloud_arg:"endTime,omitempty"`
}

type Batch struct {
	Dimensions []Dimension `qcloud_arg:"dimensions"`
}

type BatchGetMonitorDataResponse struct {
	StartTime  QCloudMonitorAPITime `json:"startTime"`
	EndTime    QCloudMonitorAPITime `json:"endTime"`
	MetricName string               `json:"metricName"`
	Period     int                  `json:"period"`
	DataPoints map[string][]*float64 `json:"dataPoints"`
}

func (client *Client) GetMonitorData(args *GetMonitorDataArgs) (*GetMonitorDataResponse, error) {
	response := &GetMonitorDataResponse{}
	err := client.Invoke("GetMonitorData", args, response)
	if err != nil {
		return &GetMonitorDataResponse{}, err
	}
	return response, nil
}

func (client *Client) BatchGetMonitorData(args *BatchGetMonitorDataArgs) (*BatchGetMonitorDataResponse, error) {
	response := &BatchGetMonitorDataResponse{}
	err := client.Invoke("GetMonitorData", args, response)
	if err != nil {
		return &BatchGetMonitorDataResponse{}, err
	}
	return response, nil
}
<|endoftext|>


<commit_before>package gcloud

import (
	"encoding/json"
	"fmt"
	"io/ioutil"

	"cloud.google.com/go/storage"
	uuid "github.com/hashicorp/go-uuid"
	"github.com/hashicorp/terraform/state"
	"github.com/hashicorp/terraform/state/remote"
	"golang.org/x/net/context"
)

type RemoteClient struct {
	storageContext context.Context
	storageClient  *storage.Client
	bucketName     string
	stateFilePath  string
	lockFilePath   string
}

func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
	bucket := c.storageClient.Bucket(c.bucketName)
	stateFile := bucket.Object(c.stateFilePath)
	stateFileURL := c.stateFileURL()

	stateFileReader, err := stateFile.NewReader(c.storageContext)
	if err != nil {
		if err == storage.ErrObjectNotExist {
			return nil, nil
		} else {
			return nil, fmt.Errorf("Failed to open state file at %v: %v", stateFileURL, err)
		}
	}
	defer stateFileReader.Close()

	stateFileContents, err := ioutil.ReadAll(stateFileReader)
	if err != nil {
		return nil, fmt.Errorf("Failed to read state file from %v: %v", stateFileURL, err)
	}

	stateFileAttrs, err := stateFile.Attrs(c.storageContext)
	if err != nil {
		return nil, fmt.Errorf("Failed to read state file attrs from %v: %v", stateFileURL, err)
	}

	result := &remote.Payload{
		Data: stateFileContents,
		MD5:  stateFileAttrs.MD5,
	}

	return result, nil
}

func (c *RemoteClient) Put(data []byte) error {
	bucket := c.storageClient.Bucket(c.bucketName)
	stateFile := bucket.Object(c.stateFilePath)

	stateFileWriter := stateFile.NewWriter(c.storageContext)

	stateFileWriter.Write(data)
	err := stateFileWriter.Close()

	if err != nil {
		return fmt.Errorf("Failed to upload state to %v: %v", c.stateFileURL(), err)
	}

	return nil
}

func (c *RemoteClient) Delete() error {
	bucket := c.storageClient.Bucket(c.bucketName)
	stateFile := bucket.Object(c.stateFilePath)

	err := stateFile.Delete(c.storageContext)

	if err != nil {
		return fmt.Errorf("Failed to delete state file %v: %v", c.stateFileURL(), err)
	}

	return nil
}

func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
	if info.ID == "" {
		lockID, err := uuid.GenerateUUID()
		if err != nil {
			return "", err
		}

		info.ID = lockID
	}

	info.Path = c.lockFileURL()

	infoJson, err := json.Marshal(info)
	if err != nil {
		return "", err
	}

	bucket := c.storageClient.Bucket(c.bucketName)
	lockFile := bucket.Object(c.lockFilePath)

	writer := lockFile.If(storage.Conditions{DoesNotExist: true}).NewWriter(c.storageContext)
	writer.Write(infoJson)
	if err := writer.Close(); err != nil {
		return "", fmt.Errorf("Error while saving lock file (%v): %v", info.Path, err)
	}

	return info.ID, nil
}

func (c *RemoteClient) Unlock(id string) error {
	lockErr := &state.LockError{}

	bucket := c.storageClient.Bucket(c.bucketName)
	lockFile := bucket.Object(c.lockFilePath)
	lockFileURL := c.lockFileURL()

	lockFileReader, err := lockFile.NewReader(c.storageContext)
	if err != nil {
		lockErr.Err = fmt.Errorf("Failed to retrieve lock info (%v): %v", lockFileURL, err)
		return lockErr
	}
	defer lockFileReader.Close()

	lockFileContents, err := ioutil.ReadAll(lockFileReader)
	if err != nil {
		lockErr.Err = fmt.Errorf("Failed to retrieve lock info (%v): %v", lockFileURL, err)
		return lockErr
	}

	lockInfo := &state.LockInfo{}
	err = json.Unmarshal(lockFileContents, lockInfo)
	if err != nil {
		lockErr.Err = fmt.Errorf("Failed to unmarshal lock info (%v): %v", lockFileURL, err)
		return lockErr
	}

	lockErr.Info = lockInfo

	if lockInfo.ID != id {
		lockErr.Err = fmt.Errorf("Lock id %q does not match existing lock", id)
		return lockErr
	}

	lockFileAttrs, err := lockFile.Attrs(c.storageContext)
	if err != nil {
		lockErr.Err = fmt.Errorf("Failed to fetch lock file attrs (%v): %v", lockFileURL, err)
		return lockErr
	}

	err = lockFile.If(storage.Conditions{GenerationMatch: lockFileAttrs.Generation}).Delete(c.storageContext)
	if err != nil {
		lockErr.Err = fmt.Errorf("Failed to delete lock file (%v): %v", lockFileURL, err)
		return lockErr
	}

	return nil
}

func (c *RemoteClient) stateFileURL() string {
	return fmt.Sprintf("gs://%v/%v", c.bucketName, c.stateFilePath)
}

func (c *RemoteClient) lockFileURL() string {
	return fmt.Sprintf("gs://%v/%v", c.bucketName, c.lockFilePath)
}
<commit_msg>backend/remote-state/gcloud: Add the RemoteClient.{state,lock}File() methods.<commit_after>package gcloud

import (
	"encoding/json"
	"fmt"
	"io/ioutil"

	"cloud.google.com/go/storage"
	uuid "github.com/hashicorp/go-uuid"
	"github.com/hashicorp/terraform/state"
	"github.com/hashicorp/terraform/state/remote"
	"golang.org/x/net/context"
)

type RemoteClient struct {
	storageContext context.Context
	storageClient  *storage.Client
	bucketName     string
	stateFilePath  string
	lockFilePath   string
}

func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
	stateFileReader, err := c.stateFile().NewReader(c.storageContext)
	if err != nil {
		if err == storage.ErrObjectNotExist {
			return nil, nil
		} else {
			return nil, fmt.Errorf("Failed to open state file at %v: %v", c.stateFileURL(), err)
		}
	}
	defer stateFileReader.Close()

	stateFileContents, err := ioutil.ReadAll(stateFileReader)
	if err != nil {
		return nil, fmt.Errorf("Failed to read state file from %v: %v", c.stateFileURL(), err)
	}

	stateFileAttrs, err := c.stateFile().Attrs(c.storageContext)
	if err != nil {
		return nil, fmt.Errorf("Failed to read state file attrs from %v: %v", c.stateFileURL(), err)
	}

	result := &remote.Payload{
		Data: stateFileContents,
		MD5:  stateFileAttrs.MD5,
	}

	return result, nil
}

func (c *RemoteClient) Put(data []byte) error {
	stateFileWriter := c.stateFile().NewWriter(c.storageContext)

	stateFileWriter.Write(data)
	err := stateFileWriter.Close()

	if err != nil {
		return fmt.Errorf("Failed to upload state to %v: %v", c.stateFileURL(), err)
	}

	return nil
}

func (c *RemoteClient) Delete() error {
	err := c.stateFile().Delete(c.storageContext)

	if err != nil {
		return fmt.Errorf("Failed to delete state file %v: %v", c.stateFileURL(), err)
	}

	return nil
}

func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
	if info.ID == "" {
		lockID, err := uuid.GenerateUUID()
		if err != nil {
			return "", err
		}

		info.ID = lockID
	}

	info.Path = c.lockFileURL()

	infoJson, err := json.Marshal(info)
	if err != nil {
		return "", err
	}

	writer := c.lockFile().If(storage.Conditions{DoesNotExist: true}).NewWriter(c.storageContext)
	writer.Write(infoJson)
	if err := writer.Close(); err != nil {
		return "", fmt.Errorf("Error while saving lock file (%v): %v", info.Path, err)
	}

	return info.ID, nil
}

func (c *RemoteClient) Unlock(id string) error {
	lockErr := &state.LockError{}

	lockFileReader, err := c.lockFile().NewReader(c.storageContext)
	if err != nil {
		lockErr.Err = fmt.Errorf("Failed to retrieve lock info (%v): %v", c.lockFileURL(), err)
		return lockErr
	}
	defer lockFileReader.Close()

	lockFileContents, err := ioutil.ReadAll(lockFileReader)
	if err != nil {
		lockErr.Err = fmt.Errorf("Failed to retrieve lock info (%v): %v", c.lockFileURL(), err)
		return lockErr
	}

	lockInfo := &state.LockInfo{}
	err = json.Unmarshal(lockFileContents, lockInfo)
	if err != nil {
		lockErr.Err = fmt.Errorf("Failed to unmarshal lock info (%v): %v", c.lockFileURL(), err)
		return lockErr
	}

	lockErr.Info = lockInfo

	if lockInfo.ID != id {
		lockErr.Err = fmt.Errorf("Lock id %q does not match existing lock", id)
		return lockErr
	}

	lockFileAttrs, err := lockFile.Attrs(c.storageContext)
	if err != nil {
		lockErr.Err = fmt.Errorf("Failed to fetch lock file attrs (%v): %v", c.lockFileURL(), err)
		return lockErr
	}

	err = lockFile.If(storage.Conditions{GenerationMatch: lockFileAttrs.Generation}).Delete(c.storageContext)
	if err != nil {
		lockErr.Err = fmt.Errorf("Failed to delete lock file (%v): %v", c.lockFileURL(), err)
		return lockErr
	}

	return nil
}

func (c *RemoteClient) stateFile() *storage.ObjectHandle {
	return c.storageClient.Bucket(c.bucketName).Object(c.stateFilePath)
}

func (c *RemoteClient) stateFileURL() string {
	return fmt.Sprintf("gs://%v/%v", c.bucketName, c.stateFilePath)
}

func (c *RemoteClient) lockFile() *storage.ObjectHandle {
	return c.storageClient.Bucket(c.bucketName).Object(c.lockFilePath)
}

func (c *RemoteClient) lockFileURL() string {
	return fmt.Sprintf("gs://%v/%v", c.bucketName, c.lockFilePath)
}
<|endoftext|>


<commit_before>/* Copyright, Anas Khan © 2017 */

package main

import (
	"reflect"
	"testing"
)

type testpair struct {
	n        int
	arr      []int
	x        int
	expected int
}

/* Example test pairs */
var tests = []testpair{{4, []int{2, -6, 2, -1}, 3, 5}, {4, []int{2, 0, 3, 1}, 2, 23}}

/* Test function */
func TestHorners(t *testing.T) {
	for _, pair := range tests {
		actual := horners(pair.arr, pair.x)
		if !reflect.DeepEqual(actual, pair.expected) {
			t.Error("For", pair.arr, "expected", pair.expected, "got", actual)
		}
	}
}
<commit_msg>added test for horners power<commit_after>/* Copyright, Anas Khan © 2017 */

package main

import (
	"reflect"
	"testing"
)

type testpair struct {
	n        int
	arr      []int
	x        int
	expected int
}

type testpairPower struct {
	a        int
	p        int
	expected int
}

/* Example test pairs */
var tests = []testpair{{4, []int{2, -6, 2, -1}, 3, 5}, {4, []int{2, 0, 3, 1}, 2, 23}}
var testsPower = []testpairPower{{3, 4, 81}, {4, 5, 1024}, {5, 17, 762939453125}}

/* Test function */
func TestHorners(t *testing.T) {
	for _, pair := range tests {
		actual := horners(pair.arr, pair.x)
		if !reflect.DeepEqual(actual, pair.expected) {
			t.Error("For", pair.arr, "expected", pair.expected, "got", actual)
		}
	}
}

func TestHornersPower(t *testing.T) {
	for _, pair := range testsPower {
		actual := hornersPower(pair.a, pair.p)
		if !reflect.DeepEqual(actual, pair.expected) {
			t.Error("For", pair.a, "expected", pair.expected, "got", actual)
		}
	}
}
<|endoftext|>


<commit_before>package zazu

import (
	"reflect"
	"runtime"
	"strconv"
	"testing"
	"time"
)

func TestGetNextJobs(t *testing.T) {
	// TODO: consider edge cases and make this test more rigorous.
	// e.g.:
	// 	1. What happens when there are no queued jobs?
	//		2. What happens when n > len(queued jobs)?
	//		3. Is the job status correct at every stage?
	//		4. Is a given job gauranteed to only be returned by getNextJobs() once?
	flushdb()

	// Create a test job with high priority
	highPriorityJob, err := createTestJob()
	if err != nil {
		t.Errorf("Unexpected error creating test job: %s", err.Error())
	}
	highPriorityJob.priority = 1000
	highPriorityJob.id = "highPriorityJob"
	if err := highPriorityJob.save(); err != nil {
		t.Errorf("Unexpected error saving test job: %s", err.Error())
	}
	if err := highPriorityJob.Enqueue(); err != nil {
		t.Errorf("Unexpected error enqueuing test job: %s", err.Error())
	}

	// Create more tests with lower priorities
	for i := 0; i < 10; i++ {
		job, err := createTestJob()
		if err != nil {
			t.Errorf("Unexpected error creating test job: %s", err.Error())
		}
		job.priority = 100
		job.id = "lowPriorityJob" + strconv.Itoa(i)
		if err := job.save(); err != nil {
			t.Errorf("Unexpected error saving test job: %s", err.Error())
		}
		if err := job.Enqueue(); err != nil {
			t.Errorf("Unexpected error enqueuing test job: %s", err.Error())
		}
	}

	// Call getNextJobs with n = 1. We expect the one job returned to be the
	// highpriority one, but the status should now be executing
	jobs, err := getNextJobs(1)
	if err != nil {
		t.Errorf("Unexpected error from getNextJobs: %s", err.Error())
	}
	if len(jobs) != 1 {
		t.Errorf("Length of jobs was incorrect. Expected 1 but got %d", len(jobs))
	}
	gotJob := jobs[0]
	expectedJob := &Job{}
	(*expectedJob) = *highPriorityJob
	expectedJob.status = StatusExecuting
	if !reflect.DeepEqual(expectedJob, gotJob) {
		t.Errorf("Job returned by getNextJobs was incorrect.\n\tExpected: %+v\n\tBut got:  %+v", expectedJob, gotJob)
	}
}

func TestWorkerPoolStart(t *testing.T) {
	flushdb()

	// Register some jobs which will simply set one of the values in data
	data := make([]string, 8)
	writeResponseJob, err := RegisterJobType("writeResponse", func(i int) {
		data[i] = "ok"
	})
	if err != nil {
		t.Errorf("Unexpected error in RegisterJobType: %s", err.Error())
	}

	// Queue up some jobs
	queuedJobs := make([]*Job, len(data))
	for i := 0; i < len(data); i++ {
		// Lower indexes have higher priority and should be completed first
		job, err := writeResponseJob.Enqueue(8-i, time.Now(), i)
		if err != nil {
			t.Errorf("Unexpected error in Enqueue: %s", err.Error())
		}
		queuedJobs[i] = job
	}

	// Start the pool with 4 workers
	runtime.GOMAXPROCS(4)
	NumWorkers = 4
	BatchSize = 4
	Pool.Start()

	// Immediately stop the pool to stop the workers from doing more jobs
	Pool.Close()

	// Wait for the workers to finish
	Pool.Wait()

	// Check that the first 4 values of data were set to "ok"
	// This would mean that the first 4 jobs (in order of priority)
	// were successfully executed.
	for i := 0; i < 4; i++ {
		if data[i] != "ok" {
			t.Errorf(`Expected data[%d] to be set to "ok" but got: "%s"`, i, data[i])
		}
	}

	// Make sure all the other values of data are still blank
	for i := 4; i < len(data); i++ {
		if data[i] != "" {
			t.Errorf(`Expected data[%d] to be set to "" but got: "%s"`, i, data[i])
		}
	}

	// Make sure the first four jobs we queued are marked as finished
	for _, job := range queuedJobs[0:4] {
		// Since we don't have a fresh copy, set the status manually. I.e. there is
		// a difference between the reference we have to the job and what actually exists
		// in the database. The database is what we care about.
		// assertJobStatusEquals will check that the job is correct in the database.
		job.status = StatusFinished
		assertJobStatusEquals(t, job, StatusFinished)
	}

	// Make sure the next four jobs we queued are marked as queued
	for _, job := range queuedJobs[4:] {
		// Since we don't have a fresh copy, set the status manually. I.e. there is
		// a difference between the reference we have to the job and what actually exists
		// in the database. The database is what we care about.
		// assertJobStatusEquals will check that the job is correct in the database.
		job.status = StatusQueued
		assertJobStatusEquals(t, job, StatusQueued)
	}
}
<commit_msg>Refactor worker_pool_test and add test to make sure each job is executed once.<commit_after>package zazu

import (
	"reflect"
	"runtime"
	"strconv"
	"testing"
	"time"
)

func TestGetNextJobs(t *testing.T) {
	// TODO: consider edge cases and make this test more rigorous.
	// e.g.:
	// 	1. What happens when there are no queued jobs?
	//		2. What happens when n > len(queued jobs)?
	//		3. Is the job status correct at every stage?
	//		4. Is a given job gauranteed to only be returned by getNextJobs() once?
	flushdb()

	// Create a test job with high priority
	highPriorityJob, err := createTestJob()
	if err != nil {
		t.Errorf("Unexpected error creating test job: %s", err.Error())
	}
	highPriorityJob.priority = 1000
	highPriorityJob.id = "highPriorityJob"
	if err := highPriorityJob.save(); err != nil {
		t.Errorf("Unexpected error saving test job: %s", err.Error())
	}
	if err := highPriorityJob.Enqueue(); err != nil {
		t.Errorf("Unexpected error enqueuing test job: %s", err.Error())
	}

	// Create more tests with lower priorities
	for i := 0; i < 10; i++ {
		job, err := createTestJob()
		if err != nil {
			t.Errorf("Unexpected error creating test job: %s", err.Error())
		}
		job.priority = 100
		job.id = "lowPriorityJob" + strconv.Itoa(i)
		if err := job.save(); err != nil {
			t.Errorf("Unexpected error saving test job: %s", err.Error())
		}
		if err := job.Enqueue(); err != nil {
			t.Errorf("Unexpected error enqueuing test job: %s", err.Error())
		}
	}

	// Call getNextJobs with n = 1. We expect the one job returned to be the
	// highpriority one, but the status should now be executing
	jobs, err := getNextJobs(1)
	if err != nil {
		t.Errorf("Unexpected error from getNextJobs: %s", err.Error())
	}
	if len(jobs) != 1 {
		t.Errorf("Length of jobs was incorrect. Expected 1 but got %d", len(jobs))
	}
	gotJob := jobs[0]
	expectedJob := &Job{}
	(*expectedJob) = *highPriorityJob
	expectedJob.status = StatusExecuting
	if !reflect.DeepEqual(expectedJob, gotJob) {
		t.Errorf("Job returned by getNextJobs was incorrect.\n\tExpected: %+v\n\tBut got:  %+v", expectedJob, gotJob)
	}
}

func TestJobsWithHigherPriorityExecutedFirst(t *testing.T) {
	flushdb()

	// Register some jobs which will simply set one of the values in data
	data := make([]string, 8)
	setStringJob, err := RegisterJobType("setString", func(i int) {
		data[i] = "ok"
	})
	if err != nil {
		t.Errorf("Unexpected error in RegisterJobType: %s", err.Error())
	}

	// Queue up some jobs
	queuedJobs := make([]*Job, len(data))
	for i := 0; i < len(data); i++ {
		// Lower indexes have higher priority and should be completed first
		job, err := setStringJob.Enqueue(8-i, time.Now(), i)
		if err != nil {
			t.Errorf("Unexpected error in Enqueue: %s", err.Error())
		}
		queuedJobs[i] = job
	}

	// Start the pool with 4 workers
	runtime.GOMAXPROCS(4)
	NumWorkers = 4
	BatchSize = 4
	Pool.Start()

	// Immediately stop the pool to stop the workers from doing more jobs
	Pool.Close()

	// Wait for the workers to finish
	Pool.Wait()

	// Check that the first 4 values of data were set to "ok"
	// This would mean that the first 4 jobs (in order of priority)
	// were successfully executed.
	for i, datum := range data[0:4] {
		if datum != "ok" {
			t.Errorf(`Expected data[%d] to be set to "ok" but got: "%s"`, i, datum)
		}
	}

	// Make sure all the other values of data are still blank
	for i, datum := range data[4:] {
		if datum != "" {
			t.Errorf(`Expected data[%d] to be set to "" but got: "%s"`, i, datum)
		}
	}

	// Make sure the first four jobs we queued are marked as finished
	for _, job := range queuedJobs[0:4] {
		// Since we don't have a fresh copy, set the status manually. I.e. there is
		// a difference between the reference we have to the job and what actually exists
		// in the database. The database is what we care about.
		// assertJobStatusEquals will check that the job is correct in the database.
		job.status = StatusFinished
		assertJobStatusEquals(t, job, StatusFinished)
	}

	// Make sure the next four jobs we queued are marked as queued
	for _, job := range queuedJobs[4:] {
		// Since we don't have a fresh copy, set the status manually. I.e. there is
		// a difference between the reference we have to the job and what actually exists
		// in the database. The database is what we care about.
		// assertJobStatusEquals will check that the job is correct in the database.
		job.status = StatusQueued
		assertJobStatusEquals(t, job, StatusQueued)
	}
}

func TestJobsOnlyExecutedOnce(t *testing.T) {
	flushdb()

	// Register some jobs which will simply increment one of the values in data
	data := make([]int, 4)
	incrementJob, err := RegisterJobType("increment", func(i int) {
		data[i] += 1
	})
	if err != nil {
		t.Errorf("Unexpected error in RegisterJobType: %s", err.Error())
	}

	// Queue up some jobs
	queuedJobs := make([]*Job, len(data))
	for i := 0; i < len(data); i++ {
		// Lower indexes have higher priority and should be completed first
		job, err := incrementJob.Enqueue(100, time.Now(), i)
		if err != nil {
			t.Errorf("Unexpected error in Enqueue: %s", err.Error())
		}
		queuedJobs[i] = job
	}

	// Start the pool with 4 workers
	runtime.GOMAXPROCS(4)
	NumWorkers = 4
	BatchSize = 4
	Pool.Start()

	// Immediately stop the pool to stop the workers from doing more jobs
	Pool.Close()

	// Wait for the workers to finish
	Pool.Wait()

	// Check that each value in data equals 1.
	// This would mean that each job was only executed once
	for i, datum := range data {
		if datum != 1 {
			t.Errorf(`Expected data[%d] to be 1 but got: %d`, i, datum)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Luke Shumaker

package web

import (
	"github.com/jinzhu/gorm"
	he "httpentity"
	"periwinkle/cfg"
)

type database struct{}

func (p database) Before(req *he.Request) {
	transaction := cfg.DB.Begin()
	req.Things["db"] = transaction
}

func (p database) After(req he.Request, res *he.Response) {
	transaction := req.Things["db"].(*gorm.DB)
	result := transaction.Commit()
	if result.Error != nil {
		// TODO: DB: handle the error; it could be either HTTP 500
		// (Internal Server Error) or 409 (Conflict)
	}
}
<commit_msg>middleware_database: detect SQLite constraint failures, and HTTP 409 them<commit_after>// Copyright 2015 Luke Shumaker

package web

import (
	"github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
	"github.com/mattn/go-sqlite3" // sqlite3
	he "httpentity"
	"httpentity/util"
	"periwinkle/cfg"
)

type database struct{}

func (p database) Before(req *he.Request) {
	transaction := cfg.DB.Begin()
	req.Things["db"] = transaction
}

func (p database) After(req he.Request, res *he.Response) {
	defer func() {
		if obj := recover(); obj != nil {
			switch err := obj.(type) {
			case sqlite3.Error:
				if err.Code == sqlite3.ErrConstraint {
					*res = he.StatusConflict(heutil.NetString(err.Error()))
					return
				}
			case mysql.MySQLError:
				// TODO: detect constraint falure for MySQL
			}
			// we didn't intercept the error, so pass it along
			panic(obj)
		}
	}()

	if obj := recover(); obj != nil {
		panic(obj)
	}

	transaction := req.Things["db"].(*gorm.DB)
	err := transaction.Commit().Error
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>// Package contains Node File struct and MultiReaderAt implementation
package file

import (
	"io"
	"os"
)

// File is the Node file structure. Contains the json/bson marshalling controls.
type File struct {
	Name         string            `bson:"name" json:"name"`
	Size         int64             `bson:"size" json:"size"`
	Checksum     map[string]string `bson:"checksum" json:"checksum"`
	Format       string            `bson:"format" json:"format"`
	Path         string            `bson:"path" json:"-"`
	Virtual      bool              `bson:"virtual" json:"virtual"`
	VirtualParts []string          `bson:"virtual_parts" json:"virtual_parts"`
}

// SectionReader interface required for MultiReaderAt
type SectionReader interface {
	io.Reader
	io.ReaderAt
}

// ReaderAt interface that is compatiable with os.File types.
type ReaderAt interface {
	SectionReader
	Stat() (os.FileInfo, error)
}

// multifd contains file boundary information
type multifd struct {
	start int64
	end   int64
	size  int64
}

// multiReaderAt is private struct for the multi-file ReaderAt
// that provides the ablity to use indexes with vitrual files.
type multiReaderAt struct {
	readers    []ReaderAt
	boundaries []multifd
	size       int64
}

// MultiReaderAt returns a ReaderAt that's the logical concatenation of
// the provided input readers. BUG / KNOW-ISSUE: all file handles are opened
// initially. May not be suitiable for large numbers of files.
func MultiReaderAt(readers ...ReaderAt) ReaderAt {
	mr := &multiReaderAt{readers: readers}
	b := []multifd{}
	start := int64(0)
	for _, r := range mr.readers {
		fi, _ := r.Stat()
		b = append(b, multifd{start: start, end: start + fi.Size(), size: fi.Size()})
		start = start + fi.Size()
	}
	mr.boundaries = b
	mr.size = b[len(b)-1].end
	return mr
}

// Read same as io.MultiReader
func (mr *multiReaderAt) Read(p []byte) (n int, err error) {
	for len(mr.readers) > 0 {
		n, err = mr.readers[0].Read(p)
		if n > 0 || err != io.EOF {
			if err == io.EOF {
				// Don't return EOF yet. There may be more bytes
				// in the remaining readers.
				err = nil
			}
			return
		}
		mr.readers = mr.readers[1:]
	}
	return 0, io.EOF
}

// ReadAt is the magic sauce. Heavily commented to include all logic.
func (mr *multiReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
	startF, endF := 0, 0
	startPos, endPos, length := int64(0), int64(0), int64(len(p))

	if off > mr.size {
		return 0, io.EOF
	}

	// find start
	for i, fd := range mr.boundaries {
		if off >= fd.start && off <= fd.end {
			startF = i
			startPos = off - fd.start
			break
		}
	}

	// find end
	if off+length > mr.size {
		endF = len(mr.readers) - 1
		endPos = mr.size - mr.boundaries[endF].start
	} else {
		for i, fd := range mr.boundaries {
			if off+length >= fd.start && off+length <= fd.end {
				endF = i
				endPos = off + length - fd.start
				break
			}
		}
	}

	if startF == endF {
		// read startpos till endpos
		// println("--> readat: startpos till endpos")
		// fmt.Printf("file: %d, offset: %d, length: %d\n", startF, startPos, endPos-startPos)
		return mr.readers[startF].ReadAt(p[0:length], startPos)
	} else {
		buffPos := 0
		for i := startF; i <= endF; i++ {
			if i == startF {
				// read startpos till end of file
				// println("--> readat: startpos till end of file")
				// fmt.Printf("file: %d, offset: %d, length: %d, buffPos: %d\n", i, startPos, mr.boundaries[i].size-startPos, buffPos)
				if rn, err := mr.readers[i].ReadAt(p[buffPos:buffPos+int(mr.boundaries[i].size-startPos)], startPos); err != nil && err != io.EOF {
					return 0, err
				} else {
					buffPos = buffPos + int(mr.boundaries[i].size-startPos)
					n = n + rn
				}
			} else if i == endF {
				// read start of file till endpos
				// println("--> readat: start of file till endpos")
				// fmt.Printf("file: %d, offset: %d, length: %d, buffPos: %d\n", i, 0, endPos, buffPos)
				if rn, err := mr.readers[i].ReadAt(p[buffPos:buffPos+int(endPos)], 0); err != nil && err != io.EOF {
					println("--> error here: ", err.Error())
					return 0, err
				} else {
					buffPos = buffPos + int(endPos)
					n = n + rn
				}
			} else {
				// read entire file
				// println("--> readat: entire file")
				// fmt.Printf("file: %d, offset: %d, length: %d, buffPos: %d\n", i, 0, mr.boundaries[i].size, buffPos)
				if rn, err := mr.readers[i].ReadAt(p[buffPos:buffPos+int(mr.boundaries[i].size)], 0); err != nil && err != io.EOF {
					return 0, err
				} else {
					buffPos = buffPos + int(mr.boundaries[i].size)
					n = n + rn
				}
			}
		}
	}
	if n < int(length) {
		return n, io.EOF
	}
	return
}

// Required for the ReaderAt interface but non-implemented
func (mr *multiReaderAt) Stat() (fi os.FileInfo, err error) {
	return
}
<commit_msg>Added Close() function to ReaderAt interface so it could be called on open file handles<commit_after>// Package contains Node File struct and MultiReaderAt implementation
package file

import (
	"io"
	"os"
)

// File is the Node file structure. Contains the json/bson marshalling controls.
type File struct {
	Name         string            `bson:"name" json:"name"`
	Size         int64             `bson:"size" json:"size"`
	Checksum     map[string]string `bson:"checksum" json:"checksum"`
	Format       string            `bson:"format" json:"format"`
	Path         string            `bson:"path" json:"-"`
	Virtual      bool              `bson:"virtual" json:"virtual"`
	VirtualParts []string          `bson:"virtual_parts" json:"virtual_parts"`
}

// SectionReader interface required for MultiReaderAt
type SectionReader interface {
	io.Reader
	io.ReaderAt
}

// ReaderAt interface that is compatiable with os.File types.
type ReaderAt interface {
	SectionReader
	Stat() (os.FileInfo, error)
	Close() error
}

// multifd contains file boundary information
type multifd struct {
	start int64
	end   int64
	size  int64
}

// multiReaderAt is private struct for the multi-file ReaderAt
// that provides the ablity to use indexes with vitrual files.
type multiReaderAt struct {
	readers    []ReaderAt
	boundaries []multifd
	size       int64
}

// MultiReaderAt returns a ReaderAt that's the logical concatenation of
// the provided input readers. BUG / KNOW-ISSUE: all file handles are opened
// initially. May not be suitiable for large numbers of files.
func MultiReaderAt(readers ...ReaderAt) ReaderAt {
	mr := &multiReaderAt{readers: readers}
	b := []multifd{}
	start := int64(0)
	for _, r := range mr.readers {
		fi, _ := r.Stat()
		b = append(b, multifd{start: start, end: start + fi.Size(), size: fi.Size()})
		start = start + fi.Size()
	}
	mr.boundaries = b
	mr.size = b[len(b)-1].end
	return mr
}

// Read same as io.MultiReader
func (mr *multiReaderAt) Read(p []byte) (n int, err error) {
	for len(mr.readers) > 0 {
		n, err = mr.readers[0].Read(p)
		if n > 0 || err != io.EOF {
			if err == io.EOF {
				// Don't return EOF yet. There may be more bytes
				// in the remaining readers.
				err = nil
			}
			return
		}
		mr.readers = mr.readers[1:]
	}
	return 0, io.EOF
}

// ReadAt is the magic sauce. Heavily commented to include all logic.
func (mr *multiReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
	startF, endF := 0, 0
	startPos, endPos, length := int64(0), int64(0), int64(len(p))

	if off > mr.size {
		return 0, io.EOF
	}

	// find start
	for i, fd := range mr.boundaries {
		if off >= fd.start && off <= fd.end {
			startF = i
			startPos = off - fd.start
			break
		}
	}

	// find end
	if off+length > mr.size {
		endF = len(mr.readers) - 1
		endPos = mr.size - mr.boundaries[endF].start
	} else {
		for i, fd := range mr.boundaries {
			if off+length >= fd.start && off+length <= fd.end {
				endF = i
				endPos = off + length - fd.start
				break
			}
		}
	}

	if startF == endF {
		// read startpos till endpos
		// println("--> readat: startpos till endpos")
		// fmt.Printf("file: %d, offset: %d, length: %d\n", startF, startPos, endPos-startPos)
		return mr.readers[startF].ReadAt(p[0:length], startPos)
	} else {
		buffPos := 0
		for i := startF; i <= endF; i++ {
			if i == startF {
				// read startpos till end of file
				// println("--> readat: startpos till end of file")
				// fmt.Printf("file: %d, offset: %d, length: %d, buffPos: %d\n", i, startPos, mr.boundaries[i].size-startPos, buffPos)
				if rn, err := mr.readers[i].ReadAt(p[buffPos:buffPos+int(mr.boundaries[i].size-startPos)], startPos); err != nil && err != io.EOF {
					return 0, err
				} else {
					buffPos = buffPos + int(mr.boundaries[i].size-startPos)
					n = n + rn
				}
			} else if i == endF {
				// read start of file till endpos
				// println("--> readat: start of file till endpos")
				// fmt.Printf("file: %d, offset: %d, length: %d, buffPos: %d\n", i, 0, endPos, buffPos)
				if rn, err := mr.readers[i].ReadAt(p[buffPos:buffPos+int(endPos)], 0); err != nil && err != io.EOF {
					println("--> error here: ", err.Error())
					return 0, err
				} else {
					buffPos = buffPos + int(endPos)
					n = n + rn
				}
			} else {
				// read entire file
				// println("--> readat: entire file")
				// fmt.Printf("file: %d, offset: %d, length: %d, buffPos: %d\n", i, 0, mr.boundaries[i].size, buffPos)
				if rn, err := mr.readers[i].ReadAt(p[buffPos:buffPos+int(mr.boundaries[i].size)], 0); err != nil && err != io.EOF {
					return 0, err
				} else {
					buffPos = buffPos + int(mr.boundaries[i].size)
					n = n + rn
				}
			}
		}
	}
	if n < int(length) {
		return n, io.EOF
	}
	return
}

// Required for the ReaderAt interface but non-implemented
func (mr *multiReaderAt) Stat() (fi os.FileInfo, err error) {
	return
}

// Required for the ReaderAt interface but non-implemented
func (mr *multiReaderAt) Close() (err error) {
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strconv"
	"strings"
)

//The IP struct
type IP struct {
	Address    string
	ServerName string
	Delay      int
	Bandwidth  int
}

const (
	tmpOkIPFileName string = "ip_tmpok.txt"
	jsonIPFileName  string = "ip_output.txt"
)

func main() {
	tips()

}
func tips() {

	fmt.Print(`请选择需要处理的操作, 输入对应的数字并按下回车:

1. 提取 ip_tmpok.txt 中的IP, 用｜分隔以及 json 格式, 并生成ip_output.txt

2. IP格式互转 GoAgent <==> GoProxy, 并生成 ip_output.txt

请输入对应的数字：`)

	switch getInputFromCommand() {
	case "1":
		convertIP2JSON()
	case "2":
		goagent2goproxy()
	default:
		tips()
	}
}
func convertIP2JSON() {
	var delay int
	var bandwidth int
	var err error
	isAll := true
	isAllBandwidth := true
	isGWS := false

	fmt.Print("\n请输入最大延迟（以毫秒计算），否则提取所有IP：")
	delaytmp := getInputFromCommand()
	if len(delaytmp) > 0 {
		delay, err = strconv.Atoi(delaytmp)
		if err != nil {
			fmt.Println("\n输入不正确，请重新输入。")
			convertIP2JSON()
			return
		}
		isAll = false
	}
	fmt.Print("\n是否只提取gws的IP，是请输入y，否请直接按回车键：")
	isgws := getInputFromCommand()
	if isgws == "y" || isgws == "Y" {
		isGWS = true
	}
	// CheckBD:
	// 	fmt.Print("\n请输入最小带宽（以KB计算，仅针对gws IP）,否则提取所有带宽的IP：")
	// 	bandwidthtmp := getInputFromCommand()
	// 	if len(bandwidthtmp) > 0 {
	// 		bandwidth, err = strconv.Atoi(bandwidthtmp)
	// 		if err != nil {
	// 			fmt.Println("\n输入不正确，请重新输入。")
	// 			goto CheckBD
	// 		}
	// 		isAllBandwidth = false
	// 	}
	gws, gvs := writeJSONIP2File(delay, bandwidth, isGWS, isAllBandwidth, isAll)
	fmt.Printf("\ndelay: %dms, ip count: %d(gws: %d, gvs: %d)\n", delay, gws+gvs, gws, gvs)

	fmt.Println("\npress Enter to continue...")
	fmt.Scanln()
	tips()
}
func goagent2goproxy() {
	fmt.Println("请输入需要转换的IP, 会自动去除重复IP，可使用右键->粘贴：")
	fmt.Println()
	rawips := getInputFromCommand()
	rawips = strings.TrimSpace(rawips)
	var ipstr string
	m := make(map[string]string)
	if strings.Contains(rawips, "|") {
		ips := strings.Split(rawips, "|")
		for _, ip := range ips {
			tmpip := net.ParseIP(ip)
			if tmpip != nil {
				m[tmpip.String()] = tmpip.String()
			}
		}
		var ipbuf bytes.Buffer
		for k := range m {
			ipbuf.WriteString("\"")
			ipbuf.WriteString(k)
			ipbuf.WriteString("\",")
		}
		ipstr = ipbuf.String()
		ipstr = ipstr[:len(ipstr)-1]
	} else {
		rawips = rawips[1 : len(rawips)-1]
		ips := strings.Split(strings.TrimSpace(rawips), "\",\"")
		for _, ip := range ips {
			tmpip := net.ParseIP(ip)
			if tmpip != nil {
				m[tmpip.String()] = tmpip.String()
			}
		}
		var ipbuf bytes.Buffer
		for k := range m {
			ipbuf.WriteString(k)
			ipbuf.WriteString("|")
		}
		ipstr = ipbuf.String()
		ipstr = ipstr[:len(ipstr)-1]
	}
	fmt.Println()
	fmt.Println(ipstr)
	fmt.Println("\npress Enter to continue...")
	fmt.Scanln()
	tips()
}
func getInputFromCommand() string {
	reader := bufio.NewReader(os.Stdin)
	input, _ := reader.ReadString('\n')
	input = input[:len(input)-2]

	return input
}

//get last ok ip
func getLastOkIP() []IP {
	m := make(map[string]IP)
	var checkedip IP
	var ips []IP
	if isFileExist(tmpOkIPFileName) {
		bytes, err := ioutil.ReadFile(tmpOkIPFileName)
		if err != nil {
			fmt.Printf("read file %s error: %v", tmpOkIPFileName, err)
		}
		lines := strings.Split(string(bytes), "\n")
		for _, line := range lines {
			ipInfo := strings.Split(line, " ")
			if len(ipInfo) == 6 || len(ipInfo) == 5 {
				delay, _ := strconv.Atoi(ipInfo[1][:len(ipInfo[1])-2])
				// bandwidth, err := strconv.Atoi(ipInfo[5][:len(ipInfo[5])-4])
				// if err != nil {
				// fmt.Println("bandwidth conversion failed: ", err)
				// }
				checkedip = IP{
					Address:    ipInfo[0],
					Delay:      delay,
					ServerName: ipInfo[3],
					// Bandwidth:  bandwidth,
				}
				m[ipInfo[0]] = checkedip
			}
		}
	}
	for _, v := range m {
		ips = append(ips, v)
	}
	return ips
}

/**
writeJSONIP2File: sorting ip, ridding duplicate ip, generating json ip and
bar-separated ip
*/
func writeJSONIP2File(delay int, bandwidth int, isGWS, isAllBandwidth, isAll bool) (gws, gvs int) {
	okIPs := getLastOkIP()
	_, err := os.Create(jsonIPFileName)
	if err != nil {
		fmt.Printf("create file %s error: %v", jsonIPFileName, err)
	}
	var gaipbuf, gpipbuf bytes.Buffer
	for _, ip := range okIPs {
		if isAllBandwidth {
			if isGWS {
				if ip.ServerName == "gws" {
					if isAll {
						gws++
						gaipbuf.WriteString(ip.Address)
						gaipbuf.WriteString("|")
						gpipbuf.WriteString("\"")
						gpipbuf.WriteString(ip.Address)
						gpipbuf.WriteString("\",")
					} else {
						if ip.Delay <= delay {
							gws++
							gaipbuf.WriteString(ip.Address)
							gaipbuf.WriteString("|")
							gpipbuf.WriteString("\"")
							gpipbuf.WriteString(ip.Address)
							gpipbuf.WriteString("\",")
						}
					}
				}
			} else {
				if isAll {
					if ip.ServerName == "gws" {
						gws++
					}
					if ip.ServerName == "gvs" {
						gvs++
					}
					gaipbuf.WriteString(ip.Address)
					gaipbuf.WriteString("|")
					gpipbuf.WriteString("\"")
					gpipbuf.WriteString(ip.Address)
					gpipbuf.WriteString("\",")
				} else {
					if ip.Delay <= delay {
						if ip.ServerName == "gws" {
							gws++
						}
						if ip.ServerName == "gvs" {
							gvs++
						}
						gaipbuf.WriteString(ip.Address)
						gaipbuf.WriteString("|")
						gpipbuf.WriteString("\"")
						gpipbuf.WriteString(ip.Address)
						gpipbuf.WriteString("\",")
					}
				}
			}
		} else {
			if ip.Bandwidth >= bandwidth {
				if isGWS {
					if ip.ServerName == "gws" {
						if isAll {
							gws++
							gaipbuf.WriteString(ip.Address)
							gaipbuf.WriteString("|")
							gpipbuf.WriteString("\"")
							gpipbuf.WriteString(ip.Address)
							gpipbuf.WriteString("\",")
						} else {
							if ip.Delay <= delay {
								gws++
								gaipbuf.WriteString(ip.Address)
								gaipbuf.WriteString("|")
								gpipbuf.WriteString("\"")
								gpipbuf.WriteString(ip.Address)
								gpipbuf.WriteString("\",")
							}
						}
					}
				} else {
					if isAll {
						if ip.ServerName == "gws" {
							gws++
						}
						if ip.ServerName == "gvs" {
							gvs++
						}
						gaipbuf.WriteString(ip.Address)
						gaipbuf.WriteString("|")
						gpipbuf.WriteString("\"")
						gpipbuf.WriteString(ip.Address)
						gpipbuf.WriteString("\",")
					} else {
						if ip.Delay <= delay {
							if ip.ServerName == "gws" {
								gws++
							}
							if ip.ServerName == "gvs" {
								gvs++
							}
							gaipbuf.WriteString(ip.Address)
							gaipbuf.WriteString("|")
							gpipbuf.WriteString("\"")
							gpipbuf.WriteString(ip.Address)
							gpipbuf.WriteString("\",")
						}
					}
				}
			}
		}
	}
	gaip := gaipbuf.String()
	gpip := gpipbuf.String()

	if len(gaip) > 0 {
		gaip = gaip[:len(gaip)-1]
	}
	if len(gpip) > 0 {
		gpip = gpip[:len(gpip)-1]
	}
	err = ioutil.WriteFile(jsonIPFileName, []byte(gaip+"\n\n\n"+gpip), 0755)
	if err != nil {
		fmt.Printf("write ip to file %s error: %v", jsonIPFileName, err)
	}
	return gws, gvs
}

//Whether file exists.
func isFileExist(file string) bool {
	_, err := os.Stat(file)
	if err != nil && os.IsNotExist(err) {
		return false
	}
	return true
}
<commit_msg>bugfix for arm arch<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strconv"
	"strings"
)

//The IP struct
type IP struct {
	Address    string
	ServerName string
	Delay      int
	Bandwidth  int
}

const (
	tmpOkIPFileName string = "ip_tmpok.txt"
	jsonIPFileName  string = "ip_output.txt"
)

func main() {
	tips()

}
func tips() {

	fmt.Print(`请选择需要处理的操作, 输入对应的数字并按下回车:

1. 提取 ip_tmpok.txt 中的IP, 用｜分隔以及 json 格式, 并生成ip_output.txt

2. IP格式互转 GoAgent <==> GoProxy, 并生成 ip_output.txt

请输入对应的数字：`)

	switch getInputFromCommand() {
	case "1":
		convertIP2JSON()
	case "2":
		goagent2goproxy()
	default:
		tips()
	}
}
func convertIP2JSON() {
	var delay int
	var bandwidth int
	var err error
	isAll := true
	isAllBandwidth := true
	isGWS := false

	fmt.Print("\n请输入最大延迟（以毫秒计算），否则提取所有IP：")
	delaytmp := getInputFromCommand()
	if len(delaytmp) > 0 {
		delay, err = strconv.Atoi(delaytmp)
		if err != nil {
			fmt.Println("\n输入不正确，请重新输入。")
			convertIP2JSON()
			return
		}
		isAll = false
	}
	fmt.Print("\n是否只提取gws的IP，是请输入y，否请直接按回车键：")
	isgws := getInputFromCommand()
	if isgws == "y" || isgws == "Y" {
		isGWS = true
	}
	// CheckBD:
	// 	fmt.Print("\n请输入最小带宽（以KB计算，仅针对gws IP）,否则提取所有带宽的IP：")
	// 	bandwidthtmp := getInputFromCommand()
	// 	if len(bandwidthtmp) > 0 {
	// 		bandwidth, err = strconv.Atoi(bandwidthtmp)
	// 		if err != nil {
	// 			fmt.Println("\n输入不正确，请重新输入。")
	// 			goto CheckBD
	// 		}
	// 		isAllBandwidth = false
	// 	}
	gws, gvs := writeJSONIP2File(delay, bandwidth, isGWS, isAllBandwidth, isAll)
	fmt.Printf("\ndelay: %dms, ip count: %d(gws: %d, gvs: %d)\n", delay, gws+gvs, gws, gvs)

	fmt.Println("\npress Enter to continue...")
	fmt.Scanln()
	tips()
}
func goagent2goproxy() {
	fmt.Println("请输入需要转换的IP, 会自动去除重复IP，可使用右键->粘贴：")
	fmt.Println()
	rawips := getInputFromCommand()
	rawips = strings.TrimSpace(rawips)
	var ipstr string
	m := make(map[string]string)
	if strings.Contains(rawips, "|") {
		ips := strings.Split(rawips, "|")
		for _, ip := range ips {
			tmpip := net.ParseIP(ip)
			if tmpip != nil {
				m[tmpip.String()] = tmpip.String()
			}
		}
		var ipbuf bytes.Buffer
		for k := range m {
			ipbuf.WriteString("\"")
			ipbuf.WriteString(k)
			ipbuf.WriteString("\",")
		}
		ipstr = ipbuf.String()
		ipstr = ipstr[:len(ipstr)-1]
	} else {
		rawips = rawips[1 : len(rawips)-1]
		ips := strings.Split(strings.TrimSpace(rawips), "\",\"")
		for _, ip := range ips {
			tmpip := net.ParseIP(ip)
			if tmpip != nil {
				m[tmpip.String()] = tmpip.String()
			}
		}
		var ipbuf bytes.Buffer
		for k := range m {
			ipbuf.WriteString(k)
			ipbuf.WriteString("|")
		}
		ipstr = ipbuf.String()
		ipstr = ipstr[:len(ipstr)-1]
	}
	fmt.Println()
	fmt.Println(ipstr)
	fmt.Println("\npress Enter to continue...")
	fmt.Scanln()
	tips()
}
func getInputFromCommand() string {
	reader := bufio.NewReader(os.Stdin)
	input, _ := reader.ReadString('\n')
	input = strings.Replace(strings.Replace(input, "\n", "", -1), "\r", "", -1)
	return input
}

//get last ok ip
func getLastOkIP() []IP {
	m := make(map[string]IP)
	var checkedip IP
	var ips []IP
	if isFileExist(tmpOkIPFileName) {
		bytes, err := ioutil.ReadFile(tmpOkIPFileName)
		if err != nil {
			fmt.Printf("read file %s error: %v", tmpOkIPFileName, err)
		}
		lines := strings.Split(string(bytes), "\n")
		for _, line := range lines {
			ipInfo := strings.Split(line, " ")
			if len(ipInfo) == 6 || len(ipInfo) == 5 {
				delay, _ := strconv.Atoi(ipInfo[1][:len(ipInfo[1])-2])
				// bandwidth, err := strconv.Atoi(ipInfo[5][:len(ipInfo[5])-4])
				// if err != nil {
				// fmt.Println("bandwidth conversion failed: ", err)
				// }
				checkedip = IP{
					Address:    ipInfo[0],
					Delay:      delay,
					ServerName: ipInfo[3],
					// Bandwidth:  bandwidth,
				}
				m[ipInfo[0]] = checkedip
			}
		}
	}
	for _, v := range m {
		ips = append(ips, v)
	}
	return ips
}

/**
writeJSONIP2File: sorting ip, ridding duplicate ip, generating json ip and
bar-separated ip
*/
func writeJSONIP2File(delay int, bandwidth int, isGWS, isAllBandwidth, isAll bool) (gws, gvs int) {
	okIPs := getLastOkIP()
	_, err := os.Create(jsonIPFileName)
	if err != nil {
		fmt.Printf("create file %s error: %v", jsonIPFileName, err)
	}
	var gaipbuf, gpipbuf bytes.Buffer
	for _, ip := range okIPs {
		if isAllBandwidth {
			if isGWS {
				if ip.ServerName == "gws" {
					if isAll {
						gws++
						gaipbuf.WriteString(ip.Address)
						gaipbuf.WriteString("|")
						gpipbuf.WriteString("\"")
						gpipbuf.WriteString(ip.Address)
						gpipbuf.WriteString("\",")
					} else {
						if ip.Delay <= delay {
							gws++
							gaipbuf.WriteString(ip.Address)
							gaipbuf.WriteString("|")
							gpipbuf.WriteString("\"")
							gpipbuf.WriteString(ip.Address)
							gpipbuf.WriteString("\",")
						}
					}
				}
			} else {
				if isAll {
					if ip.ServerName == "gws" {
						gws++
					}
					if ip.ServerName == "gvs" {
						gvs++
					}
					gaipbuf.WriteString(ip.Address)
					gaipbuf.WriteString("|")
					gpipbuf.WriteString("\"")
					gpipbuf.WriteString(ip.Address)
					gpipbuf.WriteString("\",")
				} else {
					if ip.Delay <= delay {
						if ip.ServerName == "gws" {
							gws++
						}
						if ip.ServerName == "gvs" {
							gvs++
						}
						gaipbuf.WriteString(ip.Address)
						gaipbuf.WriteString("|")
						gpipbuf.WriteString("\"")
						gpipbuf.WriteString(ip.Address)
						gpipbuf.WriteString("\",")
					}
				}
			}
		} else {
			if ip.Bandwidth >= bandwidth {
				if isGWS {
					if ip.ServerName == "gws" {
						if isAll {
							gws++
							gaipbuf.WriteString(ip.Address)
							gaipbuf.WriteString("|")
							gpipbuf.WriteString("\"")
							gpipbuf.WriteString(ip.Address)
							gpipbuf.WriteString("\",")
						} else {
							if ip.Delay <= delay {
								gws++
								gaipbuf.WriteString(ip.Address)
								gaipbuf.WriteString("|")
								gpipbuf.WriteString("\"")
								gpipbuf.WriteString(ip.Address)
								gpipbuf.WriteString("\",")
							}
						}
					}
				} else {
					if isAll {
						if ip.ServerName == "gws" {
							gws++
						}
						if ip.ServerName == "gvs" {
							gvs++
						}
						gaipbuf.WriteString(ip.Address)
						gaipbuf.WriteString("|")
						gpipbuf.WriteString("\"")
						gpipbuf.WriteString(ip.Address)
						gpipbuf.WriteString("\",")
					} else {
						if ip.Delay <= delay {
							if ip.ServerName == "gws" {
								gws++
							}
							if ip.ServerName == "gvs" {
								gvs++
							}
							gaipbuf.WriteString(ip.Address)
							gaipbuf.WriteString("|")
							gpipbuf.WriteString("\"")
							gpipbuf.WriteString(ip.Address)
							gpipbuf.WriteString("\",")
						}
					}
				}
			}
		}
	}
	gaip := gaipbuf.String()
	gpip := gpipbuf.String()

	if len(gaip) > 0 {
		gaip = gaip[:len(gaip)-1]
	}
	if len(gpip) > 0 {
		gpip = gpip[:len(gpip)-1]
	}
	err = ioutil.WriteFile(jsonIPFileName, []byte(gaip+"\n\n\n"+gpip), 0755)
	if err != nil {
		fmt.Printf("write ip to file %s error: %v", jsonIPFileName, err)
	}
	return gws, gvs
}

//Whether file exists.
func isFileExist(file string) bool {
	_, err := os.Stat(file)
	if err != nil && os.IsNotExist(err) {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>//go:build linux && cgo && !agent

package state

import (
	"context"
	"net/http"
	"net/url"

	"github.com/lxc/lxd/lxd/bgp"
	clusterConfig "github.com/lxc/lxd/lxd/cluster/config"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/dns"
	"github.com/lxc/lxd/lxd/endpoints"
	"github.com/lxc/lxd/lxd/events"
	"github.com/lxc/lxd/lxd/firewall"
	"github.com/lxc/lxd/lxd/fsmonitor"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/maas"
	"github.com/lxc/lxd/lxd/sys"
	"github.com/lxc/lxd/shared"
)

// State is a gateway to the two main stateful components of LXD, the database
// and the operating system. It's typically used by model entities such as
// containers, volumes, etc. in order to perform changes.
type State struct {
	// Shutdown Context
	ShutdownCtx context.Context

	// Databases
	DB *db.DB

	// MAAS server
	MAAS *maas.Controller

	// BGP server
	BGP *bgp.Server

	// DNS server
	DNS *dns.Server

	// OS access
	OS    *sys.OS
	Proxy func(req *http.Request) (*url.URL, error)

	// LXD server
	Endpoints *endpoints.Endpoints

	// Event server
	DevlxdEvents *events.DevLXDServer
	Events       *events.Server

	// Firewall instance
	Firewall firewall.Firewall

	// Server certificate
	ServerCert             func() *shared.CertInfo
	UpdateCertificateCache func()

	// Available instance types based on operational drivers.
	InstanceTypes map[instancetype.Type]error

	// Filesystem monitor
	DevMonitor fsmonitor.FSMonitor

	// Global configuration
	GlobalConfig *clusterConfig.Config
}
<commit_msg>lxd/state: Add ServerName<commit_after>//go:build linux && cgo && !agent

package state

import (
	"context"
	"net/http"
	"net/url"

	"github.com/lxc/lxd/lxd/bgp"
	clusterConfig "github.com/lxc/lxd/lxd/cluster/config"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/dns"
	"github.com/lxc/lxd/lxd/endpoints"
	"github.com/lxc/lxd/lxd/events"
	"github.com/lxc/lxd/lxd/firewall"
	"github.com/lxc/lxd/lxd/fsmonitor"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/maas"
	"github.com/lxc/lxd/lxd/sys"
	"github.com/lxc/lxd/shared"
)

// State is a gateway to the two main stateful components of LXD, the database
// and the operating system. It's typically used by model entities such as
// containers, volumes, etc. in order to perform changes.
type State struct {
	// Shutdown Context
	ShutdownCtx context.Context

	// Databases
	DB *db.DB

	// MAAS server
	MAAS *maas.Controller

	// BGP server
	BGP *bgp.Server

	// DNS server
	DNS *dns.Server

	// OS access
	OS    *sys.OS
	Proxy func(req *http.Request) (*url.URL, error)

	// LXD server
	Endpoints *endpoints.Endpoints

	// Event server
	DevlxdEvents *events.DevLXDServer
	Events       *events.Server

	// Firewall instance
	Firewall firewall.Firewall

	// Server certificate
	ServerCert             func() *shared.CertInfo
	UpdateCertificateCache func()

	// Available instance types based on operational drivers.
	InstanceTypes map[instancetype.Type]error

	// Filesystem monitor
	DevMonitor fsmonitor.FSMonitor

	// Global configuration
	GlobalConfig *clusterConfig.Config

	// Local server name.
	ServerName string
}
<|endoftext|>