<commit_before>// 13 february 2014

package ui

import (
	"fmt"
	"sync"
)

type orientation bool

const (
	horizontal orientation = false
	vertical   orientation = true
)

// A Stack stacks controls horizontally or vertically within the Stack's parent.
// A horizontal Stack gives all controls the same height and their preferred widths.
// A vertical Stack gives all controls the same width and their preferred heights.
// Any extra space at the end of a Stack is left blank.
// Some controls may be marked as "stretchy": when the Window they are in changes size, stretchy controls resize to take up the remaining space after non-stretchy controls are laid out. If multiple controls are marked stretchy, they are alloted equal distribution of the remaining space.
type Stack struct {
	lock          sync.Mutex
	created       bool
	orientation   orientation
	controls      []Control
	stretchy      []bool
	width, height []int // caches to avoid reallocating these each time
}

func newStack(o orientation, controls ...Control) *Stack {
	return &Stack{
		orientation: o,
		controls:    controls,
		stretchy:    make([]bool, len(controls)),
		width:       make([]int, len(controls)),
		height:      make([]int, len(controls)),
	}
}

// NewHorizontalStack creates a new Stack that arranges the given Controls horizontally.
func NewHorizontalStack(controls ...Control) *Stack {
	return newStack(horizontal, controls...)
}

// NewVerticalStack creates a new Stack that arranges the given Controls vertically.
func NewVerticalStack(controls ...Control) *Stack {
	return newStack(vertical, controls...)
}

// SetStretchy marks a control in a Stack as stretchy. This cannot be called once the Window containing the Stack has been created.
// It panics if index is out of range.
func (s *Stack) SetStretchy(index int) {
	s.lock.Lock()
	defer s.lock.Unlock()

	if s.created {
		panic("call to Stack.SetStretchy() after Stack has been created")
	}
	if index < 0 || index > len(s.stretchy) {
		panic(fmt.Errorf("index %d out of range in Stack.SetStretchy()", index))
	}
	s.stretchy[index] = true
}

func (s *Stack) make(window *sysData) error {
	s.lock.Lock()
	defer s.lock.Unlock()

	for i, c := range s.controls {
		err := c.make(window)
		if err != nil {
			return fmt.Errorf("error adding control %d to Stack: %v", i, err)
		}
	}
	s.created = true
	return nil
}

func (s *Stack) allocate(x int, y int, width int, height int, d *sysSizeData) (allocations []*allocation) {
	var stretchywid, stretchyht int
	var current *allocation		// for neighboring

	if len(s.controls) == 0 { // do nothing if there's nothing to do
		return nil
	}
	// before we do anything, steal the margin so nested Stacks/Grids don't double down
	xmargin := d.xmargin
	ymargin := d.ymargin
	d.xmargin = 0
	d.ymargin = 0
	// 0) inset the available rect by the margins
	x += xmargin
	y += ymargin
	width -= xmargin * 2
	height -= ymargin * 2
	// 1) get height and width of non-stretchy controls; figure out how much space is alloted to stretchy controls
	stretchywid = width
	stretchyht = height
	nStretchy := 0
	for i, c := range s.controls {
		if s.stretchy[i] {
			nStretchy++
			continue
		}
		w, h := c.preferredSize(d)
		if s.orientation == horizontal { // all controls have same height
			s.width[i] = w
			s.height[i] = height
			stretchywid -= w
		} else { // all controls have same width
			s.width[i] = width
			s.height[i] = h
			stretchyht -= h
		}
	}
	// 2) figure out size of stretchy controls
	if nStretchy != 0 {
		if s.orientation == horizontal { // split rest of width
			stretchywid /= nStretchy
		} else { // split rest of height
			stretchyht /= nStretchy
		}
	}
	for i := range s.controls {
		if !s.stretchy[i] {
			continue
		}
		s.width[i] = stretchywid
		s.height[i] = stretchyht
	}
	// 3) now actually place controls
	for i, c := range s.controls {
		as := c.allocate(x, y, s.width[i], s.height[i], d)
		if s.orientation == horizontal {		// no vertical neighbors
			if current != nil {			// connect first left to first right
				current.neighbor = c
			}
			if len(as) != 0 {
				current = as[0]			// next left is first subwidget
			} else {
				current = nil			// spaces don't have allocation data
			}
		}
		allocations = append(allocations, as...)
		if s.orientation == horizontal {
			x += s.width[i]
		} else {
			y += s.height[i]
		}
	}
	return allocations
}

// The preferred size of a Stack is the sum of the preferred sizes of non-stretchy controls + (the number of stretchy controls * the largest preferred size among all stretchy controls).
func (s *Stack) preferredSize(d *sysSizeData) (width int, height int) {
	max := func(a int, b int) int {
		if a > b {
			return a
		}
		return b
	}

	var nStretchy int
	var maxswid, maxsht int

	if len(s.controls) == 0 { // no controls, so return emptiness
		return 0, 0
	}
	for i, c := range s.controls {
		w, h := c.preferredSize(d)
		if s.stretchy[i] {
			nStretchy++
			maxswid = max(maxswid, w)
			maxsht = max(maxsht, h)
		}
		if s.orientation == horizontal { // max vertical size
			if !s.stretchy[i] {
				width += w
			}
			height = max(height, h)
		} else {
			width = max(width, w)
			if !s.stretchy[i] {
				height += h
			}
		}
	}
	if s.orientation == horizontal {
		width += nStretchy * maxswid
	} else {
		height += nStretchy * maxsht
	}
	return
}

func (s *Stack) commitResize(c *allocation, d *sysSizeData) {
	// this is to satisfy Control; nothing to do here
}

func (s *Stack) getAuxResizeInfo(d *sysSizeData) {
	// this is to satisfy Control; nothing to do here
}

// Space returns a null Control intended for padding layouts with blank space.
// It appears to its owner as a Control of 0x0 size.
//
// For a Stack, Space can be used to insert spaces in the beginning or middle of Stacks (Stacks by nature handle spaces at the end themselves). In order for this to work properly, make the Space stretchy.
//
// For a Grid, Space can be used to have an empty cell. A stretchy Grid cell with a Space can be used to anchor the perimeter of a Grid to the respective Window edges without making one of the other controls stretchy instead (leaving empty space in the Window otherwise). Otherwise, you do not need to do anything special for the Space to work (though remember that an entire row or column of Spaces will appear as having height or width zero, respectively, unless one is marked as stretchy).
//
// The value returned from Space() may or may not be unique.
func Space() Control {
	return space
}

// As above, a Stack with no controls draws nothing and reports no errors; its parent will still size it properly if made stretchy.
var space Control = newStack(horizontal)
<commit_msg>Implemented padding on Stack.<commit_after>// 13 february 2014

package ui

import (
	"fmt"
	"sync"
)

type orientation bool

const (
	horizontal orientation = false
	vertical   orientation = true
)

// A Stack stacks controls horizontally or vertically within the Stack's parent.
// A horizontal Stack gives all controls the same height and their preferred widths.
// A vertical Stack gives all controls the same width and their preferred heights.
// Any extra space at the end of a Stack is left blank.
// Some controls may be marked as "stretchy": when the Window they are in changes size, stretchy controls resize to take up the remaining space after non-stretchy controls are laid out. If multiple controls are marked stretchy, they are alloted equal distribution of the remaining space.
type Stack struct {
	lock          sync.Mutex
	created       bool
	orientation   orientation
	controls      []Control
	stretchy      []bool
	width, height []int // caches to avoid reallocating these each time
}

func newStack(o orientation, controls ...Control) *Stack {
	return &Stack{
		orientation: o,
		controls:    controls,
		stretchy:    make([]bool, len(controls)),
		width:       make([]int, len(controls)),
		height:      make([]int, len(controls)),
	}
}

// NewHorizontalStack creates a new Stack that arranges the given Controls horizontally.
func NewHorizontalStack(controls ...Control) *Stack {
	return newStack(horizontal, controls...)
}

// NewVerticalStack creates a new Stack that arranges the given Controls vertically.
func NewVerticalStack(controls ...Control) *Stack {
	return newStack(vertical, controls...)
}

// SetStretchy marks a control in a Stack as stretchy. This cannot be called once the Window containing the Stack has been created.
// It panics if index is out of range.
func (s *Stack) SetStretchy(index int) {
	s.lock.Lock()
	defer s.lock.Unlock()

	if s.created {
		panic("call to Stack.SetStretchy() after Stack has been created")
	}
	if index < 0 || index > len(s.stretchy) {
		panic(fmt.Errorf("index %d out of range in Stack.SetStretchy()", index))
	}
	s.stretchy[index] = true
}

func (s *Stack) make(window *sysData) error {
	s.lock.Lock()
	defer s.lock.Unlock()

	for i, c := range s.controls {
		err := c.make(window)
		if err != nil {
			return fmt.Errorf("error adding control %d to Stack: %v", i, err)
		}
	}
	s.created = true
	return nil
}

func (s *Stack) allocate(x int, y int, width int, height int, d *sysSizeData) (allocations []*allocation) {
	var stretchywid, stretchyht int
	var current *allocation		// for neighboring

	if len(s.controls) == 0 { // do nothing if there's nothing to do
		return nil
	}
	// before we do anything, steal the margin so nested Stacks/Grids don't double down
	xmargin := d.xmargin
	ymargin := d.ymargin
	d.xmargin = 0
	d.ymargin = 0
	// 0) inset the available rect by the margins and needed padding
	x += xmargin
	y += ymargin
	width -= xmargin * 2
	height -= ymargin * 2
	if s.orientation == horizontal {
		width -= (len(s.controls) - 1) * d.xpadding
	} else {
		height -= (len(s.controls) - 1) * d.ypadding
	}
	// 1) get height and width of non-stretchy controls; figure out how much space is alloted to stretchy controls
	stretchywid = width
	stretchyht = height
	nStretchy := 0
	for i, c := range s.controls {
		if s.stretchy[i] {
			nStretchy++
			continue
		}
		w, h := c.preferredSize(d)
		if s.orientation == horizontal { // all controls have same height
			s.width[i] = w
			s.height[i] = height
			stretchywid -= w
		} else { // all controls have same width
			s.width[i] = width
			s.height[i] = h
			stretchyht -= h
		}
	}
	// 2) figure out size of stretchy controls
	if nStretchy != 0 {
		if s.orientation == horizontal { // split rest of width
			stretchywid /= nStretchy
		} else { // split rest of height
			stretchyht /= nStretchy
		}
	}
	for i := range s.controls {
		if !s.stretchy[i] {
			continue
		}
		s.width[i] = stretchywid
		s.height[i] = stretchyht
	}
	// 3) now actually place controls
	for i, c := range s.controls {
		as := c.allocate(x, y, s.width[i], s.height[i], d)
		if s.orientation == horizontal {		// no vertical neighbors
			if current != nil {			// connect first left to first right
				current.neighbor = c
			}
			if len(as) != 0 {
				current = as[0]			// next left is first subwidget
			} else {
				current = nil			// spaces don't have allocation data
			}
		}
		allocations = append(allocations, as...)
		if s.orientation == horizontal {
			x += s.width[i] + d.xpadding
		} else {
			y += s.height[i] + d.ypadding
		}
	}
	return allocations
}

// The preferred size of a Stack is the sum of the preferred sizes of non-stretchy controls + (the number of stretchy controls * the largest preferred size among all stretchy controls).
// We don't consider the margins here, but will need to if Window.SizeToFit() is ever made a thing.
func (s *Stack) preferredSize(d *sysSizeData) (width int, height int) {
	max := func(a int, b int) int {
		if a > b {
			return a
		}
		return b
	}

	var nStretchy int
	var maxswid, maxsht int

	if len(s.controls) == 0 { // no controls, so return emptiness
		return 0, 0
	}
	if s.orientation == horizontal {
		width = (len(s.controls) - 1) * d.xpadding
	} else {
		height = (len(s.controls) - 1) * d.ypadding
	}
	for i, c := range s.controls {
		w, h := c.preferredSize(d)
		if s.stretchy[i] {
			nStretchy++
			maxswid = max(maxswid, w)
			maxsht = max(maxsht, h)
		}
		if s.orientation == horizontal { // max vertical size
			if !s.stretchy[i] {
				width += w
			}
			height = max(height, h)
		} else {
			width = max(width, w)
			if !s.stretchy[i] {
				height += h
			}
		}
	}
	if s.orientation == horizontal {
		width += nStretchy * maxswid
	} else {
		height += nStretchy * maxsht
	}
	return
}

func (s *Stack) commitResize(c *allocation, d *sysSizeData) {
	// this is to satisfy Control; nothing to do here
}

func (s *Stack) getAuxResizeInfo(d *sysSizeData) {
	// this is to satisfy Control; nothing to do here
}

// Space returns a null Control intended for padding layouts with blank space.
// It appears to its owner as a Control of 0x0 size.
//
// For a Stack, Space can be used to insert spaces in the beginning or middle of Stacks (Stacks by nature handle spaces at the end themselves). In order for this to work properly, make the Space stretchy.
//
// For a Grid, Space can be used to have an empty cell. A stretchy Grid cell with a Space can be used to anchor the perimeter of a Grid to the respective Window edges without making one of the other controls stretchy instead (leaving empty space in the Window otherwise). Otherwise, you do not need to do anything special for the Space to work (though remember that an entire row or column of Spaces will appear as having height or width zero, respectively, unless one is marked as stretchy).
//
// The value returned from Space() may or may not be unique.
func Space() Control {
	return space
}

// As above, a Stack with no controls draws nothing and reports no errors; its parent will still size it properly if made stretchy.
var space Control = newStack(horizontal)
<|endoftext|>


<commit_before>package kuiperbelt

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"sync/atomic"
	"time"
)

// macopy may be embedded into structs which must not be copied
// after the first use.
// See https://github.com/golang/go/issues/8005#issuecomment-190753527
// for details.
type macopy struct{}

func (*macopy) Lock() {}

type Stats struct {
	connections        int64
	totalConnections   int64
	totalMessages      int64
	connectErrors      int64
	messageErrors      int64
	closingConnections int64
	noCopy             macopy
}

func NewStats() *Stats {
	return &Stats{}
}

func (s *Stats) Connections() int64 {
	return atomic.LoadInt64(&s.connections)
}

func (s *Stats) TotalConnections() int64 {
	return atomic.LoadInt64(&s.totalConnections)
}

func (s *Stats) TotalMessages() int64 {
	return atomic.LoadInt64(&s.totalMessages)
}

func (s *Stats) ConnectErrors() int64 {
	return atomic.LoadInt64(&s.connectErrors)
}

func (s *Stats) MessageErrors() int64 {
	return atomic.LoadInt64(&s.messageErrors)
}

func (s *Stats) ClosingConnections() int64 {
	return atomic.LoadInt64(&s.closingConnections)
}

func (s *Stats) Dump(w io.Writer) error {
	return json.NewEncoder(w).Encode(struct {
		Connections        int64 `json:"connections"`
		TotalConnections   int64 `json:"total_connections"`
		TotalMessages      int64 `json:"total_messages"`
		ConnectErrors      int64 `json:"connect_errors"`
		MessageErrors      int64 `json:"message_errors"`
		ClosingConnections int64 `json:"closing_connections"`
	}{
		Connections:        s.Connections(),
		TotalConnections:   s.TotalConnections(),
		TotalMessages:      s.TotalMessages(),
		ConnectErrors:      s.ConnectErrors(),
		MessageErrors:      s.MessageErrors(),
		ClosingConnections: s.ClosingConnections(),
	})
}

func (s *Stats) DumpText(w io.Writer) error {
	now := time.Now().Unix()
	var b [512]byte
	buf := bytes.NewBuffer(b[:])
	fmt.Fprintf(buf, "kuiperbelt.connections\t%d\t%d\n", s.Connections(), now)
	fmt.Fprintf(buf, "kuiperbelt.total_connections\t%d\t%d\n", s.TotalConnections(), now)
	fmt.Fprintf(buf, "kuiperbelt.total_messages\t%d\t%d\n", s.TotalMessages(), now)
	fmt.Fprintf(buf, "kuiperbelt.connect_errors\t%d\t%d\n", s.ConnectErrors(), now)
	fmt.Fprintf(buf, "kuiperbelt.message_errors\t%d\t%d\n", s.MessageErrors(), now)
	fmt.Fprintf(buf, "kuiperbelt.closing_connections\t%d\t%d\n", s.ClosingConnections(), now)
	_, err := buf.WriteTo(w)
	return err
}

func (s *Stats) ConnectEvent() {
	atomic.AddInt64(&s.totalConnections, 1)
	atomic.AddInt64(&s.connections, 1)
}

func (s *Stats) ConnectErrorEvent() {
	atomic.AddInt64(&s.connectErrors, 1)
}

func (s *Stats) DisconnectEvent() {
	atomic.AddInt64(&s.connections, -1)
}

func (s *Stats) MessageEvent() {
	atomic.AddInt64(&s.totalMessages, 1)
}

func (s *Stats) MessageErrorEvent() {
	atomic.AddInt64(&s.messageErrors, 1)
}

func (s *Stats) ClosingEvent() {
	atomic.AddInt64(&s.closingConnections, 1)
}

func (s *Stats) ClosedEvent() {
	atomic.AddInt64(&s.closingConnections, -1)
}
<commit_msg>Do not fill 0 to buffer.<commit_after>package kuiperbelt

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"sync/atomic"
	"time"
)

// macopy may be embedded into structs which must not be copied
// after the first use.
// See https://github.com/golang/go/issues/8005#issuecomment-190753527
// for details.
type macopy struct{}

func (*macopy) Lock() {}

type Stats struct {
	connections        int64
	totalConnections   int64
	totalMessages      int64
	connectErrors      int64
	messageErrors      int64
	closingConnections int64
	noCopy             macopy
}

func NewStats() *Stats {
	return &Stats{}
}

func (s *Stats) Connections() int64 {
	return atomic.LoadInt64(&s.connections)
}

func (s *Stats) TotalConnections() int64 {
	return atomic.LoadInt64(&s.totalConnections)
}

func (s *Stats) TotalMessages() int64 {
	return atomic.LoadInt64(&s.totalMessages)
}

func (s *Stats) ConnectErrors() int64 {
	return atomic.LoadInt64(&s.connectErrors)
}

func (s *Stats) MessageErrors() int64 {
	return atomic.LoadInt64(&s.messageErrors)
}

func (s *Stats) ClosingConnections() int64 {
	return atomic.LoadInt64(&s.closingConnections)
}

func (s *Stats) Dump(w io.Writer) error {
	return json.NewEncoder(w).Encode(struct {
		Connections        int64 `json:"connections"`
		TotalConnections   int64 `json:"total_connections"`
		TotalMessages      int64 `json:"total_messages"`
		ConnectErrors      int64 `json:"connect_errors"`
		MessageErrors      int64 `json:"message_errors"`
		ClosingConnections int64 `json:"closing_connections"`
	}{
		Connections:        s.Connections(),
		TotalConnections:   s.TotalConnections(),
		TotalMessages:      s.TotalMessages(),
		ConnectErrors:      s.ConnectErrors(),
		MessageErrors:      s.MessageErrors(),
		ClosingConnections: s.ClosingConnections(),
	})
}

func (s *Stats) DumpText(w io.Writer) error {
	now := time.Now().Unix()
	buf := new(bytes.Buffer)
	buf.Grow(512)
	fmt.Fprintf(buf, "kuiperbelt.connections\t%d\t%d\n", s.Connections(), now)
	fmt.Fprintf(buf, "kuiperbelt.total_connections\t%d\t%d\n", s.TotalConnections(), now)
	fmt.Fprintf(buf, "kuiperbelt.total_messages\t%d\t%d\n", s.TotalMessages(), now)
	fmt.Fprintf(buf, "kuiperbelt.connect_errors\t%d\t%d\n", s.ConnectErrors(), now)
	fmt.Fprintf(buf, "kuiperbelt.message_errors\t%d\t%d\n", s.MessageErrors(), now)
	fmt.Fprintf(buf, "kuiperbelt.closing_connections\t%d\t%d\n", s.ClosingConnections(), now)
	_, err := buf.WriteTo(w)
	return err
}

func (s *Stats) ConnectEvent() {
	atomic.AddInt64(&s.totalConnections, 1)
	atomic.AddInt64(&s.connections, 1)
}

func (s *Stats) ConnectErrorEvent() {
	atomic.AddInt64(&s.connectErrors, 1)
}

func (s *Stats) DisconnectEvent() {
	atomic.AddInt64(&s.connections, -1)
}

func (s *Stats) MessageEvent() {
	atomic.AddInt64(&s.totalMessages, 1)
}

func (s *Stats) MessageErrorEvent() {
	atomic.AddInt64(&s.messageErrors, 1)
}

func (s *Stats) ClosingEvent() {
	atomic.AddInt64(&s.closingConnections, 1)
}

func (s *Stats) ClosedEvent() {
	atomic.AddInt64(&s.closingConnections, -1)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/ecc1/kenken"
	"github.com/mattn/go-gtk/gdk"
	"github.com/mattn/go-gtk/gtk"
)

const (
	cellSize      = 100
	cageThickness = 4
)

func main() {
	k := kenken.ReadPuzzle()
	size := k.Size()

	gtk.Init(nil)

	window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
	window.SetTitle(fmt.Sprintf("%d×%d KenKen", size, size))
	window.Connect("destroy", gtk.MainQuit)
	window.SetResizable(false)

	table := gtk.NewTable(uint(size), uint(size), true)
	for y := 0; y < size; y++ {
		for x := 0; x < size; x++ {
			vbox := gtk.NewVBox(false, 0)
			vbox.SetSizeRequest(cellSize, cellSize)

			// Clue, if any
			str := ""
			switch k.Operation[y][x] {
			case kenken.None, kenken.Given:
			default:
				str = fmt.Sprintf("%d %s", k.Clue[y][x], k.Operation[y][x].Symbol())
			}
			label := gtk.NewLabel(str)
			label.ModifyFontEasy("DejaVu Sans 12")
			label.ModifyFG(gtk.STATE_INSENSITIVE, white)
			align := gtk.NewAlignment(0, 0, 0, 0)
			align.Add(label)
			vbox.PackStart(align, false, false, 0)

			// Notes
			label = gtk.NewLabel("")
			label.ModifyFontEasy("DejaVu Sans 12")
			align = gtk.NewAlignment(1, 0, 0, 0)
			align.Add(label)
			vbox.PackEnd(align, false, false, 0)

			// Cell contents
			label = gtk.NewLabel(fmt.Sprintf("%d", k.Answer[y][x]))
			label.ModifyFontEasy("DejaVu Sans 28")
			label.ModifyFG(gtk.STATE_INSENSITIVE, white)
			vbox.Add(label)

			button := gtk.NewButton()
			button.SetRelief(gtk.RELIEF_NONE)
			button.SetSensitive(false)
			button.Add(vbox)

			table.AttachDefaults(button, uint(x), uint(x+1), uint(y), uint(y+1))
		}
	}
	window.Add(table)
	window.Connect("configure-event", func() {
		drawCages(k, table.GetWindow().GetDrawable(), table.GetAllocation())
	})
	window.ShowAll()

	gtk.Main()
}

var white = gdk.NewColor("white")

func drawCages(k *kenken.KenKen, d *gdk.Drawable, a *gtk.Allocation) {
	size := k.Size()
	w := a.Width / size
	h := a.Height / size
	gc := gdk.NewGC(d)
	gc.SetRgbFgColor(white)

	t := cageThickness

	d.DrawRectangle(gc, true, 0, 0, t, a.Height)
	d.DrawRectangle(gc, true, 0, 0, a.Width, t)
	d.DrawRectangle(gc, true, 0, a.Height-t, a.Width, t)
	d.DrawRectangle(gc, true, a.Width-t, 0, t, a.Height)

	for j := 0; j < size; j++ {
		y := j*h - t/2
		for i := 0; i < size; i++ {
			x := i*w - t/2
			if i > 0 && k.Vertical[j][i-1] {
				d.DrawRectangle(gc, true, x, y, t, h+t/2)
			}
			if j > 0 && k.Horizontal[i][j-1] {
				d.DrawRectangle(gc, true, x, y, w+t/2, t)
			}
		}
	}
}
<commit_msg>Use pathname returned by ReadPuzzle<commit_after>package main

import (
	"fmt"
	"path/filepath"

	"github.com/ecc1/kenken"
	"github.com/mattn/go-gtk/gdk"
	"github.com/mattn/go-gtk/gtk"
)

const (
	cellSize      = 100
	cageThickness = 4
)

func main() {
	k, path := kenken.ReadPuzzle()
	size := k.Size()

	gtk.Init(nil)

	window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
	window.SetTitle(fmt.Sprintf("KenKen %s", filepath.Base(path)))
	window.Connect("destroy", gtk.MainQuit)
	window.SetResizable(false)

	table := gtk.NewTable(uint(size), uint(size), true)
	for y := 0; y < size; y++ {
		for x := 0; x < size; x++ {
			vbox := gtk.NewVBox(false, 0)
			vbox.SetSizeRequest(cellSize, cellSize)

			// Clue, if any
			str := ""
			switch k.Operation[y][x] {
			case kenken.None, kenken.Given:
			default:
				str = fmt.Sprintf("%d %s", k.Clue[y][x], k.Operation[y][x].Symbol())
			}
			label := gtk.NewLabel(str)
			label.ModifyFontEasy("DejaVu Sans 12")
			label.ModifyFG(gtk.STATE_INSENSITIVE, white)
			align := gtk.NewAlignment(0, 0, 0, 0)
			align.Add(label)
			vbox.PackStart(align, false, false, 0)

			// Notes
			label = gtk.NewLabel("")
			label.ModifyFontEasy("DejaVu Sans 12")
			align = gtk.NewAlignment(1, 0, 0, 0)
			align.Add(label)
			vbox.PackEnd(align, false, false, 0)

			// Cell contents
			label = gtk.NewLabel(fmt.Sprintf("%d", k.Answer[y][x]))
			label.ModifyFontEasy("DejaVu Sans 28")
			label.ModifyFG(gtk.STATE_INSENSITIVE, white)
			vbox.Add(label)

			button := gtk.NewButton()
			button.SetRelief(gtk.RELIEF_NONE)
			button.SetSensitive(false)
			button.Add(vbox)

			table.AttachDefaults(button, uint(x), uint(x+1), uint(y), uint(y+1))
		}
	}
	window.Add(table)
	window.Connect("configure-event", func() {
		drawCages(k, table.GetWindow().GetDrawable(), table.GetAllocation())
	})
	window.ShowAll()

	gtk.Main()
}

var white = gdk.NewColor("white")

func drawCages(k *kenken.KenKen, d *gdk.Drawable, a *gtk.Allocation) {
	size := k.Size()
	w := a.Width / size
	h := a.Height / size
	gc := gdk.NewGC(d)
	gc.SetRgbFgColor(white)

	t := cageThickness

	d.DrawRectangle(gc, true, 0, 0, t, a.Height)
	d.DrawRectangle(gc, true, 0, 0, a.Width, t)
	d.DrawRectangle(gc, true, 0, a.Height-t, a.Width, t)
	d.DrawRectangle(gc, true, a.Width-t, 0, t, a.Height)

	for j := 0; j < size; j++ {
		y := j*h - t/2
		for i := 0; i < size; i++ {
			x := i*w - t/2
			if i > 0 && k.Vertical[j][i-1] {
				d.DrawRectangle(gc, true, x, y, t, h+t/2)
			}
			if j > 0 && k.Horizontal[i][j-1] {
				d.DrawRectangle(gc, true, x, y, w+t/2, t)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"github.com/donovanhide/eventsource"
	_ "github.com/mattn/go-sqlite3"
	"strconv"
)

// Store manages an archive of recent press releases.
// It also implements eventsource.Repository to allow the press releases to be
// streamed out as server side events.
// Can stash away press releases for multiple sources.
type Store struct {
	db *sql.DB
}

// pressReleaseEvent wraps up a PressRelease for use as a server-sent event.
type pressReleaseEvent struct {
	payload *PressRelease
	id      int
}

func (ev *pressReleaseEvent) Id() string {
	return strconv.Itoa(ev.id)
}

func (ev *pressReleaseEvent) Event() string {
	return "press_release"
}

func (ev *pressReleaseEvent) Data() string {
	out, _ := json.Marshal(*ev.payload)
	return string(out)
}

func NewStore(dbfile string) *Store {
	store := new(Store)
	db, err := sql.Open("sqlite3", dbfile)
	if err != nil {
		panic(err)
	}
	store.db = db

	_, err = db.Exec(`CREATE TABLE IF NOT EXISTS press_release (
         id INTEGER PRIMARY KEY,
         title TEXT NOT NULL,
         source TEXT NOT NULL,
         permalink TEXT NOT NULL,
         pubdate DATETIME NOT NULL,
         content TEXT NOT NULL )`)
	if err != nil {
		panic(err)
	}

	return store
}

// returns a list of press releases with the ones already in the store culled out
func (store *Store) WhichAreNew(incoming []*PressRelease) []*PressRelease {
	var unseen []*PressRelease
	// should really just use a single sql query ("WHERE permalink IN (...)" but hey.
	for _, pr := range incoming {
		var id int64
		err := store.db.QueryRow("SELECT id FROM press_release WHERE permalink=$1 AND source=$2", pr.Permalink, pr.Source).Scan(&id)
		switch err {
		case nil:
			// it's already in db
		case sql.ErrNoRows:
			// it's a new one
			unseen = append(unseen, pr)
		default:
			panic(err)
		}
	}
	return unseen
}

// Stash adds a press release into the store
func (store *Store) Stash(pr *PressRelease) *pressReleaseEvent {

	res, err := store.db.Exec("INSERT INTO press_release (title,source,permalink,pubdate,content) VALUES ($1,$2,$3,$4,$5)", pr.Title, pr.Source, pr.Permalink, pr.PubDate, pr.Content)
	if err != nil {
		panic(err)
	}
	id, err := res.LastInsertId()
	if err != nil {
		panic(err)
	}
	return &pressReleaseEvent{pr, int(id)}
}

// Get to help handle last-event-id catchups
// note: channel contains the source (eg 'tesco'...)
func (store *Store) Get(channel, eventId string) eventsource.Event {
	id, err := strconv.Atoi(eventId)
	if err != nil {
		panic(err)
	}
	row := store.db.QueryRow(`SELECT title,source,permalink,pubdate,content FROM press_release WHERE id=$1 AND source=$2`, id, channel)
	var pr PressRelease
	if err := row.Scan(&pr.Title, &pr.Source, &pr.Permalink, &pr.PubDate, &pr.Content); err != nil {
		panic(err) // TODO: log and return nil
	}
	pr.complete = true

	return &pressReleaseEvent{&pr, id}
}

// Replay to handle last-event-id catchups
// note: channel contains the source (eg 'tesco'...)
func (store *Store) Replay(channel, lastEventId string) (ids chan string) {
	var err error
	var rows *sql.Rows
	if lastEventId == "" {
		// no last eventid, just replay everything
		if rows, err = store.db.Query("SELECT id FROM press_release WHERE source=$1", channel); err != nil {
			panic(err)
		}
	} else {
		// only fetch events after lastEventId
		id, err := strconv.Atoi(lastEventId)
		if err != nil {
			panic(err)
		}
		if rows, err = store.db.Query("SELECT id FROM press_release WHERE id>$1 AND source=$2", id, channel); err != nil {
			panic(err)
		}
	}

	ids = make(chan string)
	go func() {
		defer rows.Close()
		for rows.Next() {
			var id int
			err := rows.Scan(&id)
			if err != nil {
				panic(err)
			}
			ids <- strconv.Itoa(id)
		}
		close(ids)
	}()
	return ids
}
<commit_msg>Update store.go<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"github.com/donovanhide/eventsource"
	_ "code.google.com/p/go-sqlite/go1/sqlite3"
	"strconv"
)

// Store manages an archive of recent press releases.
// It also implements eventsource.Repository to allow the press releases to be
// streamed out as server side events.
// Can stash away press releases for multiple sources.
type Store struct {
	db *sql.DB
}

// pressReleaseEvent wraps up a PressRelease for use as a server-sent event.
type pressReleaseEvent struct {
	payload *PressRelease
	id      int
}

func (ev *pressReleaseEvent) Id() string {
	return strconv.Itoa(ev.id)
}

func (ev *pressReleaseEvent) Event() string {
	return "press_release"
}

func (ev *pressReleaseEvent) Data() string {
	out, _ := json.Marshal(*ev.payload)
	return string(out)
}

func NewStore(dbfile string) *Store {
	store := new(Store)
	db, err := sql.Open("sqlite3", dbfile)
	if err != nil {
		panic(err)
	}
	store.db = db

	_, err = db.Exec(`CREATE TABLE IF NOT EXISTS press_release (
         id INTEGER PRIMARY KEY,
         title TEXT NOT NULL,
         source TEXT NOT NULL,
         permalink TEXT NOT NULL,
         pubdate DATETIME NOT NULL,
         content TEXT NOT NULL )`)
	if err != nil {
		panic(err)
	}

	return store
}

// returns a list of press releases with the ones already in the store culled out
func (store *Store) WhichAreNew(incoming []*PressRelease) []*PressRelease {
	var unseen []*PressRelease
	// should really just use a single sql query ("WHERE permalink IN (...)" but hey.
	for _, pr := range incoming {
		var id int64
		err := store.db.QueryRow("SELECT id FROM press_release WHERE permalink=$1 AND source=$2", pr.Permalink, pr.Source).Scan(&id)
		switch err {
		case nil:
			// it's already in db
		case sql.ErrNoRows:
			// it's a new one
			unseen = append(unseen, pr)
		default:
			panic(err)
		}
	}
	return unseen
}

// Stash adds a press release into the store
func (store *Store) Stash(pr *PressRelease) *pressReleaseEvent {

	res, err := store.db.Exec("INSERT INTO press_release (title,source,permalink,pubdate,content) VALUES ($1,$2,$3,$4,$5)", pr.Title, pr.Source, pr.Permalink, pr.PubDate, pr.Content)
	if err != nil {
		panic(err)
	}
	id, err := res.LastInsertId()
	if err != nil {
		panic(err)
	}
	return &pressReleaseEvent{pr, int(id)}
}

// Get to help handle last-event-id catchups
// note: channel contains the source (eg 'tesco'...)
func (store *Store) Get(channel, eventId string) eventsource.Event {
	id, err := strconv.Atoi(eventId)
	if err != nil {
		panic(err)
	}
	row := store.db.QueryRow(`SELECT title,source,permalink,pubdate,content FROM press_release WHERE id=$1 AND source=$2`, id, channel)
	var pr PressRelease
	if err := row.Scan(&pr.Title, &pr.Source, &pr.Permalink, &pr.PubDate, &pr.Content); err != nil {
		panic(err) // TODO: log and return nil
	}
	pr.complete = true

	return &pressReleaseEvent{&pr, id}
}

// Replay to handle last-event-id catchups
// note: channel contains the source (eg 'tesco'...)
func (store *Store) Replay(channel, lastEventId string) (ids chan string) {
	var err error
	var rows *sql.Rows
	if lastEventId == "" {
		// no last eventid, just replay everything
		if rows, err = store.db.Query("SELECT id FROM press_release WHERE source=$1", channel); err != nil {
			panic(err)
		}
	} else {
		// only fetch events after lastEventId
		id, err := strconv.Atoi(lastEventId)
		if err != nil {
			panic(err)
		}
		if rows, err = store.db.Query("SELECT id FROM press_release WHERE id>$1 AND source=$2", id, channel); err != nil {
			panic(err)
		}
	}

	ids = make(chan string)
	go func() {
		defer rows.Close()
		for rows.Next() {
			var id int
			err := rows.Scan(&id)
			if err != nil {
				panic(err)
			}
			ids <- strconv.Itoa(id)
		}
		close(ids)
	}()
	return ids
}
<|endoftext|>


<commit_before><commit_msg>image: implement OCI -> Docker v1 conversion<commit_after><|endoftext|>


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

// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
// and ftp://munnari.oz.au/pub/oldtz/

package time

import (
	"io";
	"once";
	"os"
)

const (
	maxFileSize = 8192;	// actual files are closer to 1K
	headerSize = 4+16+4*7;

	zoneDir = "/usr/share/zoneinfo/";
)

// Errors that can be generated recovering time zone information.
type TimeZoneError struct {
	os.ErrorString
}

func error(bytes []byte) os.Error {
	// TODO(rsc): provide better diagnostics
	return TimeZoneError{ "time: malformed zoneinfo"};
}

// Simple I/O interface to binary blob of data.
type data struct {
	p []byte;
	error bool;
}

func (d *data) read(n int) []byte {
	if len(d.p) < n {
		d.p = nil;
		d.error = true;
		return nil;
	}
	p := d.p[0:n];
	d.p = d.p[n:len(d.p)];
	return p
}

func (d *data) big4() (n uint32, ok bool) {
	p := d.read(4);
	if len(p) < 4 {
		d.error = true;
		return 0, false
	}
	return uint32(p[0]) << 24 | uint32(p[1]) << 16 | uint32(p[2]) << 8 | uint32(p[3]), true
}

func (d *data) byte() (n byte, ok bool) {
	p := d.read(1);
	if len(p) < 1 {
		d.error = true;
		return 0, false
	}
	return p[0], true
}

// Make a string by stopping at the first NUL
func byteString(p []byte) string {
	for i := 0; i < len(p); i++ {
		if p[i] == 0 {
			return string(p[0:i])
		}
	}
	return string(p)
}

// Parsed representation
type zone struct {
	utcoff int;
	isdst bool;
	name string;
}

type zonetime struct {
	time int32;		// transition time, in seconds since 1970 GMT
	zone *zone;		// the zone that goes into effect at that time
	isstd, isutc bool;	// ignored - no idea what these mean
}

func parseinfo(bytes []byte) (zt []zonetime, err os.Error) {
	d := data{bytes, false};

	// 4-byte magic "TZif"
	if magic := d.read(4); string(magic) != "TZif" {
		return nil, error(bytes)
	}

	// 1-byte version, then 15 bytes of padding
	var p []byte;
	if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
		return nil, error(bytes)
	}
	vers := p[0];

	// six big-endian 32-bit integers:
	//	number of UTC/local indicators
	//	number of standard/wall indicators
	//	number of leap seconds
	//	number of transition times
	//	number of local time zones
	//	number of characters of time zone abbrev strings
	const (
		NUTCLocal = iota;
		NStdWall;
		NLeap;
		NTime;
		NZone;
		NChar
	)
	var n [6]int;
	for i := 0; i < 6; i++ {
		nn, ok := d.big4();
		if !ok {
			return nil, error(bytes)
		}
		n[i] = int(nn);
	}

	// Transition times.
	txtimes := data{d.read(n[NTime]*4), false};

	// Time zone indices for transition times.
	txzones := d.read(n[NTime]);

	// Zone info structures
	zonedata := data{d.read(n[NZone]*6), false};

	// Time zone abbreviations.
	abbrev := d.read(n[NChar]);

	// Leap-second time pairs
	leapdata := data{d.read(n[NLeap]*8), false};

	// Whether tx times associated with local time types
	// are specified as standard time or wall time.
	isstd := d.read(n[NStdWall]);

	// Whether tx times associated with local time types
	// are specified as UTC or local time.
	isutc := d.read(n[NUTCLocal]);

	if d.error {	// ran out of data
		return nil, error(bytes)
	}

	// If version == 2, the entire file repeats, this time using
	// 8-byte ints for txtimes and leap seconds.
	// We won't need those until 2106.

	// Now we can build up a useful data structure.
	// First the zone information.
	//	utcoff[4] isdst[1] nameindex[1]
	z := make([]zone, n[NZone]);
	for i := 0; i < len(z); i++ {
		var ok bool;
		var n uint32;
		if n, ok = zonedata.big4(); !ok {
			return nil, error(bytes)
		}
		z[i].utcoff = int(n);
		var b byte;
		if b, ok = zonedata.byte(); !ok {
			return nil, error(bytes)
		}
		z[i].isdst = b != 0;
		if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
			return nil, error(bytes)
		}
		z[i].name = byteString(abbrev[b:len(abbrev)])
	}

	// Now the transition time info.
	zt = make([]zonetime, n[NTime]);
	for i := 0; i < len(zt); i++ {
		var ok bool;
		var n uint32;
		if n, ok = txtimes.big4(); !ok {
			return nil, error(bytes)
		}
		zt[i].time = int32(n);
		if int(txzones[i]) >= len(z) {
			return nil, error(bytes)
		}
		zt[i].zone = &z[txzones[i]];
		if i < len(isstd) {
			zt[i].isstd = isstd[i] != 0
		}
		if i < len(isutc) {
			zt[i].isutc = isutc[i] != 0
		}
	}
	return zt, nil
}

func readfile(name string, max int) (p []byte, err os.Error) {
	f, e := os.Open(name, os.O_RDONLY, 0);
	if e != nil {
		return nil, e;
	}
	p = make([]byte, max);
	n, err1 := io.FullRead(f, p);
	f.Close();
	if err1 == nil {	// too long
		return nil, TimeZoneError{ "time: zone file too long: " + name };
	}
	if err1 != io.ErrEOF {
		return nil, err1;
	}
	return p[0:n], nil;
}

func readinfofile(name string) (tx []zonetime, err os.Error) {
	buf, e := readfile(name, maxFileSize);
	if e != nil {
		return nil, e
	}
	tx, err = parseinfo(buf);
	return tx, err
}

var zones []zonetime
var zoneerr os.Error

func setupZone() {
	// consult $TZ to find the time zone to use.
	// no $TZ means use the system default /etc/localtime.
	// $TZ="" means use UTC.
	// $TZ="foo" means use /usr/share/zoneinfo/foo.

	tz, err := os.Getenv("TZ");
	var file string;
	switch {
	case err == os.ENOENV:
		zones, zoneerr = readinfofile("/etc/localtime");
	case err != nil:
		zoneerr = err;
	case len(tz) > 0:
		zones, zoneerr = readinfofile(zoneDir + tz);
	case len(tz) == 0:
		// do nothing: use UTC
	}
}

func lookupTimezone(sec int64) (zone string, offset int, err os.Error) {
	once.Do(setupZone);
	if zoneerr != nil || len(zones) == 0 {
		return "UTC", 0, zoneerr
	}

	// Binary search for entry with largest time <= sec
	tz := zones;
	for len(tz) > 1 {
		m := len(tz)/2;
		if sec < int64(tz[m].time) {
			tz = tz[0:m]
		} else {
			tz = tz[m:len(tz)]
		}
	}
	z := tz[0].zone;
	return z.name, z.utcoff, nil
}
<commit_msg>better error messages, not that anyone ever sees them<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
// and ftp://munnari.oz.au/pub/oldtz/

package time

import (
	"io";
	"once";
	"os"
)

const (
	maxFileSize = 8192;	// actual files are closer to 1K
	headerSize = 4+16+4*7;

	zoneDir = "/usr/share/zoneinfo/";
)

// Errors that can be generated recovering time zone information.
type TimeZoneError struct {
	os.ErrorString
}

var errShort = TimeZoneError{ "time: short zone file" }
var errInvalid = TimeZoneError{ "time: invalid zone file" }
var errLong = TimeZoneError{ "time: zone file too long" }

// Simple I/O interface to binary blob of data.
type data struct {
	p []byte;
	error bool;
}

func (d *data) read(n int) []byte {
	if len(d.p) < n {
		d.p = nil;
		d.error = true;
		return nil;
	}
	p := d.p[0:n];
	d.p = d.p[n:len(d.p)];
	return p
}

func (d *data) big4() (n uint32, ok bool) {
	p := d.read(4);
	if len(p) < 4 {
		d.error = true;
		return 0, false
	}
	return uint32(p[0]) << 24 | uint32(p[1]) << 16 | uint32(p[2]) << 8 | uint32(p[3]), true
}

func (d *data) byte() (n byte, ok bool) {
	p := d.read(1);
	if len(p) < 1 {
		d.error = true;
		return 0, false
	}
	return p[0], true
}

// Make a string by stopping at the first NUL
func byteString(p []byte) string {
	for i := 0; i < len(p); i++ {
		if p[i] == 0 {
			return string(p[0:i])
		}
	}
	return string(p)
}

// Parsed representation
type zone struct {
	utcoff int;
	isdst bool;
	name string;
}

type zonetime struct {
	time int32;		// transition time, in seconds since 1970 GMT
	zone *zone;		// the zone that goes into effect at that time
	isstd, isutc bool;	// ignored - no idea what these mean
}

func parseinfo(bytes []byte) (zt []zonetime, err os.Error) {
	d := data{bytes, false};

	// 4-byte magic "TZif"
	if magic := d.read(4); string(magic) != "TZif" {
		return nil, TimeZoneError{ "time: bad zone magic" }
	}

	// 1-byte version, then 15 bytes of padding
	var p []byte;
	if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
		return nil, TimeZoneError { "time: bad zone file version" }
	}
	vers := p[0];

	// six big-endian 32-bit integers:
	//	number of UTC/local indicators
	//	number of standard/wall indicators
	//	number of leap seconds
	//	number of transition times
	//	number of local time zones
	//	number of characters of time zone abbrev strings
	const (
		NUTCLocal = iota;
		NStdWall;
		NLeap;
		NTime;
		NZone;
		NChar
	)
	var n [6]int;
	for i := 0; i < 6; i++ {
		nn, ok := d.big4();
		if !ok {
			return nil, errShort
		}
		n[i] = int(nn);
	}

	// Transition times.
	txtimes := data{d.read(n[NTime]*4), false};

	// Time zone indices for transition times.
	txzones := d.read(n[NTime]);

	// Zone info structures
	zonedata := data{d.read(n[NZone]*6), false};

	// Time zone abbreviations.
	abbrev := d.read(n[NChar]);

	// Leap-second time pairs
	leapdata := data{d.read(n[NLeap]*8), false};

	// Whether tx times associated with local time types
	// are specified as standard time or wall time.
	isstd := d.read(n[NStdWall]);

	// Whether tx times associated with local time types
	// are specified as UTC or local time.
	isutc := d.read(n[NUTCLocal]);

	if d.error {	// ran out of data
		return nil, errShort
	}

	// If version == 2, the entire file repeats, this time using
	// 8-byte ints for txtimes and leap seconds.
	// We won't need those until 2106.

	// Now we can build up a useful data structure.
	// First the zone information.
	//	utcoff[4] isdst[1] nameindex[1]
	z := make([]zone, n[NZone]);
	for i := 0; i < len(z); i++ {
		var ok bool;
		var n uint32;
		if n, ok = zonedata.big4(); !ok {
			return nil, errShort
		}
		z[i].utcoff = int(n);
		var b byte;
		if b, ok = zonedata.byte(); !ok {
			return nil, errShort
		}
		z[i].isdst = b != 0;
		if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
			return nil, errInvalid
		}
		z[i].name = byteString(abbrev[b:len(abbrev)])
	}

	// Now the transition time info.
	zt = make([]zonetime, n[NTime]);
	for i := 0; i < len(zt); i++ {
		var ok bool;
		var n uint32;
		if n, ok = txtimes.big4(); !ok {
			return nil, errShort
		}
		zt[i].time = int32(n);
		if int(txzones[i]) >= len(z) {
			return nil, errInvalid
		}
		zt[i].zone = &z[txzones[i]];
		if i < len(isstd) {
			zt[i].isstd = isstd[i] != 0
		}
		if i < len(isutc) {
			zt[i].isutc = isutc[i] != 0
		}
	}
	return zt, nil
}

func readfile(name string, max int) (p []byte, err os.Error) {
	f, e := os.Open(name, os.O_RDONLY, 0);
	if e != nil {
		return nil, e;
	}
	p = make([]byte, max);
	n, err1 := io.FullRead(f, p);
	f.Close();
	if err1 == nil {	// too long
		return nil, errLong;
	}
	if err1 != io.ErrEOF {
		return nil, err1;
	}
	return p[0:n], nil;
}

func readinfofile(name string) ([]zonetime, os.Error) {
	buf, err := readfile(name, maxFileSize);
	if err != nil {
		goto Error;
	}
	tx, err := parseinfo(buf);
	if err != nil {
		goto Error;
	}
	return tx, nil;

Error:
	if tzerr, ok := err.(TimeZoneError); ok {
		tzerr.ErrorString += ": " + name
	}
	return nil, err
}

var zones []zonetime
var zoneerr os.Error

func setupZone() {
	// consult $TZ to find the time zone to use.
	// no $TZ means use the system default /etc/localtime.
	// $TZ="" means use UTC.
	// $TZ="foo" means use /usr/share/zoneinfo/foo.

	tz, err := os.Getenv("TZ");
	var file string;
	switch {
	case err == os.ENOENV:
		zones, zoneerr = readinfofile("/etc/localtime");
	case err != nil:
		zoneerr = err;
	case len(tz) > 0:
		zones, zoneerr = readinfofile(zoneDir + tz);
	case len(tz) == 0:
		// do nothing: use UTC
	}
}

func lookupTimezone(sec int64) (zone string, offset int, err os.Error) {
	once.Do(setupZone);
	if zoneerr != nil || len(zones) == 0 {
		return "UTC", 0, zoneerr
	}

	// Binary search for entry with largest time <= sec
	tz := zones;
	for len(tz) > 1 {
		m := len(tz)/2;
		if sec < int64(tz[m].time) {
			tz = tz[0:m]
		} else {
			tz = tz[m:len(tz)]
		}
	}
	z := tz[0].zone;
	return z.name, z.utcoff, nil
}
<|endoftext|>


<commit_before>package middleware

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/dustin/go-humanize"
	"github.com/go-chi/chi/middleware"
)

// Logger is a middleware that logs useful data about each HTTP request.
type Logger struct {
	Logger middleware.LoggerInterface
}

// NewLogger creates a new RequestLogger Handler.
func NewLogger() func(next http.Handler) http.Handler {
	return middleware.RequestLogger(&Logger{})
}

// NewLogEntry creates a new LogEntry for the request.
func (l *Logger) NewLogEntry(r *http.Request) middleware.LogEntry {
	e := &LogEntry{
		req: r,
		buf: &bytes.Buffer{},
	}

	return e
}

// LogEntry represents an individual log entry.
type LogEntry struct {
	*Logger
	req *http.Request
	buf *bytes.Buffer
}

// Write constructs and writes the final log entry.
func (l *LogEntry) Write(status, bytes int, elapsed time.Duration) {
	rid := GetReqID(l.req.Context())
	if rid != "" {
		fmt.Fprintf(l.buf, "[%s] ", rid)
	}

	fmt.Fprintf(l.buf, "%03d | %s | %s | ", status, humanize.IBytes(uint64(bytes)), elapsed)
	l.buf.WriteString(l.req.Host + " | " + l.req.Method + " " + l.req.RequestURI)
	log.Print(l.buf.String())
}

// Panic prints the call stack for a panic.
func (l *LogEntry) Panic(v interface{}, stack []byte) {
	e := l.NewLogEntry(l.req).(*LogEntry)
	fmt.Fprintf(e.buf, "panic: %#v", v)
	log.Print(e.buf.String())
	log.Print(string(stack))
}
<commit_msg>Rename var to avoid shadowing bytes package<commit_after>package middleware

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/dustin/go-humanize"
	"github.com/go-chi/chi/middleware"
)

// Logger is a middleware that logs useful data about each HTTP request.
type Logger struct {
	Logger middleware.LoggerInterface
}

// NewLogger creates a new RequestLogger Handler.
func NewLogger() func(next http.Handler) http.Handler {
	return middleware.RequestLogger(&Logger{})
}

// NewLogEntry creates a new LogEntry for the request.
func (l *Logger) NewLogEntry(r *http.Request) middleware.LogEntry {
	e := &LogEntry{
		req: r,
		buf: &bytes.Buffer{},
	}

	return e
}

// LogEntry represents an individual log entry.
type LogEntry struct {
	*Logger
	req *http.Request
	buf *bytes.Buffer
}

// Write constructs and writes the final log entry.
func (l *LogEntry) Write(status, totalBytes int, elapsed time.Duration) {
	rid := GetReqID(l.req.Context())
	if rid != "" {
		fmt.Fprintf(l.buf, "[%s] ", rid)
	}

	fmt.Fprintf(l.buf, "%03d | %s | %s | ", status, humanize.IBytes(uint64(totalBytes)), elapsed)
	l.buf.WriteString(l.req.Host + " | " + l.req.Method + " " + l.req.RequestURI)
	log.Print(l.buf.String())
}

// Panic prints the call stack for a panic.
func (l *LogEntry) Panic(v interface{}, stack []byte) {
	e := l.NewLogEntry(l.req).(*LogEntry)
	fmt.Fprintf(e.buf, "panic: %#v", v)
	log.Print(e.buf.String())
	log.Print(string(stack))
}
<|endoftext|>


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

// Package source contains the logic related to the concept of the source which may be tainted.
package source

import (
	"fmt"
	"go/token"
	"go/types"
	"log"
	"strings"

	"github.com/google/go-flow-levee/internal/pkg/sanitizer"
	"github.com/google/go-flow-levee/internal/pkg/utils"
	"golang.org/x/tools/go/analysis/passes/buildssa"
	"golang.org/x/tools/go/ssa"
)

type classifier interface {
	IsSource(types.Type) bool
	IsSanitizer(*ssa.Call) bool
	IsSourceFieldAddr(*ssa.FieldAddr) bool
	IsSinkFunction(fn *ssa.Function) bool
}

// Source represents a Source in an SSA call tree.
// It is based on ssa.Node, with the added functionality of computing the recursive graph of
// its referrers.
// Source.sanitized notes sanitizer calls that sanitize this Source
type Source struct {
	node             ssa.Node
	marked           map[ssa.Node]bool
	preOrder         []ssa.Node
	sanitizers       []*sanitizer.Sanitizer
	config           classifier
	maxInstrReached  map[*ssa.BasicBlock]int
	lastBlockVisited *ssa.BasicBlock
}

// Node returns the underlying ssa.Node of the Source.
func (a *Source) Node() ssa.Node {
	return a.node
}

// New constructs a Source
func New(in ssa.Node, config classifier) *Source {
	a := &Source{
		node:            in,
		marked:          make(map[ssa.Node]bool),
		config:          config,
		maxInstrReached: map[*ssa.BasicBlock]int{},
	}
	a.dfs(in)
	return a
}

// dfs performs Depth-First-Search on the def-use graph of the input Source.
// While traversing the graph we also look for potential sanitizers of this Source.
// If the Source passes through a sanitizer, dfs does not continue through that Node.
func (a *Source) dfs(n ssa.Node) {
	a.preOrder = append(a.preOrder, n)
	a.marked[n.(ssa.Node)] = true

	if instr, ok := n.(ssa.Instruction); ok {
		a.record(instr)
	}

	a.visitReferrers(n)

	operands := n.Operands(nil)
	if operands != nil {
		a.visitOperands(n, operands)
	}
}

func (a *Source) record(target ssa.Instruction) {
	b := target.Block()
	a.lastBlockVisited = b
	i, ok := indexInBlock(target)
	if !ok {
		return
	}
	if a.maxInstrReached[b] < i {
		a.maxInstrReached[b] = i
	}
}

func (a *Source) visitReferrers(n ssa.Node) {
	referrers := a.referrersToVisit(n)

	for _, r := range referrers {
		if a.marked[r.(ssa.Node)] {
			continue
		}

		switch v := r.(type) {
		case *ssa.Call:
			if a.config.IsSanitizer(v) {
				a.sanitizers = append(a.sanitizers, &sanitizer.Sanitizer{Call: v})
			}

		case *ssa.FieldAddr:
			if !a.config.IsSourceFieldAddr(v) {
				continue
			}
		}

		a.dfs(r.(ssa.Node))
	}
}

// referrersToVisit produces a filtered list of Referrers for an ssa.Node.
// Specifically, we avoid referrers that:
// - Are in a block that is not reachable from the current instruction
// - Are calls to a Source method
// - Are calls that occur earlier in the same block as the value being referred
func (a *Source) referrersToVisit(n ssa.Node) (referrers []ssa.Instruction) {
	if n.Referrers() == nil {
		return
	}
	for _, r := range *n.Referrers() {
		// If the referrer is in a different block from the one we last visited,
		// and it can't be reached from the block we are visiting, then stop visiting.
		if rb := r.Block(); a.lastBlockVisited != nil &&
			rb != a.lastBlockVisited &&
			!a.canReach(a.lastBlockVisited, rb) {
			continue
		}

		if c, ok := r.(*ssa.Call); ok {
			// This is to avoid attaching calls where the source is the receiver, ex:
			// core.Sinkf("Source id: %v", wrapper.Source.GetID())
			if recv := c.Call.Signature().Recv(); recv != nil && a.config.IsSource(utils.Dereference(recv.Type())) {
				continue
			}

			// If this call's index is lower than the highest in its block,
			// then this call is "in the past" and we should stop traversing.
			i, ok := indexInBlock(r)
			if !ok {
				continue
			}
			if i < a.maxInstrReached[r.Block()] {
				continue
			}
		}
		referrers = append(referrers, r)
	}
	return referrers
}

func (a *Source) canReach(start *ssa.BasicBlock, dest *ssa.BasicBlock) bool {
	if start.Dominates(dest) {
		return true
	}

	stack := stack([]*ssa.BasicBlock{start})
	seen := map[*ssa.BasicBlock]bool{start: true}
	for len(stack) > 0 {
		current := stack.pop()
		if current == dest {
			return true
		}
		for _, s := range current.Succs {
			if seen[s] {
				continue
			}
			seen[s] = true
			stack.push(s)
		}
	}
	return false
}

func (a *Source) visitOperands(n ssa.Node, operands []*ssa.Value) {
	_, visitingFromExtract := n.(*ssa.Extract)

	for _, o := range operands {
		n, ok := (*o).(ssa.Node)
		if !ok || a.marked[n] {
			continue
		}

		// Do not visit a Call if the current node is an Extract.
		// This is to avoid incorrectly tainting non-Source values that are
		// returned from a call that has a Source among its return values,
		// e.g. a call to a function with a signature like:
		// func CreateSource() (core.Source, error)
		if _, ok := (*o).(*ssa.Call); visitingFromExtract && ok {
			continue
		}

		// An Alloc represents the allocation of space for a variable. If a Node is an Alloc,
		// and the thing being allocated is not an array, then either:
		// a) it is a Source value, in which case it will get its own traversal when sourcesFromBlocks
		//    finds this Alloc
		// b) it is not a Source value, in which case we should not visit it.
		// However, if the Alloc is an array, then that means the source that we are visiting from
		// is being placed into an array, slice or varags, so we do need to keep visiting.
		if al, isAlloc := (*o).(*ssa.Alloc); isAlloc {
			if _, isArray := utils.Dereference(al.Type()).(*types.Array); !isArray {
				return
			}
		}
		a.dfs(n)
	}
}

// compress removes the elements from the graph that are not required by the
// taint-propagation analysis. Concretely, only propagators, sanitizers and
// sinks should constitute the output. Since, we already know what the source
// is, it is also removed.
func (a *Source) compress() []ssa.Node {
	var compressed []ssa.Node
	for _, n := range a.preOrder {
		switch n.(type) {
		case *ssa.Call:
			compressed = append(compressed, n)
		}
	}

	return compressed
}

func (a *Source) RefersTo(n ssa.Node) bool {
	return a.HasPathTo(n)
}

// HasPathTo returns true when a Node is part of declaration-use graph.
func (a *Source) HasPathTo(n ssa.Node) bool {
	return a.marked[n]
}

// IsSanitizedAt returns true when the Source is sanitized by the supplied instruction.
func (a *Source) IsSanitizedAt(call ssa.Instruction) bool {
	for _, s := range a.sanitizers {
		if s.Dominates(call) {
			return true
		}
	}

	return false
}

// String implements Stringer interface.
func (a *Source) String() string {
	var b strings.Builder
	for _, n := range a.compress() {
		b.WriteString(fmt.Sprintf("%v ", n))
	}

	return b.String()
}

func identify(conf classifier, ssaInput *buildssa.SSA) map[*ssa.Function][]*Source {
	sourceMap := make(map[*ssa.Function][]*Source)

	for _, fn := range ssaInput.SrcFuncs {
		// no need to analyze the body of sinks
		if conf.IsSinkFunction(fn) {
			continue
		}

		var sources []*Source
		sources = append(sources, sourcesFromParams(fn, conf)...)
		sources = append(sources, sourcesFromClosure(fn, conf)...)
		sources = append(sources, sourcesFromBlocks(fn, conf)...)

		if len(sources) > 0 {
			sourceMap[fn] = sources
		}
	}
	return sourceMap
}

func sourcesFromParams(fn *ssa.Function, conf classifier) []*Source {
	var sources []*Source
	for _, p := range fn.Params {
		switch t := p.Type().(type) {
		case *types.Pointer:
			if n, ok := t.Elem().(*types.Named); ok && conf.IsSource(n) {
				sources = append(sources, New(p, conf))
			}
			// TODO Handle the case where sources arepassed by value: func(c sourceType)
			// TODO Handle cases where PII is wrapped in struct/slice/map
		}
	}
	return sources
}

func sourcesFromClosure(fn *ssa.Function, conf classifier) []*Source {
	var sources []*Source
	for _, p := range fn.FreeVars {
		switch t := p.Type().(type) {
		case *types.Pointer:
			// FreeVars (variables from a closure) appear as double-pointers
			// Hence, the need to dereference them recursively.
			if s, ok := utils.Dereference(t).(*types.Named); ok && conf.IsSource(s) {
				sources = append(sources, New(p, conf))
			}
		}
	}
	return sources
}

// sourcesFromBlocks finds Source values created by instructions within a function's body.
func sourcesFromBlocks(fn *ssa.Function, conf classifier) []*Source {
	var sources []*Source
	for _, b := range fn.Blocks {
		if b == fn.Recover {
			// TODO Handle calls to log in a recovery block.
			continue
		}

		for _, instr := range b.Instrs {
			// This type switch is used to catch instructions that could produce sources.
			// All instructions that do not match one of the cases will hit the "default"
			// and they will not be examined any further.
			switch v := instr.(type) {
			// drop anything that doesn't match one of the following cases
			default:
				continue

			// source defined as a local variable or returned from a call
			case *ssa.Alloc, *ssa.Call:
				// Allocs and Calls are values
				if isProducedBySanitizer(v.(ssa.Value), conf) {
					continue
				}

			// An Extract is used to obtain a value from an instruction that returns multiple values.
			// If the Extract is used to get a Pointer, create a Source, otherwise the Source won't
			// have an Alloc and we'll miss it.
			case *ssa.Extract:
				t := v.Tuple.Type().(*types.Tuple).At(v.Index).Type()
				if _, ok := t.(*types.Pointer); ok && conf.IsSource(utils.Dereference(t)) {
					sources = append(sources, New(v, conf))
				}
				continue

			// source received from chan
			case *ssa.UnOp:
				// not a <-chan operation
				if v.Op != token.ARROW {
					continue
				}

			// source obtained through a field or an index operation
			case *ssa.FieldAddr, *ssa.IndexAddr, *ssa.Lookup:
			}

			// all of the instructions that the switch lets through are values as per ssa/doc.go
			if v := instr.(ssa.Value); conf.IsSource(utils.Dereference(v.Type())) {
				sources = append(sources, New(v.(ssa.Node), conf))
			}
		}
	}
	return sources
}

func isProducedBySanitizer(v ssa.Value, conf classifier) bool {
	for _, instr := range *v.Referrers() {
		store, ok := instr.(*ssa.Store)
		if !ok {
			continue
		}
		call, ok := store.Val.(*ssa.Call)
		if !ok {
			continue
		}
		if conf.IsSanitizer(call) {
			return true
		}
	}
	return false
}

// indexInBlock returns this instruction's index in its parent block.
func indexInBlock(target ssa.Instruction) (int, bool) {
	for i, instr := range target.Block().Instrs {
		if instr == target {
			return i, true
		}
	}
	// we can only hit this return if there is a bug in the ssa package
	// i.e. an instruction does not appear within its parent block
	return 0, false
}

type stack []*ssa.BasicBlock

func (s *stack) pop() *ssa.BasicBlock {
	if len(*s) == 0 {
		log.Println("tried to pop from empty stack")
	}
	popped := (*s)[len(*s)-1]
	*s = (*s)[:len(*s)-1]
	return popped
}

func (s *stack) push(b *ssa.BasicBlock) {
	*s = append(*s, b)
}
<commit_msg>remove dead todo comments (#112)<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package source contains the logic related to the concept of the source which may be tainted.
package source

import (
	"fmt"
	"go/token"
	"go/types"
	"log"
	"strings"

	"github.com/google/go-flow-levee/internal/pkg/sanitizer"
	"github.com/google/go-flow-levee/internal/pkg/utils"
	"golang.org/x/tools/go/analysis/passes/buildssa"
	"golang.org/x/tools/go/ssa"
)

type classifier interface {
	IsSource(types.Type) bool
	IsSanitizer(*ssa.Call) bool
	IsSourceFieldAddr(*ssa.FieldAddr) bool
	IsSinkFunction(fn *ssa.Function) bool
}

// Source represents a Source in an SSA call tree.
// It is based on ssa.Node, with the added functionality of computing the recursive graph of
// its referrers.
// Source.sanitized notes sanitizer calls that sanitize this Source
type Source struct {
	node             ssa.Node
	marked           map[ssa.Node]bool
	preOrder         []ssa.Node
	sanitizers       []*sanitizer.Sanitizer
	config           classifier
	maxInstrReached  map[*ssa.BasicBlock]int
	lastBlockVisited *ssa.BasicBlock
}

// Node returns the underlying ssa.Node of the Source.
func (a *Source) Node() ssa.Node {
	return a.node
}

// New constructs a Source
func New(in ssa.Node, config classifier) *Source {
	a := &Source{
		node:            in,
		marked:          make(map[ssa.Node]bool),
		config:          config,
		maxInstrReached: map[*ssa.BasicBlock]int{},
	}
	a.dfs(in)
	return a
}

// dfs performs Depth-First-Search on the def-use graph of the input Source.
// While traversing the graph we also look for potential sanitizers of this Source.
// If the Source passes through a sanitizer, dfs does not continue through that Node.
func (a *Source) dfs(n ssa.Node) {
	a.preOrder = append(a.preOrder, n)
	a.marked[n.(ssa.Node)] = true

	if instr, ok := n.(ssa.Instruction); ok {
		a.record(instr)
	}

	a.visitReferrers(n)

	operands := n.Operands(nil)
	if operands != nil {
		a.visitOperands(n, operands)
	}
}

func (a *Source) record(target ssa.Instruction) {
	b := target.Block()
	a.lastBlockVisited = b
	i, ok := indexInBlock(target)
	if !ok {
		return
	}
	if a.maxInstrReached[b] < i {
		a.maxInstrReached[b] = i
	}
}

func (a *Source) visitReferrers(n ssa.Node) {
	referrers := a.referrersToVisit(n)

	for _, r := range referrers {
		if a.marked[r.(ssa.Node)] {
			continue
		}

		switch v := r.(type) {
		case *ssa.Call:
			if a.config.IsSanitizer(v) {
				a.sanitizers = append(a.sanitizers, &sanitizer.Sanitizer{Call: v})
			}

		case *ssa.FieldAddr:
			if !a.config.IsSourceFieldAddr(v) {
				continue
			}
		}

		a.dfs(r.(ssa.Node))
	}
}

// referrersToVisit produces a filtered list of Referrers for an ssa.Node.
// Specifically, we avoid referrers that:
// - Are in a block that is not reachable from the current instruction
// - Are calls to a Source method
// - Are calls that occur earlier in the same block as the value being referred
func (a *Source) referrersToVisit(n ssa.Node) (referrers []ssa.Instruction) {
	if n.Referrers() == nil {
		return
	}
	for _, r := range *n.Referrers() {
		// If the referrer is in a different block from the one we last visited,
		// and it can't be reached from the block we are visiting, then stop visiting.
		if rb := r.Block(); a.lastBlockVisited != nil &&
			rb != a.lastBlockVisited &&
			!a.canReach(a.lastBlockVisited, rb) {
			continue
		}

		if c, ok := r.(*ssa.Call); ok {
			// This is to avoid attaching calls where the source is the receiver, ex:
			// core.Sinkf("Source id: %v", wrapper.Source.GetID())
			if recv := c.Call.Signature().Recv(); recv != nil && a.config.IsSource(utils.Dereference(recv.Type())) {
				continue
			}

			// If this call's index is lower than the highest in its block,
			// then this call is "in the past" and we should stop traversing.
			i, ok := indexInBlock(r)
			if !ok {
				continue
			}
			if i < a.maxInstrReached[r.Block()] {
				continue
			}
		}
		referrers = append(referrers, r)
	}
	return referrers
}

func (a *Source) canReach(start *ssa.BasicBlock, dest *ssa.BasicBlock) bool {
	if start.Dominates(dest) {
		return true
	}

	stack := stack([]*ssa.BasicBlock{start})
	seen := map[*ssa.BasicBlock]bool{start: true}
	for len(stack) > 0 {
		current := stack.pop()
		if current == dest {
			return true
		}
		for _, s := range current.Succs {
			if seen[s] {
				continue
			}
			seen[s] = true
			stack.push(s)
		}
	}
	return false
}

func (a *Source) visitOperands(n ssa.Node, operands []*ssa.Value) {
	_, visitingFromExtract := n.(*ssa.Extract)

	for _, o := range operands {
		n, ok := (*o).(ssa.Node)
		if !ok || a.marked[n] {
			continue
		}

		// Do not visit a Call if the current node is an Extract.
		// This is to avoid incorrectly tainting non-Source values that are
		// returned from a call that has a Source among its return values,
		// e.g. a call to a function with a signature like:
		// func CreateSource() (core.Source, error)
		if _, ok := (*o).(*ssa.Call); visitingFromExtract && ok {
			continue
		}

		// An Alloc represents the allocation of space for a variable. If a Node is an Alloc,
		// and the thing being allocated is not an array, then either:
		// a) it is a Source value, in which case it will get its own traversal when sourcesFromBlocks
		//    finds this Alloc
		// b) it is not a Source value, in which case we should not visit it.
		// However, if the Alloc is an array, then that means the source that we are visiting from
		// is being placed into an array, slice or varags, so we do need to keep visiting.
		if al, isAlloc := (*o).(*ssa.Alloc); isAlloc {
			if _, isArray := utils.Dereference(al.Type()).(*types.Array); !isArray {
				return
			}
		}
		a.dfs(n)
	}
}

// compress removes the elements from the graph that are not required by the
// taint-propagation analysis. Concretely, only propagators, sanitizers and
// sinks should constitute the output. Since, we already know what the source
// is, it is also removed.
func (a *Source) compress() []ssa.Node {
	var compressed []ssa.Node
	for _, n := range a.preOrder {
		switch n.(type) {
		case *ssa.Call:
			compressed = append(compressed, n)
		}
	}

	return compressed
}

func (a *Source) RefersTo(n ssa.Node) bool {
	return a.HasPathTo(n)
}

// HasPathTo returns true when a Node is part of declaration-use graph.
func (a *Source) HasPathTo(n ssa.Node) bool {
	return a.marked[n]
}

// IsSanitizedAt returns true when the Source is sanitized by the supplied instruction.
func (a *Source) IsSanitizedAt(call ssa.Instruction) bool {
	for _, s := range a.sanitizers {
		if s.Dominates(call) {
			return true
		}
	}

	return false
}

// String implements Stringer interface.
func (a *Source) String() string {
	var b strings.Builder
	for _, n := range a.compress() {
		b.WriteString(fmt.Sprintf("%v ", n))
	}

	return b.String()
}

func identify(conf classifier, ssaInput *buildssa.SSA) map[*ssa.Function][]*Source {
	sourceMap := make(map[*ssa.Function][]*Source)

	for _, fn := range ssaInput.SrcFuncs {
		// no need to analyze the body of sinks
		if conf.IsSinkFunction(fn) {
			continue
		}

		var sources []*Source
		sources = append(sources, sourcesFromParams(fn, conf)...)
		sources = append(sources, sourcesFromClosure(fn, conf)...)
		sources = append(sources, sourcesFromBlocks(fn, conf)...)

		if len(sources) > 0 {
			sourceMap[fn] = sources
		}
	}
	return sourceMap
}

func sourcesFromParams(fn *ssa.Function, conf classifier) []*Source {
	var sources []*Source
	for _, p := range fn.Params {
		switch t := p.Type().(type) {
		case *types.Pointer:
			if n, ok := t.Elem().(*types.Named); ok && conf.IsSource(n) {
				sources = append(sources, New(p, conf))
			}
		}
	}
	return sources
}

func sourcesFromClosure(fn *ssa.Function, conf classifier) []*Source {
	var sources []*Source
	for _, p := range fn.FreeVars {
		switch t := p.Type().(type) {
		case *types.Pointer:
			// FreeVars (variables from a closure) appear as double-pointers
			// Hence, the need to dereference them recursively.
			if s, ok := utils.Dereference(t).(*types.Named); ok && conf.IsSource(s) {
				sources = append(sources, New(p, conf))
			}
		}
	}
	return sources
}

// sourcesFromBlocks finds Source values created by instructions within a function's body.
func sourcesFromBlocks(fn *ssa.Function, conf classifier) []*Source {
	var sources []*Source
	for _, b := range fn.Blocks {
		if b == fn.Recover {
			// TODO Handle calls to log in a recovery block.
			continue
		}

		for _, instr := range b.Instrs {
			// This type switch is used to catch instructions that could produce sources.
			// All instructions that do not match one of the cases will hit the "default"
			// and they will not be examined any further.
			switch v := instr.(type) {
			// drop anything that doesn't match one of the following cases
			default:
				continue

			// source defined as a local variable or returned from a call
			case *ssa.Alloc, *ssa.Call:
				// Allocs and Calls are values
				if isProducedBySanitizer(v.(ssa.Value), conf) {
					continue
				}

			// An Extract is used to obtain a value from an instruction that returns multiple values.
			// If the Extract is used to get a Pointer, create a Source, otherwise the Source won't
			// have an Alloc and we'll miss it.
			case *ssa.Extract:
				t := v.Tuple.Type().(*types.Tuple).At(v.Index).Type()
				if _, ok := t.(*types.Pointer); ok && conf.IsSource(utils.Dereference(t)) {
					sources = append(sources, New(v, conf))
				}
				continue

			// source received from chan
			case *ssa.UnOp:
				// not a <-chan operation
				if v.Op != token.ARROW {
					continue
				}

			// source obtained through a field or an index operation
			case *ssa.FieldAddr, *ssa.IndexAddr, *ssa.Lookup:
			}

			// all of the instructions that the switch lets through are values as per ssa/doc.go
			if v := instr.(ssa.Value); conf.IsSource(utils.Dereference(v.Type())) {
				sources = append(sources, New(v.(ssa.Node), conf))
			}
		}
	}
	return sources
}

func isProducedBySanitizer(v ssa.Value, conf classifier) bool {
	for _, instr := range *v.Referrers() {
		store, ok := instr.(*ssa.Store)
		if !ok {
			continue
		}
		call, ok := store.Val.(*ssa.Call)
		if !ok {
			continue
		}
		if conf.IsSanitizer(call) {
			return true
		}
	}
	return false
}

// indexInBlock returns this instruction's index in its parent block.
func indexInBlock(target ssa.Instruction) (int, bool) {
	for i, instr := range target.Block().Instrs {
		if instr == target {
			return i, true
		}
	}
	// we can only hit this return if there is a bug in the ssa package
	// i.e. an instruction does not appear within its parent block
	return 0, false
}

type stack []*ssa.BasicBlock

func (s *stack) pop() *ssa.BasicBlock {
	if len(*s) == 0 {
		log.Println("tried to pop from empty stack")
	}
	popped := (*s)[len(*s)-1]
	*s = (*s)[:len(*s)-1]
	return popped
}

func (s *stack) push(b *ssa.BasicBlock) {
	*s = append(*s, b)
}
<|endoftext|>


<commit_before>package spline

import (
	"github.com/ready-steady/linear/system"
)

// Cubic represents a cubic interpolant.
type Cubic struct {
	breaks  []float64
	weights []float64
}

// NewCubic constructs a cubic interpolant for a series of points. The abscissae
// should be a strictly increasing sequence with at least two elements. The
// ordinates can be multidimensional.
func NewCubic(x, y []float64) *Cubic {
	n := len(x)
	nd := len(y) / n

	dx := make([]float64, n-1)
	dydx := make([]float64, (n-1)*nd)
	for i := 0; i < (n - 1); i++ {
		dx[i] = x[i+1] - x[i]
		for j := 0; j < nd; j++ {
			dydx[i*nd+j] = (y[(i+1)*nd+j] - y[i*nd+j]) / dx[i]
		}
	}

	s := &Cubic{}

	switch n {
	case 2:
		s.breaks = []float64{x[0], x[1]}
		s.weights = make([]float64, nd*4)
		for j := 0; j < nd; j++ {
			s.weights[j*4+2] = dydx[j]
			s.weights[j*4+3] = y[j]
		}
	case 3:
		s.breaks = []float64{x[0], x[2]}
		s.weights = make([]float64, nd*4)
		for j := 0; j < nd; j++ {
			c1 := (dydx[nd+j] - dydx[j]) / (x[2] - x[0])
			s.weights[j*4+1] = c1
			s.weights[j*4+2] = dydx[j] - c1*dx[0]
			s.weights[j*4+3] = y[j]
		}
	default:
		xb := x[2] - x[0]
		xe := x[n-1] - x[n-3]

		a := make([]float64, n)
		for i := 0; i < (n - 2); i++ {
			a[i] = dx[i+1]
		}
		a[n-2] = xe

		b := make([]float64, n)
		b[0] = dx[1]
		for i := 1; i < (n - 1); i++ {
			b[i] = 2 * (dx[i] + dx[i-1])
		}
		b[n-1] = dx[n-3]

		c := make([]float64, n)
		c[1] = xb
		for i := 2; i < n; i++ {
			c[i] = dx[i-2]
		}

		d := make([]float64, nd*n)
		for j := 0; j < nd; j++ {
			d[j*n] = ((dx[0]+2*xb)*dx[1]*dydx[j] + dx[0]*dx[0]*dydx[nd+j]) / xb
			for i := 1; i < (n - 1); i++ {
				d[j*n+i] = 3 * (dx[i]*dydx[(i-1)*nd+j] + dx[i-1]*dydx[i*nd+j])
			}
			d[j*n+n-1] = (dx[n-2]*dx[n-2]*dydx[(n-3)*nd+j] +
				(2*xe+dx[n-2])*dx[n-3]*dydx[(n-2)*nd+j]) / xe
		}

		slopes := system.ComputeTridiagonal(a, b, c, d)

		s.breaks = make([]float64, n)
		copy(s.breaks, x)

		s.weights = make([]float64, (n-1)*nd*4)
		for i := 0; i < (n - 1); i++ {
			for j := 0; j < nd; j++ {
				α := (dydx[i*nd+j] - slopes[j*n+i]) / dx[i]
				β := (slopes[j*n+i+1] - dydx[i*nd+j]) / dx[i]
				s.weights[i*nd*4+j*4] = (β - α) / dx[i]
				s.weights[i*nd*4+j*4+1] = 2*α - β
				s.weights[i*nd*4+j*4+2] = slopes[j*n+i]
				s.weights[i*nd*4+j*4+3] = y[i*nd+j]
			}
		}
	}

	return s
}

// Compute calculates the ordinates corresponding to a series of abscissae. The
// abscissae should be an increasing sequence.
func (s *Cubic) Compute(x []float64) []float64 {
	n, nb := len(x), len(s.breaks)
	nd := len(s.weights) / (4 * (nb - 1))

	y := make([]float64, n*nd)

	for i, k := 0, 0; i < n; i++ {
		for x[i] > s.breaks[k+1] && k < (nb-2) {
			k++
		}

		z := x[i] - s.breaks[k]
		for j := 0; j < nd; j++ {
			y[i*nd+j] = s.weights[k*nd*4+j*4]
			y[i*nd+j] = z*y[i*nd+j] + s.weights[k*nd*4+j*4+1]
			y[i*nd+j] = z*y[i*nd+j] + s.weights[k*nd*4+j*4+2]
			y[i*nd+j] = z*y[i*nd+j] + s.weights[k*nd*4+j*4+3]
		}
	}

	return y
}
<commit_msg>Adjusted the description of Cubic<commit_after>package spline

import (
	"github.com/ready-steady/linear/system"
)

// Cubic represents a cubic interpolant.
type Cubic struct {
	breaks  []float64
	weights []float64
}

// NewCubic constructs a cubic interpolant for a series of nodes. The abscissae
// of the nodes should be a strictly increasing sequence with at least two
// elements. The ordinates of the nodes can be multidimensional.
func NewCubic(x, y []float64) *Cubic {
	n := len(x)
	nd := len(y) / n

	dx := make([]float64, n-1)
	dydx := make([]float64, (n-1)*nd)
	for i := 0; i < (n - 1); i++ {
		dx[i] = x[i+1] - x[i]
		for j := 0; j < nd; j++ {
			dydx[i*nd+j] = (y[(i+1)*nd+j] - y[i*nd+j]) / dx[i]
		}
	}

	s := &Cubic{}

	switch n {
	case 2:
		s.breaks = []float64{x[0], x[1]}
		s.weights = make([]float64, nd*4)
		for j := 0; j < nd; j++ {
			s.weights[j*4+2] = dydx[j]
			s.weights[j*4+3] = y[j]
		}
	case 3:
		s.breaks = []float64{x[0], x[2]}
		s.weights = make([]float64, nd*4)
		for j := 0; j < nd; j++ {
			c1 := (dydx[nd+j] - dydx[j]) / (x[2] - x[0])
			s.weights[j*4+1] = c1
			s.weights[j*4+2] = dydx[j] - c1*dx[0]
			s.weights[j*4+3] = y[j]
		}
	default:
		xb := x[2] - x[0]
		xe := x[n-1] - x[n-3]

		a := make([]float64, n)
		for i := 0; i < (n - 2); i++ {
			a[i] = dx[i+1]
		}
		a[n-2] = xe

		b := make([]float64, n)
		b[0] = dx[1]
		for i := 1; i < (n - 1); i++ {
			b[i] = 2 * (dx[i] + dx[i-1])
		}
		b[n-1] = dx[n-3]

		c := make([]float64, n)
		c[1] = xb
		for i := 2; i < n; i++ {
			c[i] = dx[i-2]
		}

		d := make([]float64, nd*n)
		for j := 0; j < nd; j++ {
			d[j*n] = ((dx[0]+2*xb)*dx[1]*dydx[j] + dx[0]*dx[0]*dydx[nd+j]) / xb
			for i := 1; i < (n - 1); i++ {
				d[j*n+i] = 3 * (dx[i]*dydx[(i-1)*nd+j] + dx[i-1]*dydx[i*nd+j])
			}
			d[j*n+n-1] = (dx[n-2]*dx[n-2]*dydx[(n-3)*nd+j] +
				(2*xe+dx[n-2])*dx[n-3]*dydx[(n-2)*nd+j]) / xe
		}

		slopes := system.ComputeTridiagonal(a, b, c, d)

		s.breaks = make([]float64, n)
		copy(s.breaks, x)

		s.weights = make([]float64, (n-1)*nd*4)
		for i := 0; i < (n - 1); i++ {
			for j := 0; j < nd; j++ {
				α := (dydx[i*nd+j] - slopes[j*n+i]) / dx[i]
				β := (slopes[j*n+i+1] - dydx[i*nd+j]) / dx[i]
				s.weights[i*nd*4+j*4] = (β - α) / dx[i]
				s.weights[i*nd*4+j*4+1] = 2*α - β
				s.weights[i*nd*4+j*4+2] = slopes[j*n+i]
				s.weights[i*nd*4+j*4+3] = y[i*nd+j]
			}
		}
	}

	return s
}

// Compute interpolates the ordinates of a series of points. The abscissae of
// the points should be an increasing sequence whose elements are in the range
// of the nodes fed into NewCubic.
func (s *Cubic) Compute(x []float64) []float64 {
	n, nb := len(x), len(s.breaks)
	nd := len(s.weights) / (4 * (nb - 1))

	y := make([]float64, n*nd)

	for i, k := 0, 0; i < n; i++ {
		for x[i] > s.breaks[k+1] && k < (nb-2) {
			k++
		}

		z := x[i] - s.breaks[k]
		for j := 0; j < nd; j++ {
			y[i*nd+j] = s.weights[k*nd*4+j*4]
			y[i*nd+j] = z*y[i*nd+j] + s.weights[k*nd*4+j*4+1]
			y[i*nd+j] = z*y[i*nd+j] + s.weights[k*nd*4+j*4+2]
			y[i*nd+j] = z*y[i*nd+j] + s.weights[k*nd*4+j*4+3]
		}
	}

	return y
}
<|endoftext|>


<commit_before>package main

import "netlink"
import "netlink/rtmanip"
import "netlink/rtnetlink/link"
import "flag"
import "log"
import "os"

var DoUp = flag.Bool("up",false, "Turn interface up")
var DoDown = flag.Bool("down",false, "Turn interface up")
var IfName = flag.String("ifname", "", "Interface to use")

func main(){
  flag.Parse()
  nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE)
  if err != nil {
    log.Exitf("Couldn't dial netlink: %v", err)
  }
  h := netlink.NewHandler(nlsock)
  ec := make(chan os.Error)
  go func(){
    for e := range(ec) {
      log.Printf("Netlink error: %v", e)
    }
  }()
  go h.Start(ec)
  lf := rtmanip.NewLinkFinder(h)
  l, err := lf.GetLinkByName(*IfName)
  if err == nil {
    if *DoDown {
      err = l.SetLinkState(^link.IFF_UP)
      if err != nil { log.Printf("Couldn't turn down interface: %v", err) }
      l.Refresh()
    }
    if *DoUp {
      err = l.SetLinkState(link.IFF_UP)
      if err != nil { log.Printf("Couldn't turn up interface: %v", err) }
      l.Refresh()
    }
    log.Printf("Link Index: %d", l.LinkIndex())
    log.Printf("Link Name: %s", l.LinkName())
    log.Printf("Link Flags: %s", l.LinkFlags())
    log.Printf("Link MTU: %d", l.LinkMTU())
    log.Printf("Link (l2) Address: %x", l.LinkAddress())
    log.Printf("Link (l2) Broadcast: %x", l.LinkBroadcastAddress())
  } else {
    log.Exitf("Couldn't get link: %v", err)
  }
}
<commit_msg>Lower case ifmanip flag vars (godoc)<commit_after>package main

import "netlink"
import "netlink/rtmanip"
import "netlink/rtnetlink/link"
import "flag"
import "log"
import "os"

var doUp = flag.Bool("up",false, "Turn interface up")
var doDown = flag.Bool("down",false, "Turn interface up")
var ifName = flag.String("ifname", "", "Interface to use")

func main(){
  flag.Parse()
  nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE)
  if err != nil {
    log.Exitf("Couldn't dial netlink: %v", err)
  }
  h := netlink.NewHandler(nlsock)
  ec := make(chan os.Error)
  go func(){
    for e := range(ec) {
      log.Printf("Netlink error: %v", e)
    }
  }()
  go h.Start(ec)
  lf := rtmanip.NewLinkFinder(h)
  l, err := lf.GetLinkByName(*ifName)
  if err == nil {
    if *doDown {
      err = l.SetLinkState(^link.IFF_UP)
      if err != nil { log.Printf("Couldn't turn down interface: %v", err) }
      l.Refresh()
    }
    if *doUp {
      err = l.SetLinkState(link.IFF_UP)
      if err != nil { log.Printf("Couldn't turn up interface: %v", err) }
      l.Refresh()
    }
    log.Printf("Link Index: %d", l.LinkIndex())
    log.Printf("Link Name: %s", l.LinkName())
    log.Printf("Link Flags: %s", l.LinkFlags())
    log.Printf("Link MTU: %d", l.LinkMTU())
    log.Printf("Link (l2) Address: %x", l.LinkAddress())
    log.Printf("Link (l2) Broadcast: %x", l.LinkBroadcastAddress())
  } else {
    log.Exitf("Couldn't get link: %v", err)
  }
}
<|endoftext|>