<commit_before>// Copyright ©2012-2013 The bíogo.bam Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package bam

import (
	"bytes"
	"errors"
	"fmt"
	"unsafe"
)

// Record represents a SAM/BAM record.
type Record struct {
	Name    string
	Ref     *Reference
	Pos     int
	MapQ    byte
	Cigar   Cigar
	Flags   Flags
	MateRef *Reference
	MatePos int
	TempLen int
	Seq     NybbleSeq
	Qual    []byte
	AuxTags []Aux
}

// NewRecord returns a Record, checking for consistency of the provided
// attributes.
func NewRecord(name string, ref, mRef *Reference, p, mPos, tLen int, mapQ byte, co []CigarOp, seq, qual []byte, aux []Aux) (*Record, error) {
	if !(validPos(p) && validPos(mPos) && validTmpltLen(tLen) && validLen(len(seq)) && validLen(len(qual))) {
		return nil, errors.New("bam: value out of range")
	}
	if len(qual) != len(seq) {
		return nil, errors.New("bam: sequence/quality length mismatch")
	}
	if ref != nil {
		if ref.id < 0 {
			return nil, errors.New("bam: linking to invalid reference")
		}
	} else {
		if p != -1 {
			return nil, errors.New("bam: specified position != -1 without reference")
		}
	}
	if mRef != nil {
		if mRef.id < 0 {
			return nil, errors.New("bam: linking to invalid mate reference")
		}
	} else {
		if mPos != -1 {
			return nil, errors.New("bam: specified mate position != -1 without mate reference")
		}
	}
	r := &Record{
		Name:    name,
		Ref:     ref,
		Pos:     p,
		MapQ:    mapQ,
		Cigar:   co,
		MateRef: mRef,
		MatePos: mPos,
		TempLen: tLen,
		Seq:     NewNybbleSeq(seq),
		Qual:    qual,
		AuxTags: aux,
	}
	return r, nil
}

// IsValidRecord returns whether the record satisfies the conditions that
// it has the Unmapped flag set if it not placed; that the MateUnmapped
// flag is set if it paired its mate is unplaced; that the CIGAR length
// matches the sequence and quality string lengths if they are non-zero; and
// that the Paired, ProperPair, Unmapped and MateUnmapped flags are consistent.
func IsValidRecord(r *Record) bool {
	if (r.Ref == nil || r.Pos == -1) && r.Flags&Unmapped == 0 {
		return false
	}
	if r.Flags&Paired != 0 && (r.MateRef == nil || r.MatePos == -1) && r.Flags&MateUnmapped == 0 {
		return false
	}
	if r.Flags&(Unmapped|ProperPair) == Unmapped|ProperPair {
		return false
	}
	if r.Flags&(Paired|MateUnmapped|ProperPair) == Paired|MateUnmapped|ProperPair {
		return false
	}
	if len(r.Qual) != 0 && r.Seq.Length != len(r.Qual) {
		return false
	}
	if cigarLen := r.Len(); cigarLen < 0 || (r.Seq.Length != 0 && r.Seq.Length != cigarLen) {
		return false
	}
	return true
}

// Reference returns the records reference.
func (r *Record) Reference() *Reference {
	return r.Ref
}

// Tag returns an Aux tag whose tag ID matches the first two bytes of tag and true.
// If no tag matches, nil and false are returned.
func (r *Record) Tag(tag []byte) (v Aux, ok bool) {
	for i := range r.AuxTags {
		if bytes.Compare(r.AuxTags[i][:2], tag) == 0 {
			return r.AuxTags[i], true
		}
	}
	return
}

// Start returns the lower-coordinate end of the alignment.
func (r *Record) Start() int {
	return r.Pos
}

// Bin returns the BAM index bin of the record.
func (r *Record) Bin() int {
	if r.Flags&Unmapped != 0 {
		return 4680 // reg2bin(-1, 0)
	}
	return int(reg2bin(r.Pos, r.End()))
}

// Len returns the length of the alignment.
func (r *Record) Len() int {
	return r.End() - r.Start()
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

// End returns the highest query-consuming coordinate end of the alignment.
// The position returned by End is not valid if r.Cigar.IsValid(r.Seq.Length)
// is false.
func (r *Record) End() int {
	pos := r.Pos
	end := r.Pos
	var con Consume
	for _, co := range r.Cigar {
		con = co.Type().Consumes()
		pos += co.Len() * con.Reference
		if con.Query != 0 {
			end = max(end, pos)
		}
	}
	return end
}

// Strand returns an int8 indicating the strand of the alignment. A positive return indicates
// alignment in the forward orientation, a negative returns indicates alignment in the reverse
// orientation.
func (r *Record) Strand() int8 {
	if r.Flags&Reverse == Reverse {
		return -1
	}
	return 1
}

// String returns a string representation of the Record.
func (r *Record) String() string {
	end := r.End()
	return fmt.Sprintf("%s %v %v %d %s:%d..%d (%d) %d %s:%d %d %s %v %v",
		r.Name,
		r.Flags,
		r.Cigar,
		r.MapQ,
		r.Ref.Name(),
		r.Pos,
		end,
		int(reg2bin(r.Pos, end)),
		end-r.Pos,
		r.MateRef.Name(),
		r.MatePos,
		r.TempLen,
		r.Seq.Expand(),
		r.Qual,
		r.AuxTags,
	)
}

// MarshalText implements encoding.TextMarshaler. It calls MarshalSAM with FlagDecimal.
func (r *Record) MarshalText() ([]byte, error) {
	return r.MarshalSAM(0)
}

// MarshalSAM formats a Record as SAM using the specified flag format. Acceptable
// formats are FlagDecimal, FlagHex and FlagString.
func (r *Record) MarshalSAM(flags int) ([]byte, error) {
	if flags < FlagDecimal || flags > FlagString {
		return nil, errors.New("bam: flag format option out of range")
	}
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%s\t%v\t%s\t%d\t%d\t%s\t%s\t%d\t%d\t%s\t%s",
		r.Name,
		formatFlags(r.Flags, flags),
		r.Ref.Name(),
		r.Pos,
		r.MapQ,
		r.Cigar,
		r.MateRef.Name(),
		r.MatePos,
		r.TempLen,
		r.Seq.Expand(),
		r.Qual,
	)
	if len(r.AuxTags) > 0 {
		fmt.Fprintf(&buf, "\t%v", r.AuxTags)
	}
	return buf.Bytes(), nil
}

// Flag format constants.
const (
	FlagDecimal = iota
	FlagHex
	FlagString
)

func formatFlags(f Flags, format int) interface{} {
	switch format {
	case FlagDecimal:
		return uint16(f)
	case FlagHex:
		return fmt.Sprintf("0x%X", f)
	case FlagString:
		// If 0x01 is unset, no assumptions can be made about 0x02, 0x08, 0x20, 0x40 and 0x80
		const pairedMask = ProperPair | MateUnmapped | MateReverse | MateReverse | Read1 | Read2
		if f&1 == 0 {
			f &^= pairedMask
		}

		const flags = "pPuUrR12sfdS"

		b := make([]byte, 0, len(flags))
		for i, c := range flags {
			if f&(1<<uint(i)) != 0 {
				b = append(b, byte(c))
			}
		}

		return string(b)
	default:
		panic("bam: invalid flag format")
	}
}

type NybblePair byte

type nybblePairs []NybblePair

func (np nybblePairs) Bytes() []byte { return *(*[]byte)(unsafe.Pointer(&np)) }

type NybbleSeq struct {
	Length int
	Seq    []NybblePair
}

var (
	n16TableRev = [16]byte{'=', 'A', 'C', 'M', 'G', 'R', 'S', 'V', 'T', 'W', 'Y', 'H', 'K', 'D', 'B', 'N'}
	n16Table    = [256]NybblePair{
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0x1, 0x2, 0x4, 0x8, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 0xf, 0xf,
		0xf, 0x1, 0xe, 0x2, 0xd, 0xf, 0xf, 0x4, 0xb, 0xf, 0xf, 0xc, 0xf, 0x3, 0xf, 0xf,
		0xf, 0xf, 0x5, 0x6, 0x8, 0xf, 0x7, 0x9, 0xf, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0x1, 0xe, 0x2, 0xd, 0xf, 0xf, 0x4, 0xb, 0xf, 0xf, 0xc, 0xf, 0x3, 0xf, 0xf,
		0xf, 0xf, 0x5, 0x6, 0x8, 0xf, 0x7, 0x9, 0xf, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
	}
)

func NewNybbleSeq(s []byte) NybbleSeq {
	return NybbleSeq{
		Length: len(s),
		Seq:    contract(s),
	}
}

func contract(s []byte) []NybblePair {
	ns := make([]NybblePair, (len(s)+1)>>1)
	var np NybblePair
	for i, b := range s {
		if i&1 == 0 {
			np = n16Table[b] << 4
		} else {
			ns[i>>1] = np | n16Table[b]
		}
	}
	// We haven't written the last base if the
	// sequence was odd length, so do that now.
	if len(s)&1 != 0 {
		ns[len(ns)-1] = np
	}
	return ns
}

func (ns NybbleSeq) Expand() []byte {
	s := make([]byte, ns.Length)
	for i := range s {
		if i&1 == 0 {
			s[i] = n16TableRev[ns.Seq[i>>1]>>4]
		} else {
			s[i] = n16TableRev[ns.Seq[i>>1]&0xf]
		}
	}

	return s
}
<commit_msg>Why do they even bother with documentation?<commit_after>// Copyright ©2012-2013 The bíogo.bam Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package bam

import (
	"bytes"
	"errors"
	"fmt"
	"unsafe"
)

// Record represents a SAM/BAM record.
type Record struct {
	Name    string
	Ref     *Reference
	Pos     int
	MapQ    byte
	Cigar   Cigar
	Flags   Flags
	MateRef *Reference
	MatePos int
	TempLen int
	Seq     NybbleSeq
	Qual    []byte
	AuxTags []Aux
}

// NewRecord returns a Record, checking for consistency of the provided
// attributes.
func NewRecord(name string, ref, mRef *Reference, p, mPos, tLen int, mapQ byte, co []CigarOp, seq, qual []byte, aux []Aux) (*Record, error) {
	if !(validPos(p) && validPos(mPos) && validTmpltLen(tLen) && validLen(len(seq)) && validLen(len(qual))) {
		return nil, errors.New("bam: value out of range")
	}
	if len(qual) != len(seq) {
		return nil, errors.New("bam: sequence/quality length mismatch")
	}
	if ref != nil {
		if ref.id < 0 {
			return nil, errors.New("bam: linking to invalid reference")
		}
	} else {
		if p != -1 {
			return nil, errors.New("bam: specified position != -1 without reference")
		}
	}
	if mRef != nil {
		if mRef.id < 0 {
			return nil, errors.New("bam: linking to invalid mate reference")
		}
	} else {
		if mPos != -1 {
			return nil, errors.New("bam: specified mate position != -1 without mate reference")
		}
	}
	r := &Record{
		Name:    name,
		Ref:     ref,
		Pos:     p,
		MapQ:    mapQ,
		Cigar:   co,
		MateRef: mRef,
		MatePos: mPos,
		TempLen: tLen,
		Seq:     NewNybbleSeq(seq),
		Qual:    qual,
		AuxTags: aux,
	}
	return r, nil
}

// IsValidRecord returns whether the record satisfies the conditions that
// it has the Unmapped flag set if it not placed; that the MateUnmapped
// flag is set if it paired its mate is unplaced; that the CIGAR length
// matches the sequence and quality string lengths if they are non-zero; and
// that the Paired, ProperPair, Unmapped and MateUnmapped flags are consistent.
func IsValidRecord(r *Record) bool {
	if (r.Ref == nil || r.Pos == -1) && r.Flags&Unmapped == 0 {
		return false
	}
	if r.Flags&Paired != 0 && (r.MateRef == nil || r.MatePos == -1) && r.Flags&MateUnmapped == 0 {
		return false
	}
	if r.Flags&(Unmapped|ProperPair) == Unmapped|ProperPair {
		return false
	}
	if r.Flags&(Paired|MateUnmapped|ProperPair) == Paired|MateUnmapped|ProperPair {
		return false
	}
	if len(r.Qual) != 0 && r.Seq.Length != len(r.Qual) {
		return false
	}
	if cigarLen := r.Len(); cigarLen < 0 || (r.Seq.Length != 0 && r.Seq.Length != cigarLen) {
		return false
	}
	return true
}

// Reference returns the records reference.
func (r *Record) Reference() *Reference {
	return r.Ref
}

// Tag returns an Aux tag whose tag ID matches the first two bytes of tag and true.
// If no tag matches, nil and false are returned.
func (r *Record) Tag(tag []byte) (v Aux, ok bool) {
	for i := range r.AuxTags {
		if bytes.Compare(r.AuxTags[i][:2], tag) == 0 {
			return r.AuxTags[i], true
		}
	}
	return
}

// Start returns the lower-coordinate end of the alignment.
func (r *Record) Start() int {
	return r.Pos
}

// Bin returns the BAM index bin of the record.
func (r *Record) Bin() int {
	if r.Flags&Unmapped != 0 {
		return 4680 // reg2bin(-1, 0)
	}
	return int(reg2bin(r.Pos, r.End()))
}

// Len returns the length of the alignment.
func (r *Record) Len() int {
	return r.End() - r.Start()
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

// End returns the highest query-consuming coordinate end of the alignment.
// The position returned by End is not valid if r.Cigar.IsValid(r.Seq.Length)
// is false.
func (r *Record) End() int {
	pos := r.Pos
	end := r.Pos
	var con Consume
	for _, co := range r.Cigar {
		con = co.Type().Consumes()
		pos += co.Len() * con.Reference
		if con.Query != 0 {
			end = max(end, pos)
		}
	}
	return end
}

// Strand returns an int8 indicating the strand of the alignment. A positive return indicates
// alignment in the forward orientation, a negative returns indicates alignment in the reverse
// orientation.
func (r *Record) Strand() int8 {
	if r.Flags&Reverse == Reverse {
		return -1
	}
	return 1
}

// String returns a string representation of the Record.
func (r *Record) String() string {
	end := r.End()
	return fmt.Sprintf("%s %v %v %d %s:%d..%d (%d) %d %s:%d %d %s %v %v",
		r.Name,
		r.Flags,
		r.Cigar,
		r.MapQ,
		r.Ref.Name(),
		r.Pos,
		end,
		int(reg2bin(r.Pos, end)),
		end-r.Pos,
		r.MateRef.Name(),
		r.MatePos,
		r.TempLen,
		r.Seq.Expand(),
		r.Qual,
		r.AuxTags,
	)
}

// MarshalText implements encoding.TextMarshaler. It calls MarshalSAM with FlagDecimal.
func (r *Record) MarshalText() ([]byte, error) {
	return r.MarshalSAM(0)
}

// MarshalSAM formats a Record as SAM using the specified flag format. Acceptable
// formats are FlagDecimal, FlagHex and FlagString.
func (r *Record) MarshalSAM(flags int) ([]byte, error) {
	if flags < FlagDecimal || flags > FlagString {
		return nil, errors.New("bam: flag format option out of range")
	}
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%s\t%v\t%s\t%d\t%d\t%s\t%s\t%d\t%d\t%s\t%s",
		r.Name,
		formatFlags(r.Flags, flags),
		r.Ref.Name(),
		r.Pos,
		r.MapQ,
		r.Cigar,
		r.MateRef.Name(),
		r.MatePos,
		r.TempLen,
		r.Seq.Expand(),
		r.Qual,
	)
	if len(r.AuxTags) > 0 {
		fmt.Fprintf(&buf, "\t%v", r.AuxTags)
	}
	return buf.Bytes(), nil
}

// Flag format constants.
const (
	FlagDecimal = iota
	FlagHex
	FlagString
)

func formatFlags(f Flags, format int) interface{} {
	switch format {
	case FlagDecimal:
		return uint16(f)
	case FlagHex:
		return fmt.Sprintf("0x%x", f)
	case FlagString:
		// If 0x01 is unset, no assumptions can be made about 0x02, 0x08, 0x20, 0x40 and 0x80
		const pairedMask = ProperPair | MateUnmapped | MateReverse | MateReverse | Read1 | Read2
		if f&1 == 0 {
			f &^= pairedMask
		}

		const flags = "pPuUrR12sfdS"

		b := make([]byte, 0, len(flags))
		for i, c := range flags {
			if f&(1<<uint(i)) != 0 {
				b = append(b, byte(c))
			}
		}

		return string(b)
	default:
		panic("bam: invalid flag format")
	}
}

type NybblePair byte

type nybblePairs []NybblePair

func (np nybblePairs) Bytes() []byte { return *(*[]byte)(unsafe.Pointer(&np)) }

type NybbleSeq struct {
	Length int
	Seq    []NybblePair
}

var (
	n16TableRev = [16]byte{'=', 'A', 'C', 'M', 'G', 'R', 'S', 'V', 'T', 'W', 'Y', 'H', 'K', 'D', 'B', 'N'}
	n16Table    = [256]NybblePair{
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0x1, 0x2, 0x4, 0x8, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 0xf, 0xf,
		0xf, 0x1, 0xe, 0x2, 0xd, 0xf, 0xf, 0x4, 0xb, 0xf, 0xf, 0xc, 0xf, 0x3, 0xf, 0xf,
		0xf, 0xf, 0x5, 0x6, 0x8, 0xf, 0x7, 0x9, 0xf, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0x1, 0xe, 0x2, 0xd, 0xf, 0xf, 0x4, 0xb, 0xf, 0xf, 0xc, 0xf, 0x3, 0xf, 0xf,
		0xf, 0xf, 0x5, 0x6, 0x8, 0xf, 0x7, 0x9, 0xf, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
		0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
	}
)

func NewNybbleSeq(s []byte) NybbleSeq {
	return NybbleSeq{
		Length: len(s),
		Seq:    contract(s),
	}
}

func contract(s []byte) []NybblePair {
	ns := make([]NybblePair, (len(s)+1)>>1)
	var np NybblePair
	for i, b := range s {
		if i&1 == 0 {
			np = n16Table[b] << 4
		} else {
			ns[i>>1] = np | n16Table[b]
		}
	}
	// We haven't written the last base if the
	// sequence was odd length, so do that now.
	if len(s)&1 != 0 {
		ns[len(ns)-1] = np
	}
	return ns
}

func (ns NybbleSeq) Expand() []byte {
	s := make([]byte, ns.Length)
	for i := range s {
		if i&1 == 0 {
			s[i] = n16TableRev[ns.Seq[i>>1]>>4]
		} else {
			s[i] = n16TableRev[ns.Seq[i>>1]&0xf]
		}
	}

	return s
}
<|endoftext|>


<commit_before>package mmatcher

type Record struct {
	Id   string
	Atts []Atter
}

func (a *Record) IsMatch(b *Record, positions ...int) bool {
	if len(positions) <= 0 {
		positions = make([]int, len(a.Atts))
		for i := range positions {
			positions[i] = i
		}
	}
	e := make([]Atter, len(a.Atts))
	return a.IsMatchWithRanges(b, e, positions...)
}

func (a *Record) IsMatchWithRanges(b *Record, e []Atter, positions ...int) bool {
	if len(a.Atts) != len(b.Atts) || len(e) != len(a.Atts) {
		return false
	}
	if len(positions) <= 0 {
		positions = make([]int, len(a.Atts))
		for i := range positions {
			positions[i] = i
		}
	}
	matches := make([]bool, len(positions))
	for i, n := range positions {
		if n >= len(a.Atts) {
			return false
		}
		matches[i] = a.isMatchAt(b, e[n], n)
	}
	for _, m := range matches {
		if !m {
			return false
		}
	}
	return true
}

func (a *Record) isMatchAt(b *Record, e Atter, i int) bool {
	if i < len(a.Atts) && i < len(b.Atts) {
		return a.Atts[i].Equal(b.Atts[i], e)
	}
	return false
}

type Records []Record

func (a *Record) MatchesAll(r Records, e ...Atter) []int {
	positions := make([]int, len(a.Atts))
	for i := range a.Atts {
		positions[i] = i
	}
	return a.Matches(r, positions, e...)
}

func (a *Record) Matches(r Records, positions []int, e ...Atter) (matches []int) {
	if len(e) <= 0 {
		e = make([]Atter, len(a.Atts))
	}
	for i, b := range r {
		if a.IsMatchWithRanges(&b, e, positions...) {
			matches = append(matches, i)
		}
	}
	return
}
<commit_msg>Add fix in case someone tries a negative attribute index<commit_after>package mmatcher

type Record struct {
	Id   string
	Atts []Atter
}

func (a *Record) IsMatch(b *Record, positions ...int) bool {
	if len(positions) <= 0 {
		positions = make([]int, len(a.Atts))
		for i := range positions {
			positions[i] = i
		}
	}
	e := make([]Atter, len(a.Atts))
	return a.IsMatchWithRanges(b, e, positions...)
}

func (a *Record) IsMatchWithRanges(b *Record, e []Atter, positions ...int) bool {
	if len(a.Atts) != len(b.Atts) || len(e) != len(a.Atts) {
		return false
	}
	if len(positions) <= 0 {
		positions = make([]int, len(a.Atts))
		for i := range positions {
			positions[i] = i
		}
	}
	matches := make([]bool, len(positions))
	for i, n := range positions {
		if n >= len(a.Atts) {
			return false
		}
		matches[i] = a.isMatchAt(b, e[n], n)
	}
	for _, m := range matches {
		if !m {
			return false
		}
	}
	return true
}

func (a *Record) isMatchAt(b *Record, e Atter, i int) bool {
	if i >= 0 && i < len(a.Atts) && i < len(b.Atts) {
		return a.Atts[i].Equal(b.Atts[i], e)
	}
	return false
}

type Records []Record

func (a *Record) MatchesAll(r Records, e ...Atter) []int {
	positions := make([]int, len(a.Atts))
	for i := range a.Atts {
		positions[i] = i
	}
	return a.Matches(r, positions, e...)
}

func (a *Record) Matches(r Records, positions []int, e ...Atter) (matches []int) {
	if len(e) <= 0 {
		e = make([]Atter, len(a.Atts))
	}
	for i, b := range r {
		if a.IsMatchWithRanges(&b, e, positions...) {
			matches = append(matches, i)
		}
	}
	return
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"errors"
	"fmt"
	"go/ast"
	"go/importer"
	"go/parser"
	"go/printer"
	"go/token"
	"go/types"
	"html/template"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
)

const mainFile = "goreduce_main.go"

var (
	mainTmpl = template.Must(template.New("test").Parse(`` +
	`package main

func main() {
	{{ .Func }}()
}
`))
	rawPrinter = printer.Config{Mode: printer.RawFormat}
)

func emptyFile(f *os.File) error {
	if err := f.Truncate(0); err != nil {
		return err
	}
	_, err := f.Seek(0, 0)
	return err
}

type reducer struct {
	dir     string
	matchRe *regexp.Regexp

	fset     *token.FileSet
	pkg      *ast.Package
	files    []*ast.File
	file     *ast.File
	funcDecl *ast.FuncDecl

	tinfo types.Config

	outBin  string
	goArgs  []string
	dstFile *os.File

	didChange bool
	stmt      *ast.Stmt
	expr      *ast.Expr
}

func reduce(dir, funcName, matchStr string, bflags ...string) error {
	r := &reducer{dir: dir}
	tdir, err := ioutil.TempDir("", "goreduce")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tdir)
	r.tinfo.Importer = importer.Default()
	if r.matchRe, err = regexp.Compile(matchStr); err != nil {
		return err
	}
	r.fset = token.NewFileSet()
	pkgs, err := parser.ParseDir(r.fset, r.dir, nil, 0)
	if err != nil {
		return err
	}
	if len(pkgs) != 1 {
		return fmt.Errorf("expected 1 package, got %d", len(pkgs))
	}
	for _, pkg := range pkgs {
		r.pkg = pkg
	}
	for _, file := range r.pkg.Files {
		r.files = append(r.files, file)
	}
	r.file, r.funcDecl = findFunc(r.files, funcName)
	if r.file == nil {
		return fmt.Errorf("top-level func %s does not exist", funcName)
	}
	tfnames := make([]string, 0, len(r.files)+1)
	for _, file := range r.files {
		fname := r.fset.Position(file.Pos()).Filename
		tfname := filepath.Join(tdir, filepath.Base(fname))
		dst, err := os.Create(tfname)
		if err != nil {
			return nil
		}
		file.Name.Name = "main"
		if err := rawPrinter.Fprint(dst, r.fset, file); err != nil {
			return err
		}
		if file == r.file {
			r.dstFile = dst
		} else if err := dst.Close(); err != nil {
			return err
		}
		tfnames = append(tfnames, tfname)
	}
	mfname := filepath.Join(tdir, mainFile)
	mf, err := os.Create(mfname)
	if err != nil {
		return err
	}
	// Check that it compiles and the output matches before we apply
	// any changes
	if err := mainTmpl.Execute(mf, struct {
		Func string
	}{
		Func: funcName,
	}); err != nil {
		return err
	}
	if err := mf.Close(); err != nil {
		return err
	}
	tfnames = append(tfnames, mfname)
	r.outBin = filepath.Join(tdir, "bin")
	r.goArgs = []string{"build", "-o", r.outBin}
	r.goArgs = append(r.goArgs, buildFlags...)
	r.goArgs = append(r.goArgs, tfnames...)
	if err := r.checkRun(); err != nil {
		return err
	}
	anyChanges := false
	for err == nil {
		if err = r.step(); err == errNoChange {
			err = nil
			break // we're done
		}
		anyChanges = true
	}
	if anyChanges {
		fname := r.fset.Position(r.file.Pos()).Filename
		f, err := os.Create(fname)
		if err != nil {
			return err
		}
		r.file.Name.Name = r.pkg.Name
		if err := rawPrinter.Fprint(f, r.fset, r.file); err != nil {
			return err
		}
		if err := f.Close(); err != nil {
			return err
		}
	}
	if err2 := r.dstFile.Close(); err == nil && err2 != nil {
		return err2
	}
	return err
}

func (r *reducer) logChange(node ast.Node, format string, a ...interface{}) {
	if *verbose {
		pos := r.fset.Position(node.Pos())
		fmt.Fprintf(os.Stderr, "%s:%d: %s\n", pos.Filename, pos.Line,
			fmt.Sprintf(format, a...))
	}
}

func (r *reducer) checkRun() error {
	err := r.buildAndRun()
	if err == nil {
		return fmt.Errorf("expected an error to occur")
	}
	if s := err.Error(); !r.matchRe.MatchString(s) {
		return fmt.Errorf("error does not match:\n%s", s)
	}
	return nil
}

var errNoChange = fmt.Errorf("no reduction to apply")

func (r *reducer) okChange() bool {
	if r.didChange {
		return false
	}
	// go/types catches most compile errors before writing
	// to disk and running the go tool. Since quite a lot of
	// changes are nonsensical, this is often a big win.
	if _, err := r.tinfo.Check(r.dir, r.fset, r.files, nil); err != nil {
		terr, ok := err.(types.Error)
		if ok && terr.Soft && r.shouldRetry(terr) {
			return r.okChange()
		}
		return false
	}
	if err := emptyFile(r.dstFile); err != nil {
		return false
	}
	if err := printer.Fprint(r.dstFile, r.fset, r.file); err != nil {
		return false
	}
	if err := r.checkRun(); err != nil {
		return false
	}
	// Reduction worked
	r.didChange = true
	return true
}

var importNotUsed = regexp.MustCompile(`"(.*)" imported but not used`)

func (r *reducer) shouldRetry(terr types.Error) bool {
	// Useful as it can handle dot and underscore imports gracefully
	if sm := importNotUsed.FindStringSubmatch(terr.Msg); sm != nil {
		name, path := "", sm[1]
		for _, imp := range r.file.Imports {
			if imp.Name != nil && strings.Trim(imp.Path.Value, `"`) == path {
				name = imp.Name.Name
				break
			}
		}
		return astutil.DeleteNamedImport(r.fset, r.file, name, path)
	}
	return false
}

func (r *reducer) step() error {
	r.didChange = false
	r.walk(r.file, func(v interface{}) bool {
		if r.didChange {
			return false
		}
		return r.reduceNode(v)
	})
	if r.didChange {
		return nil
	}
	return errNoChange
}

func findFunc(files []*ast.File, name string) (*ast.File, *ast.FuncDecl) {
	for _, file := range files {
		for _, decl := range file.Decls {
			funcDecl, ok := decl.(*ast.FuncDecl)
			if ok && funcDecl.Name.Name == name {
				return file, funcDecl
			}
		}
	}
	return nil, nil
}

func (r *reducer) buildAndRun() error {
	cmd := exec.Command("go", r.goArgs...)
	if out, err := cmd.CombinedOutput(); err != nil {
		if strings.HasPrefix(err.Error(), "exit status") {
			return errors.New(string(out))
		}
		return err
	}
	if out, err := exec.Command(r.outBin).CombinedOutput(); err != nil {
		if strings.HasPrefix(err.Error(), "exit status") {
			return errors.New(string(out))
		}
		return err
	}
	return nil
}
<commit_msg>Don't check for close error on tmp file<commit_after>// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"errors"
	"fmt"
	"go/ast"
	"go/importer"
	"go/parser"
	"go/printer"
	"go/token"
	"go/types"
	"html/template"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
)

const mainFile = "goreduce_main.go"

var (
	mainTmpl = template.Must(template.New("test").Parse(`` +
	`package main

func main() {
	{{ .Func }}()
}
`))
	rawPrinter = printer.Config{Mode: printer.RawFormat}
)

func emptyFile(f *os.File) error {
	if err := f.Truncate(0); err != nil {
		return err
	}
	_, err := f.Seek(0, 0)
	return err
}

type reducer struct {
	dir     string
	matchRe *regexp.Regexp

	fset     *token.FileSet
	pkg      *ast.Package
	files    []*ast.File
	file     *ast.File
	funcDecl *ast.FuncDecl

	tinfo types.Config

	outBin  string
	goArgs  []string
	dstFile *os.File

	didChange bool
	stmt      *ast.Stmt
	expr      *ast.Expr
}

func reduce(dir, funcName, matchStr string, bflags ...string) error {
	r := &reducer{dir: dir}
	tdir, err := ioutil.TempDir("", "goreduce")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tdir)
	r.tinfo.Importer = importer.Default()
	if r.matchRe, err = regexp.Compile(matchStr); err != nil {
		return err
	}
	r.fset = token.NewFileSet()
	pkgs, err := parser.ParseDir(r.fset, r.dir, nil, 0)
	if err != nil {
		return err
	}
	if len(pkgs) != 1 {
		return fmt.Errorf("expected 1 package, got %d", len(pkgs))
	}
	for _, pkg := range pkgs {
		r.pkg = pkg
	}
	for _, file := range r.pkg.Files {
		r.files = append(r.files, file)
	}
	r.file, r.funcDecl = findFunc(r.files, funcName)
	if r.file == nil {
		return fmt.Errorf("top-level func %s does not exist", funcName)
	}
	tfnames := make([]string, 0, len(r.files)+1)
	for _, file := range r.files {
		fname := r.fset.Position(file.Pos()).Filename
		tfname := filepath.Join(tdir, filepath.Base(fname))
		dst, err := os.Create(tfname)
		if err != nil {
			return nil
		}
		file.Name.Name = "main"
		if err := rawPrinter.Fprint(dst, r.fset, file); err != nil {
			return err
		}
		if file == r.file {
			r.dstFile = dst
		} else if err := dst.Close(); err != nil {
			return err
		}
		tfnames = append(tfnames, tfname)
	}
	mfname := filepath.Join(tdir, mainFile)
	mf, err := os.Create(mfname)
	if err != nil {
		return err
	}
	// Check that it compiles and the output matches before we apply
	// any changes
	if err := mainTmpl.Execute(mf, struct {
		Func string
	}{
		Func: funcName,
	}); err != nil {
		return err
	}
	if err := mf.Close(); err != nil {
		return err
	}
	tfnames = append(tfnames, mfname)
	r.outBin = filepath.Join(tdir, "bin")
	r.goArgs = []string{"build", "-o", r.outBin}
	r.goArgs = append(r.goArgs, buildFlags...)
	r.goArgs = append(r.goArgs, tfnames...)
	if err := r.checkRun(); err != nil {
		return err
	}
	anyChanges := false
	for err == nil {
		if err = r.step(); err == errNoChange {
			err = nil
			break // we're done
		}
		anyChanges = true
	}
	if anyChanges {
		fname := r.fset.Position(r.file.Pos()).Filename
		f, err := os.Create(fname)
		if err != nil {
			return err
		}
		r.file.Name.Name = r.pkg.Name
		if err := rawPrinter.Fprint(f, r.fset, r.file); err != nil {
			return err
		}
		if err := f.Close(); err != nil {
			return err
		}
	}
	r.dstFile.Close()
	return err
}

func (r *reducer) logChange(node ast.Node, format string, a ...interface{}) {
	if *verbose {
		pos := r.fset.Position(node.Pos())
		fmt.Fprintf(os.Stderr, "%s:%d: %s\n", pos.Filename, pos.Line,
			fmt.Sprintf(format, a...))
	}
}

func (r *reducer) checkRun() error {
	err := r.buildAndRun()
	if err == nil {
		return fmt.Errorf("expected an error to occur")
	}
	if s := err.Error(); !r.matchRe.MatchString(s) {
		return fmt.Errorf("error does not match:\n%s", s)
	}
	return nil
}

var errNoChange = fmt.Errorf("no reduction to apply")

func (r *reducer) okChange() bool {
	if r.didChange {
		return false
	}
	// go/types catches most compile errors before writing
	// to disk and running the go tool. Since quite a lot of
	// changes are nonsensical, this is often a big win.
	if _, err := r.tinfo.Check(r.dir, r.fset, r.files, nil); err != nil {
		terr, ok := err.(types.Error)
		if ok && terr.Soft && r.shouldRetry(terr) {
			return r.okChange()
		}
		return false
	}
	if err := emptyFile(r.dstFile); err != nil {
		return false
	}
	if err := printer.Fprint(r.dstFile, r.fset, r.file); err != nil {
		return false
	}
	if err := r.checkRun(); err != nil {
		return false
	}
	// Reduction worked
	r.didChange = true
	return true
}

var importNotUsed = regexp.MustCompile(`"(.*)" imported but not used`)

func (r *reducer) shouldRetry(terr types.Error) bool {
	// Useful as it can handle dot and underscore imports gracefully
	if sm := importNotUsed.FindStringSubmatch(terr.Msg); sm != nil {
		name, path := "", sm[1]
		for _, imp := range r.file.Imports {
			if imp.Name != nil && strings.Trim(imp.Path.Value, `"`) == path {
				name = imp.Name.Name
				break
			}
		}
		return astutil.DeleteNamedImport(r.fset, r.file, name, path)
	}
	return false
}

func (r *reducer) step() error {
	r.didChange = false
	r.walk(r.file, func(v interface{}) bool {
		if r.didChange {
			return false
		}
		return r.reduceNode(v)
	})
	if r.didChange {
		return nil
	}
	return errNoChange
}

func findFunc(files []*ast.File, name string) (*ast.File, *ast.FuncDecl) {
	for _, file := range files {
		for _, decl := range file.Decls {
			funcDecl, ok := decl.(*ast.FuncDecl)
			if ok && funcDecl.Name.Name == name {
				return file, funcDecl
			}
		}
	}
	return nil, nil
}

func (r *reducer) buildAndRun() error {
	cmd := exec.Command("go", r.goArgs...)
	if out, err := cmd.CombinedOutput(); err != nil {
		if strings.HasPrefix(err.Error(), "exit status") {
			return errors.New(string(out))
		}
		return err
	}
	if out, err := exec.Command(r.outBin).CombinedOutput(); err != nil {
		if strings.HasPrefix(err.Error(), "exit status") {
			return errors.New(string(out))
		}
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package vsolver

import (
	"fmt"
	"net/url"
	"regexp"
	"strings"
)

// A remoteRepo represents a potential remote repository resource.
//
// RemoteRepos are based purely on lexical analysis; successfully constructing
// one is not a guarantee that the resource it identifies actually exists or is
// accessible.
type remoteRepo struct {
	Base     string
	RelPkg   string
	CloneURL *url.URL
	Schemes  []string
	VCS      []string
}

//type remoteResult struct {
//r   remoteRepo
//err error
//}

// TODO sync access to this map
//var remoteCache = make(map[string]remoteResult)

// Regexes for the different known import path flavors
var (
	ghRegex      = regexp.MustCompile(`^(?P<root>github\.com/([A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`)
	gpinNewRegex = regexp.MustCompile(`^(?P<root>gopkg\.in/(?:([a-zA-Z0-9][-a-zA-Z0-9]+)/)?([a-zA-Z][-.a-zA-Z0-9]*)\.((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2}(-unstable)?)(?:\.git))?((?:/[a-zA-Z0-9][-.a-zA-Z0-9]*)*)$`)
	//gpinOldRegex = regexp.MustCompile(`^(?P<root>gopkg\.in/(?:([a-z0-9][-a-z0-9]+)/)?((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2}(-unstable)?))/([a-zA-Z][-a-zA-Z0-9]*)(?:\.git)?((?:/[a-zA-Z][-a-zA-Z0-9]*)*)$`)
	bbRegex = regexp.MustCompile(`^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`)
	lpRegex = regexp.MustCompile(`^(?P<root>launchpad.net/([A-Za-z0-9-._]+)(/[A-Za-z0-9-._]+)?)(/.+)?`)
	//glpRegex = regexp.MustCompile(`^(?P<root>git\.launchpad\.net/(([A-Za-z0-9_.\-]+)|~[A-Za-z0-9_.\-]+/(\+git|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))$`)
	//gcRegex      = regexp.MustCompile(`^(?P<root>code\.google\.com/[pr]/(?P<project>[a-z0-9\-]+)(\.(?P<subrepo>[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`)
	jazzRegex    = regexp.MustCompile(`^(?P<root>hub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`)
	apacheRegex  = regexp.MustCompile(`^(?P<root>git.apache.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`)
	genericRegex = regexp.MustCompile(`^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/~]*?)\.(?P<vcs>bzr|git|hg|svn))([/A-Za-z0-9_.\-]+)*$`)
)

// Other helper regexes
var (
	scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
	pathvld     = regexp.MustCompile(`^([A-Za-z0-9-]+)(\.[A-Za-z0-9-]+)+(/[A-Za-z0-9-_.~]+)*$`)
)

// deduceRemoteRepo takes a potential import path and returns a RemoteRepo
// representing the remote location of the source of an import path. Remote
// repositories can be bare import paths, or urls including a checkout scheme.
func deduceRemoteRepo(path string) (rr remoteRepo, err error) {
	if m := scpSyntaxRe.FindStringSubmatch(path); m != nil {
		// Match SCP-like syntax and convert it to a URL.
		// Eg, "git@github.com:user/repo" becomes
		// "ssh://git@github.com/user/repo".
		rr.CloneURL = &url.URL{
			Scheme:  "ssh",
			User:    url.User(m[1]),
			Host:    m[2],
			RawPath: m[3],
		}
	} else {
		rr.CloneURL, err = url.Parse(path)
		if err != nil {
			return remoteRepo{}, fmt.Errorf("%q is not a valid import path", path)
		}
	}

	path = rr.CloneURL.Host + rr.CloneURL.Path
	if !pathvld.MatchString(path) {
		return remoteRepo{}, fmt.Errorf("%q is not a valid import path", path)
	}

	if rr.CloneURL.Scheme != "" {
		rr.Schemes = []string{rr.CloneURL.Scheme}
	}

	switch {
	case ghRegex.MatchString(path):
		v := ghRegex.FindStringSubmatch(path)

		rr.CloneURL.Host = "github.com"
		rr.CloneURL.Path = v[2]
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[3], "/")
		rr.VCS = []string{"git"}

		return

	case gpinNewRegex.MatchString(path):
		v := gpinNewRegex.FindStringSubmatch(path)

		// Duplicate some logic from the gopkg.in server in order to validate
		// the import path string without having to hit the server
		if strings.Contains(v[4], ".") {
			return remoteRepo{}, fmt.Errorf("%q is not a valid import path; gopkg.in only allows major versions (%q instead of %q)",
				path, v[4][:strings.Index(v[4], ".")], v[4])
		}

		// If the third position is empty, it's the shortened form that expands
		// to the go-pkg github user
		if v[3] != "" {
			rr.CloneURL.Path = "go-pkg/" + v[4]
		} else {
			rr.CloneURL.Path = v[2] + v[4]
		}
		rr.CloneURL.Host = "github.com"
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[6], "/")
		rr.VCS = []string{"git"}

		return
	//case gpinOldRegex.MatchString(path):

	case bbRegex.MatchString(path):
		v := bbRegex.FindStringSubmatch(path)

		rr.CloneURL.Host = "bitbucket.org"
		rr.CloneURL.Path = v[2]
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[5], "/")
		rr.VCS = []string{"git", "hg"}

		return

	//case gcRegex.MatchString(path):
	//v := gcRegex.FindStringSubmatch(path)

	//rr.CloneURL.Host = "code.google.com"
	//rr.CloneURL.Path = "p/" + v[2]
	//rr.Base = v[1]
	//rr.RelPkg = strings.TrimPrefix(v[5], "/")
	//rr.VCS = []string{"hg", "git"}

	//return

	case lpRegex.MatchString(path):
		v := lpRegex.FindStringSubmatch(path)
		v = append(v, "", "")

		rr.CloneURL.Host = "launchpad.net"
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[4], "/")
		rr.VCS = []string{"bzr"}

		if v[3] == "" {
			// launchpad.net/project"
			rr.Base = fmt.Sprintf("https://launchpad.net/%v", v[2])
		} else {
			// launchpad.net/project/series"
			rr.Base = fmt.Sprintf("https://launchpad.net/%s/%s", v[2], v[3])
		}
		return

	case jazzRegex.MatchString(path):
		v := jazzRegex.FindStringSubmatch(path)

		rr.CloneURL.Host = "hub.jazz.net"
		rr.CloneURL.Path = "git" + v[2]
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[2], "/")
		rr.VCS = []string{"git"}

		return

	case apacheRegex.MatchString(path):
		v := apacheRegex.FindStringSubmatch(path)

		rr.CloneURL.Host = "git.apache.org"
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[2], "/")
		rr.VCS = []string{"git"}

		return

	//case glpRegex.MatchString(path):
	//// TODO too many rules for this, commenting out for now
	//v := lpRegex.FindStringSubmatch(path)

	//rr.CloneURL.Host = "launchpad.net"
	//rr.RelPkg = strings.TrimPrefix(v[3], "/")
	//rr.VCS = []string{"git"}

	//v = append(v, "", "")
	//if v[2] == "" {
	//// launchpad.net/project"
	//rr.Base = fmt.Sprintf("https://launchpad.net/%v", v[1])
	//} else {
	//// launchpad.net/project/series"
	//rr.Base = fmt.Sprintf("https://launchpad.net/%s/%s", v[1], v[2])
	//}
	//return

	// try the general syntax
	case genericRegex.MatchString(path):
		v := genericRegex.FindStringSubmatch(path)
		switch v[5] {
		case "git", "hg", "bzr":
			x := strings.SplitN(v[1], "/", 2)
			// TODO is this actually correct for bzr?
			rr.CloneURL.Host = x[0]
			rr.CloneURL.Path = x[1]
			rr.VCS = []string{v[5]}
			rr.Base = v[1]
			rr.RelPkg = strings.TrimPrefix(v[6], "/")
			return
		default:
			return remoteRepo{}, fmt.Errorf("unknown repository type: %q", v[5])
		}
	}

	// TODO use HTTP metadata to resolve vanity imports
	return remoteRepo{}, fmt.Errorf("unable to deduct repository and source type for: %q", path)
}
<commit_msg>Return pointer type from deduceRemoteRepo()<commit_after>package vsolver

import (
	"fmt"
	"net/url"
	"regexp"
	"strings"
)

// A remoteRepo represents a potential remote repository resource.
//
// RemoteRepos are based purely on lexical analysis; successfully constructing
// one is not a guarantee that the resource it identifies actually exists or is
// accessible.
type remoteRepo struct {
	Base     string
	RelPkg   string
	CloneURL *url.URL
	Schemes  []string
	VCS      []string
}

//type remoteResult struct {
//r   remoteRepo
//err error
//}

// TODO sync access to this map
//var remoteCache = make(map[string]remoteResult)

// Regexes for the different known import path flavors
var (
	ghRegex      = regexp.MustCompile(`^(?P<root>github\.com/([A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`)
	gpinNewRegex = regexp.MustCompile(`^(?P<root>gopkg\.in/(?:([a-zA-Z0-9][-a-zA-Z0-9]+)/)?([a-zA-Z][-.a-zA-Z0-9]*)\.((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2}(-unstable)?)(?:\.git))?((?:/[a-zA-Z0-9][-.a-zA-Z0-9]*)*)$`)
	//gpinOldRegex = regexp.MustCompile(`^(?P<root>gopkg\.in/(?:([a-z0-9][-a-z0-9]+)/)?((?:v0|v[1-9][0-9]*)(?:\.0|\.[1-9][0-9]*){0,2}(-unstable)?))/([a-zA-Z][-a-zA-Z0-9]*)(?:\.git)?((?:/[a-zA-Z][-a-zA-Z0-9]*)*)$`)
	bbRegex = regexp.MustCompile(`^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`)
	lpRegex = regexp.MustCompile(`^(?P<root>launchpad.net/([A-Za-z0-9-._]+)(/[A-Za-z0-9-._]+)?)(/.+)?`)
	//glpRegex = regexp.MustCompile(`^(?P<root>git\.launchpad\.net/(([A-Za-z0-9_.\-]+)|~[A-Za-z0-9_.\-]+/(\+git|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))$`)
	//gcRegex      = regexp.MustCompile(`^(?P<root>code\.google\.com/[pr]/(?P<project>[a-z0-9\-]+)(\.(?P<subrepo>[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`)
	jazzRegex    = regexp.MustCompile(`^(?P<root>hub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`)
	apacheRegex  = regexp.MustCompile(`^(?P<root>git.apache.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`)
	genericRegex = regexp.MustCompile(`^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/~]*?)\.(?P<vcs>bzr|git|hg|svn))([/A-Za-z0-9_.\-]+)*$`)
)

// Other helper regexes
var (
	scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
	pathvld     = regexp.MustCompile(`^([A-Za-z0-9-]+)(\.[A-Za-z0-9-]+)+(/[A-Za-z0-9-_.~]+)*$`)
)

// deduceRemoteRepo takes a potential import path and returns a RemoteRepo
// representing the remote location of the source of an import path. Remote
// repositories can be bare import paths, or urls including a checkout scheme.
func deduceRemoteRepo(path string) (rr *remoteRepo, err error) {
	rr = &remoteRepo{}
	if m := scpSyntaxRe.FindStringSubmatch(path); m != nil {
		// Match SCP-like syntax and convert it to a URL.
		// Eg, "git@github.com:user/repo" becomes
		// "ssh://git@github.com/user/repo".
		rr.CloneURL = &url.URL{
			Scheme:  "ssh",
			User:    url.User(m[1]),
			Host:    m[2],
			RawPath: m[3],
		}
	} else {
		rr.CloneURL, err = url.Parse(path)
		if err != nil {
			return nil, fmt.Errorf("%q is not a valid import path", path)
		}
	}

	path = rr.CloneURL.Host + rr.CloneURL.Path
	if !pathvld.MatchString(path) {
		return nil, fmt.Errorf("%q is not a valid import path", path)
	}

	if rr.CloneURL.Scheme != "" {
		rr.Schemes = []string{rr.CloneURL.Scheme}
	}

	switch {
	case ghRegex.MatchString(path):
		v := ghRegex.FindStringSubmatch(path)

		rr.CloneURL.Host = "github.com"
		rr.CloneURL.Path = v[2]
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[3], "/")
		rr.VCS = []string{"git"}

		return

	case gpinNewRegex.MatchString(path):
		v := gpinNewRegex.FindStringSubmatch(path)

		// Duplicate some logic from the gopkg.in server in order to validate
		// the import path string without having to hit the server
		if strings.Contains(v[4], ".") {
			return nil, fmt.Errorf("%q is not a valid import path; gopkg.in only allows major versions (%q instead of %q)",
				path, v[4][:strings.Index(v[4], ".")], v[4])
		}

		// If the third position is empty, it's the shortened form that expands
		// to the go-pkg github user
		if v[3] != "" {
			rr.CloneURL.Path = "go-pkg/" + v[4]
		} else {
			rr.CloneURL.Path = v[2] + v[4]
		}
		rr.CloneURL.Host = "github.com"
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[6], "/")
		rr.VCS = []string{"git"}

		return
	//case gpinOldRegex.MatchString(path):

	case bbRegex.MatchString(path):
		v := bbRegex.FindStringSubmatch(path)

		rr.CloneURL.Host = "bitbucket.org"
		rr.CloneURL.Path = v[2]
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[5], "/")
		rr.VCS = []string{"git", "hg"}

		return

	//case gcRegex.MatchString(path):
	//v := gcRegex.FindStringSubmatch(path)

	//rr.CloneURL.Host = "code.google.com"
	//rr.CloneURL.Path = "p/" + v[2]
	//rr.Base = v[1]
	//rr.RelPkg = strings.TrimPrefix(v[5], "/")
	//rr.VCS = []string{"hg", "git"}

	//return

	case lpRegex.MatchString(path):
		v := lpRegex.FindStringSubmatch(path)
		v = append(v, "", "")

		rr.CloneURL.Host = "launchpad.net"
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[4], "/")
		rr.VCS = []string{"bzr"}

		if v[3] == "" {
			// launchpad.net/project"
			rr.Base = fmt.Sprintf("https://launchpad.net/%v", v[2])
		} else {
			// launchpad.net/project/series"
			rr.Base = fmt.Sprintf("https://launchpad.net/%s/%s", v[2], v[3])
		}
		return

	case jazzRegex.MatchString(path):
		v := jazzRegex.FindStringSubmatch(path)

		rr.CloneURL.Host = "hub.jazz.net"
		rr.CloneURL.Path = "git" + v[2]
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[2], "/")
		rr.VCS = []string{"git"}

		return

	case apacheRegex.MatchString(path):
		v := apacheRegex.FindStringSubmatch(path)

		rr.CloneURL.Host = "git.apache.org"
		rr.Base = v[1]
		rr.RelPkg = strings.TrimPrefix(v[2], "/")
		rr.VCS = []string{"git"}

		return

	//case glpRegex.MatchString(path):
	//// TODO too many rules for this, commenting out for now
	//v := lpRegex.FindStringSubmatch(path)

	//rr.CloneURL.Host = "launchpad.net"
	//rr.RelPkg = strings.TrimPrefix(v[3], "/")
	//rr.VCS = []string{"git"}

	//v = append(v, "", "")
	//if v[2] == "" {
	//// launchpad.net/project"
	//rr.Base = fmt.Sprintf("https://launchpad.net/%v", v[1])
	//} else {
	//// launchpad.net/project/series"
	//rr.Base = fmt.Sprintf("https://launchpad.net/%s/%s", v[1], v[2])
	//}
	//return

	// try the general syntax
	case genericRegex.MatchString(path):
		v := genericRegex.FindStringSubmatch(path)
		switch v[5] {
		case "git", "hg", "bzr":
			x := strings.SplitN(v[1], "/", 2)
			// TODO is this actually correct for bzr?
			rr.CloneURL.Host = x[0]
			rr.CloneURL.Path = x[1]
			rr.VCS = []string{v[5]}
			rr.Base = v[1]
			rr.RelPkg = strings.TrimPrefix(v[6], "/")
			return
		default:
			return nil, fmt.Errorf("unknown repository type: %q", v[5])
		}
	}

	// TODO use HTTP metadata to resolve vanity imports
	return nil, fmt.Errorf("unable to deduct repository and source type for: %q", path)
}
<|endoftext|>


<commit_before>package widget

import (
	"bytes"
	"errors"
	"fmt"
	"html/template"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/qor/qor/utils"
)

// Render find widget by name, render it based on current context
func (widgets *Widgets) Render(widgetName string, context *Context, availableWidgets ...string) template.HTML {
	if context == nil {
		context = NewContext(map[string]interface{}{})
	}

	if len(availableWidgets) == 0 {
		availableWidgets = append(availableWidgets, widgetName)
	}

	var (
		setting      = findSettingByNameAndKinds(widgets.Config.DB, widgetName, availableWidgets)
		widgetObj    = GetWidget(setting.Kind)
		settingValue = setting.GetSerializableArgument(setting)
		newContext   = widgetObj.Context(context, settingValue)
		url          = widgets.settingEditURL(setting)
		prefix       = widgets.Resource.GetAdmin().GetRouter().Prefix
	)

	return template.HTML(fmt.Sprintf("
\n%v\n
", prefix, prefix, utils.ToParamString(widgetObj.Name), "/admin/widgets/frontend-edit", url, widgetObj.Render(newContext, url)))
}

func (widgets *Widgets) settingEditURL(setting *QorWidgetSetting) string {
	prefix := widgets.WidgetSettingResource.GetAdmin().GetRouter().Prefix
	return fmt.Sprintf("%v/%v/%v/edit", prefix, widgets.WidgetSettingResource.ToParam(), setting.ID)
}

// FuncMap return view functions map
func (widgets *Widgets) FuncMap() template.FuncMap {
	funcMap := template.FuncMap{}

	funcMap["render_widget"] = func(key string, context *Context, availableWidgets ...string) template.HTML {
		return widgets.Render(key, context, availableWidgets...)
	}

	return funcMap
}

// Render register widget itself content
func (w *Widget) Render(context *Context, url string) template.HTML {
	var err error
	var result = bytes.NewBufferString("")
	file := w.Template

	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("Get error when render file %v: %v", file, r)
			utils.ExitWithMsg(err)
		}
	}()

	if file, err = w.findTemplate(file + ".tmpl"); err == nil {
		if tmpl, err := template.New(filepath.Base(file)).ParseFiles(file); err == nil {
			if err = tmpl.Execute(result, context.Options); err == nil {
				return template.HTML(result.String())
			}
		}
	}

	return template.HTML(err.Error())
}

// RegisterViewPath register views directory
func (widgets *Widgets) RegisterViewPath(p string) {
	for _, gopath := range strings.Split(os.Getenv("GOPATH"), ":") {
		if registerViewPath(path.Join(gopath, "src", p)) == nil {
			return
		}
	}
}

func isExistingDir(pth string) bool {
	fi, err := os.Stat(pth)
	if err != nil {
		return false
	}
	return fi.Mode().IsDir()
}

func registerViewPath(path string) error {
	if isExistingDir(path) {
		var found bool

		for _, viewPath := range viewPaths {
			if path == viewPath {
				found = true
				break
			}
		}

		if !found {
			viewPaths = append(viewPaths, path)
		}
		return nil
	}
	return errors.New("path not found")
}

func (w *Widget) findTemplate(layouts ...string) (string, error) {
	for _, layout := range layouts {
		for _, p := range viewPaths {
			if _, err := os.Stat(filepath.Join(p, layout)); !os.IsNotExist(err) {
				return filepath.Join(p, layout), nil
			}
		}
	}
	return "", fmt.Errorf("template not found: %v", layouts)
}
<commit_msg>Fix hard coded dependency<commit_after>package widget

import (
	"bytes"
	"errors"
	"fmt"
	"html/template"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/qor/qor/utils"
)

// Render find widget by name, render it based on current context
func (widgets *Widgets) Render(widgetName string, context *Context, availableWidgets ...string) template.HTML {
	if context == nil {
		context = NewContext(map[string]interface{}{})
	}

	if len(availableWidgets) == 0 {
		availableWidgets = append(availableWidgets, widgetName)
	}

	var (
		setting      = findSettingByNameAndKinds(widgets.Config.DB, widgetName, availableWidgets)
		widgetObj    = GetWidget(setting.Kind)
		settingValue = setting.GetSerializableArgument(setting)
		newContext   = widgetObj.Context(context, settingValue)
		url          = widgets.settingEditURL(setting)
		prefix       = widgets.Resource.GetAdmin().GetRouter().Prefix
	)

	return template.HTML(fmt.Sprintf(
		"
\n%v\n
",
		prefix,
		prefix,
		utils.ToParamString(widgetObj.Name),
		fmt.Sprintf("%v/%v/frontend-edit", prefix, widgets.Resource.ToParam()),
		url,
		widgetObj.Render(newContext, url),
	))
}

func (widgets *Widgets) settingEditURL(setting *QorWidgetSetting) string {
	prefix := widgets.WidgetSettingResource.GetAdmin().GetRouter().Prefix
	return fmt.Sprintf("%v/%v/%v/edit", prefix, widgets.WidgetSettingResource.ToParam(), setting.ID)
}

// FuncMap return view functions map
func (widgets *Widgets) FuncMap() template.FuncMap {
	funcMap := template.FuncMap{}

	funcMap["render_widget"] = func(key string, context *Context, availableWidgets ...string) template.HTML {
		return widgets.Render(key, context, availableWidgets...)
	}

	return funcMap
}

// Render register widget itself content
func (w *Widget) Render(context *Context, url string) template.HTML {
	var err error
	var result = bytes.NewBufferString("")
	file := w.Template

	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("Get error when render file %v: %v", file, r)
			utils.ExitWithMsg(err)
		}
	}()

	if file, err = w.findTemplate(file + ".tmpl"); err == nil {
		if tmpl, err := template.New(filepath.Base(file)).ParseFiles(file); err == nil {
			if err = tmpl.Execute(result, context.Options); err == nil {
				return template.HTML(result.String())
			}
		}
	}

	return template.HTML(err.Error())
}

// RegisterViewPath register views directory
func (widgets *Widgets) RegisterViewPath(p string) {
	for _, gopath := range strings.Split(os.Getenv("GOPATH"), ":") {
		if registerViewPath(path.Join(gopath, "src", p)) == nil {
			return
		}
	}
}

func isExistingDir(pth string) bool {
	fi, err := os.Stat(pth)
	if err != nil {
		return false
	}
	return fi.Mode().IsDir()
}

func registerViewPath(path string) error {
	if isExistingDir(path) {
		var found bool

		for _, viewPath := range viewPaths {
			if path == viewPath {
				found = true
				break
			}
		}

		if !found {
			viewPaths = append(viewPaths, path)
		}
		return nil
	}
	return errors.New("path not found")
}

func (w *Widget) findTemplate(layouts ...string) (string, error) {
	for _, layout := range layouts {
		for _, p := range viewPaths {
			if _, err := os.Stat(filepath.Join(p, layout)); !os.IsNotExist(err) {
				return filepath.Join(p, layout), nil
			}
		}
	}
	return "", fmt.Errorf("template not found: %v", layouts)
}
<|endoftext|>


<commit_before>package core

import (
	"fmt"
	"bytes"
	"github.com/fire/go-ogre3d"
	"github.com/jmckaskill/go-capnproto"
)

type RenderState struct {
	mouseControl bool
	headNode     ogre.SceneNode
	//rotationVectorObj ogre.ManualObject
	rotationVectorNode ogre.SceneNode
}

func parseRenderState(rs *RenderState, srs *SharedRenderState, b *[]byte) {
	var buf bytes.Buffer
	r := bytes.NewReader(*b)
	s, err := capn.ReadFromPackedStream(r, &buf)
	if err != nil {
		fmt.Printf("Read error %v\n", err)
		return
	}
        state := ReadRootRenderStateMsg(s)
	if state.HeadTrigger() {
		if state.FreeSpin() == false {
			rs.mouseControl = false
			rs.rotationVectorNode.SetVisible(false)
		}
		if state.FreeSpin() {
			rs.mouseControl = true
			// Note: Uncomment to visualize the rotation vector
			rs.rotationVectorNode.SetVisible(true)
		}
		// Resume updating render state on next loop
		return
	}

	renderState := ReadRootEmittedRenderState(s)
	srs.gameTime = renderState.Time()
	srs.position.SetX(renderState.Position().X())
	srs.position.SetY(renderState.Position().Y())
	srs.orientation = ogre.CreateQuaternionFromValues(renderState.Orientation().W(), renderState.Orientation().X(), renderState.Orientation().Y(), renderState.Orientation().Z())
	srs.position.SetZ(0.0)
}

func renderInit(params *RenderThreadParams, rs *RenderState, srs *SharedRenderState) {
	fmt.Printf("Render Init:\n")
	rs.mouseControl = false

	mgr := ogre.GetResourceGroupManager()

	mgr.AddResourceLocation("media/models", "FileSystem", "General");
	mgr.AddResourceLocation("media/materials/scripts", "FileSystem", "General")
	mgr.AddResourceLocation("media/materials/textures", "FileSystem", "General")
	mgr.AddResourceLocation("media/materials/programs", "FileSystem", "General")

	mgr.InitialiseAllResourceGroups()

	scene := params.root.CreateSceneManager("ST_GENERIC", "SimpleStaticCheck")
	scene.SetAmbientLight(0.5, 0.5, 0.5)
	head := scene.CreateEntity("head", "ogre.mesh", "head_group")
	rootNode := scene.GetRootSceneNode()
	zero := ogre.CreateVector3()
	zero.Zero()
	rs.headNode = rootNode.CreateChildSceneNode("head_node", zero , ogre.CreateQuaternion())
	//rs.headNode.AttachObject(head)
	light := scene.CreateLight("light")
	light.SetPosition(20.0, 80.0, 50.0)
	cam := scene.CreateCamera("cam")
	cam.SetPosition(0,0,90)
	cam.LookAt(0,0,-300)
	cam.SetNearClipDistance(5)

	viewport := params.ogreWindow.AddViewport(cam)
	viewport.SetBackgroundColour(0, 0, 0, 0)

	cam.SetAspectRatio(viewport.GetActualWidth(), viewport.GetActualHeight())

	//rs.rotationVectorObj := scene.CreateManualObject("rotation_vector")
	//rs.rotationVectorObj.SetDynamic(true)
	//rs.rotatiobVectorObj.Begin("BaseWhiteNoLighting", ogre.OT_LINE_LIST)
	//rs.rotationVectorObj.Position(0.0, 0.0, 0.0)
	//rs.rotationVectorObj.Position(0.0, 0.0, 0.0)
	//rs.rotationVectorObj.Position(0.0, 0.0, 0.0)
	//rs.rotationVectorObj.End()
	//rs.rotationVectorNode := scene.GetSceneNode.CreateChildSceneNode("rotation_vector_node)
	//rs.rotationVectorNode.AttachObject(rs.rotationVectorObj)
	//rs.rotationVectorNode.SetVisible(false)
}

func interpolateAndRender(rsockets *RenderThreadSockets, rs *RenderState,
	ratio float32, previousRender *SharedRenderState, nextRender *SharedRenderState) {
	temp := previousRender.position.MultiplyScalar(1.0 - ratio)
	interpPosition := temp.AddVector3(nextRender.position.MultiplyScalar(ratio))
	rs.headNode.SetPosition(interpPosition.X(), interpPosition.Y(), interpPosition.Z())
	if rs.mouseControl {
		t := capn.NewBuffer(nil)
		inputMouse := NewRootState(t)
		inputMouse.SetMouse(true)
		buf := bytes.Buffer{}
		t.WriteToPacked(&buf)
		rsockets.inputPush.Send(buf.Bytes(), 0)
		fmt.Printf("Render mouse_state requested\n")

		b, err := rsockets.inputMouseSub.Recv(0)
		if err != nil {
			fmt.Printf("%s\n", err)
		}
		b = bytes.TrimPrefix(b, []byte("input.mouse:"))
		var bBuf bytes.Buffer
		bBuf.Read(b)
		r := bytes.NewReader(b)
		fmt.Printf("Bytestring START%sEND\n", bBuf.String())
		var rBuf bytes.Buffer
		s, err := capn.ReadFromPackedStream(r, &rBuf)
		if err != nil {
			fmt.Printf("Read error %v\n", err)
			return
		}
		fmt.Printf("Render mouse_state received\n")
		input := ReadRootInputMouse(s)
		orientation := ogre.CreateQuaternionFromValues(input.W(), input.X(), input.Y(), input.Z())
		// Use latest mouse data to orient the head.
		//rs.headNode.SetOrientation(orientation)
		// Update the rotation axis of the head (smoothed over a few frames in the game thread)
		/*rs.rotationVectorObj.BeginUpdate(0)
		rs.rotationVectorObj.Position(interpPosition)
		temp := previousRender.smoothedAngular.MultiplyScalar(1.0 - ratio)
		interpSmoothedAngular := temp.AddVector3(nextRender.smoothedAngular.AddScalar(ratio))
		rotationVectorEnd := interpPosition.AddVector3(interpSmoothedAngular.MultiplyScalar(40.0))
		rotationVectorObj.Position(RotationVectorEnd)
		rs.rotationVectorObj.End()
                */
	} else {
		//rs.headNode.SetOrientation(ogre.Quaternion.Slerp(ratio, previousRender.orientation, nextRender.orientation))
	}
}
<commit_msg>Make attachobject work.<commit_after>package core

import (
	"fmt"
	"bytes"
	"github.com/fire/go-ogre3d"
	"github.com/jmckaskill/go-capnproto"
)

type RenderState struct {
	mouseControl bool
	headNode     ogre.SceneNode
	//rotationVectorObj ogre.ManualObject
	rotationVectorNode ogre.SceneNode
}

func parseRenderState(rs *RenderState, srs *SharedRenderState, b *[]byte) {
	var buf bytes.Buffer
	r := bytes.NewReader(*b)
	s, err := capn.ReadFromPackedStream(r, &buf)
	if err != nil {
		fmt.Printf("Read error %v\n", err)
		return
	}
        state := ReadRootRenderStateMsg(s)
	if state.HeadTrigger() {
		if state.FreeSpin() == false {
			rs.mouseControl = false
			rs.rotationVectorNode.SetVisible(false)
		}
		if state.FreeSpin() {
			rs.mouseControl = true
			// Note: Uncomment to visualize the rotation vector
			rs.rotationVectorNode.SetVisible(true)
		}
		// Resume updating render state on next loop
		return
	}

	renderState := ReadRootEmittedRenderState(s)
	srs.gameTime = renderState.Time()
	srs.position.SetX(renderState.Position().X())
	srs.position.SetY(renderState.Position().Y())
	srs.orientation = ogre.CreateQuaternionFromValues(renderState.Orientation().W(), renderState.Orientation().X(), renderState.Orientation().Y(), renderState.Orientation().Z())
	srs.position.SetZ(0.0)
}

func renderInit(params *RenderThreadParams, rs *RenderState, srs *SharedRenderState) {
	fmt.Printf("Render Init:\n")
	rs.mouseControl = false

	mgr := ogre.GetResourceGroupManager()

	mgr.AddResourceLocation("media/models", "FileSystem", "General");
	mgr.AddResourceLocation("media/materials/scripts", "FileSystem", "General")
	mgr.AddResourceLocation("media/materials/textures", "FileSystem", "General")
	mgr.AddResourceLocation("media/materials/programs", "FileSystem", "General")

	mgr.InitialiseAllResourceGroups()

	scene := params.root.CreateSceneManager("ST_GENERIC", "SimpleStaticCheck")
	scene.SetAmbientLight(0.5, 0.5, 0.5)
	head := scene.CreateEntity("head", "ogre.mesh", "head_group")
	rootNode := scene.GetRootSceneNode()
	zero := ogre.CreateVector3()
	zero.Zero()
	rs.headNode = rootNode.CreateChildSceneNode("head_node", zero , ogre.CreateQuaternion())
	rs.headNode.AttachObject(ogre.GetEntityBase(head))
	light := scene.CreateLight("light")
	light.SetPosition(20.0, 80.0, 50.0)
	cam := scene.CreateCamera("cam")
	cam.SetPosition(0,0,90)
	cam.LookAt(0,0,-300)
	cam.SetNearClipDistance(5)

	viewport := params.ogreWindow.AddViewport(cam)
	viewport.SetBackgroundColour(0, 0, 0, 0)

	cam.SetAspectRatio(viewport.GetActualWidth(), viewport.GetActualHeight())

	//rs.rotationVectorObj := scene.CreateManualObject("rotation_vector")
	//rs.rotationVectorObj.SetDynamic(true)
	//rs.rotatiobVectorObj.Begin("BaseWhiteNoLighting", ogre.OT_LINE_LIST)
	//rs.rotationVectorObj.Position(0.0, 0.0, 0.0)
	//rs.rotationVectorObj.Position(0.0, 0.0, 0.0)
	//rs.rotationVectorObj.Position(0.0, 0.0, 0.0)
	//rs.rotationVectorObj.End()
	//rs.rotationVectorNode := scene.GetSceneNode.CreateChildSceneNode("rotation_vector_node)
	//rs.rotationVectorNode.AttachObject(rs.rotationVectorObj)
	//rs.rotationVectorNode.SetVisible(false)
}

func interpolateAndRender(rsockets *RenderThreadSockets, rs *RenderState,
	ratio float32, previousRender *SharedRenderState, nextRender *SharedRenderState) {
	temp := previousRender.position.MultiplyScalar(1.0 - ratio)
	interpPosition := temp.AddVector3(nextRender.position.MultiplyScalar(ratio))
	rs.headNode.SetPosition(interpPosition.X(), interpPosition.Y(), interpPosition.Z())
	if rs.mouseControl {
		t := capn.NewBuffer(nil)
		inputMouse := NewRootState(t)
		inputMouse.SetMouse(true)
		buf := bytes.Buffer{}
		t.WriteToPacked(&buf)
		rsockets.inputPush.Send(buf.Bytes(), 0)
		fmt.Printf("Render mouse_state requested\n")

		b, err := rsockets.inputMouseSub.Recv(0)
		if err != nil {
			fmt.Printf("%s\n", err)
		}
		b = bytes.TrimPrefix(b, []byte("input.mouse:"))
		var bBuf bytes.Buffer
		bBuf.Read(b)
		r := bytes.NewReader(b)
		fmt.Printf("Bytestring START%sEND\n", bBuf.String())
		var rBuf bytes.Buffer
		s, err := capn.ReadFromPackedStream(r, &rBuf)
		if err != nil {
			fmt.Printf("Read error %v\n", err)
			return
		}
		fmt.Printf("Render mouse_state received\n")
		input := ReadRootInputMouse(s)
		orientation := ogre.CreateQuaternionFromValues(input.W(), input.X(), input.Y(), input.Z())
		// Use latest mouse data to orient the head.
		//rs.headNode.SetOrientation(orientation)
		// Update the rotation axis of the head (smoothed over a few frames in the game thread)
		/*rs.rotationVectorObj.BeginUpdate(0)
		rs.rotationVectorObj.Position(interpPosition)
		temp := previousRender.smoothedAngular.MultiplyScalar(1.0 - ratio)
		interpSmoothedAngular := temp.AddVector3(nextRender.smoothedAngular.AddScalar(ratio))
		rotationVectorEnd := interpPosition.AddVector3(interpSmoothedAngular.MultiplyScalar(40.0))
		rotationVectorObj.Position(RotationVectorEnd)
		rs.rotationVectorObj.End()
                */
	} else {
		//rs.headNode.SetOrientation(ogre.Quaternion.Slerp(ratio, previousRender.orientation, nextRender.orientation))
	}
}
<|endoftext|>


<commit_before>package qshell

import (
	"bufio"
	"fmt"
	"github.com/qiniu/log"
	"os"
	"path/filepath"
	"strings"
	"time"
)

type DirCache struct {
}

func (this *DirCache) Cache(cacheRootPath string, cacheResultFile string) (fileCount int) {
	if _, err := os.Stat(cacheResultFile); err != nil {
		log.Debug(fmt.Sprintf("No cache file `%s' found, will create one", cacheResultFile))
	} else {
		if rErr := os.Rename(cacheResultFile, cacheResultFile+".old"); rErr != nil {
			log.Error(fmt.Sprintf("Unable to rename cache file, plz manually delete `%s' and `%s.old'",
				cacheResultFile, cacheResultFile))
			return
		}
	}
	cacheResultFileH, err := os.OpenFile(cacheResultFile, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Error(fmt.Sprintf("Failed to open cache file `%s'", cacheResultFile))
		return
	}
	defer cacheResultFileH.Close()
	bWriter := bufio.NewWriter(cacheResultFileH)
	walkStart := time.Now()
	log.Debug(fmt.Sprintf("Walk `%s' start from `%s'", cacheRootPath, walkStart.String()))
	log.Debug(fmt.Sprintf("Save dir cache result to `%s' and may take some time...", cacheResultFile))
	filepath.Walk(cacheRootPath, func(path string, fi os.FileInfo, err error) error {
		var retErr error
		log.Debug(fmt.Sprintf("Walking through `%s'", cacheRootPath))
		if !fi.IsDir() {
			relPath := strings.TrimPrefix(strings.TrimPrefix(path, cacheRootPath), string(os.PathSeparator))
			fsize := fi.Size()
			//Unit is 100ns
			flmd := fi.ModTime().UnixNano() / 100
			log.Debug(fmt.Sprintf("Hit file `%s' size: `%d' mode time: `%d`", relPath, fsize, flmd))
			fmeta := fmt.Sprintln(fmt.Sprintf("%s\t%d\t%d", relPath, fsize, flmd))
			if _, err := bWriter.WriteString(fmeta); err != nil {
				log.Error(fmt.Sprintf("Failed to write data `%s' to cache file", fmeta))
				retErr = err
			}
			fileCount += 1
		}
		return retErr
	})
	if err := bWriter.Flush(); err != nil {
		log.Error(fmt.Sprintf("Failed to flush to cache file `%s'", cacheResultFile))
	}

	walkEnd := time.Now()
	log.Debug(fmt.Sprintf("Walk `%s' end at `%s'", cacheRootPath, walkEnd.String()))
	log.Debug(fmt.Sprintf("Walk `%s' last for `%s'", cacheRootPath, time.Since(walkStart)))
	return
}
<commit_msg>Fix bug under windows. To auto delete the old cache file.<commit_after>package qshell

import (
	"bufio"
	"fmt"
	"github.com/qiniu/log"
	"os"
	"path/filepath"
	"strings"
	"time"
)

type DirCache struct {
}

func (this *DirCache) Cache(cacheRootPath string, cacheResultFile string) (fileCount int) {
	if _, err := os.Stat(cacheResultFile); err != nil {
		log.Debug(fmt.Sprintf("No cache file `%s' found, will create one", cacheResultFile))
	} else {
		os.Remove(cacheResultFile+".old")
		if rErr := os.Rename(cacheResultFile, cacheResultFile+".old"); rErr != nil {
			log.Error(fmt.Sprintf("Unable to rename cache file, plz manually delete `%s' and `%s.old'",
				cacheResultFile, cacheResultFile))
			log.Error(rErr)
			return
		}
	}
	cacheResultFileH, err := os.OpenFile(cacheResultFile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
	if err != nil {
		log.Error(fmt.Sprintf("Failed to open cache file `%s'", cacheResultFile))
		return
	}
	defer cacheResultFileH.Close()
	bWriter := bufio.NewWriter(cacheResultFileH)
	walkStart := time.Now()
	log.Debug(fmt.Sprintf("Walk `%s' start from `%s'", cacheRootPath, walkStart.String()))
	log.Debug(fmt.Sprintf("Save dir cache result to `%s' and may take some time...", cacheResultFile))
	filepath.Walk(cacheRootPath, func(path string, fi os.FileInfo, err error) error {
		var retErr error
		log.Debug(fmt.Sprintf("Walking through `%s'", cacheRootPath))
		if !fi.IsDir() {
			relPath := strings.TrimPrefix(strings.TrimPrefix(path, cacheRootPath), string(os.PathSeparator))
			fsize := fi.Size()
			//Unit is 100ns
			flmd := fi.ModTime().UnixNano() / 100
			log.Debug(fmt.Sprintf("Hit file `%s' size: `%d' mode time: `%d`", relPath, fsize, flmd))
			fmeta := fmt.Sprintln(fmt.Sprintf("%s\t%d\t%d", relPath, fsize, flmd))
			if _, err := bWriter.WriteString(fmeta); err != nil {
				log.Error(fmt.Sprintf("Failed to write data `%s' to cache file", fmeta))
				retErr = err
			}
			fileCount += 1
		}
		return retErr
	})
	if err := bWriter.Flush(); err != nil {
		log.Error(fmt.Sprintf("Failed to flush to cache file `%s'", cacheResultFile))
	}

	walkEnd := time.Now()
	log.Debug(fmt.Sprintf("Walk `%s' end at `%s'", cacheRootPath, walkEnd.String()))
	log.Debug(fmt.Sprintf("Walk `%s' last for `%s'", cacheRootPath, time.Since(walkStart)))
	return
}
<|endoftext|>


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

// Package httprouter is a trie based high performance HTTP request router.
//
// A trivial example server is:
//
//  package main
//
//  import (
//      "fmt"
//      "github.com/julienschmidt/httprouter"
//      "net/http"
//      "log"
//  )
//
//  func Index(w http.ResponseWriter, r *http.Request, _ map[string]string) {
//      fmt.Fprint(w, "Welcome!\n")
//  }
//
//  func Hello(w http.ResponseWriter, r *http.Request, vars map[string]string) {
//      fmt.Fprintf(w, "hello, %s!\n", vars["name"])
//  }
//
//  func main() {
//      router := httprouter.New()
//      router.GET("/", Index)
//      router.GET("/hello/:name", Hello)
//
//      log.Fatal(http.ListenAndServe(":12345", router))
//  }
//
// The router matches incoming requests by the request method and the path.
// If a handle is registered for this path and method, the router delegates the
// request to that function.
// For the methods GET, POST, PUT and DELETE shortcut functions exist to
// register handles, for all other methods router.Handle can be used.
//
// The registered path, against which the router matches incoming requests, can
// contain two types of wildcards:
//  Syntax    Type
//  :name     Parameter
//  *name     CatchAll
// The value of wildcards is saved in a map as vars[name] = value. The map is
// passed to the Handle as a parameter.
//
// Parameters are variable path segments. They match anything until the next /
// or the path end:
//  Path: /blog/:category/:post
//
//  Requests:
//   /blog/go/request-routers            match: category="go"; post="request-routers"
//   /blog/go/                           no match
//   /blog/go/request-routers/comments   no match
//
// CatchAll wildcards match anything until the path end, including the directory
// index (the / before the CatchAll). Since they match anything until the end,
// CatchAll wildcards must always be the last element in the defined path.
//  Path: /files/*filepath
//
//  Requests:
//   /files/                             match: filepath="/"
//   /files/LICENSE                      match: filepath="/LICENSE"
//   /files/templates/article.html       match: filepath="/templates/article.html"
//   /files                              no match, but the router would redirect
//
package httprouter

import (
	"net/http"
)

// Handle is a function that can be registered to a route to handle HTTP
// requests. Like http.HandlerFunc, but has a third parameter for the route
// parameters.
type Handle func(http.ResponseWriter, *http.Request, map[string]string)

// NotFound is the default HTTP handler func for routes that can't be matched
// with an existing route.
// NotFound tries to redirect to a canonical URL generated with CleanPath.
// Otherwise the request is delegated to http.NotFound.
func NotFound(w http.ResponseWriter, req *http.Request) {
	if req.Method != "CONNECT" {
		path := req.URL.Path
		if cp := CleanPath(path); cp != path && cp != req.Referer() {
			http.Redirect(w, req, cp, http.StatusMovedPermanently)
			return
		}
	}

	http.NotFound(w, req)
}

// Router is a http.Handler which can be used to dispatch requests to different
// handler functions via configurable routes
type Router struct {
	node

	// Enables automatic redirection if the current route can't be matched but
	// handler for the path with (without) the trailing slash exists.
	// For example if /foo/ is requested but a route only exists for /foo, the
	// client is redirected to /foo with http status code 301.
	RedirectTrailingSlash bool

	// Configurable handler func which is used when no matching route is found.
	// Default is the NotFound func of this package.
	NotFound http.HandlerFunc

	// Handler func to handle panics recovered from http handlers.
	// It should be used to generate a error page and return the http error code
	// "500 - Internal Server Error".
	// The handler can be used to keep your server from crashing because of
	// unrecovered panics.
	PanicHandler func(http.ResponseWriter, *http.Request, interface{})
}

// Make sure the Router conforms with the http.Handler interface
var _ http.Handler = New()

// New returnes a new initialized Router.
// The router can be configured to also match the requested HTTP method or the
// requested Host.
func New() *Router {
	return &Router{
		RedirectTrailingSlash: true,
		NotFound:              NotFound,
	}
}

// GET is a shortcut for router.Handle("GET", path, handle)
func (r *Router) GET(path string, handle Handle) {
	r.Handle("GET", path, handle)
}

// POST is a shortcut for router.Handle("POST", path, handle)
func (r *Router) POST(path string, handle Handle) {
	r.Handle("POST", path, handle)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func (r *Router) PUT(path string, handle Handle) {
	r.Handle("PUT", path, handle)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (r *Router) DELETE(path string, handle Handle) {
	r.Handle("DELETE", path, handle)
}

// Handle registers a new request handle with the given path and method.
//
// For GET / POST / PUT or DELETE requests the respective shortcut functions can
// be used.
//
// This function is intended to allow the usage of less frequently used,
// non-standardized or custom methods (e.g. for internal communication with a
// proxy).
func (r *Router) Handle(method, path string, handle Handle) {
	if path[0] != '/' {
		panic("path must begin with '/'")
	}
	r.addRoute(method, path, handle)
}

// HandlerFunc is an adapter which allows the usage of a http.HandlerFunc as a
// request handle.
func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
	r.Handle(method, path,
		func(w http.ResponseWriter, req *http.Request, _ map[string]string) {
			handler(w, req)
		},
	)
}

// ServeFiles serves files from the given file system root.
// The path must end with "/*filepath", files are then served from the local
// path /defined/root/dir/*filepath.
// For example if root is "/etc" and *filepath is "passwd", the local file
// "/etc/passwd" would be served.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use http.Dir:
//
//     router.ServeFiles("/*filepath", http.Dir("/var/www"))
func (r *Router) ServeFiles(path string, root http.FileSystem) {
	if len(path) < 10 || path[len(path)-10:] != "/*filepath" {
		panic("path must end with /*filepath")
	}

	fileServer := http.FileServer(root)

	r.GET(path, func(w http.ResponseWriter, req *http.Request, vars map[string]string) {
		req.URL.Path = vars["filepath"]
		fileServer.ServeHTTP(w, req)
	})
}

func (r *Router) recv(w http.ResponseWriter, req *http.Request) {
	if rcv := recover(); rcv != nil {
		r.PanicHandler(w, req, rcv)
	}
}

// Make the router implement the http.Handler interface.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if r.PanicHandler != nil {
		defer r.recv(w, req)
	}

	path := req.URL.Path

	if handle, vars, tsr := r.getValue(req.Method, path); handle != nil {
		handle(w, req, vars)
	} else if tsr && r.RedirectTrailingSlash && path != "/" {
		if path[len(path)-1] == '/' {
			path = path[:len(path)-1]
		} else {
			path = path + "/"
		}
		http.Redirect(w, req, path, http.StatusMovedPermanently)
		return
	} else { // Handle 404
		if r.NotFound != nil {
			r.NotFound(w, req)
		} else {
			http.NotFound(w, req)
		}
	}
}
<commit_msg>Update godoc<commit_after>// Copyright 2013 Julien Schmidt. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.

// Package httprouter is a trie based high performance HTTP request router.
//
// A trivial example is:
//
//  package main
//
//  import (
//      "fmt"
//      "github.com/julienschmidt/httprouter"
//      "net/http"
//      "log"
//  )
//
//  func Index(w http.ResponseWriter, r *http.Request, _ map[string]string) {
//      fmt.Fprint(w, "Welcome!\n")
//  }
//
//  func Hello(w http.ResponseWriter, r *http.Request, vars map[string]string) {
//      fmt.Fprintf(w, "hello, %s!\n", vars["name"])
//  }
//
//  func main() {
//      router := httprouter.New()
//      router.GET("/", Index)
//      router.GET("/hello/:name", Hello)
//
//      log.Fatal(http.ListenAndServe(":12345", router))
//  }
//
// The router matches incoming requests by the request method and the path.
// If a handle is registered for this path and method, the router delegates the
// request to that function.
// For the methods GET, POST, PUT and DELETE shortcut functions exist to
// register handles, for all other methods router.Handle can be used.
//
// The registered path, against which the router matches incoming requests, can
// contain two types of wildcards:
//  Syntax    Type
//  :name     Parameter
//  *name     CatchAll
// The value of wildcards is saved in a map as vars["name"] = value. The map is
// passed to the Handle func as a parameter.
//
// Parameters are variable path segments. They match anything until the next '/'
// or the path end:
//  Path: /blog/:category/:post
//
//  Requests:
//   /blog/go/request-routers            match: category="go", post="request-routers"
//   /blog/go/request-routers/           no match, but the router would redirect
//   /blog/go/                           no match
//   /blog/go/request-routers/comments   no match
//
// CatchAll wildcards match anything until the path end, including the directory
// index (the '/'' before the CatchAll). Since they match anything until the end,
// CatchAll wildcards must always be the last element in the defined path.
//  Path: /files/*filepath
//
//  Requests:
//   /files/                             match: filepath="/"
//   /files/LICENSE                      match: filepath="/LICENSE"
//   /files/templates/article.html       match: filepath="/templates/article.html"
//   /files                              no match, but the router would redirect
//
package httprouter

import (
	"net/http"
)

// Handle is a function that can be registered to a route to handle HTTP
// requests. Like http.HandlerFunc, but has a third parameter for the values of
// wildcards (variables).
type Handle func(http.ResponseWriter, *http.Request, map[string]string)

// NotFound is the default HTTP handler func for routes that can't be matched
// with an existing route.
// NotFound tries to redirect to a canonical URL generated with CleanPath.
// Otherwise the request is delegated to http.NotFound.
func NotFound(w http.ResponseWriter, req *http.Request) {
	if req.Method != "CONNECT" {
		path := req.URL.Path
		if cp := CleanPath(path); cp != path && cp != req.Referer() {
			http.Redirect(w, req, cp, http.StatusMovedPermanently)
			return
		}
	}

	http.NotFound(w, req)
}

// Router is a http.Handler which can be used to dispatch requests to different
// handler functions via configurable routes
type Router struct {
	node

	// Enables automatic redirection if the current route can't be matched but
	// handler for the path with (without) the trailing slash exists.
	// For example if /foo/ is requested but a route only exists for /foo, the
	// client is redirected to /foo with http status code 301.
	RedirectTrailingSlash bool

	// Configurable handler func which is used when no matching route is found.
	// Default is the NotFound func of this package.
	NotFound http.HandlerFunc

	// Handler func to handle panics recovered from http handlers.
	// It should be used to generate a error page and return the http error code
	// "500 - Internal Server Error".
	// The handler can be used to keep your server from crashing because of
	// unrecovered panics.
	PanicHandler func(http.ResponseWriter, *http.Request, interface{})
}

// Make sure the Router conforms with the http.Handler interface
var _ http.Handler = New()

// New returnes a new initialized Router.
// The router can be configured to also match the requested HTTP method or the
// requested Host.
func New() *Router {
	return &Router{
		RedirectTrailingSlash: true,
		NotFound:              NotFound,
	}
}

// GET is a shortcut for router.Handle("GET", path, handle)
func (r *Router) GET(path string, handle Handle) {
	r.Handle("GET", path, handle)
}

// POST is a shortcut for router.Handle("POST", path, handle)
func (r *Router) POST(path string, handle Handle) {
	r.Handle("POST", path, handle)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func (r *Router) PUT(path string, handle Handle) {
	r.Handle("PUT", path, handle)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (r *Router) DELETE(path string, handle Handle) {
	r.Handle("DELETE", path, handle)
}

// Handle registers a new request handle with the given path and method.
//
// For GET, POST, PUT and DELETE requests the respective shortcut functions can
// be used.
//
// This function is intended to allow the usage of less frequently used,
// non-standardized or custom methods (e.g. for internal communication with a
// proxy).
func (r *Router) Handle(method, path string, handle Handle) {
	if path[0] != '/' {
		panic("path must begin with '/'")
	}
	r.addRoute(method, path, handle)
}

// HandlerFunc is an adapter which allows the usage of a http.HandlerFunc as a
// request handle.
func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
	r.Handle(method, path,
		func(w http.ResponseWriter, req *http.Request, _ map[string]string) {
			handler(w, req)
		},
	)
}

// ServeFiles serves files from the given file system root.
// The path must end with "/*filepath", files are then served from the local
// path /defined/root/dir/*filepath.
// For example if root is "/etc" and *filepath is "passwd", the local file
// "/etc/passwd" would be served.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use http.Dir:
//
//     router.ServeFiles("/*filepath", http.Dir("/var/www"))
func (r *Router) ServeFiles(path string, root http.FileSystem) {
	if len(path) < 10 || path[len(path)-10:] != "/*filepath" {
		panic("path must end with /*filepath")
	}

	fileServer := http.FileServer(root)

	r.GET(path, func(w http.ResponseWriter, req *http.Request, vars map[string]string) {
		req.URL.Path = vars["filepath"]
		fileServer.ServeHTTP(w, req)
	})
}

func (r *Router) recv(w http.ResponseWriter, req *http.Request) {
	if rcv := recover(); rcv != nil {
		r.PanicHandler(w, req, rcv)
	}
}

// Make the router implement the http.Handler interface.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if r.PanicHandler != nil {
		defer r.recv(w, req)
	}

	path := req.URL.Path

	if handle, vars, tsr := r.getValue(req.Method, path); handle != nil {
		handle(w, req, vars)
	} else if tsr && r.RedirectTrailingSlash && path != "/" {
		if path[len(path)-1] == '/' {
			path = path[:len(path)-1]
		} else {
			path = path + "/"
		}
		http.Redirect(w, req, path, http.StatusMovedPermanently)
		return
	} else { // Handle 404
		if r.NotFound != nil {
			r.NotFound(w, req)
		} else {
			http.NotFound(w, req)
		}
	}
}
<|endoftext|>


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

// Package httprouter is a trie based high performance HTTP request router.
//
// A trivial example server is:
//
//  package main
//
//  import (
//      "fmt"
//      "github.com/julienschmidt/httprouter"
//      "net/http"
//      "log"
//  )
//
//  func Index(w http.ResponseWriter, r *http.Request, _ map[string]string) {
//      fmt.Fprint(w, "Welcome!\n")
//  }
//
//  func Hello(w http.ResponseWriter, r *http.Request, vars map[string]string) {
//      fmt.Fprintf(w, "hello, %s!\n", vars["name"])
//  }
//
//  func main() {
//      router := httprouter.New()
//      router.GET("/", Index)
//      router.GET("/hello/:name", Hello)
//
//      log.Fatal(http.ListenAndServe(":12345", router))
//  }
//
//
package httprouter

import (
	"net/http"
)

// Handle is a function that can be registered to a route to handle HTTP
// requests. Like http.HandlerFunc, but has a third parameter for the route
// parameters.
type Handle func(http.ResponseWriter, *http.Request, map[string]string)

// NotFound is the default HTTP handler func for routes that can't be matched
// with an existing route.
// NotFound tries to redirect to a canonical URL generated with CleanPath.
// Otherwise the request is delegated to http.NotFound.
func NotFound(w http.ResponseWriter, req *http.Request) {
	if req.Method != "CONNECT" {
		path := req.URL.Path
		if cp := CleanPath(path); cp != path && cp != req.Referer() {
			http.Redirect(w, req, cp, http.StatusMovedPermanently)
			return
		}
	}

	http.NotFound(w, req)
}

// Router is a http.Handler which can be used to dispatch requests to different
// handler functions via configurable routes
type Router struct {
	node

	// Enables automatic redirection if the current route can't be matched but
	// handler for the path with (without) the trailing slash exists.
	// For example if /foo/ is requested but a route only exists for /foo, the
	// client is redirected to /foo with http status code 301.
	RedirectTrailingSlash bool

	// Configurable handler func which is used when no matching route is found.
	// Default is the NotFound func of this package.
	NotFound http.HandlerFunc

	// Handler func to handle panics recovered from http handlers.
	// It should be used to generate a error page and return the http error code
	// "500 - Internal Server Error".
	// The handler can be used to keep your server from crashing because of
	// unrecovered panics.
	PanicHandler func(http.ResponseWriter, *http.Request, interface{})
}

// Make sure the Router conforms with the http.Handler interface
var _ http.Handler = New()

// New returnes a new initialized Router.
// The router can be configured to also match the requested HTTP method or the
// requested Host.
func New() *Router {
	return &Router{
		RedirectTrailingSlash: true,
		NotFound:              NotFound,
	}
}

// GET is a shortcut for router.Handle("GET", path, handle)
func (r *Router) GET(path string, handle Handle) {
	r.Handle("GET", path, handle)
}

// POST is a shortcut for router.Handle("POST", path, handle)
func (r *Router) POST(path string, handle Handle) {
	r.Handle("POST", path, handle)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func (r *Router) PUT(path string, handle Handle) {
	r.Handle("PUT", path, handle)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (r *Router) DELETE(path string, handle Handle) {
	r.Handle("DELETE", path, handle)
}

// Handle registers a new request handle with the given path and method.
func (r *Router) Handle(method, path string, handle Handle) {
	if path[0] != '/' {
		panic("path must begin with '/'")
	}
	r.addRoute(method, path, handle)
}

// HandlerFunc is an adapter which allows the usage of a http.HandlerFunc as a
// request handle.
func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
	r.Handle(method, path,
		func(w http.ResponseWriter, req *http.Request, _ map[string]string) {
			handler(w, req)
		},
	)
}

// ServeFiles serves files from the given file system root.
// The path must end with "/*filepath", files are then served from the local
// path /defined/root/dir/*filepath.
// For example if root is "/etc" and *filepath is "passwd", the local file
// "/etc/passwd" would be served.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use http.Dir:
//
//     router.ServeFiles("/*filepath", http.Dir("/var/www"))
func (r *Router) ServeFiles(path string, root http.FileSystem) {
	if len(path) < 10 || path[len(path)-9:] != "*filepath" {
		panic("path must end with *filepath")
	}

	fileServer := http.FileServer(root)

	r.GET(path, func(w http.ResponseWriter, req *http.Request, vars map[string]string) {
		fp, ok := vars["filepath"]
		if !ok {
			panic("routed request has no *filepath")
		}

		req.URL.Path = fp
		fileServer.ServeHTTP(w, req)
	})
}

func (r *Router) recv(w http.ResponseWriter, req *http.Request) {
	if rcv := recover(); rcv != nil {
		r.PanicHandler(w, req, rcv)
	}
}

// Make the router implement the http.Handler interface.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if r.PanicHandler != nil {
		defer r.recv(w, req)
	}

	path := req.URL.Path

	if handle, vars, tsr := r.getValue(req.Method, path); handle != nil {
		handle(w, req, vars)
	} else if tsr && r.RedirectTrailingSlash && path != "/" {
		if path[len(path)-1] == '/' {
			path = path[:len(path)-1]
		} else {
			path = path + "/"
		}
		http.Redirect(w, req, path, http.StatusMovedPermanently)
		return
	} else { // Handle 404
		if r.NotFound != nil {
			r.NotFound(w, req)
		} else {
			http.NotFound(w, req)
		}
	}
}
<commit_msg>Simplify router.ServeFiles a bit<commit_after>// Copyright 2013 Julien Schmidt. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.

// Package httprouter is a trie based high performance HTTP request router.
//
// A trivial example server is:
//
//  package main
//
//  import (
//      "fmt"
//      "github.com/julienschmidt/httprouter"
//      "net/http"
//      "log"
//  )
//
//  func Index(w http.ResponseWriter, r *http.Request, _ map[string]string) {
//      fmt.Fprint(w, "Welcome!\n")
//  }
//
//  func Hello(w http.ResponseWriter, r *http.Request, vars map[string]string) {
//      fmt.Fprintf(w, "hello, %s!\n", vars["name"])
//  }
//
//  func main() {
//      router := httprouter.New()
//      router.GET("/", Index)
//      router.GET("/hello/:name", Hello)
//
//      log.Fatal(http.ListenAndServe(":12345", router))
//  }
//
//
package httprouter

import (
	"net/http"
)

// Handle is a function that can be registered to a route to handle HTTP
// requests. Like http.HandlerFunc, but has a third parameter for the route
// parameters.
type Handle func(http.ResponseWriter, *http.Request, map[string]string)

// NotFound is the default HTTP handler func for routes that can't be matched
// with an existing route.
// NotFound tries to redirect to a canonical URL generated with CleanPath.
// Otherwise the request is delegated to http.NotFound.
func NotFound(w http.ResponseWriter, req *http.Request) {
	if req.Method != "CONNECT" {
		path := req.URL.Path
		if cp := CleanPath(path); cp != path && cp != req.Referer() {
			http.Redirect(w, req, cp, http.StatusMovedPermanently)
			return
		}
	}

	http.NotFound(w, req)
}

// Router is a http.Handler which can be used to dispatch requests to different
// handler functions via configurable routes
type Router struct {
	node

	// Enables automatic redirection if the current route can't be matched but
	// handler for the path with (without) the trailing slash exists.
	// For example if /foo/ is requested but a route only exists for /foo, the
	// client is redirected to /foo with http status code 301.
	RedirectTrailingSlash bool

	// Configurable handler func which is used when no matching route is found.
	// Default is the NotFound func of this package.
	NotFound http.HandlerFunc

	// Handler func to handle panics recovered from http handlers.
	// It should be used to generate a error page and return the http error code
	// "500 - Internal Server Error".
	// The handler can be used to keep your server from crashing because of
	// unrecovered panics.
	PanicHandler func(http.ResponseWriter, *http.Request, interface{})
}

// Make sure the Router conforms with the http.Handler interface
var _ http.Handler = New()

// New returnes a new initialized Router.
// The router can be configured to also match the requested HTTP method or the
// requested Host.
func New() *Router {
	return &Router{
		RedirectTrailingSlash: true,
		NotFound:              NotFound,
	}
}

// GET is a shortcut for router.Handle("GET", path, handle)
func (r *Router) GET(path string, handle Handle) {
	r.Handle("GET", path, handle)
}

// POST is a shortcut for router.Handle("POST", path, handle)
func (r *Router) POST(path string, handle Handle) {
	r.Handle("POST", path, handle)
}

// PUT is a shortcut for router.Handle("PUT", path, handle)
func (r *Router) PUT(path string, handle Handle) {
	r.Handle("PUT", path, handle)
}

// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (r *Router) DELETE(path string, handle Handle) {
	r.Handle("DELETE", path, handle)
}

// Handle registers a new request handle with the given path and method.
func (r *Router) Handle(method, path string, handle Handle) {
	if path[0] != '/' {
		panic("path must begin with '/'")
	}
	r.addRoute(method, path, handle)
}

// HandlerFunc is an adapter which allows the usage of a http.HandlerFunc as a
// request handle.
func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
	r.Handle(method, path,
		func(w http.ResponseWriter, req *http.Request, _ map[string]string) {
			handler(w, req)
		},
	)
}

// ServeFiles serves files from the given file system root.
// The path must end with "/*filepath", files are then served from the local
// path /defined/root/dir/*filepath.
// For example if root is "/etc" and *filepath is "passwd", the local file
// "/etc/passwd" would be served.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use http.Dir:
//
//     router.ServeFiles("/*filepath", http.Dir("/var/www"))
func (r *Router) ServeFiles(path string, root http.FileSystem) {
	if len(path) < 10 || path[len(path)-10:] != "/*filepath" {
		panic("path must end with /*filepath")
	}

	fileServer := http.FileServer(root)

	r.GET(path, func(w http.ResponseWriter, req *http.Request, vars map[string]string) {
		req.URL.Path = vars["filepath"]
		fileServer.ServeHTTP(w, req)
	})
}

func (r *Router) recv(w http.ResponseWriter, req *http.Request) {
	if rcv := recover(); rcv != nil {
		r.PanicHandler(w, req, rcv)
	}
}

// Make the router implement the http.Handler interface.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if r.PanicHandler != nil {
		defer r.recv(w, req)
	}

	path := req.URL.Path

	if handle, vars, tsr := r.getValue(req.Method, path); handle != nil {
		handle(w, req, vars)
	} else if tsr && r.RedirectTrailingSlash && path != "/" {
		if path[len(path)-1] == '/' {
			path = path[:len(path)-1]
		} else {
			path = path + "/"
		}
		http.Redirect(w, req, path, http.StatusMovedPermanently)
		return
	} else { // Handle 404
		if r.NotFound != nil {
			r.NotFound(w, req)
		} else {
			http.NotFound(w, req)
		}
	}
}
<|endoftext|>