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

package form

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"reflect"
	"strconv"
	"time"
)

// NewDecoder returns a new form decoder.
func NewDecoder(r io.Reader) *decoder {
	return &decoder{r}
}

// decoder decodes data from a form (application/x-www-form-urlencoded).
type decoder struct {
	r io.Reader
}

// Decode reads in and decodes form-encoded data into dst.
func (d decoder) Decode(dst interface{}) error {
	bs, err := ioutil.ReadAll(d.r)
	if err != nil {
		return err
	}
	vs, err := url.ParseQuery(string(bs))
	if err != nil {
		return err
	}
	v := reflect.ValueOf(dst)
	return decodeNode(v, parseValues(vs, canIndex(v)))
}

// DecodeString decodes src into dst.
func DecodeString(dst interface{}, src string) error {
	vs, err := url.ParseQuery(src)
	if err != nil {
		return err
	}
	v := reflect.ValueOf(dst)
	return decodeNode(v, parseValues(vs, canIndex(v)))
}

// DecodeValues decodes vs into dst.
func DecodeValues(dst interface{}, vs url.Values) error {
	v := reflect.ValueOf(dst)
	return decodeNode(v, parseValues(vs, canIndex(v)))
}

func decodeNode(v reflect.Value, n node) (err error) {
	/*defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("%v", e)
		}
	}()*/

	if v.Kind() == reflect.Slice {
		return fmt.Errorf("could not decode directly into slice; use pointer to slice")
	}
	decodeValue(v, n)
	return nil
}

func decodeValue(v reflect.Value, x interface{}) {
	t := v.Type()
	k := v.Kind()

	if k == reflect.Ptr && v.IsNil() {
		v.Set(reflect.New(t.Elem()))
	}

	if unmarshalValue(v, x) {
		return
	}

	switch k {
	case reflect.Ptr, reflect.Interface:
		decodeValue(v.Elem(), x)
		return
	}

	if isEmpty(x) {
		v.Set(reflect.Zero(t)) // Treat the empty string as the zero value.
		return
	}

	switch k {
	case reflect.Struct:
		if t.ConvertibleTo(timeType) {
			decodeTime(v, x)
		} else {
			decodeStruct(v, x)
		}
	case reflect.Slice:
		decodeSlice(v, x)
	case reflect.Array:
		decodeArray(v, x)
	case reflect.Map:
		decodeMap(v, x)
	case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer,
		reflect.Complex64, reflect.Complex128, reflect.Chan, reflect.Func:
		panic(t.String() + " has unsupported kind " + k.String())
	default:
		decodeBasic(v, x)
	}
}

func decodeStruct(v reflect.Value, x interface{}) {
	t := v.Type()
	for k, c := range getNode(x) {
		if f, ok := findField(v, k); !ok && k == "" {
			panic(getString(x) + " cannot be decoded as struct " + t.String())
		} else if !ok {
			panic(k + " doesn't exist in struct " + t.String())
		} else if !f.CanSet() {
			panic(k + " cannot be set in struct " + t.String())
		} else {
			decodeValue(f, c)
		}
	}
}

func decodeMap(v reflect.Value, x interface{}) {
	t := v.Type()
	if v.IsNil() {
		v.Set(reflect.MakeMap(t))
	}
	for k, c := range getNode(x) {
		i := reflect.New(t.Key()).Elem()
		decodeValue(i, k)

		w := v.MapIndex(i)
		if w.IsValid() { // We have an actual element value to decode into.
			if w.Kind() == reflect.Interface {
				w = w.Elem()
			}
			w = reflect.New(w.Type()).Elem()
		} else if t.Elem().Kind() != reflect.Interface { // The map's element type is concrete.
			w = reflect.New(t.Elem()).Elem()
		} else {
			// The best we can do here is to decode as either a string (for scalars) or a map[string]interface {} (for the rest).
			// We could try to guess the type based on the string (e.g. true/false => bool) but that'll get ugly fast,
			// especially if we have to guess the kind (slice vs. array vs. map) and index type (e.g. string, int, etc.)
			switch c.(type) {
			case node:
				w = reflect.MakeMap(stringMapType)
			case string:
				w = reflect.New(stringType).Elem()
			default:
				panic("value is neither node nor string")
			}
		}

		decodeValue(w, c)
		v.SetMapIndex(i, w)
	}
}

func decodeArray(v reflect.Value, x interface{}) {
	t := v.Type()
	for k, c := range getNode(x) {
		i, err := strconv.Atoi(k)
		if err != nil {
			panic(k + " is not a valid index for type " + t.String())
		}
		if l := v.Len(); i >= l {
			panic("index is above array size")
		}
		decodeValue(v.Index(i), c)
	}
}

func decodeSlice(v reflect.Value, x interface{}) {
	t := v.Type()
	if t.Elem().Kind() == reflect.Uint8 {
		// Allow, but don't require, byte slices to be encoded as a single string.
		if s, ok := x.(string); ok {
			v.SetBytes([]byte(s))
			return
		}
	}

	for k, c := range getNode(x) {
		i, err := strconv.Atoi(k)
		if err != nil {
			panic(k + " is not a valid index for type " + t.String())
		}
		// "Extend" the slice if it's too short.
		if l := v.Len(); i >= l {
			delta := i - l + 1
			v.Set(reflect.AppendSlice(v, reflect.MakeSlice(t, delta, delta)))
		}
		decodeValue(v.Index(i), c)
	}
}

func decodeBasic(v reflect.Value, x interface{}) {
	t := v.Type()
	switch k, s := t.Kind(), getString(x); k {
	case reflect.Bool:
		if b, e := strconv.ParseBool(s); e == nil {
			v.SetBool(b)
		} else {
			panic("could not parse bool from " + s)
		}
	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64:
		if i, e := strconv.ParseInt(s, 10, 64); e == nil {
			v.SetInt(i)
		} else {
			panic("could not parse int from " + s)
		}
	case reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64:
		if u, e := strconv.ParseUint(s, 10, 64); e == nil {
			v.SetUint(u)
		} else {
			panic("could not parse uint from " + s)
		}
	case reflect.Float32,
		reflect.Float64:
		if f, e := strconv.ParseFloat(s, 64); e == nil {
			v.SetFloat(f)
		} else {
			panic("could not parse float from " + s)
		}
	case reflect.String:
		v.SetString(s)
	default:
		panic(t.String() + " has unsupported kind " + k.String())
	}
}

func decodeTime(v reflect.Value, x interface{}) {
	t := v.Type()
	s := getString(x)
	// TODO: Find a more efficient way to do this.
	for _, f := range allowedTimeFormats {
		if p, err := time.Parse(f, s); err == nil {
			v.Set(reflect.ValueOf(p).Convert(v.Type()))
			return
		}
	}
	panic("cannot decode string `" + s + "` as " + t.String())
}

var allowedTimeFormats = []string{
	"2006-01-02T15:04:05.999999999Z07:00",
	"2006-01-02T15:04:05.999999999Z07",
	"2006-01-02T15:04:05.999999999Z",
	"2006-01-02T15:04:05.999999999",
	"2006-01-02T15:04:05Z07:00",
	"2006-01-02T15:04:05Z07",
	"2006-01-02T15:04:05Z",
	"2006-01-02T15:04:05",
	"2006-01-02T15:04Z",
	"2006-01-02T15:04",
	"2006-01-02T15Z",
	"2006-01-02T15",
	"2006-01-02",
	"2006-01",
	"2006",
	"15:04:05.999999999Z07:00",
	"15:04:05.999999999Z07",
	"15:04:05.999999999Z",
	"15:04:05.999999999",
	"15:04:05Z07:00",
	"15:04:05Z07",
	"15:04:05Z",
	"15:04:05",
	"15:04Z",
	"15:04",
	"15Z",
	"15",
}
<commit_msg>Re-enable top-level panic handler<commit_after>// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package form

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"reflect"
	"strconv"
	"time"
)

// NewDecoder returns a new form decoder.
func NewDecoder(r io.Reader) *decoder {
	return &decoder{r}
}

// decoder decodes data from a form (application/x-www-form-urlencoded).
type decoder struct {
	r io.Reader
}

// Decode reads in and decodes form-encoded data into dst.
func (d decoder) Decode(dst interface{}) error {
	bs, err := ioutil.ReadAll(d.r)
	if err != nil {
		return err
	}
	vs, err := url.ParseQuery(string(bs))
	if err != nil {
		return err
	}
	v := reflect.ValueOf(dst)
	return decodeNode(v, parseValues(vs, canIndex(v)))
}

// DecodeString decodes src into dst.
func DecodeString(dst interface{}, src string) error {
	vs, err := url.ParseQuery(src)
	if err != nil {
		return err
	}
	v := reflect.ValueOf(dst)
	return decodeNode(v, parseValues(vs, canIndex(v)))
}

// DecodeValues decodes vs into dst.
func DecodeValues(dst interface{}, vs url.Values) error {
	v := reflect.ValueOf(dst)
	return decodeNode(v, parseValues(vs, canIndex(v)))
}

func decodeNode(v reflect.Value, n node) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("%v", e)
		}
	}()

	if v.Kind() == reflect.Slice {
		return fmt.Errorf("could not decode directly into slice; use pointer to slice")
	}
	decodeValue(v, n)
	return nil
}

func decodeValue(v reflect.Value, x interface{}) {
	t := v.Type()
	k := v.Kind()

	if k == reflect.Ptr && v.IsNil() {
		v.Set(reflect.New(t.Elem()))
	}

	if unmarshalValue(v, x) {
		return
	}

	switch k {
	case reflect.Ptr, reflect.Interface:
		decodeValue(v.Elem(), x)
		return
	}

	if isEmpty(x) {
		v.Set(reflect.Zero(t)) // Treat the empty string as the zero value.
		return
	}

	switch k {
	case reflect.Struct:
		if t.ConvertibleTo(timeType) {
			decodeTime(v, x)
		} else {
			decodeStruct(v, x)
		}
	case reflect.Slice:
		decodeSlice(v, x)
	case reflect.Array:
		decodeArray(v, x)
	case reflect.Map:
		decodeMap(v, x)
	case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer,
		reflect.Complex64, reflect.Complex128, reflect.Chan, reflect.Func:
		panic(t.String() + " has unsupported kind " + k.String())
	default:
		decodeBasic(v, x)
	}
}

func decodeStruct(v reflect.Value, x interface{}) {
	t := v.Type()
	for k, c := range getNode(x) {
		if f, ok := findField(v, k); !ok && k == "" {
			panic(getString(x) + " cannot be decoded as struct " + t.String())
		} else if !ok {
			panic(k + " doesn't exist in struct " + t.String())
		} else if !f.CanSet() {
			panic(k + " cannot be set in struct " + t.String())
		} else {
			decodeValue(f, c)
		}
	}
}

func decodeMap(v reflect.Value, x interface{}) {
	t := v.Type()
	if v.IsNil() {
		v.Set(reflect.MakeMap(t))
	}
	for k, c := range getNode(x) {
		i := reflect.New(t.Key()).Elem()
		decodeValue(i, k)

		w := v.MapIndex(i)
		if w.IsValid() { // We have an actual element value to decode into.
			if w.Kind() == reflect.Interface {
				w = w.Elem()
			}
			w = reflect.New(w.Type()).Elem()
		} else if t.Elem().Kind() != reflect.Interface { // The map's element type is concrete.
			w = reflect.New(t.Elem()).Elem()
		} else {
			// The best we can do here is to decode as either a string (for scalars) or a map[string]interface {} (for the rest).
			// We could try to guess the type based on the string (e.g. true/false => bool) but that'll get ugly fast,
			// especially if we have to guess the kind (slice vs. array vs. map) and index type (e.g. string, int, etc.)
			switch c.(type) {
			case node:
				w = reflect.MakeMap(stringMapType)
			case string:
				w = reflect.New(stringType).Elem()
			default:
				panic("value is neither node nor string")
			}
		}

		decodeValue(w, c)
		v.SetMapIndex(i, w)
	}
}

func decodeArray(v reflect.Value, x interface{}) {
	t := v.Type()
	for k, c := range getNode(x) {
		i, err := strconv.Atoi(k)
		if err != nil {
			panic(k + " is not a valid index for type " + t.String())
		}
		if l := v.Len(); i >= l {
			panic("index is above array size")
		}
		decodeValue(v.Index(i), c)
	}
}

func decodeSlice(v reflect.Value, x interface{}) {
	t := v.Type()
	if t.Elem().Kind() == reflect.Uint8 {
		// Allow, but don't require, byte slices to be encoded as a single string.
		if s, ok := x.(string); ok {
			v.SetBytes([]byte(s))
			return
		}
	}

	for k, c := range getNode(x) {
		i, err := strconv.Atoi(k)
		if err != nil {
			panic(k + " is not a valid index for type " + t.String())
		}
		// "Extend" the slice if it's too short.
		if l := v.Len(); i >= l {
			delta := i - l + 1
			v.Set(reflect.AppendSlice(v, reflect.MakeSlice(t, delta, delta)))
		}
		decodeValue(v.Index(i), c)
	}
}

func decodeBasic(v reflect.Value, x interface{}) {
	t := v.Type()
	switch k, s := t.Kind(), getString(x); k {
	case reflect.Bool:
		if b, e := strconv.ParseBool(s); e == nil {
			v.SetBool(b)
		} else {
			panic("could not parse bool from " + s)
		}
	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64:
		if i, e := strconv.ParseInt(s, 10, 64); e == nil {
			v.SetInt(i)
		} else {
			panic("could not parse int from " + s)
		}
	case reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64:
		if u, e := strconv.ParseUint(s, 10, 64); e == nil {
			v.SetUint(u)
		} else {
			panic("could not parse uint from " + s)
		}
	case reflect.Float32,
		reflect.Float64:
		if f, e := strconv.ParseFloat(s, 64); e == nil {
			v.SetFloat(f)
		} else {
			panic("could not parse float from " + s)
		}
	case reflect.String:
		v.SetString(s)
	default:
		panic(t.String() + " has unsupported kind " + k.String())
	}
}

func decodeTime(v reflect.Value, x interface{}) {
	t := v.Type()
	s := getString(x)
	// TODO: Find a more efficient way to do this.
	for _, f := range allowedTimeFormats {
		if p, err := time.Parse(f, s); err == nil {
			v.Set(reflect.ValueOf(p).Convert(v.Type()))
			return
		}
	}
	panic("cannot decode string `" + s + "` as " + t.String())
}

var allowedTimeFormats = []string{
	"2006-01-02T15:04:05.999999999Z07:00",
	"2006-01-02T15:04:05.999999999Z07",
	"2006-01-02T15:04:05.999999999Z",
	"2006-01-02T15:04:05.999999999",
	"2006-01-02T15:04:05Z07:00",
	"2006-01-02T15:04:05Z07",
	"2006-01-02T15:04:05Z",
	"2006-01-02T15:04:05",
	"2006-01-02T15:04Z",
	"2006-01-02T15:04",
	"2006-01-02T15Z",
	"2006-01-02T15",
	"2006-01-02",
	"2006-01",
	"2006",
	"15:04:05.999999999Z07:00",
	"15:04:05.999999999Z07",
	"15:04:05.999999999Z",
	"15:04:05.999999999",
	"15:04:05Z07:00",
	"15:04:05Z07",
	"15:04:05Z",
	"15:04:05",
	"15:04Z",
	"15:04",
	"15Z",
	"15",
}
<|endoftext|>


<commit_before>package zog

import "fmt"

func Decode(inCh chan byte) (chan instruction, chan error) {
	errCh := make(chan error)
	iCh := make(chan instruction)
	go decode(inCh, iCh, errCh)
	return iCh, errCh
}

func DecodeBytes(buf []byte) ([]instruction, error) {

	ch := make(chan byte)

	go func() {
		for _, n := range buf {
			ch <- n
		}
		close(ch)
	}()

	var insts []instruction
	var err error
	var ok bool

	instCh, errCh := Decode(ch)
	looping := true
	for looping {
		select {
		case inst, ok := <-instCh:
			if !ok {
				looping = false
				break
			}
			insts = append(insts, inst)
		case err, ok = <-errCh:
			if !ok {
				looping = false
				break
			}
			break
		}
	}

	return insts, err
}

func getImmd(inCh chan byte) (Disp, error) {
	d, ok := <-inCh
	if !ok {
		return 0, fmt.Errorf("getImmd: Can't get byte")
	}
	return Disp(d), nil
}
func getImmN(inCh chan byte) (Imm8, error) {
	n, ok := <-inCh
	if !ok {
		return 0, fmt.Errorf("getImmN: Can't get byte")
	}
	return Imm8(n), nil
}

func getImmNN(inCh chan byte) (Imm16, error) {
	l, ok := <-inCh
	if !ok {
		return 0, fmt.Errorf("getImmNN: Can't get lo byte")
	}
	h, ok := <-inCh
	if !ok {
		return 0, fmt.Errorf("getImmNN: Can't get hi byte")
	}
	return Imm16(uint16(h)<<8 | uint16(l)), nil
}

func decode(inCh chan byte, iCh chan instruction, errCh chan error) {

	// Set to 0 if no prefix in effect
	var opPrefix byte
	var indexPrefix byte

	t := NewTable(inCh)

	for n := range inCh {

		if opPrefix == 0 {
			switch n {
			case 0xcb, 0xed:
				opPrefix = n
				continue
			case 0xdd, 0xfd:
				// Last one wins
				indexPrefix = n
				continue
			}
		}

		t.ResetPrefix(indexPrefix)

		var inst instruction
		var err error

		switch opPrefix {
		case 0:
			inst, err = baseDecode(t, inCh, indexPrefix, n)
		case 0xcb:
			inst, err = cbDecode(t, inCh, indexPrefix, n)
		case 0xed:
			inst, err = edDecode(t, inCh, indexPrefix, n)
		}

		fmt.Printf("D: inst [%v] err [%v]\n", inst, err)

		if inst == nil {
			if err == nil {
				err = fmt.Errorf("TODO - impl %02X [%02X] (%02X)", n, opPrefix, indexPrefix)
			}
			errCh <- err
		} else {
			iCh <- inst
		}

		opPrefix = 0
		indexPrefix = 0
	}
	close(iCh)
	close(errCh)
}

func cbDecode(t *Table, inCh chan byte, indexPrefix, n byte) (instruction, error) {
	var err error
	var inst instruction

	x, y, z, p, q := decomposeByte(n)
	fmt.Printf("D: N %02X, x %d y %d z %d p %d q %d\n", n, x, y, z, p, q)

	switch x {
	case 0:
		info := tableROT[y]
		inst = &ROT{name: info.name /* f: info.f, */, r: t.LookupR(z)}
	case 1:
		inst = &BIT{y, t.LookupR(z)}
	case 2:
		inst = &RES{y, t.LookupR(z)}
	case 3:
		inst = &SET{y, t.LookupR(z)}
	}

	return inst, err
}

func edDecode(t *Table, inCh chan byte, indexPrefix, n byte) (instruction, error) {
	panic("TODO - impl ed")
}

func baseDecode(t *Table, inCh chan byte, indexPrefix, n byte) (instruction, error) {
	var err error
	var inst instruction

	// We lookup this to get (HL)
	//	hlci := byte(6)
	hl := HL
	if indexPrefix == 0xDD {
		hl = IX
	} else if indexPrefix == 0xFD {
		hl = IY
	}

	x, y, z, p, q := decomposeByte(n)
	fmt.Printf("D: N %02X, x %d y %d z %d p %d q %d\n", n, x, y, z, p, q)

	switch x {
	case 0:
		switch z {
		case 0:
			switch y {
			case 0:
				inst = NOP
			case 1:
				inst = &EX{AF, AF_PRIME}
			case 2:
				d, err := getImmd(inCh)
				if err == nil {
					inst = &DJNZ{d}
				}
			case 3:
				d, err := getImmd(inCh)
				if err == nil {
					inst = &JR{True, d}
				}
			case 4, 5, 6, 7:
				d, err := getImmd(inCh)
				if err == nil {
					inst = &JR{tableCC[y-4], d}
				}
			}
		case 1:
			if q == 0 {
				nn, err := getImmNN(inCh)
				if err == nil {
					inst = &LD16{t.LookupRP(p), nn}
				}
			} else {
				inst = &ADD16{hl, t.LookupRP(p)}
			}
		case 2:
			if q == 0 {
				switch p {
				case 0:
					inst = &LD8{Contents{BC}, A}
				case 1:
					inst = &LD8{Contents{DE}, A}
				case 2:
					nn, err := getImmNN(inCh)
					if err == nil {
						inst = &LD16{Contents{nn}, hl}
					}
				case 3:
					nn, err := getImmNN(inCh)
					if err == nil {
						inst = &LD8{Contents{nn}, A}
					}
				}
			} else {
				switch p {
				case 0:
					inst = &LD8{A, Contents{BC}}
				case 1:
					inst = &LD8{A, Contents{DE}}
				case 2:
					nn, err := getImmNN(inCh)
					if err == nil {
						inst = &LD16{hl, Contents{nn}}
					}
				case 3:
					nn, err := getImmNN(inCh)
					if err == nil {
						inst = &LD8{A, Contents{nn}}
					}
				}
			}
		case 3:
			if q == 0 {
				inst = &INC16{t.LookupRP(p)}
			} else {
				inst = &DEC16{t.LookupRP(p)}
			}
		case 4:
			inst = &INC8{t.LookupR(y)}
		case 5:
			inst = &DEC8{t.LookupR(y)}
		case 6:
			// Lookup before immmediate, so we handle IX/IY index before immediate N
			r := t.LookupR(y)
			n, err := getImmN(inCh)
			if err == nil {
				inst = &LD8{r, n}
			}
		case 7:
			switch y {
			case 0:
				inst = RLCA
			case 1:
				inst = RRCA
			case 2:
				inst = RLA
			case 3:
				inst = RRA
			case 4:
				inst = DAA
			case 5:
				inst = CPL
			case 6:
				inst = SCF
			case 7:
				inst = CCF
			}
		}
	case 1:
		if z == 6 && y == 6 {
			inst = HALT
		} else {
			// Annoying prefix case, if we have (IX+d), we *don't* index-replace
			// H or L
			dst := t.LookupR(y)
			src := t.LookupR(z)
			t.ResetPrefix(0x00)
			if _, ok := dst.(IndexedContents); ok {
				src = t.LookupR(z)
			}
			if _, ok := src.(IndexedContents); ok {
				dst = t.LookupR(y)
			}
			inst = &LD8{dst, src}
		}
	case 2:
		info := tableALU[y]
		inst = &Accum{name: info.name /* f: info.f, */, src: t.LookupR(z)}
	case 3:
		switch z {
		case 0:
			inst = &RET{tableCC[y]}
		case 1:
			if q == 0 {
				inst = &POP{t.LookupRP2(p)}
			} else {
				switch p {
				case 0:
					inst = &RET{True}
				case 1:
					inst = EXX
				case 2:
					inst = &JP{True, hl}
				case 3:
					inst = &LD16{SP, hl}
				}
			}
		case 2:
			nn, err := getImmNN(inCh)
			if err == nil {
				inst = &JP{tableCC[y], nn}
			}
		case 3:
			switch y {
			case 0:
				nn, err := getImmNN(inCh)
				if err == nil {
					inst = &JP{True, nn}
				}
			case 1:
				panic(fmt.Sprintf("Decoding CB [%02X] as instruction, not prefix", n))
			case 2:
				n, err := getImmN(inCh)
				if err == nil {
					inst = &OUT{n, A}
				}
			case 3:
				n, err := getImmN(inCh)
				if err == nil {
					inst = &IN{A, n}
				}
			case 4:
				inst = &EX{Contents{SP}, hl}
			case 5:
				// We use real HL for this, it is an exception
				inst = &EX{DE, HL}
			case 6:
				inst = DI
			case 7:
				inst = EI
			}
		case 4:
			nn, err := getImmNN(inCh)
			if err == nil {
				inst = &CALL{tableCC[y], nn}
			}
		case 5:
			if q == 0 {
				inst = &PUSH{t.LookupRP2(p)}
			} else {
				switch p {
				case 0:
					nn, err := getImmNN(inCh)
					if err == nil {
						inst = &CALL{True, nn}
					}
				case 1:
					panic(fmt.Sprintf("Decoding DD [%02X] as instruction, not prefix", n))
				case 2:
					panic(fmt.Sprintf("Decoding ED [%02X] as instruction, not prefix", n))
				case 3:
					panic(fmt.Sprintf("Decoding FD [%02X] as instruction, not prefix", n))
				}
			}
		case 6:
			n, err := getImmN(inCh)
			if err == nil {
				info := tableALU[y]
				inst = &Accum{name: info.name /* f: info.f, */, src: n}
			}
		case 7:
			inst = &RST{y * 8}
		}
	}

	return inst, err
}

func decomposeByte(n byte) (byte, byte, byte, byte, byte) {
	// We follow terminology from http://www.z80.info/decoding.htm
	// x = the opcode's 1st octal digit (i.e. bits 7-6)
	// y = the opcode's 2nd octal digit (i.e. bits 5-3)
	// z = the opcode's 3rd octal digit (i.e. bits 2-0)
	// p = y rightshifted one position (i.e. bits 5-4)
	// q = y modulo 2 (i.e. bit 3)
	z := n & 0x07
	y := (n >> 3) & 0x07
	x := (n >> 6) & 0x07
	p := y >> 1
	q := y & 0x01

	return x, y, z, p, q
}
<commit_msg>show byte decomposition for unimpl ED<commit_after>package zog

import "fmt"

func Decode(inCh chan byte) (chan instruction, chan error) {
	errCh := make(chan error)
	iCh := make(chan instruction)
	go decode(inCh, iCh, errCh)
	return iCh, errCh
}

func DecodeBytes(buf []byte) ([]instruction, error) {

	ch := make(chan byte)

	go func() {
		for _, n := range buf {
			ch <- n
		}
		close(ch)
	}()

	var insts []instruction
	var err error
	var ok bool

	instCh, errCh := Decode(ch)
	looping := true
	for looping {
		select {
		case inst, ok := <-instCh:
			if !ok {
				looping = false
				break
			}
			insts = append(insts, inst)
		case err, ok = <-errCh:
			if !ok {
				looping = false
				break
			}
			break
		}
	}

	return insts, err
}

func getImmd(inCh chan byte) (Disp, error) {
	d, ok := <-inCh
	if !ok {
		return 0, fmt.Errorf("getImmd: Can't get byte")
	}
	return Disp(d), nil
}
func getImmN(inCh chan byte) (Imm8, error) {
	n, ok := <-inCh
	if !ok {
		return 0, fmt.Errorf("getImmN: Can't get byte")
	}
	return Imm8(n), nil
}

func getImmNN(inCh chan byte) (Imm16, error) {
	l, ok := <-inCh
	if !ok {
		return 0, fmt.Errorf("getImmNN: Can't get lo byte")
	}
	h, ok := <-inCh
	if !ok {
		return 0, fmt.Errorf("getImmNN: Can't get hi byte")
	}
	return Imm16(uint16(h)<<8 | uint16(l)), nil
}

func decode(inCh chan byte, iCh chan instruction, errCh chan error) {

	// Set to 0 if no prefix in effect
	var opPrefix byte
	var indexPrefix byte

	t := NewTable(inCh)

	for n := range inCh {

		if opPrefix == 0 {
			switch n {
			case 0xcb, 0xed:
				opPrefix = n
				continue
			case 0xdd, 0xfd:
				// Last one wins
				indexPrefix = n
				continue
			}
		}

		t.ResetPrefix(indexPrefix)

		var inst instruction
		var err error

		switch opPrefix {
		case 0:
			inst, err = baseDecode(t, inCh, indexPrefix, n)
		case 0xcb:
			inst, err = cbDecode(t, inCh, indexPrefix, n)
		case 0xed:
			inst, err = edDecode(t, inCh, indexPrefix, n)
		}

		fmt.Printf("D: inst [%v] err [%v]\n", inst, err)

		if inst == nil {
			if err == nil {
				err = fmt.Errorf("TODO - impl %02X [%02X] (%02X)", n, opPrefix, indexPrefix)
			}
			errCh <- err
		} else {
			iCh <- inst
		}

		opPrefix = 0
		indexPrefix = 0
	}
	close(iCh)
	close(errCh)
}

func cbDecode(t *Table, inCh chan byte, indexPrefix, n byte) (instruction, error) {
	var err error
	var inst instruction

	x, y, z, p, q := decomposeByte(n)
	fmt.Printf("D: N %02X, x %d y %d z %d p %d q %d\n", n, x, y, z, p, q)

	switch x {
	case 0:
		info := tableROT[y]
		inst = &ROT{name: info.name /* f: info.f, */, r: t.LookupR(z)}
	case 1:
		inst = &BIT{y, t.LookupR(z)}
	case 2:
		inst = &RES{y, t.LookupR(z)}
	case 3:
		inst = &SET{y, t.LookupR(z)}
	}

	return inst, err
}

func edDecode(t *Table, inCh chan byte, indexPrefix, n byte) (instruction, error) {
	var err error
	var inst instruction

	x, y, z, p, q := decomposeByte(n)
	fmt.Printf("D: N %02X, x %d y %d z %d p %d q %d\n", n, x, y, z, p, q)

	panic("TODO -impl")
	return inst, err
}

func baseDecode(t *Table, inCh chan byte, indexPrefix, n byte) (instruction, error) {
	var err error
	var inst instruction

	// We lookup this to get (HL)
	//	hlci := byte(6)
	hl := HL
	if indexPrefix == 0xDD {
		hl = IX
	} else if indexPrefix == 0xFD {
		hl = IY
	}

	x, y, z, p, q := decomposeByte(n)
	fmt.Printf("D: N %02X, x %d y %d z %d p %d q %d\n", n, x, y, z, p, q)

	switch x {
	case 0:
		switch z {
		case 0:
			switch y {
			case 0:
				inst = NOP
			case 1:
				inst = &EX{AF, AF_PRIME}
			case 2:
				d, err := getImmd(inCh)
				if err == nil {
					inst = &DJNZ{d}
				}
			case 3:
				d, err := getImmd(inCh)
				if err == nil {
					inst = &JR{True, d}
				}
			case 4, 5, 6, 7:
				d, err := getImmd(inCh)
				if err == nil {
					inst = &JR{tableCC[y-4], d}
				}
			}
		case 1:
			if q == 0 {
				nn, err := getImmNN(inCh)
				if err == nil {
					inst = &LD16{t.LookupRP(p), nn}
				}
			} else {
				inst = &ADD16{hl, t.LookupRP(p)}
			}
		case 2:
			if q == 0 {
				switch p {
				case 0:
					inst = &LD8{Contents{BC}, A}
				case 1:
					inst = &LD8{Contents{DE}, A}
				case 2:
					nn, err := getImmNN(inCh)
					if err == nil {
						inst = &LD16{Contents{nn}, hl}
					}
				case 3:
					nn, err := getImmNN(inCh)
					if err == nil {
						inst = &LD8{Contents{nn}, A}
					}
				}
			} else {
				switch p {
				case 0:
					inst = &LD8{A, Contents{BC}}
				case 1:
					inst = &LD8{A, Contents{DE}}
				case 2:
					nn, err := getImmNN(inCh)
					if err == nil {
						inst = &LD16{hl, Contents{nn}}
					}
				case 3:
					nn, err := getImmNN(inCh)
					if err == nil {
						inst = &LD8{A, Contents{nn}}
					}
				}
			}
		case 3:
			if q == 0 {
				inst = &INC16{t.LookupRP(p)}
			} else {
				inst = &DEC16{t.LookupRP(p)}
			}
		case 4:
			inst = &INC8{t.LookupR(y)}
		case 5:
			inst = &DEC8{t.LookupR(y)}
		case 6:
			// Lookup before immmediate, so we handle IX/IY index before immediate N
			r := t.LookupR(y)
			n, err := getImmN(inCh)
			if err == nil {
				inst = &LD8{r, n}
			}
		case 7:
			switch y {
			case 0:
				inst = RLCA
			case 1:
				inst = RRCA
			case 2:
				inst = RLA
			case 3:
				inst = RRA
			case 4:
				inst = DAA
			case 5:
				inst = CPL
			case 6:
				inst = SCF
			case 7:
				inst = CCF
			}
		}
	case 1:
		if z == 6 && y == 6 {
			inst = HALT
		} else {
			// Annoying prefix case, if we have (IX+d), we *don't* index-replace
			// H or L
			dst := t.LookupR(y)
			src := t.LookupR(z)
			t.ResetPrefix(0x00)
			if _, ok := dst.(IndexedContents); ok {
				src = t.LookupR(z)
			}
			if _, ok := src.(IndexedContents); ok {
				dst = t.LookupR(y)
			}
			inst = &LD8{dst, src}
		}
	case 2:
		info := tableALU[y]
		inst = &Accum{name: info.name /* f: info.f, */, src: t.LookupR(z)}
	case 3:
		switch z {
		case 0:
			inst = &RET{tableCC[y]}
		case 1:
			if q == 0 {
				inst = &POP{t.LookupRP2(p)}
			} else {
				switch p {
				case 0:
					inst = &RET{True}
				case 1:
					inst = EXX
				case 2:
					inst = &JP{True, hl}
				case 3:
					inst = &LD16{SP, hl}
				}
			}
		case 2:
			nn, err := getImmNN(inCh)
			if err == nil {
				inst = &JP{tableCC[y], nn}
			}
		case 3:
			switch y {
			case 0:
				nn, err := getImmNN(inCh)
				if err == nil {
					inst = &JP{True, nn}
				}
			case 1:
				panic(fmt.Sprintf("Decoding CB [%02X] as instruction, not prefix", n))
			case 2:
				n, err := getImmN(inCh)
				if err == nil {
					inst = &OUT{n, A}
				}
			case 3:
				n, err := getImmN(inCh)
				if err == nil {
					inst = &IN{A, n}
				}
			case 4:
				inst = &EX{Contents{SP}, hl}
			case 5:
				// We use real HL for this, it is an exception
				inst = &EX{DE, HL}
			case 6:
				inst = DI
			case 7:
				inst = EI
			}
		case 4:
			nn, err := getImmNN(inCh)
			if err == nil {
				inst = &CALL{tableCC[y], nn}
			}
		case 5:
			if q == 0 {
				inst = &PUSH{t.LookupRP2(p)}
			} else {
				switch p {
				case 0:
					nn, err := getImmNN(inCh)
					if err == nil {
						inst = &CALL{True, nn}
					}
				case 1:
					panic(fmt.Sprintf("Decoding DD [%02X] as instruction, not prefix", n))
				case 2:
					panic(fmt.Sprintf("Decoding ED [%02X] as instruction, not prefix", n))
				case 3:
					panic(fmt.Sprintf("Decoding FD [%02X] as instruction, not prefix", n))
				}
			}
		case 6:
			n, err := getImmN(inCh)
			if err == nil {
				info := tableALU[y]
				inst = &Accum{name: info.name /* f: info.f, */, src: n}
			}
		case 7:
			inst = &RST{y * 8}
		}
	}

	return inst, err
}

func decomposeByte(n byte) (byte, byte, byte, byte, byte) {
	// We follow terminology from http://www.z80.info/decoding.htm
	// x = the opcode's 1st octal digit (i.e. bits 7-6)
	// y = the opcode's 2nd octal digit (i.e. bits 5-3)
	// z = the opcode's 3rd octal digit (i.e. bits 2-0)
	// p = y rightshifted one position (i.e. bits 5-4)
	// q = y modulo 2 (i.e. bit 3)
	z := n & 0x07
	y := (n >> 3) & 0x07
	x := (n >> 6) & 0x07
	p := y >> 1
	q := y & 0x01

	return x, y, z, p, q
}
<|endoftext|>


<commit_before>package dejavu

import (
	"crypto/sha256"
	"github.com/AndreasBriese/bbloom"
	"sync"
)

// DejaVu witnesses data and recalls if seen before.
type DejaVu interface {

	// Witness data and add to memory. Returns true if previously seen.
	Witness(data []byte) bool

	// WitnessDigest is equivalent to the Winness method but bypasses hashing
	// the data. Use this to improve performance if you already happen
	// to have the sha256 digest.
	WitnessDigest(digest [sha256.Size]byte) bool
}

//////////////////////////////////
// DETERMINISTIC IMPLEMENTATION //
//////////////////////////////////

type deterministic struct {
	buffer [][sha256.Size]byte       // ring buffer
	size   int                       // ring buffer size
	index  int                       // current ring buffer index
	lookup map[[sha256.Size]byte]int // digest -> newest index (optimization)
	mutex  *sync.Mutex
}

// NewDeterministic creates a deterministic DejaVu memory. Will remember
// most recent entries within given entrie limit and forget older entries.
func NewDeterministic(entrieLimit uint32) DejaVu {
	return &deterministic{
		buffer: make([][sha256.Size]byte, entrieLimit),
		size:   int(entrieLimit),
		index:  0,
		lookup: make(map[[sha256.Size]byte]int),
		mutex:  new(sync.Mutex),
	}
}

func (d *deterministic) WitnessDigest(digest [sha256.Size]byte) bool {
	d.mutex.Lock()

	_, familiar := d.lookup[digest] // check if previously seen

	// rm oldest lookup key if no newer entry
	maxed := len(d.buffer) == d.size // overwriting oldest entry
	if maxed && (d.lookup[d.buffer[d.index]] == d.index) {
		delete(d.lookup, d.buffer[d.index]) // no newer entries
	}

	// add entry and update index/lookup
	d.buffer[d.index] = digest
	d.lookup[digest] = d.index
	d.index = (d.index + 1) % d.size

	d.mutex.Unlock()
	return familiar
}

func (d *deterministic) Witness(data []byte) bool {
	return d.WitnessDigest(sha256.Sum256(data))
}

//////////////////////////////////
// PROBABILISTIC IMPLEMENTATION //
//////////////////////////////////

type probabilistic struct {
	filters            [2]*bbloom.Bloom // alternatingly replaced when maxed
	entrieLimit        uint32           // filter size
	falsePositiveRatio float64          // remember for buffer switch
	index              int              // current filter index
	entries            uint32           // entries in currently indexed filter
	mutex              *sync.Mutex
}

// NewProbabilistic creates a probabilistic DejaVu memory. Probably remembers
// most recent entries within given entrie limit and false positive ratio.
// False positive ratio should be between 0.0 and 1.0.
func NewProbabilistic(entrieLimit uint32, falsePositiveRatio float64) DejaVu {
	a := bbloom.New(float64(entrieLimit), falsePositiveRatio)
	b := bbloom.New(float64(entrieLimit), falsePositiveRatio)
	return &probabilistic{
		filters:            [2]*bbloom.Bloom{&a, &b},
		entrieLimit:        entrieLimit,
		falsePositiveRatio: falsePositiveRatio,
		index:              0,
		entries:            0,
		mutex:              new(sync.Mutex),
	}
}

func (p *probabilistic) WitnessDigest(digest [sha256.Size]byte) bool {
	p.mutex.Lock()

	// check if exists
	d := digest[:]
	familiar := p.filters[0].Has(d) || p.filters[1].Has(d)

	// always add in case its from the old buffer
	p.filters[p.index].AddIfNotHas(d)
	p.entries++

	// switch buffers if current is maxed
	if p.entries >= p.entrieLimit {
		p.entries = 0
		p.index = (p.index + 1) % 2
		f := bbloom.New(float64(p.entrieLimit), p.falsePositiveRatio)
		p.filters[p.index] = &f // replace old filter
	}

	p.mutex.Unlock()
	return familiar
}

func (p *probabilistic) Witness(data []byte) bool {
	return p.WitnessDigest(sha256.Sum256(data))
}
<commit_msg>replaced bloom filter lib with better maintained version by willf<commit_after>package dejavu

import (
	"crypto/sha256"
	"github.com/willf/bloom"
	"sync"
)

// DejaVu witnesses data and recalls if seen before.
type DejaVu interface {

	// Witness data and add to memory. Returns true if previously seen.
	Witness(data []byte) bool

	// WitnessDigest is equivalent to the Winness method but bypasses hashing
	// the data. Use this to improve performance if you already happen
	// to have the sha256 digest.
	WitnessDigest(digest [sha256.Size]byte) bool
}

//////////////////////////////////
// DETERMINISTIC IMPLEMENTATION //
//////////////////////////////////

type deterministic struct {
	buffer [][sha256.Size]byte       // ring buffer
	size   int                       // ring buffer size
	index  int                       // current ring buffer index
	lookup map[[sha256.Size]byte]int // digest -> newest index (optimization)
	mutex  *sync.Mutex
}

// NewDeterministic creates a deterministic DejaVu memory. Will remember
// most recent entries within given entrie limit and forget older entries.
func NewDeterministic(entrieLimit uint32) DejaVu {
	return &deterministic{
		buffer: make([][sha256.Size]byte, entrieLimit),
		size:   int(entrieLimit),
		index:  0,
		lookup: make(map[[sha256.Size]byte]int),
		mutex:  new(sync.Mutex),
	}
}

func (d *deterministic) WitnessDigest(digest [sha256.Size]byte) bool {
	d.mutex.Lock()

	_, familiar := d.lookup[digest] // check if previously seen

	// rm oldest lookup key if no newer entry
	maxed := len(d.buffer) == d.size // overwriting oldest entry
	if maxed && (d.lookup[d.buffer[d.index]] == d.index) {
		delete(d.lookup, d.buffer[d.index]) // no newer entries
	}

	// add entry and update index/lookup
	d.buffer[d.index] = digest
	d.lookup[digest] = d.index
	d.index = (d.index + 1) % d.size

	d.mutex.Unlock()
	return familiar
}

func (d *deterministic) Witness(data []byte) bool {
	return d.WitnessDigest(sha256.Sum256(data))
}

//////////////////////////////////
// PROBABILISTIC IMPLEMENTATION //
//////////////////////////////////

type probabilistic struct {
	filters            [2]*bloom.BloomFilter // alternatingly replaced when maxed
	entrieLimit        uint32                // filter size
	falsePositiveRatio float64               // remember for buffer switch
	index              int                   // current filter index
	entries            uint32                // entries in currently indexed filter
	mutex              *sync.Mutex
}

// NewProbabilistic creates a probabilistic DejaVu memory. Probably remembers
// most recent entries within given entrie limit and false positive ratio.
// False positive ratio should be between 0.0 and 1.0.
func NewProbabilistic(entrieLimit uint32, falsePositiveRatio float64) DejaVu {
	a := bloom.NewWithEstimates(uint(entrieLimit), falsePositiveRatio)
	b := bloom.NewWithEstimates(uint(entrieLimit), falsePositiveRatio)
	return &probabilistic{
		filters:            [2]*bloom.BloomFilter{a, b},
		entrieLimit:        entrieLimit,
		falsePositiveRatio: falsePositiveRatio,
		index:              0,
		entries:            0,
		mutex:              new(sync.Mutex),
	}
}

func (p *probabilistic) WitnessDigest(digest [sha256.Size]byte) bool {
	p.mutex.Lock()

	// check if exists
	d := digest[:]
	familiar := p.filters[0].Test(d) || p.filters[1].Test(d)

	// always add in case its from the old buffer
	p.filters[p.index].Add(d)
	p.entries++

	// switch buffers if current is maxed
	if p.entries >= p.entrieLimit {
		p.entries = 0
		p.index = (p.index + 1) % 2
		f := bloom.NewWithEstimates(uint(p.entrieLimit), p.falsePositiveRatio)
		p.filters[p.index] = f // replace old filter
	}

	p.mutex.Unlock()
	return familiar
}

func (p *probabilistic) Witness(data []byte) bool {
	return p.WitnessDigest(sha256.Sum256(data))
}
<|endoftext|>


<commit_before><commit_msg>git buggy and broken... blanked the file; restoring<commit_after>package frame

import (
	_ "github.com/as/etch"
	"image"
)

func (f *Frame) Delete(p0, p1 int64) int {

	if p0 >= f.Nchars || p0 == p1 || f.b == nil {
		return 0
	}

	if p1 > f.Nchars {
		p1 = f.Nchars
	}
	if f.p0 == f.p1 {
		f.tickat(f.PointOf(int64(f.p0)), false)
	}
	n0 := f.Find(0, 0, p0)
	nn0 := n0
	n1 := f.Find(n0, p0, p1)
	pt0 := f.ptOfCharNBox(p0, n0)
	ppt0 := pt0
	pt1 := f.PointOf(p1)
	f.Free(n0, n1-1)
	f.modified = true

	// Advance forward, copying the first un-deleted box
	// on the right all the way to the left, splitting them
	// when necessary to fit on a wrapped line. A bit of draw
	// computation is saved by keeping track of the selection
	// and interpolating its drawing routine into the same
	// loop.
	//
	// Might have to rethink this when adding support for
	// multiple selections.
	//
	// pt0/pt1: deletion start/stop
	// n0/n1: deleted box/first surviving box
	// cn1: char index of the surviving box

	cn1 := int64(p1)
	pt0, pt1, n0, n1, cn1 = f.delete(pt0, pt1, n0, n1, cn1)

	if n1 == f.Nbox && pt0.X != pt1.X {
		f.Paint(pt0, pt1, f.Color.Back)
	}

	// Delete more than a line. All the boxes have been shifted
	// but the bitmap might still have a copy of them down below
	if pt1.Y != pt0.Y {
		pt0, pt1, n1 = f.fixTrailer(pt0, pt1, n1)
	}

	f.Run.Close(n0, n1-1)
	if nn0 > 0 && f.Box[nn0-1].Nrune >= 0 && ppt0.X-f.Box[nn0-1].Width >= f.r.Min.X {
		nn0--
		ppt0.X -= f.Box[nn0].Width
	}

	if n0 < f.Nbox-1 {
		n0++
	}
	f.clean(ppt0, nn0, n0)

	if f.p1 > p1 {
		f.p1 -= p1 - p0
	} else if f.p1 > p0 {
		f.p1 = p0
	}
	if f.p0 > p1 {
		f.p0 -= p1 - p0
	} else if f.p0 > p0 {
		f.p0 = p0
	}

	f.Nchars -= p1 - p0
	if f.p0 == f.p1 {
		f.tickat(f.PointOf(f.p0), true)
	}
	pt0 = f.PointOf(f.Nchars)
	extra := 0
	if pt0.X > f.r.Min.X {
		extra = 1
	}
	h := f.Font.Dy()
	f.Nlines = (pt0.Y-f.r.Min.Y)/h + extra
	if ForceElasticTabstopExperiment {
		// Just to see if the algorithm works not ideal to sift through all of
		// the boxes per insertion, although surprisingly faster than expected
		// to the point of where its almost unnoticable without the print
		// statements
		f.Stretch(0)
		f.Refresh() // must do this until line mapper is fixed
	}
	return int(p1 - p0) //n - f.Nlines
}
func (f *Frame) delete(pt0, pt1 image.Point, n0, n1 int, cn1 int64) (image.Point, image.Point, int, int, int64) {
	h := f.Font.Dy()
	for pt1.X != pt0.X && n1 < f.Nbox {
		b := &f.Box[n1]
		pt0 = f.lineWrap0(pt0, b)
		pt1 = f.lineWrap(pt1, b)
		r := image.Rectangle{pt0, pt0}
		r.Max.Y += h

		if b.Nrune > 0 { // non-newline
			n := f.canFit(pt0, b)
			if n != b.Nrune {
				f.Split(n1, n)
				b = &f.Box[n1]
			}
			r.Max.X += b.Width
			f.Draw(f.b, r, f.b, pt1, f.op)
			//drawBorder(f.b, r.Inset(-4), Green, image.ZP, 8)
			cn1 += int64(b.Nrune)
		} else {
			r.Max.X = min(r.Max.X+f.newWid0(pt0, b), f.r.Max.X)
			_, col := f.pick(cn1, f.p0, f.p1)
			f.Draw(f.b, r, col, pt0, f.op)
			cn1++
		}
		pt1 = f.advance(pt1, b)
		pt0.X += f.newWid(pt0, b)
		f.Box[n0] = f.Box[n1]
		n0++
		n1++
	}
	return pt0, pt1, n0, n1, cn1
}
func (f *Frame) fixTrailer(pt0, pt1 image.Point, n1 int) (image.Point, image.Point, int) {
	if n1 == f.Nbox && pt0.X != pt1.X {
		f.Paint(pt0, pt1, f.Color.Back)
	}
	h := f.Font.Dy()
	pt2 := f.ptOfCharPtBox(32768, pt1, n1)
	if pt2.Y > f.r.Max.Y {
		pt2.Y = f.r.Max.Y - h
	}
	if n1 < f.Nbox {
		q0 := pt0.Y + h
		q1 := pt1.Y + h
		q2 := pt2.Y + h
		if q2 > f.r.Max.Y {
			q2 = f.r.Max.Y
		}
		f.Draw(f.b, image.Rect(pt0.X, pt0.Y, pt0.X+(f.r.Max.X-pt1.X), q0), f.b, pt1, f.op)
		f.Draw(f.b, image.Rect(f.r.Min.X, q0, f.r.Max.X, q0+(q2-q1)), f.b, image.Pt(f.r.Min.X, q1), f.op)
		f.Paint(image.Pt(pt2.X, pt2.Y-(pt1.Y-pt0.Y)), pt2, f.Color.Back)
	} else {
		f.Paint(pt0, pt2, f.Color.Back)
	}
	return pt0, pt1, n1
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
func max(a, b int) int {
	if a < b {
		return a
	}
	return b
}
<|endoftext|>


<commit_before>package docker

import (
	"github.com/kelseyhightower/envconfig"
	"github.com/davidhiendl/telegraf-docker-sd/app/logger"
)

type DockerConfigSpec struct {
	AutoConfPrefix string `envconfig:"AUTO_CONF_PREFIX",default:"docker_"`
	TagsFromLabels string `envconfig:"TAGS_FROM_LABELS"`
	TagsFromSwarm  bool   `envconfig:"TAGS_FROM_SWARM",default:"true"`
}

func LoadConfig() *DockerConfigSpec {
	cfg := &DockerConfigSpec{}
	err := envconfig.Process("TSD_DOCKER_", cfg)

	if err != nil {
		logger.Fatalf("failed to parse config: %v", err)
	}

	return cfg
}
<commit_msg>fixed envconf prefix<commit_after>package docker

import (
	"github.com/kelseyhightower/envconfig"
	"github.com/davidhiendl/telegraf-docker-sd/app/logger"
)

type DockerConfigSpec struct {
	AutoConfPrefix string `envconfig:"AUTO_CONF_PREFIX",default:"docker_"`
	TagsFromLabels string `envconfig:"TAGS_FROM_LABELS"`
	TagsFromSwarm  bool   `envconfig:"TAGS_FROM_SWARM",default:"true"`
}

func LoadConfig() *DockerConfigSpec {
	cfg := &DockerConfigSpec{}
	err := envconfig.Process("TSD_DOCKER", cfg)

	if err != nil {
		logger.Fatalf("failed to parse config: %v", err)
	}

	return cfg
}
<|endoftext|>


<commit_before>// Package combiner contains methods to consume Job objects, orchestrating
// the download, combination, and upload of a group of related PDF files.
// TODO now that s.Stat{} can return errors, maybe the err chan is unnecessary
package combiner

import (
	"errors"
	"io/ioutil"
	"log"
	"pdfcombiner/cpdf"
	"pdfcombiner/job"
	"pdfcombiner/notifier"
	s "pdfcombiner/stat"
	"runtime"
	"time"
)

var (
	downloadTimeout = 3 * time.Minute
	verbose         = true
	basedir         = "/tmp/"
	MaxGoroutines   = 30
)

// Get an individual file from S3.  If successful, writes the file out to disk
// and sends a stat object back to the main channel.  If there are errors they
// are sent back through the error channel.
func getFile(j *job.Job, docname string, c chan<- s.Stat, e chan<- s.Stat) {
	start := time.Now()
	data, err := j.Get(docname)
	if err != nil {
		e <- s.Stat{Filename: docname, Err: err}
		return
	}
	path := basedir + docname
	err = ioutil.WriteFile(path, data, 0644)
	if err != nil {
		e <- s.Stat{Filename: docname, Err: err}
		return
	}
	c <- s.Stat{Filename: docname,
		Size:   len(data),
		DlTime: time.Since(start)}
}

// Fan out workers to download each document in parallel, then block
// until all downloads are complete.
func getAllFiles(j *job.Job) {
	start := time.Now()
	c := make(chan s.Stat, j.DocCount())
	e := make(chan s.Stat, j.DocCount())
	for _, doc := range j.DocList {
		throttle()
		go getFile(j, doc, c, e)
	}

	totalBytes := waitForDownloads(j, c, e)
	printSummary(start, totalBytes, j.CompleteCount())
}

// Prevents the system from being overwhelmed with work.
// Blocks until the number of Goroutines is less than a preset threshold.
func throttle() {
	for {
		if runtime.NumGoroutine() < MaxGoroutines {
			break
		}
		time.Sleep(50 * time.Millisecond)
	}
}

// Listen on several channels for information from background download
// tasks -- each task will either send a s.Stat through c, an error through
// e, or timeout.  Once all docs are accounted for, return the total number
// of bytes recieved.
func waitForDownloads(j *job.Job, c <-chan s.Stat, e <-chan s.Stat) (totalBytes int) {
	for _, _ = range j.DocList {
		select {
		case packet := <-c:
			if verbose {
				log.Printf("%s was %d bytes\n", packet.Filename, packet.Size)
			}
			totalBytes += packet.Size
			j.MarkComplete(packet.Filename, packet)
		case bad := <-e:
			j.AddError(bad.Filename, bad.Err)
		case <-time.After(downloadTimeout):
			j.AddError("general", errors.New("Timed out while downloading"))
			return
		}
	}
	return
}

// Print a summary of the download activity.
func printSummary(start time.Time, bytes int, count int) {
	elapsed := time.Since(start)
	seconds := elapsed.Seconds()
	mbps := float64(bytes) / 1024 / 1024 / seconds
	log.Printf("got %d bytes over %d files in %f secs (%f MB/s)\n",
		bytes, count, seconds, mbps)
}

// Send an update on the success or failure of the operation to the
// callback URL provided by the job originator.
func postToCallback(j *job.Job) {
	log.Println("work complete, posting status to callback:", j.Callback)
	_ = j.ToJson()
	notifier.SendNotification(j)
}

// The entry point to this package.  Given a Job, download all the files,
// combine them into a single one, upload it to AWS and post the status to
// a callback endpoint.
func Combine(j *job.Job) bool {
	defer postToCallback(j)
	getAllFiles(j)
	if j.HasDownloadedDocs() {
		cpdf.Merge(j.Downloaded)
	}
	return true
}
<commit_msg>No need for verbose<commit_after>// Package combiner contains methods to consume Job objects, orchestrating
// the download, combination, and upload of a group of related PDF files.
// TODO now that s.Stat{} can return errors, maybe the err chan is unnecessary
package combiner

import (
	"errors"
	"io/ioutil"
	"log"
	"pdfcombiner/cpdf"
	"pdfcombiner/job"
	"pdfcombiner/notifier"
	s "pdfcombiner/stat"
	"runtime"
	"time"
)

var (
	downloadTimeout = 3 * time.Minute
	basedir         = "/tmp/"
	MaxGoroutines   = 30
)

// Get an individual file from S3.  If successful, writes the file out to disk
// and sends a stat object back to the main channel.  If there are errors they
// are sent back through the error channel.
func getFile(j *job.Job, docname string, c chan<- s.Stat, e chan<- s.Stat) {
	start := time.Now()
	data, err := j.Get(docname)
	if err != nil {
		e <- s.Stat{Filename: docname, Err: err}
		return
	}
	path := basedir + docname
	err = ioutil.WriteFile(path, data, 0644)
	if err != nil {
		e <- s.Stat{Filename: docname, Err: err}
		return
	}
	c <- s.Stat{Filename: docname,
		Size:   len(data),
		DlTime: time.Since(start)}
}

// Fan out workers to download each document in parallel, then block
// until all downloads are complete.
func getAllFiles(j *job.Job) {
	start := time.Now()
	c := make(chan s.Stat, j.DocCount())
	e := make(chan s.Stat, j.DocCount())
	for _, doc := range j.DocList {
		throttle()
		go getFile(j, doc, c, e)
	}

	totalBytes := waitForDownloads(j, c, e)
	printSummary(start, totalBytes, j.CompleteCount())
}

// Prevents the system from being overwhelmed with work.
// Blocks until the number of Goroutines is less than a preset threshold.
func throttle() {
	for {
		if runtime.NumGoroutine() < MaxGoroutines {
			break
		}
		time.Sleep(50 * time.Millisecond)
	}
}

// Listen on several channels for information from background download
// tasks -- each task will either send a s.Stat through c, an error through
// e, or timeout.  Once all docs are accounted for, return the total number
// of bytes recieved.
func waitForDownloads(j *job.Job, c <-chan s.Stat, e <-chan s.Stat) (totalBytes int) {
	for _, _ = range j.DocList {
		select {
		case packet := <-c:
			log.Printf("%s was %d bytes\n", packet.Filename, packet.Size)
			totalBytes += packet.Size
			j.MarkComplete(packet.Filename, packet)
		case bad := <-e:
			j.AddError(bad.Filename, bad.Err)
		case <-time.After(downloadTimeout):
			j.AddError("general", errors.New("Timed out while downloading"))
			return
		}
	}
	return
}

// Print a summary of the download activity.
func printSummary(start time.Time, bytes int, count int) {
	elapsed := time.Since(start)
	seconds := elapsed.Seconds()
	mbps := float64(bytes) / 1024 / 1024 / seconds
	log.Printf("got %d bytes over %d files in %f secs (%f MB/s)\n",
		bytes, count, seconds, mbps)
}

// Send an update on the success or failure of the operation to the
// callback URL provided by the job originator.
func postToCallback(j *job.Job) {
	log.Println("work complete, posting status to callback:", j.Callback)
	_ = j.ToJson()
	notifier.SendNotification(j)
}

// The entry point to this package.  Given a Job, download all the files,
// combine them into a single one, upload it to AWS and post the status to
// a callback endpoint.
func Combine(j *job.Job) bool {
	defer postToCallback(j)
	getAllFiles(j)
	if j.HasDownloadedDocs() {
		cpdf.Merge(j.Downloaded)
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package commands

import (
	"os"
	"runtime"
	"strings"

	"github.com/bogem/nehm/applescript"
	"github.com/bogem/nehm/config"
	"github.com/bogem/nehm/ui"
	"github.com/bogem/nehm/util"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var RootCmd = listCommand

// Variables used in flags
var (
	limit, offset                       uint
	dlFolder, itunesPlaylist, permalink string
)

func Execute() {
	RootCmd.AddCommand(getCommand)
	RootCmd.AddCommand(searchCommand)
	RootCmd.AddCommand(versionCommand)
	RootCmd.Execute()
}

// addCommonFlags adds common flags related to download tracks.
func addCommonFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&dlFolder, "dlFolder", "f", "", "filesystem path to download folder")

	if runtime.GOOS == "darwin" {
		cmd.Flags().StringVarP(&itunesPlaylist, "itunesPlaylist", "i", "", "name of iTunes playlist")
	}
}

func addLimitFlag(cmd *cobra.Command) {
	cmd.Flags().UintVarP(&limit, "limit", "l", 10, "count of tracks on each page")
}

func addOffsetFlag(cmd *cobra.Command) {
	cmd.Flags().UintVarP(&offset, "offset", "o", 0, "offset relative to first like")
}

func addPermalinkFlag(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&permalink, "permalink", "p", "", "user's permalink")
}

// initializeConfig initializes a config with flags.
func initializeConfig(cmd *cobra.Command) {
	err := config.ReadInConfig()
	if err == config.ErrNotExist {
		ui.Warning("there is no config file. Read README to configure nehm")
	} else if err != nil {
		ui.Term("", err)
	}

	loadDefaultSettings()

	initializeDlFolder(cmd)
	initializePermalink(cmd)
	if runtime.GOOS == "darwin" {
		initializeItunesPlaylist(cmd)
	}
}

func loadDefaultSettings() {
	config.SetDefault("dlFolder", os.Getenv("HOME"))
	config.SetDefault("itunesPlaylist", "")
}

func flagChanged(fs *pflag.FlagSet, key string) bool {
	flag := fs.Lookup(key)
	if flag == nil {
		return false
	}
	return flag.Changed
}

// initializeDlFolder initializes dlFolder value. If there is no dlFolder
// set up, then dlFolder is set to HOME env variable.
func initializeDlFolder(cmd *cobra.Command) {
	var df string

	if flagChanged(cmd.Flags(), "dlFolder") {
		df = dlFolder
	} else {
		df = config.Get("dlFolder")
	}

	if df == "" {
		ui.Warning("you didn't set a download folder. Tracks will be downloaded to your home directory.")
		df = os.Getenv("HOME")
	}

	config.Set("dlFolder", util.SanitizePath(df))
}

// initializePermalink initializes permalink value. If there is no permalink
// set up, then program is terminating.
func initializePermalink(cmd *cobra.Command) {
	var p string

	if flagChanged(cmd.Flags(), "permalink") {
		p = permalink
	} else {
		p = config.Get("permalink")
	}

	if p == "" {
		ui.Term("you didn't set a permalink. Use flag '-p' or set permalink in config file.\nTo know, what is permalink, read FAQ.", nil)
	} else {
		config.Set("permalink", p)
	}
}

// initializeItunesPlaylist initializes itunesPlaylist value. If there is no
// itunesPlaylist set up, then itunesPlaylist set up to blank string. Blank
// string is the sign, what tracks should not to be added to iTunes.
func initializeItunesPlaylist(cmd *cobra.Command) {
	var playlist string

	if runtime.GOOS == "darwin" {
		if flagChanged(cmd.Flags(), "itunesPlaylist") {
			playlist = itunesPlaylist
		} else {
			playlist = config.Get("itunesPlaylist")
		}

		if playlist == "" {
			ui.Warning("you didn't set an iTunes playlist. Tracks won't be added to iTunes.")
		} else {
			playlistsList, err := applescript.ListOfPlaylists()
			if err != nil {
				ui.Term("couldn't get list of playlists", err)
			}
			if !strings.Contains(playlistsList, playlist) {
				ui.Term("playlist "+playlist+" doesn't exist. Please enter correct name.", nil)
			}
		}
	}

	config.Set("itunesPlaylist", playlist)
}
<commit_msg>Delete redundant detection of OS in initializeConfig And note the detection of OS in comment of initializeItunesPlaylist<commit_after>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package commands

import (
	"os"
	"runtime"
	"strings"

	"github.com/bogem/nehm/applescript"
	"github.com/bogem/nehm/config"
	"github.com/bogem/nehm/ui"
	"github.com/bogem/nehm/util"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var RootCmd = listCommand

// Variables used in flags
var (
	limit, offset                       uint
	dlFolder, itunesPlaylist, permalink string
)

func Execute() {
	RootCmd.AddCommand(getCommand)
	RootCmd.AddCommand(searchCommand)
	RootCmd.AddCommand(versionCommand)
	RootCmd.Execute()
}

// addCommonFlags adds common flags related to download tracks.
func addCommonFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&dlFolder, "dlFolder", "f", "", "filesystem path to download folder")

	if runtime.GOOS == "darwin" {
		cmd.Flags().StringVarP(&itunesPlaylist, "itunesPlaylist", "i", "", "name of iTunes playlist")
	}
}

func addLimitFlag(cmd *cobra.Command) {
	cmd.Flags().UintVarP(&limit, "limit", "l", 10, "count of tracks on each page")
}

func addOffsetFlag(cmd *cobra.Command) {
	cmd.Flags().UintVarP(&offset, "offset", "o", 0, "offset relative to first like")
}

func addPermalinkFlag(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&permalink, "permalink", "p", "", "user's permalink")
}

// initializeConfig initializes a config with flags.
func initializeConfig(cmd *cobra.Command) {
	err := config.ReadInConfig()
	if err == config.ErrNotExist {
		ui.Warning("there is no config file. Read README to configure nehm")
	} else if err != nil {
		ui.Term("", err)
	}

	loadDefaultSettings()

	initializeDlFolder(cmd)
	initializePermalink(cmd)
	initializeItunesPlaylist(cmd)
}

func loadDefaultSettings() {
	config.SetDefault("dlFolder", os.Getenv("HOME"))
	config.SetDefault("itunesPlaylist", "")
}

func flagChanged(fs *pflag.FlagSet, key string) bool {
	flag := fs.Lookup(key)
	if flag == nil {
		return false
	}
	return flag.Changed
}

// initializeDlFolder initializes dlFolder value. If there is no dlFolder
// set up, then dlFolder is set to HOME env variable.
func initializeDlFolder(cmd *cobra.Command) {
	var df string

	if flagChanged(cmd.Flags(), "dlFolder") {
		df = dlFolder
	} else {
		df = config.Get("dlFolder")
	}

	if df == "" {
		ui.Warning("you didn't set a download folder. Tracks will be downloaded to your home directory.")
		df = os.Getenv("HOME")
	}

	config.Set("dlFolder", util.SanitizePath(df))
}

// initializePermalink initializes permalink value. If there is no permalink
// set up, then program is terminating.
func initializePermalink(cmd *cobra.Command) {
	var p string

	if flagChanged(cmd.Flags(), "permalink") {
		p = permalink
	} else {
		p = config.Get("permalink")
	}

	if p == "" {
		ui.Term("you didn't set a permalink. Use flag '-p' or set permalink in config file.\nTo know, what is permalink, read FAQ.", nil)
	} else {
		config.Set("permalink", p)
	}
}

// initializeItunesPlaylist initializes itunesPlaylist value. If there is no
// itunesPlaylist set up, then itunesPlaylist set up to blank string. Blank
// string is the sign, what tracks should not to be added to iTunes.
//
// initializeItunesPlaylist sets blank string to config, if OS is darwin
func initializeItunesPlaylist(cmd *cobra.Command) {
	var playlist string

	if runtime.GOOS == "darwin" {
		if flagChanged(cmd.Flags(), "itunesPlaylist") {
			playlist = itunesPlaylist
		} else {
			playlist = config.Get("itunesPlaylist")
		}

		if playlist == "" {
			ui.Warning("you didn't set an iTunes playlist. Tracks won't be added to iTunes.")
		} else {
			playlistsList, err := applescript.ListOfPlaylists()
			if err != nil {
				ui.Term("couldn't get list of playlists", err)
			}
			if !strings.Contains(playlistsList, playlist) {
				ui.Term("playlist "+playlist+" doesn't exist. Please enter correct name.", nil)
			}
		}
	}

	config.Set("itunesPlaylist", playlist)
}
<|endoftext|>


<commit_before>// +build linux

/*
Copyright 2014 The Kubernetes 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 cni

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net"
	"os"
	"path"
	"reflect"
	"testing"
	"text/template"

	types020 "github.com/containernetworking/cni/pkg/types/020"
	"github.com/stretchr/testify/mock"
	"k8s.io/api/core/v1"
	clientset "k8s.io/client-go/kubernetes"
	utiltesting "k8s.io/client-go/util/testing"
	"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
	containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
	"k8s.io/kubernetes/pkg/kubelet/dockershim/network"
	"k8s.io/kubernetes/pkg/kubelet/dockershim/network/cni/testing"
	"k8s.io/kubernetes/pkg/kubelet/dockershim/network/hostport"
	networktest "k8s.io/kubernetes/pkg/kubelet/dockershim/network/testing"
	"k8s.io/utils/exec"
	fakeexec "k8s.io/utils/exec/testing"
)

// Returns .in file path, .out file path, and .env file path
func installPluginUnderTest(t *testing.T, testBinDir, testConfDir, testDataDir, binName string, confName string) (string, string, string) {
	for _, dir := range []string{testBinDir, testConfDir, testDataDir} {
		err := os.MkdirAll(dir, 0777)
		if err != nil {
			t.Fatalf("Failed to create test plugin dir %s: %v", dir, err)
		}
	}

	confFile := path.Join(testConfDir, confName+".conf")
	f, err := os.Create(confFile)
	if err != nil {
		t.Fatalf("Failed to install plugin %s: %v", confFile, err)
	}
	networkConfig := fmt.Sprintf(`{ "name": "%s", "type": "%s", "capabilities": {"portMappings": true}  }`, confName, binName)
	_, err = f.WriteString(networkConfig)
	if err != nil {
		t.Fatalf("Failed to write network config file (%v)", err)
	}
	f.Close()

	pluginExec := path.Join(testBinDir, binName)
	f, err = os.Create(pluginExec)

	const execScriptTempl = `#!/bin/bash
cat > {{.InputFile}}
env > {{.OutputEnv}}
echo "%@" >> {{.OutputEnv}}
export $(echo ${CNI_ARGS} | sed 's/;/ /g') &> /dev/null
mkdir -p {{.OutputDir}} &> /dev/null
echo -n "$CNI_COMMAND $CNI_NETNS $K8S_POD_NAMESPACE $K8S_POD_NAME $K8S_POD_INFRA_CONTAINER_ID" >& {{.OutputFile}}
echo -n "{ \"ip4\": { \"ip\": \"10.1.0.23/24\" } }"
`
	inputFile := path.Join(testDataDir, binName+".in")
	outputFile := path.Join(testDataDir, binName+".out")
	envFile := path.Join(testDataDir, binName+".env")
	execTemplateData := &map[string]interface{}{
		"InputFile":  inputFile,
		"OutputFile": outputFile,
		"OutputEnv":  envFile,
		"OutputDir":  testDataDir,
	}

	tObj := template.Must(template.New("test").Parse(execScriptTempl))
	buf := &bytes.Buffer{}
	if err := tObj.Execute(buf, *execTemplateData); err != nil {
		t.Fatalf("Error in executing script template - %v", err)
	}
	execScript := buf.String()
	_, err = f.WriteString(execScript)
	if err != nil {
		t.Fatalf("Failed to write plugin exec - %v", err)
	}

	err = f.Chmod(0777)
	if err != nil {
		t.Fatalf("Failed to set exec perms on plugin")
	}

	f.Close()

	return inputFile, outputFile, envFile
}

func tearDownPlugin(tmpDir string) {
	err := os.RemoveAll(tmpDir)
	if err != nil {
		fmt.Printf("Error in cleaning up test: %v", err)
	}
}

type fakeNetworkHost struct {
	networktest.FakePortMappingGetter
	kubeClient clientset.Interface
	runtime    kubecontainer.Runtime
}

func NewFakeHost(kubeClient clientset.Interface, pods []*containertest.FakePod, ports map[string][]*hostport.PortMapping) *fakeNetworkHost {
	host := &fakeNetworkHost{
		networktest.FakePortMappingGetter{PortMaps: ports},
		kubeClient,
		&containertest.FakeRuntime{
			AllPodList: pods,
		},
	}
	return host
}

func (fnh *fakeNetworkHost) GetPodByName(name, namespace string) (*v1.Pod, bool) {
	return nil, false
}

func (fnh *fakeNetworkHost) GetKubeClient() clientset.Interface {
	return fnh.kubeClient
}

func (fnh *fakeNetworkHost) GetRuntime() kubecontainer.Runtime {
	return fnh.runtime
}

func (fnh *fakeNetworkHost) GetNetNS(containerID string) (string, error) {
	return fnh.GetRuntime().GetNetNS(kubecontainer.ContainerID{Type: "test", ID: containerID})
}

func (fnh *fakeNetworkHost) SupportsLegacyFeatures() bool {
	return true
}

func TestCNIPlugin(t *testing.T) {
	// install some random plugin
	netName := fmt.Sprintf("test%d", rand.Intn(1000))
	binName := fmt.Sprintf("test_vendor%d", rand.Intn(1000))

	podIP := "10.0.0.2"
	podIPOutput := fmt.Sprintf("4: eth0    inet %s/24 scope global dynamic eth0\\       valid_lft forever preferred_lft forever", podIP)
	fakeCmds := []fakeexec.FakeCommandAction{
		func(cmd string, args ...string) exec.Cmd {
			return fakeexec.InitFakeCmd(&fakeexec.FakeCmd{
				CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
					func() ([]byte, error) {
						return []byte(podIPOutput), nil
					},
				},
			}, cmd, args...)
		},
	}

	fexec := &fakeexec.FakeExec{
		CommandScript: fakeCmds,
		LookPathFunc: func(file string) (string, error) {
			return fmt.Sprintf("/fake-bin/%s", file), nil
		},
	}

	mockLoCNI := &mock_cni.MockCNI{}
	// TODO mock for the test plugin too

	tmpDir := utiltesting.MkTmpdirOrDie("cni-test")
	testConfDir := path.Join(tmpDir, "etc", "cni", "net.d")
	testBinDir := path.Join(tmpDir, "opt", "cni", "bin")
	testDataDir := path.Join(tmpDir, "output")
	defer tearDownPlugin(tmpDir)
	inputFile, outputFile, outputEnv := installPluginUnderTest(t, testBinDir, testConfDir, testDataDir, binName, netName)

	containerID := kubecontainer.ContainerID{Type: "test", ID: "test_infra_container"}
	pods := []*containertest.FakePod{{
		Pod: &kubecontainer.Pod{
			Containers: []*kubecontainer.Container{
				{ID: containerID},
			},
		},
		NetnsPath: "/proc/12345/ns/net",
	}}

	plugins := ProbeNetworkPlugins(testConfDir, []string{testBinDir})
	if len(plugins) != 1 {
		t.Fatalf("Expected only one network plugin, got %d", len(plugins))
	}
	if plugins[0].Name() != "cni" {
		t.Fatalf("Expected CNI network plugin, got %q", plugins[0].Name())
	}

	cniPlugin, ok := plugins[0].(*cniNetworkPlugin)
	if !ok {
		t.Fatalf("Not a CNI network plugin!")
	}
	cniPlugin.execer = fexec
	cniPlugin.loNetwork.CNIConfig = mockLoCNI

	mockLoCNI.On("AddNetworkList", cniPlugin.loNetwork.NetworkConfig, mock.AnythingOfType("*libcni.RuntimeConf")).Return(&types020.Result{IP4: &types020.IPConfig{IP: net.IPNet{IP: []byte{127, 0, 0, 1}}}}, nil)

	ports := map[string][]*hostport.PortMapping{
		containerID.ID: {
			{
				Name:          "name",
				HostPort:      8008,
				ContainerPort: 80,
				Protocol:      "UDP",
				HostIP:        "0.0.0.0",
			},
		},
	}
	fakeHost := NewFakeHost(nil, pods, ports)

	plug, err := network.InitNetworkPlugin(plugins, "cni", fakeHost, kubeletconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
	if err != nil {
		t.Fatalf("Failed to select the desired plugin: %v", err)
	}

	// Set up the pod
	err = plug.SetUpPod("podNamespace", "podName", containerID, map[string]string{})
	if err != nil {
		t.Errorf("Expected nil: %v", err)
	}
	eo, eerr := ioutil.ReadFile(outputEnv)
	output, err := ioutil.ReadFile(outputFile)
	if err != nil || eerr != nil {
		t.Errorf("Failed to read output file %s: %v (env %s err %v)", outputFile, err, eo, eerr)
	}

	expectedOutput := "ADD /proc/12345/ns/net podNamespace podName test_infra_container"
	if string(output) != expectedOutput {
		t.Errorf("Mismatch in expected output for setup hook. Expected '%s', got '%s'", expectedOutput, string(output))
	}

	// Verify the correct network configuration was passed
	inputConfig := struct {
		RuntimeConfig struct {
			PortMappings []map[string]interface{} `json:"portMappings"`
		} `json:"runtimeConfig"`
	}{}
	inputBytes, inerr := ioutil.ReadFile(inputFile)
	parseerr := json.Unmarshal(inputBytes, &inputConfig)
	if inerr != nil || parseerr != nil {
		t.Errorf("failed to parse reported cni input config %s: (%v %v)", inputFile, inerr, parseerr)
	}
	expectedMappings := []map[string]interface{}{
		// hah, golang always unmarshals unstructured json numbers as float64
		{"hostPort": 8008.0, "containerPort": 80.0, "protocol": "udp", "hostIP": "0.0.0.0"},
	}
	if !reflect.DeepEqual(inputConfig.RuntimeConfig.PortMappings, expectedMappings) {
		t.Errorf("mismatch in expected port mappings. expected %v got %v", expectedMappings, inputConfig.RuntimeConfig.PortMappings)
	}

	// Get its IP address
	status, err := plug.GetPodNetworkStatus("podNamespace", "podName", containerID)
	if err != nil {
		t.Errorf("Failed to read pod network status: %v", err)
	}
	if status.IP.String() != podIP {
		t.Errorf("Expected pod IP %q but got %q", podIP, status.IP.String())
	}

	// Tear it down
	err = plug.TearDownPod("podNamespace", "podName", containerID)
	if err != nil {
		t.Errorf("Expected nil: %v", err)
	}
	output, err = ioutil.ReadFile(outputFile)
	expectedOutput = "DEL /proc/12345/ns/net podNamespace podName test_infra_container"
	if string(output) != expectedOutput {
		t.Errorf("Mismatch in expected output for setup hook. Expected '%s', got '%s'", expectedOutput, string(output))
	}

	mockLoCNI.AssertExpectations(t)
}

func TestLoNetNonNil(t *testing.T) {
	if conf := getLoNetwork(nil); conf == nil {
		t.Error("Expected non-nil lo network")
	}
}
<commit_msg>add cni bandwidth test<commit_after>// +build linux

/*
Copyright 2014 The Kubernetes 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 cni

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net"
	"os"
	"path"
	"reflect"
	"testing"
	"text/template"

	types020 "github.com/containernetworking/cni/pkg/types/020"
	"github.com/stretchr/testify/mock"
	"k8s.io/api/core/v1"
	clientset "k8s.io/client-go/kubernetes"
	utiltesting "k8s.io/client-go/util/testing"
	"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
	containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
	"k8s.io/kubernetes/pkg/kubelet/dockershim/network"
	"k8s.io/kubernetes/pkg/kubelet/dockershim/network/cni/testing"
	"k8s.io/kubernetes/pkg/kubelet/dockershim/network/hostport"
	networktest "k8s.io/kubernetes/pkg/kubelet/dockershim/network/testing"
	"k8s.io/utils/exec"
	fakeexec "k8s.io/utils/exec/testing"
)

// Returns .in file path, .out file path, and .env file path
func installPluginUnderTest(t *testing.T, testBinDir, testConfDir, testDataDir, binName string, confName string) (string, string, string) {
	for _, dir := range []string{testBinDir, testConfDir, testDataDir} {
		err := os.MkdirAll(dir, 0777)
		if err != nil {
			t.Fatalf("Failed to create test plugin dir %s: %v", dir, err)
		}
	}

	confFile := path.Join(testConfDir, confName+".conf")
	f, err := os.Create(confFile)
	if err != nil {
		t.Fatalf("Failed to install plugin %s: %v", confFile, err)
	}
	networkConfig := fmt.Sprintf(`{ "name": "%s", "type": "%s", "capabilities": {"portMappings": true, "bandwidth": true}  }`, confName, binName)
	_, err = f.WriteString(networkConfig)
	if err != nil {
		t.Fatalf("Failed to write network config file (%v)", err)
	}
	f.Close()

	pluginExec := path.Join(testBinDir, binName)
	f, err = os.Create(pluginExec)

	const execScriptTempl = `#!/bin/bash
cat > {{.InputFile}}
env > {{.OutputEnv}}
echo "%@" >> {{.OutputEnv}}
export $(echo ${CNI_ARGS} | sed 's/;/ /g') &> /dev/null
mkdir -p {{.OutputDir}} &> /dev/null
echo -n "$CNI_COMMAND $CNI_NETNS $K8S_POD_NAMESPACE $K8S_POD_NAME $K8S_POD_INFRA_CONTAINER_ID" >& {{.OutputFile}}
echo -n "{ \"ip4\": { \"ip\": \"10.1.0.23/24\" } }"
`
	inputFile := path.Join(testDataDir, binName+".in")
	outputFile := path.Join(testDataDir, binName+".out")
	envFile := path.Join(testDataDir, binName+".env")
	execTemplateData := &map[string]interface{}{
		"InputFile":  inputFile,
		"OutputFile": outputFile,
		"OutputEnv":  envFile,
		"OutputDir":  testDataDir,
	}

	tObj := template.Must(template.New("test").Parse(execScriptTempl))
	buf := &bytes.Buffer{}
	if err := tObj.Execute(buf, *execTemplateData); err != nil {
		t.Fatalf("Error in executing script template - %v", err)
	}
	execScript := buf.String()
	_, err = f.WriteString(execScript)
	if err != nil {
		t.Fatalf("Failed to write plugin exec - %v", err)
	}

	err = f.Chmod(0777)
	if err != nil {
		t.Fatalf("Failed to set exec perms on plugin")
	}

	f.Close()

	return inputFile, outputFile, envFile
}

func tearDownPlugin(tmpDir string) {
	err := os.RemoveAll(tmpDir)
	if err != nil {
		fmt.Printf("Error in cleaning up test: %v", err)
	}
}

type fakeNetworkHost struct {
	networktest.FakePortMappingGetter
	kubeClient clientset.Interface
	runtime    kubecontainer.Runtime
}

func NewFakeHost(kubeClient clientset.Interface, pods []*containertest.FakePod, ports map[string][]*hostport.PortMapping) *fakeNetworkHost {
	host := &fakeNetworkHost{
		networktest.FakePortMappingGetter{PortMaps: ports},
		kubeClient,
		&containertest.FakeRuntime{
			AllPodList: pods,
		},
	}
	return host
}

func (fnh *fakeNetworkHost) GetPodByName(name, namespace string) (*v1.Pod, bool) {
	return nil, false
}

func (fnh *fakeNetworkHost) GetKubeClient() clientset.Interface {
	return fnh.kubeClient
}

func (fnh *fakeNetworkHost) GetRuntime() kubecontainer.Runtime {
	return fnh.runtime
}

func (fnh *fakeNetworkHost) GetNetNS(containerID string) (string, error) {
	return fnh.GetRuntime().GetNetNS(kubecontainer.ContainerID{Type: "test", ID: containerID})
}

func (fnh *fakeNetworkHost) SupportsLegacyFeatures() bool {
	return true
}

func TestCNIPlugin(t *testing.T) {
	// install some random plugin
	netName := fmt.Sprintf("test%d", rand.Intn(1000))
	binName := fmt.Sprintf("test_vendor%d", rand.Intn(1000))

	podIP := "10.0.0.2"
	podIPOutput := fmt.Sprintf("4: eth0    inet %s/24 scope global dynamic eth0\\       valid_lft forever preferred_lft forever", podIP)
	fakeCmds := []fakeexec.FakeCommandAction{
		func(cmd string, args ...string) exec.Cmd {
			return fakeexec.InitFakeCmd(&fakeexec.FakeCmd{
				CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
					func() ([]byte, error) {
						return []byte(podIPOutput), nil
					},
				},
			}, cmd, args...)
		},
	}

	fexec := &fakeexec.FakeExec{
		CommandScript: fakeCmds,
		LookPathFunc: func(file string) (string, error) {
			return fmt.Sprintf("/fake-bin/%s", file), nil
		},
	}

	mockLoCNI := &mock_cni.MockCNI{}
	// TODO mock for the test plugin too

	tmpDir := utiltesting.MkTmpdirOrDie("cni-test")
	testConfDir := path.Join(tmpDir, "etc", "cni", "net.d")
	testBinDir := path.Join(tmpDir, "opt", "cni", "bin")
	testDataDir := path.Join(tmpDir, "output")
	defer tearDownPlugin(tmpDir)
	inputFile, outputFile, outputEnv := installPluginUnderTest(t, testBinDir, testConfDir, testDataDir, binName, netName)

	containerID := kubecontainer.ContainerID{Type: "test", ID: "test_infra_container"}
	pods := []*containertest.FakePod{{
		Pod: &kubecontainer.Pod{
			Containers: []*kubecontainer.Container{
				{ID: containerID},
			},
		},
		NetnsPath: "/proc/12345/ns/net",
	}}

	plugins := ProbeNetworkPlugins(testConfDir, []string{testBinDir})
	if len(plugins) != 1 {
		t.Fatalf("Expected only one network plugin, got %d", len(plugins))
	}
	if plugins[0].Name() != "cni" {
		t.Fatalf("Expected CNI network plugin, got %q", plugins[0].Name())
	}

	cniPlugin, ok := plugins[0].(*cniNetworkPlugin)
	if !ok {
		t.Fatalf("Not a CNI network plugin!")
	}
	cniPlugin.execer = fexec
	cniPlugin.loNetwork.CNIConfig = mockLoCNI

	mockLoCNI.On("AddNetworkList", cniPlugin.loNetwork.NetworkConfig, mock.AnythingOfType("*libcni.RuntimeConf")).Return(&types020.Result{IP4: &types020.IPConfig{IP: net.IPNet{IP: []byte{127, 0, 0, 1}}}}, nil)

	ports := map[string][]*hostport.PortMapping{
		containerID.ID: {
			{
				Name:          "name",
				HostPort:      8008,
				ContainerPort: 80,
				Protocol:      "UDP",
				HostIP:        "0.0.0.0",
			},
		},
	}
	fakeHost := NewFakeHost(nil, pods, ports)

	plug, err := network.InitNetworkPlugin(plugins, "cni", fakeHost, kubeletconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
	if err != nil {
		t.Fatalf("Failed to select the desired plugin: %v", err)
	}

	bandwidthAnnotation := make(map[string]string)
	bandwidthAnnotation["kubernetes.io/ingress-bandwidth"] = "1M"
	bandwidthAnnotation["kubernetes.io/egress-bandwidth"] = "1M"

	// Set up the pod
	err = plug.SetUpPod("podNamespace", "podName", containerID, bandwidthAnnotation)
	if err != nil {
		t.Errorf("Expected nil: %v", err)
	}
	eo, eerr := ioutil.ReadFile(outputEnv)
	output, err := ioutil.ReadFile(outputFile)
	if err != nil || eerr != nil {
		t.Errorf("Failed to read output file %s: %v (env %s err %v)", outputFile, err, eo, eerr)
	}

	expectedOutput := "ADD /proc/12345/ns/net podNamespace podName test_infra_container"
	if string(output) != expectedOutput {
		t.Errorf("Mismatch in expected output for setup hook. Expected '%s', got '%s'", expectedOutput, string(output))
	}

	// Verify the correct network configuration was passed
	inputConfig := struct {
		RuntimeConfig struct {
			Bandwidth    map[string]interface{}   `json:"bandwidth"`
			PortMappings []map[string]interface{} `json:"portMappings"`
		} `json:"runtimeConfig"`
	}{}
	inputBytes, inerr := ioutil.ReadFile(inputFile)
	parseerr := json.Unmarshal(inputBytes, &inputConfig)
	if inerr != nil || parseerr != nil {
		t.Errorf("failed to parse reported cni input config %s: (%v %v)", inputFile, inerr, parseerr)
	}
	expectedMappings := []map[string]interface{}{
		// hah, golang always unmarshals unstructured json numbers as float64
		{"hostPort": 8008.0, "containerPort": 80.0, "protocol": "udp", "hostIP": "0.0.0.0"},
	}
	if !reflect.DeepEqual(inputConfig.RuntimeConfig.PortMappings, expectedMappings) {
		t.Errorf("mismatch in expected port mappings. expected %v got %v", expectedMappings, inputConfig.RuntimeConfig.PortMappings)
	}
	expectedBandwidth := map[string]interface{}{
		"ingressRate": 1000.0, "egressRate": 1000.0,
	}
	if !reflect.DeepEqual(inputConfig.RuntimeConfig.Bandwidth, expectedBandwidth) {
		t.Errorf("mismatch in expected bandwidth. expected %v got %v", expectedBandwidth, inputConfig.RuntimeConfig.Bandwidth)
	}

	// Get its IP address
	status, err := plug.GetPodNetworkStatus("podNamespace", "podName", containerID)
	if err != nil {
		t.Errorf("Failed to read pod network status: %v", err)
	}
	if status.IP.String() != podIP {
		t.Errorf("Expected pod IP %q but got %q", podIP, status.IP.String())
	}

	// Tear it down
	err = plug.TearDownPod("podNamespace", "podName", containerID)
	if err != nil {
		t.Errorf("Expected nil: %v", err)
	}
	output, err = ioutil.ReadFile(outputFile)
	expectedOutput = "DEL /proc/12345/ns/net podNamespace podName test_infra_container"
	if string(output) != expectedOutput {
		t.Errorf("Mismatch in expected output for setup hook. Expected '%s', got '%s'", expectedOutput, string(output))
	}

	mockLoCNI.AssertExpectations(t)
}

func TestLoNetNonNil(t *testing.T) {
	if conf := getLoNetwork(nil); conf == nil {
		t.Error("Expected non-nil lo network")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"

	"github.com/haya14busa/reviewdog/doghouse"
	"github.com/haya14busa/reviewdog/doghouse/server"
	"github.com/haya14busa/reviewdog/doghouse/server/ciutil"
	"github.com/haya14busa/reviewdog/doghouse/server/storage"
	"google.golang.org/appengine"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/urlfetch"
)

type githubChecker struct {
	privateKey       []byte
	integrationID    int
	ghInstStore      storage.GitHubInstallationStore
	ghRepoTokenStore storage.GitHubRepositoryTokenStore
}

func (gc *githubChecker) handleCheck(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	ctx := appengine.NewContext(r)

	var req doghouse.CheckRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "failed to decode request: %v", err)
		return
	}

	// Check authorization.
	if !gc.validateCheckRequest(ctx, w, r, req.Owner, req.Repo) {
		return
	}

	opt := &server.NewGitHubClientOption{
		PrivateKey:        gc.privateKey,
		IntegrationID:     gc.integrationID,
		RepoOwner:         req.Owner,
		Client:            urlfetch.Client(ctx),
		InstallationStore: gc.ghInstStore,
	}

	gh, err := server.NewGitHubClient(ctx, opt)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, err)
		return
	}

	res, err := server.NewChecker(&req, gh).Check(ctx)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, err)
		return
	}
	if err := json.NewEncoder(w).Encode(res); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, err)
		return
	}
}

func (gc *githubChecker) validateCheckRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, owner, repo string) bool {
	log.Infof(ctx, "Remote Addr: %s", r.RemoteAddr)
	if ciutil.IsFromCI(r) {
		// Skip token validation if it's from trusted CI providers.
		return true
	}
	return gc.validateCheckToken(ctx, w, r, owner, repo)
}

func (gc *githubChecker) validateCheckToken(ctx context.Context, w http.ResponseWriter, r *http.Request, owner, repo string) bool {
	token := extractBearerToken(r)
	if token == "" {
		w.Header().Set("The WWW-Authenticate", `error="invalid_request", error_description="The access token not provided"`)
		w.WriteHeader(http.StatusUnauthorized)
		fmt.Fprintf(w, "The access token not provided. Get token from %s", githubRepoURL(ctx, r, owner, repo))
		return false
	}
	_, wantToken, err := gc.ghRepoTokenStore.Get(ctx, owner, repo)
	if err != nil {
		log.Errorf(ctx, "failed to get repository (%s/%s) token: %v", owner, repo, err)
	}
	if wantToken == nil {
		w.WriteHeader(http.StatusNotFound)
		return false
	}
	if token != wantToken.Token {
		w.Header().Set("The WWW-Authenticate", `error="invalid_token", error_description="The access token is invalid"`)
		w.WriteHeader(http.StatusUnauthorized)
		fmt.Fprintf(w, "The access token is invalid. Get valid token from %s", githubRepoURL(ctx, r, owner, repo))
		return false
	}
	return true
}

func githubRepoURL(ctx context.Context, r *http.Request, owner, repo string) string {
	u := doghouseBaseURL(ctx, r)
	u.Path = fmt.Sprintf("/gh/%s/%s", owner, repo)
	return u.String()
}

func doghouseBaseURL(ctx context.Context, r *http.Request) *url.URL {
	scheme := ""
	if r.URL != nil && r.URL.Scheme != "" {
		scheme = r.URL.Scheme
	}
	if scheme == "" {
		scheme = "https"
		if appengine.IsDevAppServer() {
			scheme = "http"
		}
	}
	u, err := url.Parse(scheme + "://" + r.Host)
	if err != nil {
		log.Errorf(ctx, "%v", err)
	}
	return u
}

func extractBearerToken(r *http.Request) string {
	auth := r.Header.Get("Authorization")
	prefix := "bearer "
	if strings.HasPrefix(strings.ToLower(auth), prefix) {
		return auth[len(prefix):]
	}
	return ""
}
<commit_msg>doghouse: add error logging<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"

	"github.com/haya14busa/reviewdog/doghouse"
	"github.com/haya14busa/reviewdog/doghouse/server"
	"github.com/haya14busa/reviewdog/doghouse/server/ciutil"
	"github.com/haya14busa/reviewdog/doghouse/server/storage"
	"google.golang.org/appengine"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/urlfetch"
)

type githubChecker struct {
	privateKey       []byte
	integrationID    int
	ghInstStore      storage.GitHubInstallationStore
	ghRepoTokenStore storage.GitHubRepositoryTokenStore
}

func (gc *githubChecker) handleCheck(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	ctx := appengine.NewContext(r)

	var req doghouse.CheckRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "failed to decode request: %v", err)
		return
	}

	// Check authorization.
	if !gc.validateCheckRequest(ctx, w, r, req.Owner, req.Repo) {
		return
	}

	opt := &server.NewGitHubClientOption{
		PrivateKey:        gc.privateKey,
		IntegrationID:     gc.integrationID,
		RepoOwner:         req.Owner,
		Client:            urlfetch.Client(ctx),
		InstallationStore: gc.ghInstStore,
	}

	gh, err := server.NewGitHubClient(ctx, opt)
	if err != nil {
		log.Errorf(ctx, "failed to create GitHub client: %v", err)
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, err)
		return
	}

	res, err := server.NewChecker(&req, gh).Check(ctx)
	if err != nil {
		log.Errorf(ctx, "failed to run checker: %v", err)
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, err)
		return
	}
	if err := json.NewEncoder(w).Encode(res); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, err)
		return
	}
}

func (gc *githubChecker) validateCheckRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, owner, repo string) bool {
	log.Infof(ctx, "Remote Addr: %s", r.RemoteAddr)
	if ciutil.IsFromCI(r) {
		// Skip token validation if it's from trusted CI providers.
		return true
	}
	return gc.validateCheckToken(ctx, w, r, owner, repo)
}

func (gc *githubChecker) validateCheckToken(ctx context.Context, w http.ResponseWriter, r *http.Request, owner, repo string) bool {
	token := extractBearerToken(r)
	if token == "" {
		w.Header().Set("The WWW-Authenticate", `error="invalid_request", error_description="The access token not provided"`)
		w.WriteHeader(http.StatusUnauthorized)
		fmt.Fprintf(w, "The access token not provided. Get token from %s", githubRepoURL(ctx, r, owner, repo))
		return false
	}
	_, wantToken, err := gc.ghRepoTokenStore.Get(ctx, owner, repo)
	if err != nil {
		log.Errorf(ctx, "failed to get repository (%s/%s) token: %v", owner, repo, err)
	}
	if wantToken == nil {
		w.WriteHeader(http.StatusNotFound)
		return false
	}
	if token != wantToken.Token {
		w.Header().Set("The WWW-Authenticate", `error="invalid_token", error_description="The access token is invalid"`)
		w.WriteHeader(http.StatusUnauthorized)
		fmt.Fprintf(w, "The access token is invalid. Get valid token from %s", githubRepoURL(ctx, r, owner, repo))
		return false
	}
	return true
}

func githubRepoURL(ctx context.Context, r *http.Request, owner, repo string) string {
	u := doghouseBaseURL(ctx, r)
	u.Path = fmt.Sprintf("/gh/%s/%s", owner, repo)
	return u.String()
}

func doghouseBaseURL(ctx context.Context, r *http.Request) *url.URL {
	scheme := ""
	if r.URL != nil && r.URL.Scheme != "" {
		scheme = r.URL.Scheme
	}
	if scheme == "" {
		scheme = "https"
		if appengine.IsDevAppServer() {
			scheme = "http"
		}
	}
	u, err := url.Parse(scheme + "://" + r.Host)
	if err != nil {
		log.Errorf(ctx, "%v", err)
	}
	return u
}

func extractBearerToken(r *http.Request) string {
	auth := r.Header.Get("Authorization")
	prefix := "bearer "
	if strings.HasPrefix(strings.ToLower(auth), prefix) {
		return auth[len(prefix):]
	}
	return ""
}
<|endoftext|>


<commit_before>/*
Copyright 2015 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 dockertools

import (
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/metrics"
	"github.com/fsouza/go-dockerclient"
)

type instrumentedDockerInterface struct {
	client DockerInterface
}

// Creates an instrumented DockerInterface from an existing DockerInterface.
func NewInstrumentedDockerInterface(dockerClient DockerInterface) DockerInterface {
	return instrumentedDockerInterface{
		client: dockerClient,
	}
}

func (in instrumentedDockerInterface) ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("list_containers").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.ListContainers(options)
}

func (in instrumentedDockerInterface) InspectContainer(id string) (*docker.Container, error) {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("inspect_container").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.InspectContainer(id)
}

func (in instrumentedDockerInterface) CreateContainer(opts docker.CreateContainerOptions) (*docker.Container, error) {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("create_container").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.CreateContainer(opts)
}

func (in instrumentedDockerInterface) StartContainer(id string, hostConfig *docker.HostConfig) error {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("start_container").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.StartContainer(id, hostConfig)
}

func (in instrumentedDockerInterface) StopContainer(id string, timeout uint) error {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("stop_container").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.StopContainer(id, timeout)
}

func (in instrumentedDockerInterface) RemoveContainer(opts docker.RemoveContainerOptions) error {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("remove_container").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.RemoveContainer(opts)
}

func (in instrumentedDockerInterface) InspectImage(image string) (*docker.Image, error) {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("inspect_image").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.InspectImage(image)
}

func (in instrumentedDockerInterface) ListImages(opts docker.ListImagesOptions) ([]docker.APIImages, error) {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("list_images").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.ListImages(opts)
}

func (in instrumentedDockerInterface) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("pull_image").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.PullImage(opts, auth)
}

func (in instrumentedDockerInterface) RemoveImage(image string) error {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("remove_image").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.RemoveImage(image)
}

func (in instrumentedDockerInterface) Logs(opts docker.LogsOptions) error {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("logs").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.Logs(opts)
}

func (in instrumentedDockerInterface) Version() (*docker.Env, error) {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("version").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.Version()
}

func (in instrumentedDockerInterface) Info() (*docker.Env, error) {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("info").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.Info()
}

func (in instrumentedDockerInterface) CreateExec(opts docker.CreateExecOptions) (*docker.Exec, error) {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("create_exec").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.CreateExec(opts)
}

func (in instrumentedDockerInterface) StartExec(startExec string, opts docker.StartExecOptions) error {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("start_exec").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.StartExec(startExec, opts)
}

func (in instrumentedDockerInterface) InspectExec(id string) (*docker.ExecInspect, error) {
	start := time.Now()
	defer func() {
		metrics.DockerOperationsLatency.WithLabelValues("inspect_exec").Observe(metrics.SinceInMicroseconds(start))
	}()
	return in.client.InspectExec(id)
}
<commit_msg>Refactoring handling of latency recording.<commit_after>/*
Copyright 2015 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 dockertools

import (
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/metrics"
	"github.com/fsouza/go-dockerclient"
)

type instrumentedDockerInterface struct {
	client DockerInterface
}

// Creates an instrumented DockerInterface from an existing DockerInterface.
func NewInstrumentedDockerInterface(dockerClient DockerInterface) DockerInterface {
	return instrumentedDockerInterface{
		client: dockerClient,
	}
}

// Record the duration of the operation.
func recordOperation(operation string, start time.Time) {
	metrics.DockerOperationsLatency.WithLabelValues(operation).Observe(metrics.SinceInMicroseconds(start))
}

func (in instrumentedDockerInterface) ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) {
	const operation = "list_containers"
	defer recordOperation(operation, time.Now())

	return in.client.ListContainers(options)
}

func (in instrumentedDockerInterface) InspectContainer(id string) (*docker.Container, error) {
	const operation = "inspect_container"
	defer recordOperation(operation, time.Now())

	return in.client.InspectContainer(id)
}

func (in instrumentedDockerInterface) CreateContainer(opts docker.CreateContainerOptions) (*docker.Container, error) {
	const operation = "create_container"
	defer recordOperation(operation, time.Now())

	return in.client.CreateContainer(opts)
}

func (in instrumentedDockerInterface) StartContainer(id string, hostConfig *docker.HostConfig) error {
	const operation = "start_container"
	defer recordOperation(operation, time.Now())

	return in.client.StartContainer(id, hostConfig)
}

func (in instrumentedDockerInterface) StopContainer(id string, timeout uint) error {
	const operation = "stop_container"
	defer recordOperation(operation, time.Now())

	return in.client.StopContainer(id, timeout)
}

func (in instrumentedDockerInterface) RemoveContainer(opts docker.RemoveContainerOptions) error {
	const operation = "remove_container"
	defer recordOperation(operation, time.Now())

	return in.client.RemoveContainer(opts)
}

func (in instrumentedDockerInterface) InspectImage(image string) (*docker.Image, error) {
	const operation = "inspect_image"
	defer recordOperation(operation, time.Now())

	return in.client.InspectImage(image)
}

func (in instrumentedDockerInterface) ListImages(opts docker.ListImagesOptions) ([]docker.APIImages, error) {
	const operation = "list_images"
	defer recordOperation(operation, time.Now())

	return in.client.ListImages(opts)
}

func (in instrumentedDockerInterface) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error {
	const operation = "pull_image"
	defer recordOperation(operation, time.Now())

	return in.client.PullImage(opts, auth)
}

func (in instrumentedDockerInterface) RemoveImage(image string) error {
	const operation = "remove_image"
	defer recordOperation(operation, time.Now())

	return in.client.RemoveImage(image)
}

func (in instrumentedDockerInterface) Logs(opts docker.LogsOptions) error {
	const operation = "logs"
	defer recordOperation(operation, time.Now())

	return in.client.Logs(opts)
}

func (in instrumentedDockerInterface) Version() (*docker.Env, error) {
	const operation = "version"
	defer recordOperation(operation, time.Now())

	return in.client.Version()
}

func (in instrumentedDockerInterface) Info() (*docker.Env, error) {
	const operation = "info"
	defer recordOperation(operation, time.Now())

	return in.client.Info()
}

func (in instrumentedDockerInterface) CreateExec(opts docker.CreateExecOptions) (*docker.Exec, error) {
	const operation = "create_exec"
	defer recordOperation(operation, time.Now())

	return in.client.CreateExec(opts)
}

func (in instrumentedDockerInterface) StartExec(startExec string, opts docker.StartExecOptions) error {
	const operation = "start_exec"
	defer recordOperation(operation, time.Now())

	return in.client.StartExec(startExec, opts)
}

func (in instrumentedDockerInterface) InspectExec(id string) (*docker.ExecInspect, error) {
	const operation = "inspect_exec"
	defer recordOperation(operation, time.Now())

	return in.client.InspectExec(id)
}
<|endoftext|>