<commit_before>// Copyright 2018 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.

// +build darwin dragonfly freebsd netbsd openbsd

package syscall_test

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"syscall"
	"testing"
	"unsafe"
)

func TestDirent(t *testing.T) {
	const (
		direntBufSize   = 2048
		filenameMinSize = 11
	)

	d, err := ioutil.TempDir("", "dirent-test")
	if err != nil {
		t.Fatalf("tempdir: %v", err)
	}
	defer os.RemoveAll(d)
	t.Logf("tmpdir: %s", d)

	for i, c := range []byte("0123456789") {
		name := string(bytes.Repeat([]byte{c}, filenameMinSize+i))
		err = ioutil.WriteFile(filepath.Join(d, name), nil, 0644)
		if err != nil {
			t.Fatalf("writefile: %v", err)
		}
	}

	buf := bytes.Repeat([]byte("DEADBEAF"), direntBufSize/8)
	fd, err := syscall.Open(d, syscall.O_RDONLY, 0)
	if err != nil {
		t.Fatalf("syscall.open: %v", err)
	}
	defer syscall.Close(fd)
	n, err := syscall.ReadDirent(fd, buf)
	if err != nil {
		t.Fatalf("syscall.readdir: %v", err)
	}
	buf = buf[:n]

	names := make([]string, 0, 10)
	for len(buf) > 0 {
		var bc int
		bc, _, names = syscall.ParseDirent(buf, -1, names)
		buf = buf[bc:]
	}

	sort.Strings(names)
	t.Logf("names: %q", names)

	if len(names) != 10 {
		t.Errorf("got %d names; expected 10", len(names))
	}
	for i, name := range names {
		ord, err := strconv.Atoi(name[:1])
		if err != nil {
			t.Fatalf("names[%d] is non-integer %q: %v", i, names[i], err)
		}
		if expected := string(strings.Repeat(name[:1], filenameMinSize+ord)); name != expected {
			t.Errorf("names[%d] is %q (len %d); expected %q (len %d)", i, name, len(name), expected, len(expected))
		}
	}
}

func TestDirentRepeat(t *testing.T) {
	const N = 100

	// Make a directory containing N files
	d, err := ioutil.TempDir("", "direntRepeat-test")
	if err != nil {
		t.Fatalf("tempdir: %v", err)
	}
	defer os.RemoveAll(d)

	var files []string
	for i := 0; i < N; i++ {
		files = append(files, fmt.Sprintf("file%d", i))
	}
	for _, file := range files {
		err = ioutil.WriteFile(filepath.Join(d, file), []byte("contents"), 0644)
		if err != nil {
			t.Fatalf("writefile: %v", err)
		}
	}

	// Read the directory entries using ReadDirent.
	fd, err := syscall.Open(d, syscall.O_RDONLY, 0)
	if err != nil {
		t.Fatalf("syscall.open: %v", err)
	}
	defer syscall.Close(fd)
	var files2 []string
	for {
		// Note: the buf is small enough that this loop will need to
		// execute multiple times. See issue #31368.
		buf := make([]byte, N*unsafe.Offsetof(syscall.Dirent{}.Name)/4)
		n, err := syscall.ReadDirent(fd, buf)
		if err != nil {
			t.Fatalf("syscall.readdir: %v", err)
		}
		if n == 0 {
			break
		}
		buf = buf[:n]
		for len(buf) > 0 {
			var consumed int
			consumed, _, files2 = syscall.ParseDirent(buf, -1, files2)
			buf = buf[consumed:]
		}
	}

	// Check results
	sort.Strings(files)
	sort.Strings(files2)
	if strings.Join(files, "|") != strings.Join(files2, "|") {
		t.Errorf("bad file list: want\n%q\ngot\n%q", files, files2)
	}
}
<commit_msg>syscall: enforce minimum buffer size to call ReadDirent<commit_after>// Copyright 2018 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.

// +build darwin dragonfly freebsd netbsd openbsd

package syscall_test

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"syscall"
	"testing"
	"unsafe"
)

func TestDirent(t *testing.T) {
	const (
		direntBufSize   = 2048
		filenameMinSize = 11
	)

	d, err := ioutil.TempDir("", "dirent-test")
	if err != nil {
		t.Fatalf("tempdir: %v", err)
	}
	defer os.RemoveAll(d)
	t.Logf("tmpdir: %s", d)

	for i, c := range []byte("0123456789") {
		name := string(bytes.Repeat([]byte{c}, filenameMinSize+i))
		err = ioutil.WriteFile(filepath.Join(d, name), nil, 0644)
		if err != nil {
			t.Fatalf("writefile: %v", err)
		}
	}

	buf := bytes.Repeat([]byte("DEADBEAF"), direntBufSize/8)
	fd, err := syscall.Open(d, syscall.O_RDONLY, 0)
	if err != nil {
		t.Fatalf("syscall.open: %v", err)
	}
	defer syscall.Close(fd)
	n, err := syscall.ReadDirent(fd, buf)
	if err != nil {
		t.Fatalf("syscall.readdir: %v", err)
	}
	buf = buf[:n]

	names := make([]string, 0, 10)
	for len(buf) > 0 {
		var bc int
		bc, _, names = syscall.ParseDirent(buf, -1, names)
		buf = buf[bc:]
	}

	sort.Strings(names)
	t.Logf("names: %q", names)

	if len(names) != 10 {
		t.Errorf("got %d names; expected 10", len(names))
	}
	for i, name := range names {
		ord, err := strconv.Atoi(name[:1])
		if err != nil {
			t.Fatalf("names[%d] is non-integer %q: %v", i, names[i], err)
		}
		if expected := string(strings.Repeat(name[:1], filenameMinSize+ord)); name != expected {
			t.Errorf("names[%d] is %q (len %d); expected %q (len %d)", i, name, len(name), expected, len(expected))
		}
	}
}

func TestDirentRepeat(t *testing.T) {
	const N = 100
	// Note: the size of the buffer is small enough that the loop
	// below will need to execute multiple times. See issue #31368.
	size := N * unsafe.Offsetof(syscall.Dirent{}.Name) / 4
	if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" {
		if size < 1024 {
			size = 1024 // DIRBLKSIZ, see issue 31403.
		}
	}

	// Make a directory containing N files
	d, err := ioutil.TempDir("", "direntRepeat-test")
	if err != nil {
		t.Fatalf("tempdir: %v", err)
	}
	defer os.RemoveAll(d)

	var files []string
	for i := 0; i < N; i++ {
		files = append(files, fmt.Sprintf("file%d", i))
	}
	for _, file := range files {
		err = ioutil.WriteFile(filepath.Join(d, file), []byte("contents"), 0644)
		if err != nil {
			t.Fatalf("writefile: %v", err)
		}
	}

	// Read the directory entries using ReadDirent.
	fd, err := syscall.Open(d, syscall.O_RDONLY, 0)
	if err != nil {
		t.Fatalf("syscall.open: %v", err)
	}
	defer syscall.Close(fd)
	var files2 []string
	for {
		buf := make([]byte, size)
		n, err := syscall.ReadDirent(fd, buf)
		if err != nil {
			t.Fatalf("syscall.readdir: %v", err)
		}
		if n == 0 {
			break
		}
		buf = buf[:n]
		for len(buf) > 0 {
			var consumed int
			consumed, _, files2 = syscall.ParseDirent(buf, -1, files2)
			buf = buf[consumed:]
		}
	}

	// Check results
	sort.Strings(files)
	sort.Strings(files2)
	if strings.Join(files, "|") != strings.Join(files2, "|") {
		t.Errorf("bad file list: want\n%q\ngot\n%q", files, files2)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 The Ebiten 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 text offers functions to draw texts on an Ebiten's image.
//
// For the example using a TTF font, see font package in the examples.
package text

import (
	"image"
	"image/color"
	"math"
	"sync"

	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/internal/colormcache"
)

var (
	monotonicClock int64
)

func now() int64 {
	monotonicClock++
	return monotonicClock
}

func fixed26_6ToFloat64(x fixed.Int26_6) float64 {
	return float64(x>>6) + float64(x&((1<<6)-1))/float64(1<<6)
}

func drawGlyph(dst *ebiten.Image, face font.Face, r rune, img *ebiten.Image, x, y fixed.Int26_6, clr ebiten.ColorM) {
	if img == nil {
		return
	}

	b := getGlyphBounds(face, r)
	op := &ebiten.DrawImageOptions{}
	op.GeoM.Translate(float64((x+b.Min.X)>>6), float64((y+b.Min.Y)>>6))
	op.ColorM = clr
	dst.DrawImage(img, op)
}

var (
	glyphBoundsCache = map[font.Face]map[rune]fixed.Rectangle26_6{}
)

func getGlyphBounds(face font.Face, r rune) fixed.Rectangle26_6 {
	if _, ok := glyphBoundsCache[face]; !ok {
		glyphBoundsCache[face] = map[rune]fixed.Rectangle26_6{}
	}
	if b, ok := glyphBoundsCache[face][r]; ok {
		return b
	}
	b, _, _ := face.GlyphBounds(r)
	glyphBoundsCache[face][r] = b
	return b
}

type glyphImageCacheEntry struct {
	image *ebiten.Image
	atime int64
}

var (
	glyphImageCache = map[font.Face]map[rune]*glyphImageCacheEntry{}
	emptyGlyphs     = map[font.Face]map[rune]struct{}{}
)

func getGlyphImages(face font.Face, runes []rune) []*ebiten.Image {
	if _, ok := emptyGlyphs[face]; !ok {
		emptyGlyphs[face] = map[rune]struct{}{}
	}
	if _, ok := glyphImageCache[face]; !ok {
		glyphImageCache[face] = map[rune]*glyphImageCacheEntry{}
	}

	imgs := make([]*ebiten.Image, len(runes))
	glyphBounds := map[rune]fixed.Rectangle26_6{}
	neededGlyphIndices := map[int]rune{}
	for i, r := range runes {
		if _, ok := emptyGlyphs[face][r]; ok {
			continue
		}

		if e, ok := glyphImageCache[face][r]; ok {
			e.atime = now()
			imgs[i] = e.image
			continue
		}

		b := getGlyphBounds(face, r)
		w, h := (b.Max.X - b.Min.X).Ceil(), (b.Max.Y - b.Min.Y).Ceil()
		if w == 0 || h == 0 {
			emptyGlyphs[face][r] = struct{}{}
			continue
		}

		glyphBounds[r] = b
		neededGlyphIndices[i] = r
	}

	for i, r := range neededGlyphIndices {
		b := glyphBounds[r]
		w, h := (b.Max.X - b.Min.X).Ceil(), (b.Max.Y - b.Min.Y).Ceil()
		if b.Min.X&((1<<6)-1) != 0 {
			w++
		}
		if b.Min.Y&((1<<6)-1) != 0 {
			h++
		}
		rgba := image.NewRGBA(image.Rect(0, 0, w, h))

		d := font.Drawer{
			Dst:  rgba,
			Src:  image.White,
			Face: face,
		}
		x, y := -b.Min.X, -b.Min.Y
		x, y = fixed.I(x.Ceil()), fixed.I(y.Ceil())
		d.Dot = fixed.Point26_6{X: x, Y: y}
		d.DrawString(string(r))

		img := ebiten.NewImageFromImage(rgba)
		if _, ok := glyphImageCache[face][r]; !ok {
			glyphImageCache[face][r] = &glyphImageCacheEntry{
				image: img,
				atime: now(),
			}
		}
		imgs[i] = img
	}
	return imgs
}

var textM sync.Mutex

// Draw draws a given text on a given destination image dst.
//
// face is the font for text rendering.
// (x, y) represents a 'dot' (period) position.
// This means that if the given text consisted of a single character ".",
// it would be positioned at the given position (x, y).
// Be careful that this doesn't represent left-upper corner position.
//
// clr is the color for text rendering.
//
// If you want to adjust the position of the text, these functions are useful:
//
//     * text.BoundString:                     the rendered bounds of the given text.
//     * golang.org/x/image/font.Face.Metrics: the metrics of the face.
//
// The '\n' newline character puts the following text on the next line.
// Line height is based on Metrics().Height of the font.
//
// Glyphs used for rendering are cached in least-recently-used way.
// It is OK to call Draw with a same text and a same face at every frame in terms of performance.
//
// Be careful that the passed font face is held by this package and is never released.
// This is a known issue (#498).
//
// Draw is concurrent-safe.
func Draw(dst *ebiten.Image, text string, face font.Face, x, y int, clr color.Color) {
	textM.Lock()
	defer textM.Unlock()

	fx, fy := fixed.I(x), fixed.I(y)
	prevR := rune(-1)

	faceHeight := face.Metrics().Height

	runes := []rune(text)
	glyphImgs := getGlyphImages(face, runes)
	colorm := colormcache.ColorToColorM(clr)

	for i, r := range runes {
		if prevR >= 0 {
			fx += face.Kern(prevR, r)
		}
		if r == '\n' {
			fx = fixed.I(x)
			fy += faceHeight
			prevR = rune(-1)
			continue
		}

		drawGlyph(dst, face, r, glyphImgs[i], fx, fy, colorm)
		fx += glyphAdvance(face, r)

		prevR = r
	}

	const cacheLimit = 512

	// Clean up the cache.
	for len(glyphImageCache[face]) > cacheLimit {
		oldest := int64(math.MaxInt64)
		oldestKey := rune(-1)
		for r, e := range glyphImageCache[face] {
			if e.atime < oldest {
				oldestKey = r
				oldest = e.atime
			}
		}
		delete(glyphImageCache[face], oldestKey)
	}
}

// BoundString returns the measured size of a given string using a given font.
// This method will return the exact size in pixels that a string drawn by Draw will be.
// The bound's origin point indicates the dot (period) position.
// This means that if the text consists of one character '.', this dot is rendered at (0, 0).
//
// This is very similar to golang.org/x/image/font's BoundString,
// but this BoundString calculates the actual rendered area considering multiple lines and space characters.
//
// face is the font for text rendering.
// text is the string that's being measured.
//
// Be careful that the passed font face is held by this package and is never released.
// This is a known issue (#498).
//
// BoundString is concurrent-safe.
func BoundString(face font.Face, text string) image.Rectangle {
	textM.Lock()
	defer textM.Unlock()

	m := face.Metrics()
	faceHeight := m.Height

	fx, fy := fixed.I(0), fixed.I(0)
	prevR := rune(-1)

	var bounds fixed.Rectangle26_6
	for _, r := range []rune(text) {
		if prevR >= 0 {
			fx += face.Kern(prevR, r)
		}
		if r == '\n' {
			fx = fixed.I(0)
			fy += faceHeight
			prevR = rune(-1)
			continue
		}

		b := getGlyphBounds(face, r)
		b.Min.X += fx
		b.Max.X += fx
		b.Min.Y += fy
		b.Max.Y += fy
		bounds = bounds.Union(b)

		fx += glyphAdvance(face, r)
		prevR = r
	}

	return image.Rect(
		int(math.Floor(fixed26_6ToFloat64(bounds.Min.X))),
		int(math.Floor(fixed26_6ToFloat64(bounds.Min.Y))),
		int(math.Ceil(fixed26_6ToFloat64(bounds.Max.X))),
		int(math.Ceil(fixed26_6ToFloat64(bounds.Max.Y))),
	)
}
<commit_msg>text: Add CacheGlyphs<commit_after>// Copyright 2017 The Ebiten 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 text offers functions to draw texts on an Ebiten's image.
//
// For the example using a TTF font, see font package in the examples.
package text

import (
	"image"
	"image/color"
	"math"
	"sync"

	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/internal/colormcache"
	"github.com/hajimehoshi/ebiten/v2/internal/hooks"
)

var (
	monotonicClock int64
)

func now() int64 {
	return monotonicClock
}

func init() {
	hooks.AppendHookOnBeforeUpdate(func() error {
		monotonicClock++
		return nil
	})
}

func fixed26_6ToFloat64(x fixed.Int26_6) float64 {
	return float64(x>>6) + float64(x&((1<<6)-1))/float64(1<<6)
}

func drawGlyph(dst *ebiten.Image, face font.Face, r rune, img *ebiten.Image, x, y fixed.Int26_6, clr ebiten.ColorM) {
	if img == nil {
		return
	}

	b := getGlyphBounds(face, r)
	op := &ebiten.DrawImageOptions{}
	op.GeoM.Translate(float64((x+b.Min.X)>>6), float64((y+b.Min.Y)>>6))
	op.ColorM = clr
	dst.DrawImage(img, op)
}

var (
	glyphBoundsCache = map[font.Face]map[rune]fixed.Rectangle26_6{}
)

func getGlyphBounds(face font.Face, r rune) fixed.Rectangle26_6 {
	if _, ok := glyphBoundsCache[face]; !ok {
		glyphBoundsCache[face] = map[rune]fixed.Rectangle26_6{}
	}
	if b, ok := glyphBoundsCache[face][r]; ok {
		return b
	}
	b, _, _ := face.GlyphBounds(r)
	glyphBoundsCache[face][r] = b
	return b
}

type glyphImageCacheEntry struct {
	image *ebiten.Image
	atime int64
}

var (
	glyphImageCache = map[font.Face]map[rune]*glyphImageCacheEntry{}
	emptyGlyphs     = map[font.Face]map[rune]struct{}{}
)

func getGlyphImages(face font.Face, runes []rune) []*ebiten.Image {
	if _, ok := emptyGlyphs[face]; !ok {
		emptyGlyphs[face] = map[rune]struct{}{}
	}
	if _, ok := glyphImageCache[face]; !ok {
		glyphImageCache[face] = map[rune]*glyphImageCacheEntry{}
	}

	imgs := make([]*ebiten.Image, len(runes))
	glyphBounds := map[rune]fixed.Rectangle26_6{}
	neededGlyphIndices := map[int]rune{}
	for i, r := range runes {
		if _, ok := emptyGlyphs[face][r]; ok {
			continue
		}

		if e, ok := glyphImageCache[face][r]; ok {
			e.atime = now()
			imgs[i] = e.image
			continue
		}

		b := getGlyphBounds(face, r)
		w, h := (b.Max.X - b.Min.X).Ceil(), (b.Max.Y - b.Min.Y).Ceil()
		if w == 0 || h == 0 {
			emptyGlyphs[face][r] = struct{}{}
			continue
		}

		glyphBounds[r] = b
		neededGlyphIndices[i] = r
	}

	for i, r := range neededGlyphIndices {
		b := glyphBounds[r]
		w, h := (b.Max.X - b.Min.X).Ceil(), (b.Max.Y - b.Min.Y).Ceil()
		if b.Min.X&((1<<6)-1) != 0 {
			w++
		}
		if b.Min.Y&((1<<6)-1) != 0 {
			h++
		}
		rgba := image.NewRGBA(image.Rect(0, 0, w, h))

		d := font.Drawer{
			Dst:  rgba,
			Src:  image.White,
			Face: face,
		}
		x, y := -b.Min.X, -b.Min.Y
		x, y = fixed.I(x.Ceil()), fixed.I(y.Ceil())
		d.Dot = fixed.Point26_6{X: x, Y: y}
		d.DrawString(string(r))

		img := ebiten.NewImageFromImage(rgba)
		if _, ok := glyphImageCache[face][r]; !ok {
			glyphImageCache[face][r] = &glyphImageCacheEntry{
				image: img,
				atime: now(),
			}
		}
		imgs[i] = img
	}
	return imgs
}

var textM sync.Mutex

// Draw draws a given text on a given destination image dst.
//
// face is the font for text rendering.
// (x, y) represents a 'dot' (period) position.
// This means that if the given text consisted of a single character ".",
// it would be positioned at the given position (x, y).
// Be careful that this doesn't represent left-upper corner position.
//
// clr is the color for text rendering.
//
// If you want to adjust the position of the text, these functions are useful:
//
//     * text.BoundString:                     the rendered bounds of the given text.
//     * golang.org/x/image/font.Face.Metrics: the metrics of the face.
//
// The '\n' newline character puts the following text on the next line.
// Line height is based on Metrics().Height of the font.
//
// Glyphs used for rendering are cached in least-recently-used way.
// It is OK to call Draw with a same text and a same face at every frame in terms of performance.
//
// Be careful that the passed font face is held by this package and is never released.
// This is a known issue (#498).
//
// Draw is concurrent-safe.
func Draw(dst *ebiten.Image, text string, face font.Face, x, y int, clr color.Color) {
	textM.Lock()
	defer textM.Unlock()

	fx, fy := fixed.I(x), fixed.I(y)
	prevR := rune(-1)

	faceHeight := face.Metrics().Height

	runes := []rune(text)
	glyphImgs := getGlyphImages(face, runes)
	colorm := colormcache.ColorToColorM(clr)

	for i, r := range runes {
		if prevR >= 0 {
			fx += face.Kern(prevR, r)
		}
		if r == '\n' {
			fx = fixed.I(x)
			fy += faceHeight
			prevR = rune(-1)
			continue
		}

		drawGlyph(dst, face, r, glyphImgs[i], fx, fy, colorm)
		fx += glyphAdvance(face, r)

		prevR = r
	}

	// cacheSoftLimit indicates the soft limit of the number of glyphs in the cache.
	// If the number of glyphs exceeds this soft limits, old glyphs are removed.
	// Even after clearning up the cache, the number of glyphs might still exceeds the soft limit, but
	// this is fine.
	const cacheSoftLimit = 512

	// Clean up the cache.
	if len(glyphImageCache[face]) > cacheSoftLimit {
		for r, e := range glyphImageCache[face] {
			// 60 is an arbitrary number.
			if e.atime < now()-60 {
				delete(glyphImageCache[face], r)
			}
		}
	}
}

// BoundString returns the measured size of a given string using a given font.
// This method will return the exact size in pixels that a string drawn by Draw will be.
// The bound's origin point indicates the dot (period) position.
// This means that if the text consists of one character '.', this dot is rendered at (0, 0).
//
// This is very similar to golang.org/x/image/font's BoundString,
// but this BoundString calculates the actual rendered area considering multiple lines and space characters.
//
// face is the font for text rendering.
// text is the string that's being measured.
//
// Be careful that the passed font face is held by this package and is never released.
// This is a known issue (#498).
//
// BoundString is concurrent-safe.
func BoundString(face font.Face, text string) image.Rectangle {
	textM.Lock()
	defer textM.Unlock()

	m := face.Metrics()
	faceHeight := m.Height

	fx, fy := fixed.I(0), fixed.I(0)
	prevR := rune(-1)

	var bounds fixed.Rectangle26_6
	for _, r := range []rune(text) {
		if prevR >= 0 {
			fx += face.Kern(prevR, r)
		}
		if r == '\n' {
			fx = fixed.I(0)
			fy += faceHeight
			prevR = rune(-1)
			continue
		}

		b := getGlyphBounds(face, r)
		b.Min.X += fx
		b.Max.X += fx
		b.Min.Y += fy
		b.Max.Y += fy
		bounds = bounds.Union(b)

		fx += glyphAdvance(face, r)
		prevR = r
	}

	return image.Rect(
		int(math.Floor(fixed26_6ToFloat64(bounds.Min.X))),
		int(math.Floor(fixed26_6ToFloat64(bounds.Min.Y))),
		int(math.Ceil(fixed26_6ToFloat64(bounds.Max.X))),
		int(math.Ceil(fixed26_6ToFloat64(bounds.Max.Y))),
	)
}

// CacheGlyphs precaches the glyphs for the given text and the given font face into the cache.
//
// Draw automatically creates and caches necessary glyphs, so usually you don't have to call CacheGlyphs
// explicitly. However, for example, when you call Draw for each rune of one big text, Draw tries to create the glyph
// cache and render it for each rune. This is very innefficient because creating a glyph image and rendering it are
// different operations and can never be merged as one draw calls. CacheGlyphs creates necessary glyphs without
// rendering them, and these operations are likely merged into one draw call.
func CacheGlyphs(face font.Face, text string) {
	textM.Lock()
	defer textM.Unlock()

	getGlyphImages(face, []rune(text))
}
<|endoftext|>


<commit_before>package text

import (
	"image/color"
	"math"
	"unicode"
	"unicode/utf8"

	"github.com/faiface/pixel"
	"golang.org/x/image/font"
)

// ASCII is a set of all ASCII runes. These runes are codepoints from 32 to 127 inclusive.
var ASCII []rune

func init() {
	ASCII = make([]rune, unicode.MaxASCII-32)
	for i := range ASCII {
		ASCII[i] = rune(32 + i)
	}
}

// RangeTable takes a *unicode.RangeTable and generates a set of runes contained within that
// RangeTable.
func RangeTable(table *unicode.RangeTable) []rune {
	var runes []rune
	for _, rng := range table.R16 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	for _, rng := range table.R32 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	return runes
}

// Text allows text drawing.
//
// To create a Text object, use the New constructor:
//   txt := text.New(face, text.ASCII)
//
// As suggested by the constructor, a Text object is always associated with one font face and a
// fixed set of runes. For example, the Text we create above can draw text using the font face
// contained in the `face` variable and is capable of drawing ASCII characters.
//
// Here we create a Text object which can draw ASCII and Katakana characters:
//   txt := text.New(face, text.ASCII, text.RangeTable(unicode.Katakana))
//
// Similarly to IMDraw, Text functions as a buffer. It implements io.Writer interface, so writing
// text to it is really simple:
//   fmt.Print(txt, "Hello, world!")
//
// Finally, if we want the written text to show up on some other Target, we can draw it:
//   txt.Draw(target)
//
// Text exports two important fields: Orig and Dot. Dot is the position where the next character
// will be written. Dot is automatically moved when writing to a Text object, but you can also
// manipulate it manually. Orig specifies the text origin, usually the top-left dot position. Dot is
// always aligned to Orig when writing newlines.
//
// To reset the Dot to the Orig, just assign it:
//   txt.Dot = txt.Orig
type Text struct {
	// Orig specifies the text origin, usually the top-left dot position. Dot is always aligned
	// to Orig when writing newlines.
	Orig pixel.Vec

	// Dot is the position where the next character will be written. Dot is automatically moved
	// when writing to a Text object, but you can also manipulate it manually
	Dot pixel.Vec

	atlas *Atlas

	lineHeight float64
	tabWidth   float64

	buf    []byte
	prevR  rune
	bounds pixel.Rect
	glyph  pixel.TrianglesData
	tris   pixel.TrianglesData

	mat    pixel.Matrix
	col    pixel.RGBA
	trans  pixel.TrianglesData
	transD pixel.Drawer
	dirty  bool
}

// New creates a new Text capable of drawing runes contained in the provided rune sets, plus
// unicode.ReplacementChar using the provided font.Face.
//
// Do not destroy or close the font.Face after creating a Text. Although Text caches most of the
// stuff (pre-drawn glyphs, etc.), it still uses the face for a few things.
//
// Here we create a Text capable of drawing ASCII characters using the Go Regular font.
//   ttf, err := truetype.Parse(goregular.TTF)
//   if err != nil {
//       panic(err)
//   }
//   face := truetype.NewFace(ttf, &truetype.Options{
//       Size: 14,
//   })
//   txt := text.New(face, text.ASCII)
func New(face font.Face, runeSets ...[]rune) *Text {
	runes := []rune{unicode.ReplacementChar}
	for _, set := range runeSets {
		runes = append(runes, set...)
	}

	atlas := NewAtlas(face, runes)

	txt := &Text{
		atlas:      atlas,
		lineHeight: atlas.LineHeight(),
		tabWidth:   atlas.Glyph(' ').Advance * 4,
		mat:        pixel.IM,
		col:        pixel.Alpha(1),
	}

	txt.glyph.SetLen(6)
	for i := range txt.glyph {
		txt.glyph[i].Color = pixel.Alpha(1)
		txt.glyph[i].Intensity = 1
	}

	txt.transD.Picture = txt.atlas.pic
	txt.transD.Triangles = &txt.trans

	txt.Clear()

	return txt
}

// Atlas returns the underlying Text's Atlas containing all of the pre-drawn glyphs. The Atlas is
// also useful for getting values such as the recommended line height.
func (txt *Text) Atlas() *Atlas {
	return txt.atlas
}

// SetMatrix sets a Matrix by which the text will be transformed before drawing to another Target.
func (txt *Text) SetMatrix(m pixel.Matrix) {
	if txt.mat != m {
		txt.mat = m
		txt.dirty = true
	}
}

// SetColorMask sets a color by which the text will be masked before drawingto another Target.
func (txt *Text) SetColorMask(c color.Color) {
	rgba := pixel.ToRGBA(c)
	if txt.col != rgba {
		txt.col = rgba
		txt.dirty = true
	}
}

// Bounds returns the bounding box of the text currently written to the Text excluding whitespace.
//
// If the Text is empty, a zero rectangle is returned.
func (txt *Text) Bounds() pixel.Rect {
	return txt.bounds
}

// BoundsOf returns the bounding box of s if it was to be written to the Text right now.
func (txt *Text) BoundsOf(s string) pixel.Rect {
	dot := txt.Dot
	prevR := txt.prevR
	bounds := pixel.Rect{}

	for _, r := range s {
		var control bool
		dot, control = txt.controlRune(r, dot)
		if control {
			continue
		}

		var b pixel.Rect
		_, _, b, dot = txt.Atlas().DrawRune(prevR, r, dot)

		if bounds.W()*bounds.H() == 0 {
			bounds = b
		} else {
			bounds = bounds.Union(b)
		}

		prevR = r
	}

	return bounds
}

// Color sets the text color. This does not affect any previously written text.
func (txt *Text) Color(c color.Color) {
	rgba := pixel.ToRGBA(c)
	for i := range txt.glyph {
		txt.glyph[i].Color = rgba
	}
}

// LineHeight sets the vertical distance between two lines of text. This does not affect any
// previously written text.
func (txt *Text) LineHeight(height float64) {
	txt.lineHeight = height
}

// TabWidth sets the horizontal tab width. Tab characters will align to the multiples of this width.
func (txt *Text) TabWidth(width float64) {
	txt.tabWidth = width
}

// Clear removes all written text from the Text.
func (txt *Text) Clear() {
	txt.prevR = -1
	txt.bounds = pixel.Rect{}
	txt.tris.SetLen(0)
	txt.dirty = true
}

// Write writes a slice of bytes to the Text. This method never fails, always returns len(p), nil.
func (txt *Text) Write(p []byte) (n int, err error) {
	txt.buf = append(txt.buf, p...)
	txt.drawBuf()
	return len(p), nil
}

// WriteString writes a string to the Text. This method never fails, always returns len(s), nil.
func (txt *Text) WriteString(s string) (n int, err error) {
	txt.buf = append(txt.buf, s...)
	txt.drawBuf()
	return len(s), nil
}

// WriteByte writes a byte to the Text. This method never fails, always returns nil.
//
// Writing a multi-byte rune byte-by-byte is perfectly supported.
func (txt *Text) WriteByte(c byte) error {
	txt.buf = append(txt.buf, c)
	txt.drawBuf()
	return nil
}

// WriteRune writes a rune to the Text. This method never fails, always returns utf8.RuneLen(r), nil.
func (txt *Text) WriteRune(r rune) (n int, err error) {
	var b [4]byte
	n = utf8.EncodeRune(b[:], r)
	txt.buf = append(txt.buf, b[:n]...)
	txt.drawBuf()
	return n, nil
}

// Draw draws all text written to the Text to the provided Target. The text is transformed by the
// Text's matrix and color mask.
func (txt *Text) Draw(t pixel.Target) {
	if txt.dirty {
		txt.trans.SetLen(txt.tris.Len())
		txt.trans.Update(&txt.tris)

		for i := range txt.trans {
			txt.trans[i].Position = txt.mat.Project(txt.trans[i].Position)
			txt.trans[i].Color = txt.trans[i].Color.Mul(txt.col)
		}

		txt.transD.Dirty()
		txt.dirty = false
	}

	txt.transD.Draw(t)
}

// controlRune checks if r is a control rune (newline, tab, ...). If it is, a new dot position and
// true is returned. If r is not a control rune, the original dot and false is returned.
func (txt *Text) controlRune(r rune, dot pixel.Vec) (newDot pixel.Vec, control bool) {
	switch r {
	case '\n':
		dot -= pixel.Y(txt.lineHeight)
		dot = dot.WithX(txt.Orig.X())
	case '\r':
		dot = dot.WithX(txt.Orig.X())
	case '\t':
		rem := math.Mod(dot.X()-txt.Orig.X(), txt.tabWidth)
		rem = math.Mod(rem, rem+txt.tabWidth)
		if rem == 0 {
			rem = txt.tabWidth
		}
		dot += pixel.X(rem)
	default:
		return dot, false
	}
	return dot, true
}

func (txt *Text) drawBuf() {
	for utf8.FullRune(txt.buf) {
		r, size := utf8.DecodeRune(txt.buf)
		txt.buf = txt.buf[size:]

		var control bool
		txt.Dot, control = txt.controlRune(r, txt.Dot)
		if control {
			continue
		}

		var rect, frame, bounds pixel.Rect
		rect, frame, bounds, txt.Dot = txt.Atlas().DrawRune(txt.prevR, r, txt.Dot)

		txt.prevR = r

		rv := [...]pixel.Vec{pixel.V(rect.Min.X(), rect.Min.Y()),
			pixel.V(rect.Max.X(), rect.Min.Y()),
			pixel.V(rect.Max.X(), rect.Max.Y()),
			pixel.V(rect.Min.X(), rect.Max.Y()),
		}

		fv := [...]pixel.Vec{pixel.V(frame.Min.X(), frame.Min.Y()),
			pixel.V(frame.Max.X(), frame.Min.Y()),
			pixel.V(frame.Max.X(), frame.Max.Y()),
			pixel.V(frame.Min.X(), frame.Max.Y()),
		}

		for i, j := range [...]int{0, 1, 2, 0, 2, 3} {
			txt.glyph[i].Position = rv[j]
			txt.glyph[i].Picture = fv[j]
		}

		txt.tris = append(txt.tris, txt.glyph...)
		txt.dirty = true

		if txt.bounds.W()*txt.bounds.H() == 0 {
			txt.bounds = bounds
		} else {
			txt.bounds = txt.bounds.Union(bounds)
		}
	}
}
<commit_msg>clarify doc<commit_after>package text

import (
	"image/color"
	"math"
	"unicode"
	"unicode/utf8"

	"github.com/faiface/pixel"
	"golang.org/x/image/font"
)

// ASCII is a set of all ASCII runes. These runes are codepoints from 32 to 127 inclusive.
var ASCII []rune

func init() {
	ASCII = make([]rune, unicode.MaxASCII-32)
	for i := range ASCII {
		ASCII[i] = rune(32 + i)
	}
}

// RangeTable takes a *unicode.RangeTable and generates a set of runes contained within that
// RangeTable.
func RangeTable(table *unicode.RangeTable) []rune {
	var runes []rune
	for _, rng := range table.R16 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	for _, rng := range table.R32 {
		for r := rng.Lo; r <= rng.Hi; r += rng.Stride {
			runes = append(runes, rune(r))
		}
	}
	return runes
}

// Text allows text drawing.
//
// To create a Text object, use the New constructor:
//   txt := text.New(face, text.ASCII)
//
// As suggested by the constructor, a Text object is always associated with one font face and a
// fixed set of runes. For example, the Text we create above can draw text using the font face
// contained in the `face` variable and is capable of drawing ASCII characters.
//
// Here we create a Text object which can draw ASCII and Katakana characters:
//   txt := text.New(face, text.ASCII, text.RangeTable(unicode.Katakana))
//
// Similarly to IMDraw, Text functions as a buffer. It implements io.Writer interface, so writing
// text to it is really simple:
//   fmt.Print(txt, "Hello, world!")
//
// Finally, if we want the written text to show up on some other Target, we can draw it:
//   txt.Draw(target)
//
// Text exports two important fields: Orig and Dot. Dot is the position where the next character
// will be written. Dot is automatically moved when writing to a Text object, but you can also
// manipulate it manually. Orig specifies the text origin, usually the top-left dot position. Dot is
// always aligned to Orig when writing newlines.
//
// To reset the Dot to the Orig, just assign it:
//   txt.Dot = txt.Orig
type Text struct {
	// Orig specifies the text origin, usually the top-left dot position. Dot is always aligned
	// to Orig when writing newlines.
	Orig pixel.Vec

	// Dot is the position where the next character will be written. Dot is automatically moved
	// when writing to a Text object, but you can also manipulate it manually
	Dot pixel.Vec

	atlas *Atlas

	lineHeight float64
	tabWidth   float64

	buf    []byte
	prevR  rune
	bounds pixel.Rect
	glyph  pixel.TrianglesData
	tris   pixel.TrianglesData

	mat    pixel.Matrix
	col    pixel.RGBA
	trans  pixel.TrianglesData
	transD pixel.Drawer
	dirty  bool
}

// New creates a new Text capable of drawing runes contained in the provided rune sets, plus
// unicode.ReplacementChar using the provided font.Face. New automatically generates an Atlas for
// the Text.
//
// Do not destroy or close the font.Face after creating a Text. Although Text caches most of the
// stuff (pre-drawn glyphs, etc.), it still uses the face for a few things.
//
// Here we create a Text capable of drawing ASCII characters using the Go Regular font.
//   ttf, err := truetype.Parse(goregular.TTF)
//   if err != nil {
//       panic(err)
//   }
//   face := truetype.NewFace(ttf, &truetype.Options{
//       Size: 14,
//   })
//   txt := text.New(face, text.ASCII)
func New(face font.Face, runeSets ...[]rune) *Text {
	runes := []rune{unicode.ReplacementChar}
	for _, set := range runeSets {
		runes = append(runes, set...)
	}

	atlas := NewAtlas(face, runes)

	txt := &Text{
		atlas:      atlas,
		lineHeight: atlas.LineHeight(),
		tabWidth:   atlas.Glyph(' ').Advance * 4,
		mat:        pixel.IM,
		col:        pixel.Alpha(1),
	}

	txt.glyph.SetLen(6)
	for i := range txt.glyph {
		txt.glyph[i].Color = pixel.Alpha(1)
		txt.glyph[i].Intensity = 1
	}

	txt.transD.Picture = txt.atlas.pic
	txt.transD.Triangles = &txt.trans

	txt.Clear()

	return txt
}

// Atlas returns the underlying Text's Atlas containing all of the pre-drawn glyphs. The Atlas is
// also useful for getting values such as the recommended line height.
func (txt *Text) Atlas() *Atlas {
	return txt.atlas
}

// SetMatrix sets a Matrix by which the text will be transformed before drawing to another Target.
func (txt *Text) SetMatrix(m pixel.Matrix) {
	if txt.mat != m {
		txt.mat = m
		txt.dirty = true
	}
}

// SetColorMask sets a color by which the text will be masked before drawingto another Target.
func (txt *Text) SetColorMask(c color.Color) {
	rgba := pixel.ToRGBA(c)
	if txt.col != rgba {
		txt.col = rgba
		txt.dirty = true
	}
}

// Bounds returns the bounding box of the text currently written to the Text excluding whitespace.
//
// If the Text is empty, a zero rectangle is returned.
func (txt *Text) Bounds() pixel.Rect {
	return txt.bounds
}

// BoundsOf returns the bounding box of s if it was to be written to the Text right now.
func (txt *Text) BoundsOf(s string) pixel.Rect {
	dot := txt.Dot
	prevR := txt.prevR
	bounds := pixel.Rect{}

	for _, r := range s {
		var control bool
		dot, control = txt.controlRune(r, dot)
		if control {
			continue
		}

		var b pixel.Rect
		_, _, b, dot = txt.Atlas().DrawRune(prevR, r, dot)

		if bounds.W()*bounds.H() == 0 {
			bounds = b
		} else {
			bounds = bounds.Union(b)
		}

		prevR = r
	}

	return bounds
}

// Color sets the text color. This does not affect any previously written text.
func (txt *Text) Color(c color.Color) {
	rgba := pixel.ToRGBA(c)
	for i := range txt.glyph {
		txt.glyph[i].Color = rgba
	}
}

// LineHeight sets the vertical distance between two lines of text. This does not affect any
// previously written text.
func (txt *Text) LineHeight(height float64) {
	txt.lineHeight = height
}

// TabWidth sets the horizontal tab width. Tab characters will align to the multiples of this width.
func (txt *Text) TabWidth(width float64) {
	txt.tabWidth = width
}

// Clear removes all written text from the Text.
func (txt *Text) Clear() {
	txt.prevR = -1
	txt.bounds = pixel.Rect{}
	txt.tris.SetLen(0)
	txt.dirty = true
}

// Write writes a slice of bytes to the Text. This method never fails, always returns len(p), nil.
func (txt *Text) Write(p []byte) (n int, err error) {
	txt.buf = append(txt.buf, p...)
	txt.drawBuf()
	return len(p), nil
}

// WriteString writes a string to the Text. This method never fails, always returns len(s), nil.
func (txt *Text) WriteString(s string) (n int, err error) {
	txt.buf = append(txt.buf, s...)
	txt.drawBuf()
	return len(s), nil
}

// WriteByte writes a byte to the Text. This method never fails, always returns nil.
//
// Writing a multi-byte rune byte-by-byte is perfectly supported.
func (txt *Text) WriteByte(c byte) error {
	txt.buf = append(txt.buf, c)
	txt.drawBuf()
	return nil
}

// WriteRune writes a rune to the Text. This method never fails, always returns utf8.RuneLen(r), nil.
func (txt *Text) WriteRune(r rune) (n int, err error) {
	var b [4]byte
	n = utf8.EncodeRune(b[:], r)
	txt.buf = append(txt.buf, b[:n]...)
	txt.drawBuf()
	return n, nil
}

// Draw draws all text written to the Text to the provided Target. The text is transformed by the
// Text's matrix and color mask.
func (txt *Text) Draw(t pixel.Target) {
	if txt.dirty {
		txt.trans.SetLen(txt.tris.Len())
		txt.trans.Update(&txt.tris)

		for i := range txt.trans {
			txt.trans[i].Position = txt.mat.Project(txt.trans[i].Position)
			txt.trans[i].Color = txt.trans[i].Color.Mul(txt.col)
		}

		txt.transD.Dirty()
		txt.dirty = false
	}

	txt.transD.Draw(t)
}

// controlRune checks if r is a control rune (newline, tab, ...). If it is, a new dot position and
// true is returned. If r is not a control rune, the original dot and false is returned.
func (txt *Text) controlRune(r rune, dot pixel.Vec) (newDot pixel.Vec, control bool) {
	switch r {
	case '\n':
		dot -= pixel.Y(txt.lineHeight)
		dot = dot.WithX(txt.Orig.X())
	case '\r':
		dot = dot.WithX(txt.Orig.X())
	case '\t':
		rem := math.Mod(dot.X()-txt.Orig.X(), txt.tabWidth)
		rem = math.Mod(rem, rem+txt.tabWidth)
		if rem == 0 {
			rem = txt.tabWidth
		}
		dot += pixel.X(rem)
	default:
		return dot, false
	}
	return dot, true
}

func (txt *Text) drawBuf() {
	for utf8.FullRune(txt.buf) {
		r, size := utf8.DecodeRune(txt.buf)
		txt.buf = txt.buf[size:]

		var control bool
		txt.Dot, control = txt.controlRune(r, txt.Dot)
		if control {
			continue
		}

		var rect, frame, bounds pixel.Rect
		rect, frame, bounds, txt.Dot = txt.Atlas().DrawRune(txt.prevR, r, txt.Dot)

		txt.prevR = r

		rv := [...]pixel.Vec{pixel.V(rect.Min.X(), rect.Min.Y()),
			pixel.V(rect.Max.X(), rect.Min.Y()),
			pixel.V(rect.Max.X(), rect.Max.Y()),
			pixel.V(rect.Min.X(), rect.Max.Y()),
		}

		fv := [...]pixel.Vec{pixel.V(frame.Min.X(), frame.Min.Y()),
			pixel.V(frame.Max.X(), frame.Min.Y()),
			pixel.V(frame.Max.X(), frame.Max.Y()),
			pixel.V(frame.Min.X(), frame.Max.Y()),
		}

		for i, j := range [...]int{0, 1, 2, 0, 2, 3} {
			txt.glyph[i].Position = rv[j]
			txt.glyph[i].Picture = fv[j]
		}

		txt.tris = append(txt.tris, txt.glyph...)
		txt.dirty = true

		if txt.bounds.W()*txt.bounds.H() == 0 {
			txt.bounds = bounds
		} else {
			txt.bounds = txt.bounds.Union(bounds)
		}
	}
}
<|endoftext|>


<commit_before>package main

func messageCheck(msg string) string {
	var result = ""
	if msg == "#help" {
		result = "ควย"
	} else {
		//result = getReplyMessageFromUser(msg)
		result = msg
	}

	return result
}
<commit_msg>v.3.7.1<commit_after>package main

func messageCheck(msg string) string {
	var result = ""
	if msg == "#help" {
		result = "ควย"
	} else {
		result = getReplyMessageFromUser(msg)
		//result = msg
	}

	return result
}
<|endoftext|>


<commit_before>// Package textmagic wraps the API for textmagic.com
package textmagic

import (
	"encoding/json"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/MJKWoolnough/memio"
)

var apiURLPrefix = "https://www.textmagic.com/app/api?"

const (
	cmdAccount       = "account"
	cmdCheckNumber   = "check_number"
	cmdDeleteReply   = "delete_reply"
	cmdMessageStatus = "message_status"
	cmdReceive       = "receive"
	cmdSend          = "send"
)

// TextMagic contains the data necessary for performing API requests
type TextMagic struct {
	username, password string
}

// New constructs a new TextMagic session
func New(username, password string) TextMagic {
	return TextMagic{username, password}
}

func (t TextMagic) sendAPI(cmd string, params url.Values, data interface{}) error {
	params.Set("username", t.username)
	params.Set("password", t.password)
	params.Set("cmd", cmd)
	r, err := http.Get(apiURLPrefix + params.Encode())
	if err != nil {
		return RequestError{cmd, err}
	}
	defer r.Body.Close()
	if r.StatusCode != http.StatusOK {
		return StatusError{cmd, r.StatusCode}
	}
	cL := r.ContentLength
	if cL < 0 {
		cL = 1024
	}
	jsonData := make([]byte, 0, cL) // avoid allocation using io.Pipe?
	var apiError APIError
	err = json.NewDecoder(io.TeeReader(r.Body, memio.Create(&jsonData))).Decode(&apiError)
	if err != nil {
		return JSONError{cmd, err}
	}
	if apiError.Code != 0 {
		apiError.Cmd = cmd
		return apiError
	}
	json.Unmarshal(jsonData, data)
	return nil
}

type balance struct {
	Balance float32 `json:"balance"`
}

// Account returns the balance of the given TextMagic account
func (t TextMagic) Account() (float32, error) {
	var b balance
	if err := t.sendAPI(cmdAccount, url.Values{}, &b); err != nil {
		return 0, err
	}
	return b.Balance, nil
}

// DeliveryNotificationCode is a representation of the status of a delivery
type DeliveryNotificationCode string

// Status returns the type of status based on the code
func (d DeliveryNotificationCode) Status() string {
	switch d {
	case "q", "r", "a", "b", "s":
		return "intermediate"
	case "d", "f", "e", "j", "u":
		return "final"
	}
	return "unknown"
}

func (d DeliveryNotificationCode) String() string {
	switch d {
	case "q":
		return "The message is queued on the TextMagic server."
	case "r":
		return "The message has been sent to the mobile operator."
	case "a":
		return "The mobile operator has acknowledged the message."
	case "b":
		return "The mobile operator has queued the message."
	case "d":
		return "The message has been successfully delivered to the handset."
	case "f":
		return "An error occurred while delivering message."
	case "e":
		return "An error occurred while sending message."
	case "j":
		return "The mobile operator has rejected the message."
	case "s":
		return "This message is scheduled to be sent later."
	default:
		return "The status is unknown."

	}
}

// Status represents all of the information about a sent/pending message
type Status struct {
	Text      string                   `json:"text"`
	Status    DeliveryNotificationCode `json:"status"`
	Created   int64                    `json:"created_time"`
	Reply     string                   `json:"reply_number"`
	Cost      float32                  `json:"credits_cost"`
	Completed int64                    `json:"completed_time"`
}

const joinSep = ","

// MessageStatus gathers information about the messages with the given ids
func (t TextMagic) MessageStatus(ids []string) (map[string]Status, error) {
	statuses := make(map[string]Status)
	for _, tIds := range splitSlice(ids) {
		messageIds := strings.Join(tIds, joinSep)
		strStatuses := make(map[string]Status)
		err := t.sendAPI(cmdMessageStatus, url.Values{"ids": {messageIds}}, strStatuses)
		if err != nil {
			return statuses, err
		}
		for messageID, status := range strStatuses {
			statuses[messageID] = status
		}
	}
	return statuses, nil
}

// Number represents the information about a phone number
type Number struct {
	Price   float32 `json:"price"`
	Country string  `json:"country"`
}

// CheckNumber is used to get the cost and country for the given phone numbers
func (t TextMagic) CheckNumber(numbers []string) (map[string]Number, error) {
	ns := make(map[string]Number)
	if err := t.sendAPI(cmdCheckNumber, url.Values{"phone": {strings.Join(numbers, joinSep)}}, ns); err != nil {
		return nil, err
	}
	return ns, nil
}

type deleted struct {
	Deleted []string `json:"deleted"`
}

// DeleteReply will simple delete message replies with the given ids
func (t TextMagic) DeleteReply(ids []string) ([]string, error) {
	toRet := make([]string, 0, len(ids))
	for _, tIds := range splitSlice(ids) {
		var d deleted
		if err := t.sendAPI(cmdDeleteReply, url.Values{"deleted": {strings.Join(tIds, joinSep)}}, &d); err != nil {
			return toRet, err
		}
		toRet = append(toRet, d.Deleted...)
	}
	return toRet, nil
}

// Message represents the information about a received message
type Message struct {
	ID        uint64 `json:"message_id"`
	From      string `json:"from"`
	Timestamp int64  `json:"timestamp"`
	Text      string `json:"text"`
}

type received struct {
	Messages []Message `json:"messages"`
	Unread   uint64    `json:"unread"`
}

// Receive will retrieve the number of unread messages and the 100 latest
// replies
func (t TextMagic) Receive(lastRetrieved uint64) (uint64, []Message, error) {
	var r received
	err := t.sendAPI(cmdReceive, url.Values{"last_retrieved_id": {utos(lastRetrieved)}}, &r)
	return r.Unread, r.Messages, err
}

// Option is a type representing a message sending option
type Option func(u url.Values)

// From is an option to modify the sender of a message
func From(from string) Option {
	return func(u url.Values) {
		u.Set("from", from)
	}
}

// MaxLength is an option to limit the length of a message
func MaxLength(length uint64) Option {
	if length > 3 {
		length = 3
	}
	return func(u url.Values) {
		u.Set("max_length", utos(length))
	}
}

// CutExtra sets the option to automatically trim overlong messages
func CutExtra() Option {
	return func(u url.Values) {
		u.Set("cut_extra", "1")
	}
}

// SendTime sets the option to schedule the sending of a message for a specific
// time
func SendTime(t time.Time) Option {
	return func(u url.Values) {
		u.Set("send_time", t.Format(time.RFC3339))
	}
}

type messageResponse struct {
	IDs   map[string]string `json:"message_id"`
	Text  string            `json:"sent_text"`
	Parts uint              `json:"parts_count"`
}

// Send will send a message to the given recipients. It takes options to modify
// the scheduling. sender and length of the message
func (t TextMagic) Send(message string, to []string, options ...Option) (map[string]string, string, uint, error) {
	var (
		params = url.Values{}
		text   string
		parts  uint
		ids    = make(map[string]string)
	)
	// check message for unicode/invalid chars
	params.Set("text", message)
	params.Set("unicode", "0")
	for _, o := range options {
		o(params)
	}
	for _, numbers := range splitSlice(to) {
		params.Set("phone", strings.Join(numbers, joinSep))
		var m messageResponse
		if err := t.sendAPI(cmdSend, params, &m); err != nil {
			return ids, text, parts, err
		}
		if parts == 0 {
			parts = m.Parts
			text = m.Text
		}
		for id, number := range m.IDs {
			ids[id] = number
		}
	}
	return ids, text, parts, nil
}

// Errors

// APIError is an error returned when the incorrect or unexpected data is
// received
type APIError struct {
	Cmd     string
	Code    int    `json:"error_code"`
	Message string `json:"error_message"`
}

func (a APIError) Error() string {
	return "command " + a.Cmd + " returned the following API error: " + a.Message
}

// RequestError is an error which wraps an error that occurs while making an
// API call
type RequestError struct {
	Cmd string
	Err error
}

func (r RequestError) Error() string {
	return "command " + r.Cmd + " returned the following error while makeing the API call: " + r.Err.Error()
}

// StatusError is an error that is returned when a non-200 OK http response is
// received
type StatusError struct {
	Cmd        string
	StatusCode int
}

func (s StatusError) Error() string {
	return "command " + s.Cmd + " returned a non-200 OK response: " + http.StatusText(s.StatusCode)
}

// JSONError is an error that wraps a JSON error
type JSONError struct {
	Cmd string
	Err error
}

func (j JSONError) Error() string {
	return "command " + j.Cmd + " returned malformed JSON: " + j.Err.Error()
}
<commit_msg>updated to new memio structure<commit_after>// Package textmagic wraps the API for textmagic.com
package textmagic

import (
	"encoding/json"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/MJKWoolnough/memio"
)

var apiURLPrefix = "https://www.textmagic.com/app/api?"

const (
	cmdAccount       = "account"
	cmdCheckNumber   = "check_number"
	cmdDeleteReply   = "delete_reply"
	cmdMessageStatus = "message_status"
	cmdReceive       = "receive"
	cmdSend          = "send"
)

// TextMagic contains the data necessary for performing API requests
type TextMagic struct {
	username, password string
}

// New constructs a new TextMagic session
func New(username, password string) TextMagic {
	return TextMagic{username, password}
}

func (t TextMagic) sendAPI(cmd string, params url.Values, data interface{}) error {
	params.Set("username", t.username)
	params.Set("password", t.password)
	params.Set("cmd", cmd)
	r, err := http.Get(apiURLPrefix + params.Encode())
	if err != nil {
		return RequestError{cmd, err}
	}
	defer r.Body.Close()
	if r.StatusCode != http.StatusOK {
		return StatusError{cmd, r.StatusCode}
	}
	cL := r.ContentLength
	if cL < 0 {
		cL = 1024
	}
	jsonData := make(memio.Buffer, 0, cL) // avoid allocation using io.Pipe?
	var apiError APIError
	err = json.NewDecoder(io.TeeReader(r.Body, &jsonData)).Decode(&apiError)
	if err != nil {
		return JSONError{cmd, err}
	}
	if apiError.Code != 0 {
		apiError.Cmd = cmd
		return apiError
	}
	json.Unmarshal(jsonData, data)
	return nil
}

type balance struct {
	Balance float32 `json:"balance"`
}

// Account returns the balance of the given TextMagic account
func (t TextMagic) Account() (float32, error) {
	var b balance
	if err := t.sendAPI(cmdAccount, url.Values{}, &b); err != nil {
		return 0, err
	}
	return b.Balance, nil
}

// DeliveryNotificationCode is a representation of the status of a delivery
type DeliveryNotificationCode string

// Status returns the type of status based on the code
func (d DeliveryNotificationCode) Status() string {
	switch d {
	case "q", "r", "a", "b", "s":
		return "intermediate"
	case "d", "f", "e", "j", "u":
		return "final"
	}
	return "unknown"
}

func (d DeliveryNotificationCode) String() string {
	switch d {
	case "q":
		return "The message is queued on the TextMagic server."
	case "r":
		return "The message has been sent to the mobile operator."
	case "a":
		return "The mobile operator has acknowledged the message."
	case "b":
		return "The mobile operator has queued the message."
	case "d":
		return "The message has been successfully delivered to the handset."
	case "f":
		return "An error occurred while delivering message."
	case "e":
		return "An error occurred while sending message."
	case "j":
		return "The mobile operator has rejected the message."
	case "s":
		return "This message is scheduled to be sent later."
	default:
		return "The status is unknown."

	}
}

// Status represents all of the information about a sent/pending message
type Status struct {
	Text      string                   `json:"text"`
	Status    DeliveryNotificationCode `json:"status"`
	Created   int64                    `json:"created_time"`
	Reply     string                   `json:"reply_number"`
	Cost      float32                  `json:"credits_cost"`
	Completed int64                    `json:"completed_time"`
}

const joinSep = ","

// MessageStatus gathers information about the messages with the given ids
func (t TextMagic) MessageStatus(ids []string) (map[string]Status, error) {
	statuses := make(map[string]Status)
	for _, tIds := range splitSlice(ids) {
		messageIds := strings.Join(tIds, joinSep)
		strStatuses := make(map[string]Status)
		err := t.sendAPI(cmdMessageStatus, url.Values{"ids": {messageIds}}, strStatuses)
		if err != nil {
			return statuses, err
		}
		for messageID, status := range strStatuses {
			statuses[messageID] = status
		}
	}
	return statuses, nil
}

// Number represents the information about a phone number
type Number struct {
	Price   float32 `json:"price"`
	Country string  `json:"country"`
}

// CheckNumber is used to get the cost and country for the given phone numbers
func (t TextMagic) CheckNumber(numbers []string) (map[string]Number, error) {
	ns := make(map[string]Number)
	if err := t.sendAPI(cmdCheckNumber, url.Values{"phone": {strings.Join(numbers, joinSep)}}, ns); err != nil {
		return nil, err
	}
	return ns, nil
}

type deleted struct {
	Deleted []string `json:"deleted"`
}

// DeleteReply will simple delete message replies with the given ids
func (t TextMagic) DeleteReply(ids []string) ([]string, error) {
	toRet := make([]string, 0, len(ids))
	for _, tIds := range splitSlice(ids) {
		var d deleted
		if err := t.sendAPI(cmdDeleteReply, url.Values{"deleted": {strings.Join(tIds, joinSep)}}, &d); err != nil {
			return toRet, err
		}
		toRet = append(toRet, d.Deleted...)
	}
	return toRet, nil
}

// Message represents the information about a received message
type Message struct {
	ID        uint64 `json:"message_id"`
	From      string `json:"from"`
	Timestamp int64  `json:"timestamp"`
	Text      string `json:"text"`
}

type received struct {
	Messages []Message `json:"messages"`
	Unread   uint64    `json:"unread"`
}

// Receive will retrieve the number of unread messages and the 100 latest
// replies
func (t TextMagic) Receive(lastRetrieved uint64) (uint64, []Message, error) {
	var r received
	err := t.sendAPI(cmdReceive, url.Values{"last_retrieved_id": {utos(lastRetrieved)}}, &r)
	return r.Unread, r.Messages, err
}

// Option is a type representing a message sending option
type Option func(u url.Values)

// From is an option to modify the sender of a message
func From(from string) Option {
	return func(u url.Values) {
		u.Set("from", from)
	}
}

// MaxLength is an option to limit the length of a message
func MaxLength(length uint64) Option {
	if length > 3 {
		length = 3
	}
	return func(u url.Values) {
		u.Set("max_length", utos(length))
	}
}

// CutExtra sets the option to automatically trim overlong messages
func CutExtra() Option {
	return func(u url.Values) {
		u.Set("cut_extra", "1")
	}
}

// SendTime sets the option to schedule the sending of a message for a specific
// time
func SendTime(t time.Time) Option {
	return func(u url.Values) {
		u.Set("send_time", t.Format(time.RFC3339))
	}
}

type messageResponse struct {
	IDs   map[string]string `json:"message_id"`
	Text  string            `json:"sent_text"`
	Parts uint              `json:"parts_count"`
}

// Send will send a message to the given recipients. It takes options to modify
// the scheduling. sender and length of the message
func (t TextMagic) Send(message string, to []string, options ...Option) (map[string]string, string, uint, error) {
	var (
		params = url.Values{}
		text   string
		parts  uint
		ids    = make(map[string]string)
	)
	// check message for unicode/invalid chars
	params.Set("text", message)
	params.Set("unicode", "0")
	for _, o := range options {
		o(params)
	}
	for _, numbers := range splitSlice(to) {
		params.Set("phone", strings.Join(numbers, joinSep))
		var m messageResponse
		if err := t.sendAPI(cmdSend, params, &m); err != nil {
			return ids, text, parts, err
		}
		if parts == 0 {
			parts = m.Parts
			text = m.Text
		}
		for id, number := range m.IDs {
			ids[id] = number
		}
	}
	return ids, text, parts, nil
}

// Errors

// APIError is an error returned when the incorrect or unexpected data is
// received
type APIError struct {
	Cmd     string
	Code    int    `json:"error_code"`
	Message string `json:"error_message"`
}

func (a APIError) Error() string {
	return "command " + a.Cmd + " returned the following API error: " + a.Message
}

// RequestError is an error which wraps an error that occurs while making an
// API call
type RequestError struct {
	Cmd string
	Err error
}

func (r RequestError) Error() string {
	return "command " + r.Cmd + " returned the following error while makeing the API call: " + r.Err.Error()
}

// StatusError is an error that is returned when a non-200 OK http response is
// received
type StatusError struct {
	Cmd        string
	StatusCode int
}

func (s StatusError) Error() string {
	return "command " + s.Cmd + " returned a non-200 OK response: " + http.StatusText(s.StatusCode)
}

// JSONError is an error that wraps a JSON error
type JSONError struct {
	Cmd string
	Err error
}

func (j JSONError) Error() string {
	return "command " + j.Cmd + " returned malformed JSON: " + j.Err.Error()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"io"
	"os"
	"unicode/utf8"

	"github.com/olekukonko/tablewriter"
)

var (
	fileName  = flag.String("f", "", "Set file with  eg. sample.csv")
	delimiter = flag.String("d", ",", "Set CSV File delimiter eg. ,|;|\t ")
	header    = flag.Bool("h", true, "Set header options eg. true|false ")
	align     = flag.String("a", "none", "Set aligmement with eg. none|left|right|center")
	pipe      = flag.Bool("p", false, "Suport for Piping from STDIN")
	border    = flag.Bool("b", true, "Enable / disable table border")
)

func main() {
	flag.Parse()
	fmt.Println()
	if *pipe || hasArg("-p") {
		process(os.Stdin)
	} else {
		if *fileName == "" {
			fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
			flag.PrintDefaults()
			fmt.Println()
			os.Exit(1)
		}
		processFile()
	}
	fmt.Println()
}

func hasArg(name string) bool {
	for _, v := range os.Args {
		if name == v {
			return true
		}
	}
	return false
}
func processFile() {
	r, err := os.Open(*fileName)
	if err != nil {
		exit(err)
	}
	defer r.Close()
	process(r)
}
func process(r io.Reader) {
	csvReader := csv.NewReader(r)
	rune, size := utf8.DecodeRuneInString(*delimiter)
	if size == 0 {
		rune = ','
	}
	csvReader.Comma = rune

	table, err := tablewriter.NewCSVReader(os.Stdout, csvReader, *header)

	if err != nil {
		exit(err)
	}

	switch *align {
	case "left":
		table.SetAlignment(tablewriter.ALIGN_LEFT)
	case "right":
		table.SetAlignment(tablewriter.ALIGN_RIGHT)
	case "center":
		table.SetAlignment(tablewriter.ALIGN_CENTER)
	}
	table.SetBorder(*border)
	table.Render()
}

func exit(err error) {
	fmt.Fprintf(os.Stderr, "#Error : %s", err)
	os.Exit(1)
}
<commit_msg>add option to select for title case for headers<commit_after>package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"io"
	"os"
	"unicode/utf8"

	"github.com/olekukonko/tablewriter"
)

var (
	fileName  = flag.String("f", "", "Set file with  eg. sample.csv")
	delimiter = flag.String("d", ",", "Set CSV File delimiter eg. ,|;|\t ")
	header    = flag.Bool("h", true, "Set header options eg. true|false ")
	align     = flag.String("a", "none", "Set aligmement with eg. none|left|right|center")
	pipe      = flag.Bool("p", false, "Suport for Piping from STDIN")
	border    = flag.Bool("b", true, "Enable / disable table border")
	casing    = flag.Bool("c", false, "Set header to be title case")
)

func main() {
	flag.Parse()
	fmt.Println()
	if *pipe || hasArg("-p") {
		process(os.Stdin)
	} else {
		if *fileName == "" {
			fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
			flag.PrintDefaults()
			fmt.Println()
			os.Exit(1)
		}
		processFile()
	}
	fmt.Println()
}

func hasArg(name string) bool {
	for _, v := range os.Args {
		if name == v {
			return true
		}
	}
	return false
}
func processFile() {
	r, err := os.Open(*fileName)
	if err != nil {
		exit(err)
	}
	defer r.Close()
	process(r)
}
func process(r io.Reader) {
	csvReader := csv.NewReader(r)
	rune, size := utf8.DecodeRuneInString(*delimiter)
	if size == 0 {
		rune = ','
	}
	csvReader.Comma = rune

	table, err := tablewriter.NewCSVReader(os.Stdout, csvReader, *header)

	if err != nil {
		exit(err)
	}

	switch *align {
	case "left":
		table.SetAlignment(tablewriter.ALIGN_LEFT)
	case "right":
		table.SetAlignment(tablewriter.ALIGN_RIGHT)
	case "center":
		table.SetAlignment(tablewriter.ALIGN_CENTER)
	}
	table.SetBorder(*border)
	if *casing {
		table.SetAutoFormatHeaders(false)
		table.SetTitleCase(*casing)
	}
	table.Render()
}

func exit(err error) {
	fmt.Fprintf(os.Stderr, "#Error : %s", err)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/bewuethr/advent-of-code/go/convert"
	"github.com/bewuethr/advent-of-code/go/ioutil"
	"github.com/bewuethr/advent-of-code/go/log"
)

func main() {
	scanner, err := ioutil.GetInputScanner()
	if err != nil {
		log.Die("getting scanner", err)
	}

	scanner.Scan()
	opCodesStr := strings.Split(scanner.Text(), ",")
	if err := scanner.Err(); err != nil {
		log.Die("reading input", err)
	}

	opCodes, err := convert.StrSliceToInt(opCodesStr)
	if err != nil {
		log.Die("converting string slice to int", err)
	}

	if err := runProgram(opCodes); err != nil {
		log.Die("running op codes", err)
	}
}

const (
	add         = 1
	mult        = 2
	input       = 3
	output      = 4
	jumpIfTrue  = 5
	jumpIfFalse = 6
	lessThan    = 7
	equals      = 8
	halt        = 99

	positionMode  = 0
	immediateMode = 1
)

var nargs = map[int]int{
	add:         3,
	mult:        3,
	input:       1,
	output:      1,
	jumpIfTrue:  2,
	jumpIfFalse: 2,
	lessThan:    3,
	equals:      3,
	halt:        0,
}

func runProgram(codes []int) error {
	idx := 0
	for {
		code, modes := parseValue(codes[idx])
		params := getParams(codes, idx, modes)

		switch code {
		case halt:
			return nil

		case add:
			codes[codes[idx+3]] = params[0] + params[1]
			idx += nargs[add] + 1

		case mult:
			codes[codes[idx+3]] = params[0] * params[1]
			idx += nargs[mult] + 1

		case input:
			codes[codes[idx+1]] = 5
			idx += nargs[input] + 1

		case output:
			fmt.Println(params[0])
			idx += nargs[output] + 1

		case jumpIfTrue:
			if params[0] != 0 {
				idx = params[1]
			} else {
				idx += nargs[jumpIfTrue] + 1
			}

		case jumpIfFalse:
			if params[0] == 0 {
				idx = params[1]
			} else {
				idx += nargs[jumpIfFalse] + 1
			}

		case lessThan:
			if params[0] < params[1] {
				codes[codes[idx+3]] = 1
			} else {
				codes[codes[idx+3]] = 0
			}
			idx += nargs[lessThan] + 1

		case equals:
			if params[0] == params[1] {
				codes[codes[idx+3]] = 1
			} else {
				codes[codes[idx+3]] = 0
			}
			idx += nargs[equals] + 1

		default:
			return fmt.Errorf("illegal opcode %d", codes[idx])
		}
	}
}

func parseValue(val int) (code int, modes []int) {
	code = val % 100
	if valStr := strconv.Itoa(val); len(valStr) > 2 {
		valStr = valStr[:len(valStr)-2]

		var modesStr []string
		for _, m := range valStr {
			modesStr = append([]string{string(m)}, modesStr...)
		}

		var err error
		modes, err = convert.StrSliceToInt(modesStr)
		if err != nil {
			log.Die("converting modes to int", err)
		}
	}

	for len(modes) < nargs[code] {
		modes = append(modes, 0)
	}

	return code, modes
}

func getParams(codes []int, idx int, modes []int) []int {
	var params []int

	for i := 0; i < len(modes); i++ {
		var param int
		if modes[i] == immediateMode {
			param = codes[idx+i+1]
		} else {
			param = codes[codes[idx+i+1]]
		}
		params = append(params, param)
	}

	return params
}
<commit_msg>Use intcode package for day 5, second part<commit_after>package main

import (
	"strings"

	"github.com/bewuethr/advent-of-code/go/convert"
	"github.com/bewuethr/advent-of-code/go/intcode"
	"github.com/bewuethr/advent-of-code/go/ioutil"
	"github.com/bewuethr/advent-of-code/go/log"
)

func main() {
	scanner, err := ioutil.GetInputScanner()
	if err != nil {
		log.Die("getting scanner", err)
	}

	scanner.Scan()
	opCodesStr := strings.Split(scanner.Text(), ",")
	if err := scanner.Err(); err != nil {
		log.Die("reading input", err)
	}

	opCodes, err := convert.StrSliceToInt(opCodesStr)
	if err != nil {
		log.Die("converting string slice to int", err)
	}

	comp := intcode.NewComputer(opCodes)
	if err := comp.RunProgram(5); err != nil {
		log.Die("running op codes", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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 queryparams

import (
	"fmt"
	"net/url"
	"reflect"
	"strings"

	"k8s.io/kubernetes/pkg/runtime"
)

func jsonTag(field reflect.StructField) (string, bool) {
	structTag := field.Tag.Get("json")
	if len(structTag) == 0 {
		return "", false
	}
	parts := strings.Split(structTag, ",")
	tag := parts[0]
	if tag == "-" {
		tag = ""
	}
	omitempty := false
	parts = parts[1:]
	for _, part := range parts {
		if part == "omitempty" {
			omitempty = true
			break
		}
	}
	return tag, omitempty
}

func formatValue(value interface{}) string {
	return fmt.Sprintf("%v", value)
}

func isPointerKind(kind reflect.Kind) bool {
	return kind == reflect.Ptr
}

func isStructKind(kind reflect.Kind) bool {
	return kind == reflect.Struct
}

func isValueKind(kind reflect.Kind) bool {
	switch kind {
	case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16,
		reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8,
		reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32,
		reflect.Float64, reflect.Complex64, reflect.Complex128:
		return true
	default:
		return false
	}
}

func zeroValue(value reflect.Value) bool {
	return reflect.DeepEqual(reflect.Zero(value.Type()).Interface(), value.Interface())
}

func addParam(values url.Values, tag string, omitempty bool, value reflect.Value) {
	if omitempty && zeroValue(value) {
		return
	}
	val := ""
	iValue := fmt.Sprintf("%v", value.Interface())

	if iValue != "<nil>" {
		val = iValue
	}
	values.Add(tag, val)
}

func addListOfParams(values url.Values, tag string, omitempty bool, list reflect.Value) {
	for i := 0; i < list.Len(); i++ {
		addParam(values, tag, omitempty, list.Index(i))
	}
}

// Convert takes a versioned runtime.Object and serializes it to a url.Values object
// using JSON tags as parameter names. Only top-level simple values, arrays, and slices
// are serialized. Embedded structs, maps, etc. will not be serialized.
func Convert(obj runtime.Object) (url.Values, error) {
	result := url.Values{}
	if obj == nil {
		return result, nil
	}
	var sv reflect.Value
	switch reflect.TypeOf(obj).Kind() {
	case reflect.Ptr, reflect.Interface:
		sv = reflect.ValueOf(obj).Elem()
	default:
		return nil, fmt.Errorf("expecting a pointer or interface")
	}
	st := sv.Type()
	if !isStructKind(st.Kind()) {
		return nil, fmt.Errorf("expecting a pointer to a struct")
	}

	// Check all object fields
	convertStruct(result, st, sv)

	return result, nil
}

func convertStruct(result url.Values, st reflect.Type, sv reflect.Value) {
	for i := 0; i < st.NumField(); i++ {
		field := sv.Field(i)
		tag, omitempty := jsonTag(st.Field(i))
		if len(tag) == 0 {
			continue
		}
		ft := field.Type()

		kind := ft.Kind()
		if isPointerKind(kind) {
			kind = ft.Elem().Kind()
			if !field.IsNil() {
				field = reflect.Indirect(field)
			}
		}

		switch {
		case isValueKind(kind):
			addParam(result, tag, omitempty, field)
		case kind == reflect.Array || kind == reflect.Slice:
			if isValueKind(ft.Elem().Kind()) {
				addListOfParams(result, tag, omitempty, field)
			}
		case isStructKind(kind) && !(zeroValue(field) && omitempty):
			convertStruct(result, ft, field)
		}
	}
}
<commit_msg>fix queryparams convertStruct<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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 queryparams

import (
	"fmt"
	"net/url"
	"reflect"
	"strings"

	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/runtime"
)

func jsonTag(field reflect.StructField) (string, bool) {
	structTag := field.Tag.Get("json")
	if len(structTag) == 0 {
		return "", false
	}
	parts := strings.Split(structTag, ",")
	tag := parts[0]
	if tag == "-" {
		tag = ""
	}
	omitempty := false
	parts = parts[1:]
	for _, part := range parts {
		if part == "omitempty" {
			omitempty = true
			break
		}
	}
	return tag, omitempty
}

func formatValue(value interface{}) string {
	return fmt.Sprintf("%v", value)
}

func isPointerKind(kind reflect.Kind) bool {
	return kind == reflect.Ptr
}

func isStructKind(kind reflect.Kind) bool {
	return kind == reflect.Struct
}

func isValueKind(kind reflect.Kind) bool {
	switch kind {
	case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16,
		reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8,
		reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32,
		reflect.Float64, reflect.Complex64, reflect.Complex128:
		return true
	default:
		return false
	}
}

func zeroValue(value reflect.Value) bool {
	return reflect.DeepEqual(reflect.Zero(value.Type()).Interface(), value.Interface())
}

func addParam(values url.Values, tag string, omitempty bool, value reflect.Value) {
	if omitempty && zeroValue(value) {
		return
	}
	val := ""
	iValue := fmt.Sprintf("%v", value.Interface())

	if iValue != "<nil>" {
		val = iValue
	}
	values.Add(tag, val)
}

func addListOfParams(values url.Values, tag string, omitempty bool, list reflect.Value) {
	for i := 0; i < list.Len(); i++ {
		addParam(values, tag, omitempty, list.Index(i))
	}
}

// Convert takes a versioned runtime.Object and serializes it to a url.Values object
// using JSON tags as parameter names. Only top-level simple values, arrays, and slices
// are serialized. Embedded structs, maps, etc. will not be serialized.
func Convert(obj runtime.Object) (url.Values, error) {
	result := url.Values{}
	if obj == nil {
		return result, nil
	}
	var sv reflect.Value
	switch reflect.TypeOf(obj).Kind() {
	case reflect.Ptr, reflect.Interface:
		sv = reflect.ValueOf(obj).Elem()
	default:
		return nil, fmt.Errorf("expecting a pointer or interface")
	}
	st := sv.Type()
	if !isStructKind(st.Kind()) {
		return nil, fmt.Errorf("expecting a pointer to a struct")
	}

	// Check all object fields
	convertStruct(result, st, sv)

	return result, nil
}

func convertStruct(result url.Values, st reflect.Type, sv reflect.Value) {
	for i := 0; i < st.NumField(); i++ {
		field := sv.Field(i)
		tag, omitempty := jsonTag(st.Field(i))
		if len(tag) == 0 {
			continue
		}
		ft := field.Type()

		kind := ft.Kind()
		if isPointerKind(kind) {
			kind = ft.Elem().Kind()
			if !field.IsNil() {
				field = reflect.Indirect(field)
			}
		}

		switch {
		case isValueKind(kind):
			addParam(result, tag, omitempty, field)
		case kind == reflect.Array || kind == reflect.Slice:
			if isValueKind(ft.Elem().Kind()) {
				addListOfParams(result, tag, omitempty, field)
			}
		case isStructKind(kind) && !(zeroValue(field) && omitempty):
			if selector, ok := field.Interface().(unversioned.LabelSelector); ok {
				addParam(result, tag, omitempty, reflect.ValueOf(selector.Selector.String()))
			}
			if selector, ok := field.Interface().(unversioned.FieldSelector); ok {
				addParam(result, tag, omitempty, reflect.ValueOf(selector.Selector.String()))
			}
			convertStruct(result, ft, field)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 containermatcher

import (
	"path/filepath"
	"strings"

	"github.com/richardlehane/siegfried/pkg/core"
	"github.com/richardlehane/siegfried/pkg/core/priority"
	"github.com/richardlehane/siegfried/pkg/core/siegreader"
)

func (m Matcher) Identify(n string, b siegreader.Buffer) (chan core.Result, error) {
	res := make(chan core.Result)
	// check trigger
	buf, err := b.Slice(0, 8)
	if err != nil {
		close(res)
		return res, nil
	}
	for _, c := range m {
		if c.trigger(buf) {
			if q, i := c.defaultMatch(n); q {
				go func() {
					res <- defaultHit(i)
					close(res)
				}()
				return res, nil
			}
			rdr, err := c.rdr(b)
			if err != nil {
				close(res)
				return res, err
			}
			go c.identify(rdr, res)
			return res, nil
		}
	}
	// nothing ... move on
	close(res)
	return res, nil
}

func (c *ContainerMatcher) defaultMatch(n string) (bool, int) {
	if c.Default == "" {
		return false, 0
	}
	ext := filepath.Ext(n)
	if len(ext) > 0 && strings.TrimPrefix(ext, ".") == c.Default {
		// the default is a negative value calculated from the CType
		return true, -1 - int(c.CType)
	}
	return false, 0
}

type identifier struct {
	partsMatched [][]hit // hits for parts
	ruledOut     []bool  // mark additional signatures as negatively matched
	waitSet      *priority.WaitSet
	hits         []hit // shared buffer of hits used when matching
}

func (c *ContainerMatcher) newIdentifier(numParts int) *identifier {
	return &identifier{
		make([][]hit, numParts),
		make([]bool, numParts),
		c.Priorities.WaitSet(),
		make([]hit, 0, 1),
	}
}

func (c *ContainerMatcher) identify(rdr Reader, res chan core.Result) {
	// safe to call on a nil matcher (i.e. container matching switched off)
	if c == nil {
		close(res)
		return
	}
	id := c.newIdentifier(len(c.Parts))
	var err error
	for err = rdr.Next(); err == nil; err = rdr.Next() {
		ct, ok := c.NameCTest[rdr.Name()]
		if !ok {
			continue
		}
		// name has matched, lets test the CTests
		// ct.identify will generate a slice of hits which pass to
		// processHits which will return true if we can stop
		if c.processHits(ct.identify(c, id, rdr, rdr.Name()), id, ct, rdr.Name(), res) {
			break
		}
	}
	close(res)
}

func (ct *CTest) identify(c *ContainerMatcher, id *identifier, rdr Reader, name string) []hit {
	// reset hits
	id.hits = id.hits[:0]
	for _, h := range ct.Satisfied {
		if id.waitSet.Check(h) {
			id.hits = append(id.hits, hit{h, name, "name only"})
		}
	}
	if ct.Unsatisfied != nil {
		buf, _ := rdr.SetSource(c.entryBufs) // NOTE: an error is ignored here.
		bmc, _ := ct.BM.Identify("", buf)
		for r := range bmc {
			h := ct.Unsatisfied[r.Index()]
			if id.waitSet.Check(h) && id.checkHits(h) {
				id.hits = append(id.hits, hit{h, name, r.Basis()})
			}
		}
		rdr.Close()
		c.entryBufs.Put(buf)
	}
	return id.hits
}

// process the hits from the ctest: adding hits to the parts matched, checking priorities
// return true if satisfied and can quit
func (c *ContainerMatcher) processHits(hits []hit, id *identifier, ct *CTest, name string, res chan core.Result) bool {
	// if there are no hits, rule out any sigs in the ctest
	if len(hits) == 0 {
		for _, v := range ct.Satisfied {
			id.ruledOut[v] = true
		}
		for _, v := range ct.Unsatisfied {
			id.ruledOut[v] = true
		}
		return false
	}
	for _, h := range hits {
		id.partsMatched[h.id] = append(id.partsMatched[h.id], h)
		if len(id.partsMatched[h.id]) == c.Parts[h.id] {
			if id.waitSet.Check(h.id) {
				idx, _ := c.Priorities.Index(h.id)
				res <- toResult(c.Sindexes[idx], id.partsMatched[h.id]) // send a Result here
				// set a priority list and return early if can
				if id.waitSet.Put(h.id) {
					return true
				}
			}
		}
	}
	// if nothing ruled out by this test, then we must continue
	if len(hits) == len(ct.Satisfied)+len(ct.Unsatisfied) {
		return false
	}
	// we can rule some possible matches out...
	for _, v := range ct.Satisfied {
		if len(id.partsMatched[v]) == 0 || id.partsMatched[v][len(id.partsMatched[v])-1].name != name {
			id.ruledOut[v] = true
		}
	}
	for _, v := range ct.Unsatisfied {
		if len(id.partsMatched[v]) == 0 || id.partsMatched[v][len(id.partsMatched[v])-1].name != name {
			id.ruledOut[v] = true
		}
	}
	// if we haven't got a waitList yet, then we should return false
	waitingOn := id.waitSet.WaitingOn()
	if waitingOn == nil {
		return false
	}
	// loop over the wait list, seeing if they are all ruled out
	for _, v := range waitingOn {
		if !id.ruledOut[v] {
			return false
		}
	}
	return true
}

// eliminate duplicate hits - must do this since rely on number of matches for each sig as test for full match
func (id *identifier) checkHits(i int) bool {
	for _, h := range id.hits {
		if i == h.id {
			return false
		}
	}
	return true
}

func toResult(i int, h []hit) result {
	if len(h) == 0 {
		return result(h)
	}
	h[0].id += i
	return result(h)
}

type result []hit

func (r result) Index() int {
	if len(r) == 0 {
		return -1
	}
	return r[0].id
}

func (r result) Basis() string {
	var basis string
	for i, v := range r {
		if i < 1 {
			basis += "container "
		} else {
			basis += "; "
		}
		basis += "name " + v.name
		if len(v.basis) > 0 {
			basis += " with " + v.basis
		}
	}
	return basis
}

type hit struct {
	id    int
	name  string
	basis string
}

type defaultHit int

func (d defaultHit) Index() int {
	return int(d)
}

func (d defaultHit) Basis() string {
	return "container match with trigger and default extension"
}
<commit_msg>send default hit at end rather than beginning<commit_after>// Copyright 2014 Richard Lehane. All rights reserved.
//
// 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 containermatcher

import (
	"strings"

	"github.com/richardlehane/siegfried/pkg/core"
	"github.com/richardlehane/siegfried/pkg/core/priority"
	"github.com/richardlehane/siegfried/pkg/core/siegreader"
)

func (m Matcher) Identify(n string, b siegreader.Buffer) (chan core.Result, error) {
	res := make(chan core.Result)
	// check trigger
	buf, err := b.Slice(0, 8)
	if err != nil {
		close(res)
		return res, nil
	}
	for _, c := range m {
		if c.trigger(buf) {
			rdr, err := c.rdr(b)
			if err != nil {
				close(res)
				return res, err
			}
			go c.identify(rdr, res)
			return res, nil
		}
	}
	// nothing ... move on
	close(res)
	return res, nil
}

type identifier struct {
	partsMatched [][]hit // hits for parts
	ruledOut     []bool  // mark additional signatures as negatively matched
	waitSet      *priority.WaitSet
	hits         []hit // shared buffer of hits used when matching
}

func (c *ContainerMatcher) newIdentifier(numParts int) *identifier {
	return &identifier{
		make([][]hit, numParts),
		make([]bool, numParts),
		c.Priorities.WaitSet(),
		make([]hit, 0, 1),
	}
}

func (c *ContainerMatcher) identify(rdr Reader, res chan core.Result) {
	// safe to call on a nil matcher (i.e. container matching switched off)
	if c == nil {
		close(res)
		return
	}
	id := c.newIdentifier(len(c.Parts))
	var err, hit error, bool
	for err = rdr.Next(); err == nil; err = rdr.Next() {
		ct, ok := c.NameCTest[rdr.Name()]
		if !ok {
			continue
		}
		// name has matched, lets test the CTests
		// ct.identify will generate a slice of hits which pass to
		// processHits which will return true if we can stop
		if c.processHits(ct.identify(c, id, rdr, rdr.Name()), id, ct, rdr.Name(), res) {
			hit = true
			break
		}
	}
	// if we have no hits and a default value for this matcher, send it
	if !hit && c.Default {
		// the default is a negative value calculated from the CType
		res <- defaultHit(-1 - int(c.CType))
	}
	close(res)
}

func (ct *CTest) identify(c *ContainerMatcher, id *identifier, rdr Reader, name string) []hit {
	// reset hits
	id.hits = id.hits[:0]
	for _, h := range ct.Satisfied {
		if id.waitSet.Check(h) {
			id.hits = append(id.hits, hit{h, name, "name only"})
		}
	}
	if ct.Unsatisfied != nil {
		buf, _ := rdr.SetSource(c.entryBufs) // NOTE: an error is ignored here.
		bmc, _ := ct.BM.Identify("", buf)
		for r := range bmc {
			h := ct.Unsatisfied[r.Index()]
			if id.waitSet.Check(h) && id.checkHits(h) {
				id.hits = append(id.hits, hit{h, name, r.Basis()})
			}
		}
		rdr.Close()
		c.entryBufs.Put(buf)
	}
	return id.hits
}

// process the hits from the ctest: adding hits to the parts matched, checking priorities
// return true if satisfied and can quit
func (c *ContainerMatcher) processHits(hits []hit, id *identifier, ct *CTest, name string, res chan core.Result) bool {
	// if there are no hits, rule out any sigs in the ctest
	if len(hits) == 0 {
		for _, v := range ct.Satisfied {
			id.ruledOut[v] = true
		}
		for _, v := range ct.Unsatisfied {
			id.ruledOut[v] = true
		}
		return false
	}
	for _, h := range hits {
		id.partsMatched[h.id] = append(id.partsMatched[h.id], h)
		if len(id.partsMatched[h.id]) == c.Parts[h.id] {
			if id.waitSet.Check(h.id) {
				idx, _ := c.Priorities.Index(h.id)
				res <- toResult(c.Sindexes[idx], id.partsMatched[h.id]) // send a Result here
				// set a priority list and return early if can
				if id.waitSet.Put(h.id) {
					return true
				}
			}
		}
	}
	// if nothing ruled out by this test, then we must continue
	if len(hits) == len(ct.Satisfied)+len(ct.Unsatisfied) {
		return false
	}
	// we can rule some possible matches out...
	for _, v := range ct.Satisfied {
		if len(id.partsMatched[v]) == 0 || id.partsMatched[v][len(id.partsMatched[v])-1].name != name {
			id.ruledOut[v] = true
		}
	}
	for _, v := range ct.Unsatisfied {
		if len(id.partsMatched[v]) == 0 || id.partsMatched[v][len(id.partsMatched[v])-1].name != name {
			id.ruledOut[v] = true
		}
	}
	// if we haven't got a waitList yet, then we should return false
	waitingOn := id.waitSet.WaitingOn()
	if waitingOn == nil {
		return false
	}
	// loop over the wait list, seeing if they are all ruled out
	for _, v := range waitingOn {
		if !id.ruledOut[v] {
			return false
		}
	}
	return true
}

// eliminate duplicate hits - must do this since rely on number of matches for each sig as test for full match
func (id *identifier) checkHits(i int) bool {
	for _, h := range id.hits {
		if i == h.id {
			return false
		}
	}
	return true
}

func toResult(i int, h []hit) result {
	if len(h) == 0 {
		return result(h)
	}
	h[0].id += i
	return result(h)
}

type result []hit

func (r result) Index() int {
	if len(r) == 0 {
		return -1
	}
	return r[0].id
}

func (r result) Basis() string {
	var basis string
	for i, v := range r {
		if i < 1 {
			basis += "container "
		} else {
			basis += "; "
		}
		basis += "name " + v.name
		if len(v.basis) > 0 {
			basis += " with " + v.basis
		}
	}
	return basis
}

type hit struct {
	id    int
	name  string
	basis string
}

type defaultHit int

func (d defaultHit) Index() int {
	return int(d)
}

func (d defaultHit) Basis() string {
	return "container match with trigger and default extension"
}
<|endoftext|>