<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"math"
	"os"
	unsafe "unsafe"
)

const (
	DEMO_HEADER_ID string = "HL2DEMO"
	DEMO_PROTOCOL  int32  = 4
)

type DemoHeader struct {
	demoFileStamp   [8]byte
	demoProtocol    int32
	networkProtocol int32
	serverName      [260]byte
	clientName      [260]byte
	mapName         [260]byte
	gameDirectory   [260]byte
	playbackTime    float32
	playbackTicks   int32
	playbackFrames  int32
	signonLength    int32
}

// FileStampString removes NUL values first
func (dh *DemoHeader) FileStampString() string {
	return string(bytes.Trim(dh.demoFileStamp[:], "\x00"))
}

type DemoFile struct {
	FileBuffer    string
	fileBufferPos int

	FileName   string
	DemoHeader DemoHeader
}

func (d *DemoFile) Open(fileName string) bool {
	d.Close() // reset the structure

	//open file
	f, err := os.Open(fileName)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	// get length of file
	fi, err := f.Stat()
	if err != nil {
		log.Fatal(err)
		return false
	}

	length := fi.Size()

	// check size
	// http://stackoverflow.com/questions/23202864/assigning-a-type-uintptr-to-uint64-in-golang
	hdrSize := (int64)(unsafe.Pointer(unsafe.Sizeof(d.DemoHeader))) + 3 // demoheader is off for some reason
	if length < hdrSize {
		log.Fatal("File is too small")
		return false
	}

	// fread?
	f.Seek(0, 0) // go back to the beginning of the file
	reader := bufio.NewReader(f)
	hdrBytes := make([]byte, hdrSize)
	_, err = reader.Read(hdrBytes)
	if err != nil {
		log.Fatal(err)
		return false
	}

	d.fillDemoHeader(hdrBytes)
	//d.debugHeader()

	// reduce the length var based on size of demoheader
	length -= hdrSize

	// check demofilestamp matches demo headerid
	if d.DemoHeader.FileStampString() != DEMO_HEADER_ID {
		log.Fatal("File stamp doesn't match")
	}

	// check demoprotocol is valid
	if d.DemoHeader.demoProtocol != DEMO_PROTOCOL {
		log.Fatal("Demo protocol is invalid")
		return false
	}

	// read into buffer
	var tmpFileBuffer []byte = make([]byte, length)
	_, err = reader.Read(tmpFileBuffer)
	if err != nil {
		log.Fatal(err)
		return false
	}
	d.FileBuffer = string(tmpFileBuffer)

	d.fileBufferPos = 0
	d.FileName = fileName

	return true
}

func (d *DemoFile) debugHeader() {
	fmt.Println(string(d.DemoHeader.demoFileStamp[:]))
	fmt.Println(d.DemoHeader.demoProtocol)
	fmt.Println(d.DemoHeader.networkProtocol)
	fmt.Println(string(d.DemoHeader.serverName[:]))
	fmt.Println(string(d.DemoHeader.clientName[:]))
	fmt.Println(string(d.DemoHeader.mapName[:]))
	fmt.Println(string(d.DemoHeader.gameDirectory[:]))
	fmt.Println(d.DemoHeader.playbackTime)
	fmt.Println(d.DemoHeader.playbackTicks)
	fmt.Println(d.DemoHeader.playbackFrames)
	fmt.Println(d.DemoHeader.signonLength)
}

func (d *DemoFile) fillDemoHeader(header []byte) {
	var newHeader []byte = header

	// get the demo files stamp
	copy(d.DemoHeader.demoFileStamp[:], newHeader[0:7])

	// get demo protocol
	d.DemoHeader.demoProtocol = byteSliceToInt32(newHeader[8:12])

	// get protocol version
	d.DemoHeader.networkProtocol = byteSliceToInt32(newHeader[13:17])

	// servername, clientname, mapname, directory
	copy(d.DemoHeader.serverName[:], newHeader[16:275])
	copy(d.DemoHeader.clientName[:], newHeader[276:535])
	copy(d.DemoHeader.mapName[:], newHeader[536:795])
	copy(d.DemoHeader.gameDirectory[:], newHeader[796:1055])

	// playback
	d.DemoHeader.playbackTime = byteSliceToFloat32(newHeader[1056:1060])
	d.DemoHeader.playbackTicks = byteSliceToInt32(newHeader[1061:1065])
	d.DemoHeader.playbackTicks = byteSliceToInt32(newHeader[1066:1070])
	d.DemoHeader.signonLength = byteSliceToInt32(newHeader[1071:1075])
}

func byteSliceToInt32(data []byte) int32 {
	var result int32
	buf := bytes.NewBuffer(data)
	err := binary.Read(buf, binary.LittleEndian, &result)
	if err != nil {
		panic(err)
	}
	return result
}

func byteSliceToFloat32(data []byte) float32 {
	bits := binary.LittleEndian.Uint32(data)
	result := math.Float32frombits(bits)
	return result
}

func (d *DemoFile) Close() {
	d.FileName = ""

	d.fileBufferPos = 0
	d.FileBuffer = ""
}

func (d *DemoFile) ReadRawData(buffer []byte, length int32) int32 {
	return 0
}

func (d *DemoFile) ReadSequenceInfo(seqNrIn *int32, seqNrOutAck *int32) {
}

func (d *DemoFile) ReadCmdInfo(info *DemoCmdInfo) {
}

func (d *DemoFile) ReadCmdHeader(cmd *string, tick *int32, playerSlot *string) {
}

/*func (d *DemoFile) ReadDemoHeader() DemoHeader {
	return nil
}*/
<commit_msg>Fixed header parsing<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"math"
	"os"
	unsafe "unsafe"
)

const (
	DEMO_HEADER_ID string = "HL2DEMO"
	DEMO_PROTOCOL  int32  = 4
)

type DemoHeader struct {
	demoFileStamp   [8]byte
	demoProtocol    int32
	networkProtocol int32
	serverName      [260]byte
	clientName      [260]byte
	mapName         [260]byte
	gameDirectory   [260]byte
	playbackTime    float32
	playbackTicks   int32
	playbackFrames  int32
	signonLength    int32
}

// FileStampString removes NUL values first
func (dh *DemoHeader) FileStampString() string {
	return string(bytes.Trim(dh.demoFileStamp[:], "\x00"))
}

type DemoFile struct {
	FileBuffer    string
	fileBufferPos int

	FileName   string
	DemoHeader DemoHeader
}

func (d *DemoFile) Open(fileName string) bool {
	d.Close() // reset the structure

	//open file
	f, err := os.Open(fileName)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	// get length of file
	fi, err := f.Stat()
	if err != nil {
		log.Fatal(err)
		return false
	}

	length := fi.Size()

	// check size
	// http://stackoverflow.com/questions/23202864/assigning-a-type-uintptr-to-uint64-in-golang
	hdrSize := (int64)(unsafe.Pointer(unsafe.Sizeof(d.DemoHeader)))
	if length < hdrSize {
		log.Fatal("File is too small")
		return false
	}

	// fread?
	f.Seek(0, 0) // go back to the beginning of the file
	reader := bufio.NewReader(f)
	hdrBytes := make([]byte, hdrSize)
	_, err = reader.Read(hdrBytes)
	if err != nil {
		log.Fatal(err)
		return false
	}

	d.fillDemoHeader(hdrBytes)
	//d.debugHeader()

	// reduce the length var based on size of demoheader
	length -= hdrSize

	// check demofilestamp matches demo headerid
	if d.DemoHeader.FileStampString() != DEMO_HEADER_ID {
		log.Fatal("File stamp doesn't match")
	}

	// check demoprotocol is valid
	if d.DemoHeader.demoProtocol != DEMO_PROTOCOL {
		log.Fatal("Demo protocol is invalid")
		return false
	}

	// read into buffer
	var tmpFileBuffer []byte = make([]byte, length)
	_, err = reader.Read(tmpFileBuffer)
	if err != nil {
		log.Fatal(err)
		return false
	}
	d.FileBuffer = string(tmpFileBuffer)

	d.fileBufferPos = 0
	d.FileName = fileName

	return true
}

func (d *DemoFile) debugHeader() {
	fmt.Println(string(d.DemoHeader.demoFileStamp[:]))
	fmt.Println(d.DemoHeader.demoProtocol)
	fmt.Println(d.DemoHeader.networkProtocol)
	fmt.Println(string(d.DemoHeader.serverName[:]))
	fmt.Println(string(d.DemoHeader.clientName[:]))
	fmt.Println(string(d.DemoHeader.mapName[:]))
	fmt.Println(string(d.DemoHeader.gameDirectory[:]))
	fmt.Println(d.DemoHeader.playbackTime)
	fmt.Println(d.DemoHeader.playbackTicks)
	fmt.Println(d.DemoHeader.playbackFrames)
	fmt.Println(d.DemoHeader.signonLength)
}

func (d *DemoFile) fillDemoHeader(header []byte) {
	var newHeader []byte = header
	//fmt.Println(newHeader)

	// get the demo files stamp
	copy(d.DemoHeader.demoFileStamp[:], newHeader[:7])

	// get demo protocol
	d.DemoHeader.demoProtocol = byteSliceToInt32(newHeader[8:12])

	// get protocol version
	d.DemoHeader.networkProtocol = byteSliceToInt32(newHeader[12:16])

	// servername, clientname, mapname, directory
	copy(d.DemoHeader.serverName[:], newHeader[16:276])
	copy(d.DemoHeader.clientName[:], newHeader[276:536])
	copy(d.DemoHeader.mapName[:], newHeader[536:796])
	copy(d.DemoHeader.gameDirectory[:], newHeader[796:1056])

	// playback
	d.DemoHeader.playbackTime = byteSliceToFloat32(newHeader[1056:1060])
	d.DemoHeader.playbackTicks = byteSliceToInt32(newHeader[1060:1064])
	d.DemoHeader.playbackTicks = byteSliceToInt32(newHeader[1064:1068])
	d.DemoHeader.signonLength = byteSliceToInt32(newHeader[1068:])
}

func byteSliceToInt32(data []byte) int32 {
	var result int32
	buf := bytes.NewBuffer(data)
	err := binary.Read(buf, binary.LittleEndian, &result)
	if err != nil {
		panic(err)
	}
	return result
}

func byteSliceToFloat32(data []byte) float32 {
	bits := binary.LittleEndian.Uint32(data)
	result := math.Float32frombits(bits)
	return result
}

func (d *DemoFile) Close() {
	d.FileName = ""

	d.fileBufferPos = 0
	d.FileBuffer = ""
}

func (d *DemoFile) ReadRawData(buffer []byte, length int32) int32 {
	return 0
}

func (d *DemoFile) ReadSequenceInfo(seqNrIn *int32, seqNrOutAck *int32) {
}

func (d *DemoFile) ReadCmdInfo(info *DemoCmdInfo) {
}

func (d *DemoFile) ReadCmdHeader(cmd *string, tick *int32, playerSlot *string) {
}

/*func (d *DemoFile) ReadDemoHeader() DemoHeader {
	return nil
}*/
<|endoftext|>


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

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package problemclient

import (
	"encoding/json"
	"fmt"
	"net/url"
	"os"
	"path/filepath"

	typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/kubernetes/pkg/api/legacyscheme"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/clock"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/record"

	"github.com/golang/glog"
	"k8s.io/heapster/common/kubernetes"
	"k8s.io/node-problem-detector/cmd/options"
	"k8s.io/node-problem-detector/pkg/version"
)

// Client is the interface of problem client
type Client interface {
	// GetConditions get all specifiec conditions of current node.
	GetConditions(conditionTypes []v1.NodeConditionType) ([]*v1.NodeCondition, error)
	// SetConditions set or update conditions of current node.
	SetConditions(conditions []v1.NodeCondition) error
	// Eventf reports the event.
	Eventf(eventType string, source, reason, messageFmt string, args ...interface{})
	// GetNode returns the Node object of the node on which the
	// node-problem-detector runs.
	GetNode() (*v1.Node, error)
}

type nodeProblemClient struct {
	nodeName  string
	client    typedcorev1.CoreV1Interface
	clock     clock.Clock
	recorders map[string]record.EventRecorder
	nodeRef   *v1.ObjectReference
}

// NewClientOrDie creates a new problem client, panics if error occurs.
func NewClientOrDie(npdo *options.NodeProblemDetectorOptions) Client {
	c := &nodeProblemClient{clock: clock.RealClock{}}

	// we have checked it is a valid URI after command line argument is parsed.:)
	uri, _ := url.Parse(npdo.ApiServerOverride)

	cfg, err := kubernetes.GetKubeClientConfig(uri)
	if err != nil {
		panic(err)
	}

	cfg.UserAgent = fmt.Sprintf("%s/%s", filepath.Base(os.Args[0]), version.Version())
	// TODO(random-liu): Set QPS Limit
	c.client = clientset.NewForConfigOrDie(cfg).CoreV1()
	c.nodeName = npdo.NodeName
	c.nodeRef = getNodeRef(c.nodeName)
	c.recorders = make(map[string]record.EventRecorder)
	return c
}

func (c *nodeProblemClient) GetConditions(conditionTypes []v1.NodeConditionType) ([]*v1.NodeCondition, error) {
	node, err := c.GetNode()
	if err != nil {
		return nil, err
	}
	conditions := []*v1.NodeCondition{}
	for _, conditionType := range conditionTypes {
		for _, condition := range node.Status.Conditions {
			if condition.Type == conditionType {
				conditions = append(conditions, &condition)
			}
		}
	}
	return conditions, nil
}

func (c *nodeProblemClient) SetConditions(newConditions []v1.NodeCondition) error {
	for i := range newConditions {
		// Each time we update the conditions, we update the heart beat time
		newConditions[i].LastHeartbeatTime = metav1.NewTime(c.clock.Now())
	}
	patch, err := generatePatch(newConditions)
	if err != nil {
		return err
	}
	return c.client.RESTClient().Patch(types.StrategicMergePatchType).Resource("nodes").Name(c.nodeName).SubResource("status").Body(patch).Do().Error()
}

func (c *nodeProblemClient) Eventf(eventType, source, reason, messageFmt string, args ...interface{}) {
	recorder, found := c.recorders[source]
	if !found {
		// TODO(random-liu): If needed use separate client and QPS limit for event.
		recorder = getEventRecorder(c.client, c.nodeName, source)
		c.recorders[source] = recorder
	}
	recorder.Eventf(c.nodeRef, eventType, reason, messageFmt, args...)
}

func (c *nodeProblemClient) GetNode() (*v1.Node, error) {
	return c.client.Nodes().Get(c.nodeName, metav1.GetOptions{})
}

// generatePatch generates condition patch
func generatePatch(conditions []v1.NodeCondition) ([]byte, error) {
	raw, err := json.Marshal(&conditions)
	if err != nil {
		return nil, err
	}
	return []byte(fmt.Sprintf(`{"status":{"conditions":%s}}`, raw)), nil
}

// getEventRecorder generates a recorder for specific node name and source.
func getEventRecorder(c typedcorev1.CoreV1Interface, nodeName, source string) record.EventRecorder {
	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartLogging(glog.V(4).Infof)
	recorder := eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: source, Host: nodeName})
	eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: c.Events("")})
	return recorder
}

func getNodeRef(nodeName string) *v1.ObjectReference {
	// TODO(random-liu): Get node to initialize the node reference
	return &v1.ObjectReference{
		Kind:      "Node",
		Name:      nodeName,
		UID:       types.UID(nodeName),
		Namespace: "",
	}
}
<commit_msg>fix a spelling error<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package problemclient

import (
	"encoding/json"
	"fmt"
	"net/url"
	"os"
	"path/filepath"

	typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/kubernetes/pkg/api/legacyscheme"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/clock"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/record"

	"github.com/golang/glog"
	"k8s.io/heapster/common/kubernetes"
	"k8s.io/node-problem-detector/cmd/options"
	"k8s.io/node-problem-detector/pkg/version"
)

// Client is the interface of problem client
type Client interface {
	// GetConditions get all specific conditions of current node.
	GetConditions(conditionTypes []v1.NodeConditionType) ([]*v1.NodeCondition, error)
	// SetConditions set or update conditions of current node.
	SetConditions(conditions []v1.NodeCondition) error
	// Eventf reports the event.
	Eventf(eventType string, source, reason, messageFmt string, args ...interface{})
	// GetNode returns the Node object of the node on which the
	// node-problem-detector runs.
	GetNode() (*v1.Node, error)
}

type nodeProblemClient struct {
	nodeName  string
	client    typedcorev1.CoreV1Interface
	clock     clock.Clock
	recorders map[string]record.EventRecorder
	nodeRef   *v1.ObjectReference
}

// NewClientOrDie creates a new problem client, panics if error occurs.
func NewClientOrDie(npdo *options.NodeProblemDetectorOptions) Client {
	c := &nodeProblemClient{clock: clock.RealClock{}}

	// we have checked it is a valid URI after command line argument is parsed.:)
	uri, _ := url.Parse(npdo.ApiServerOverride)

	cfg, err := kubernetes.GetKubeClientConfig(uri)
	if err != nil {
		panic(err)
	}

	cfg.UserAgent = fmt.Sprintf("%s/%s", filepath.Base(os.Args[0]), version.Version())
	// TODO(random-liu): Set QPS Limit
	c.client = clientset.NewForConfigOrDie(cfg).CoreV1()
	c.nodeName = npdo.NodeName
	c.nodeRef = getNodeRef(c.nodeName)
	c.recorders = make(map[string]record.EventRecorder)
	return c
}

func (c *nodeProblemClient) GetConditions(conditionTypes []v1.NodeConditionType) ([]*v1.NodeCondition, error) {
	node, err := c.GetNode()
	if err != nil {
		return nil, err
	}
	conditions := []*v1.NodeCondition{}
	for _, conditionType := range conditionTypes {
		for _, condition := range node.Status.Conditions {
			if condition.Type == conditionType {
				conditions = append(conditions, &condition)
			}
		}
	}
	return conditions, nil
}

func (c *nodeProblemClient) SetConditions(newConditions []v1.NodeCondition) error {
	for i := range newConditions {
		// Each time we update the conditions, we update the heart beat time
		newConditions[i].LastHeartbeatTime = metav1.NewTime(c.clock.Now())
	}
	patch, err := generatePatch(newConditions)
	if err != nil {
		return err
	}
	return c.client.RESTClient().Patch(types.StrategicMergePatchType).Resource("nodes").Name(c.nodeName).SubResource("status").Body(patch).Do().Error()
}

func (c *nodeProblemClient) Eventf(eventType, source, reason, messageFmt string, args ...interface{}) {
	recorder, found := c.recorders[source]
	if !found {
		// TODO(random-liu): If needed use separate client and QPS limit for event.
		recorder = getEventRecorder(c.client, c.nodeName, source)
		c.recorders[source] = recorder
	}
	recorder.Eventf(c.nodeRef, eventType, reason, messageFmt, args...)
}

func (c *nodeProblemClient) GetNode() (*v1.Node, error) {
	return c.client.Nodes().Get(c.nodeName, metav1.GetOptions{})
}

// generatePatch generates condition patch
func generatePatch(conditions []v1.NodeCondition) ([]byte, error) {
	raw, err := json.Marshal(&conditions)
	if err != nil {
		return nil, err
	}
	return []byte(fmt.Sprintf(`{"status":{"conditions":%s}}`, raw)), nil
}

// getEventRecorder generates a recorder for specific node name and source.
func getEventRecorder(c typedcorev1.CoreV1Interface, nodeName, source string) record.EventRecorder {
	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartLogging(glog.V(4).Infof)
	recorder := eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: source, Host: nodeName})
	eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: c.Events("")})
	return recorder
}

func getNodeRef(nodeName string) *v1.ObjectReference {
	// TODO(random-liu): Get node to initialize the node reference
	return &v1.ObjectReference{
		Kind:      "Node",
		Name:      nodeName,
		UID:       types.UID(nodeName),
		Namespace: "",
	}
}
<|endoftext|>


<commit_before>// +build tools

/*
Copyright 2020 The Knative Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

		http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package tools

import (
	_ "knative.dev/hack"
	_ "knative.dev/pkg/hack"
)
<commit_msg>Format go code (#26)<commit_after>//go:build tools
// +build tools

/*
Copyright 2020 The Knative Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

		http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package tools

import (
	_ "knative.dev/hack"
	_ "knative.dev/pkg/hack"
)
<|endoftext|>


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

// +build ignore

package main

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

func execute(command string, args ...string) error {
	cmd := exec.Command(command, args...)
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}
	if err := cmd.Start(); err != nil {
		return err
	}
	msg, err := ioutil.ReadAll(stderr)
	if err != nil {
		return err
	}
	if err := cmd.Wait(); err != nil {
		return fmt.Errorf("%v: %s", err, string(msg))
	}
	return nil
}

var license = ""

func init() {
	b, err := ioutil.ReadFile("../LICENSE")
	if err != nil {
		panic(err)
	}
	license = strings.TrimSpace(string(b))
}

var copyright = ""

func init() {
	year, err := strconv.Atoi(regexp.MustCompile(`^Copyright (\d+)`).FindStringSubmatch(license)[1])
	if err != nil {
		panic(err)
	}
	copyright = fmt.Sprintf("© %d Hajime Hoshi", year)
}

var stableVersion = ""
var devVersion = ""

func init() {
	b, err := ioutil.ReadFile("../version.txt")
	if err != nil {
		panic(err)
	}
	stableVersion = strings.TrimSpace(string(b))
}

func currentBranch() string {
	r, err := ioutil.ReadFile("../.git/HEAD")
	if err != nil {
		panic(err)
	}
	rr := strings.TrimSpace(string(r))
	return regexp.MustCompile(`^ref: refs/heads/(.+)$`).FindStringSubmatch(rr)[1]
}

func init() {
	b, err := exec.Command("git", "show", "master:version.txt").Output()
	if err != nil {
		panic(err)
	}
	devVersion = strings.TrimSpace(string(b))
}

func comment(text string) template.HTML {
	// http://www.w3.org/TR/html-markup/syntax.html#comments
	// The text part of comments has the following restrictions:
	// * must not start with a ">" character
	// * must not start with the string "->"
	// * must not contain the string "--"
	// * must not end with a "-" character

	for strings.HasPrefix(text, ">") {
		text = text[1:]
	}
	for strings.HasPrefix(text, "->") {
		text = text[2:]
	}
	text = strings.Replace(text, "--", "", -1)
	for strings.HasSuffix(text, "-") {
		text = text[:len(text)-1]
	}
	return template.HTML("<!--\n" + text + "\n-->")
}

func safeHTML(text string) template.HTML {
	return template.HTML(text)
}

type example struct {
	Name string
}

func (e *example) ThumbWidth() int {
	if e.Name == "blocks" {
		return 256
	}
	return 320
}

func (e *example) ThumbHeight() int {
	if e.Name == "blocks" {
		return 240
	}
	return 240
}

func (e *example) Width() int {
	return e.ThumbWidth() * 2
}

func (e *example) Height() int {
	return e.ThumbHeight() * 2
}

const commentForBlocks = `// Please read examples/blocks/main.go and examples/blocks/blocks/*.go
// NOTE: If Gamepad API is available in your browswer, you can use gamepads. Try it out!`

func (e *example) Source() string {
	if e.Name == "blocks" {
		return commentForBlocks
	}

	path := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "hajimehoshi", "ebiten", "examples", e.Name, "main.go")
	b, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	str := regexp.MustCompile("(?s)^.*?\n\n").ReplaceAllString(string(b), "")
	str = strings.Replace(str, "\t", "    ", -1)
	return str
}

func versions() string {
	return fmt.Sprintf("v%s (dev: v%s)", stableVersion, devVersion)
}

var examples = []example{
	{Name: "alphablending"},
	{Name: "audio"},
	{Name: "font"},
	{Name: "hsv"},
	{Name: "hue"},
	{Name: "gamepad"},
	{Name: "keyboard"},
	{Name: "masking"},
	{Name: "mosaic"},
	{Name: "noise"},
	{Name: "paint"},
	{Name: "perspective"},
	{Name: "piano"},
	{Name: "rotate"},
	{Name: "sprites"},
	{Name: "blocks"},
}

func clear() error {
	if err := filepath.Walk("public", func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if m, _ := regexp.MatchString("~$", path); m {
			return nil
		}
		// Remove auto-generated html files.
		m, err := regexp.MatchString(".html$", path)
		if err != nil {
			return err
		}
		if m {
			return os.Remove(path)
		}
		// Remove example resources that are copied.
		m, err = regexp.MatchString("^public/examples/_resources/images$", path)
		if err != nil {
			return err
		}
		if m {
			if err := os.RemoveAll(path); err != nil {
				return err
			}
			return filepath.SkipDir
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

func outputMain() error {
	f, err := os.Create("public/index.html")
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "index.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":       license,
		"Copyright":     copyright,
		"StableVersion": stableVersion,
		"DevVersion":    devVersion,
		"Examples":      examples,
	}
	return t.Funcs(funcs).Execute(f, data)
}

func outputExampleImages() error {
	// TODO: Using cp command might not be portable.
	// Use io.Copy instead.
	const dir = "public/examples"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	return execute("cp", "-R", "../examples/_resources/images", "public/examples/_resources/images")
}

func outputExampleContent(e *example) error {
	const dir = "public/examples"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	f, err := os.Create(filepath.Join(dir, e.Name+".content.html"))
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "examplecontent.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":       license,
		"Copyright":     copyright,
		"CurrentBranch": currentBranch(),
		"Example":       e,
	}
	if err := t.Funcs(funcs).Execute(f, data); err != nil {
		return err
	}

	out := filepath.Join(dir, e.Name+".js")
	path := "github.com/hajimehoshi/ebiten/examples/" + e.Name
	if err := execute("gopherjs", "build", "-m", "-o", out, path); err != nil {
		return err
	}

	return nil
}

func outputExample(e *example) error {
	const dir = "public/examples"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	f, err := os.Create(filepath.Join(dir, e.Name+".html"))
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "example.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":   license,
		"Copyright": copyright,
		"Example":   e,
	}
	return t.Funcs(funcs).Execute(f, data)
}

func main() {
	if err := clear(); err != nil {
		log.Fatal(err)
	}
	if err := outputMain(); err != nil {
		log.Fatal(err)
	}
	if err := outputExampleImages(); err != nil {
		log.Fatal(err)
	}
	for _, e := range examples {
		if err := outputExampleContent(&e); err != nil {
			log.Fatal(err)
		}
		if err := outputExample(&e); err != nil {
			log.Fatal(err)
		}
	}
}
<commit_msg>doc: Bug fix: add build tag 'example'<commit_after>// Copyright 2014 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build ignore

package main

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

func execute(command string, args ...string) error {
	cmd := exec.Command(command, args...)
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}
	if err := cmd.Start(); err != nil {
		return err
	}
	msg, err := ioutil.ReadAll(stderr)
	if err != nil {
		return err
	}
	if err := cmd.Wait(); err != nil {
		return fmt.Errorf("%v: %s", err, string(msg))
	}
	return nil
}

var license = ""

func init() {
	b, err := ioutil.ReadFile("../LICENSE")
	if err != nil {
		panic(err)
	}
	license = strings.TrimSpace(string(b))
}

var copyright = ""

func init() {
	year, err := strconv.Atoi(regexp.MustCompile(`^Copyright (\d+)`).FindStringSubmatch(license)[1])
	if err != nil {
		panic(err)
	}
	copyright = fmt.Sprintf("© %d Hajime Hoshi", year)
}

var stableVersion = ""
var devVersion = ""

func init() {
	b, err := ioutil.ReadFile("../version.txt")
	if err != nil {
		panic(err)
	}
	stableVersion = strings.TrimSpace(string(b))
}

func currentBranch() string {
	r, err := ioutil.ReadFile("../.git/HEAD")
	if err != nil {
		panic(err)
	}
	rr := strings.TrimSpace(string(r))
	return regexp.MustCompile(`^ref: refs/heads/(.+)$`).FindStringSubmatch(rr)[1]
}

func init() {
	b, err := exec.Command("git", "show", "master:version.txt").Output()
	if err != nil {
		panic(err)
	}
	devVersion = strings.TrimSpace(string(b))
}

func comment(text string) template.HTML {
	// http://www.w3.org/TR/html-markup/syntax.html#comments
	// The text part of comments has the following restrictions:
	// * must not start with a ">" character
	// * must not start with the string "->"
	// * must not contain the string "--"
	// * must not end with a "-" character

	for strings.HasPrefix(text, ">") {
		text = text[1:]
	}
	for strings.HasPrefix(text, "->") {
		text = text[2:]
	}
	text = strings.Replace(text, "--", "", -1)
	for strings.HasSuffix(text, "-") {
		text = text[:len(text)-1]
	}
	return template.HTML("<!--\n" + text + "\n-->")
}

func safeHTML(text string) template.HTML {
	return template.HTML(text)
}

type example struct {
	Name string
}

func (e *example) ThumbWidth() int {
	if e.Name == "blocks" {
		return 256
	}
	return 320
}

func (e *example) ThumbHeight() int {
	if e.Name == "blocks" {
		return 240
	}
	return 240
}

func (e *example) Width() int {
	return e.ThumbWidth() * 2
}

func (e *example) Height() int {
	return e.ThumbHeight() * 2
}

const commentForBlocks = `// Please read examples/blocks/main.go and examples/blocks/blocks/*.go
// NOTE: If Gamepad API is available in your browswer, you can use gamepads. Try it out!`

func (e *example) Source() string {
	if e.Name == "blocks" {
		return commentForBlocks
	}

	path := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "hajimehoshi", "ebiten", "examples", e.Name, "main.go")
	b, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	str := regexp.MustCompile("(?s)^.*?\n\n").ReplaceAllString(string(b), "")
	str = strings.Replace(str, "\t", "    ", -1)
	return str
}

func versions() string {
	return fmt.Sprintf("v%s (dev: v%s)", stableVersion, devVersion)
}

var examples = []example{
	{Name: "alphablending"},
	{Name: "audio"},
	{Name: "font"},
	{Name: "hsv"},
	{Name: "hue"},
	{Name: "gamepad"},
	{Name: "keyboard"},
	{Name: "masking"},
	{Name: "mosaic"},
	{Name: "noise"},
	{Name: "paint"},
	{Name: "perspective"},
	{Name: "piano"},
	{Name: "rotate"},
	{Name: "sprites"},
	{Name: "blocks"},
}

func clear() error {
	if err := filepath.Walk("public", func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if m, _ := regexp.MatchString("~$", path); m {
			return nil
		}
		// Remove auto-generated html files.
		m, err := regexp.MatchString(".html$", path)
		if err != nil {
			return err
		}
		if m {
			return os.Remove(path)
		}
		// Remove example resources that are copied.
		m, err = regexp.MatchString("^public/examples/_resources/images$", path)
		if err != nil {
			return err
		}
		if m {
			if err := os.RemoveAll(path); err != nil {
				return err
			}
			return filepath.SkipDir
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

func outputMain() error {
	f, err := os.Create("public/index.html")
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "index.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":       license,
		"Copyright":     copyright,
		"StableVersion": stableVersion,
		"DevVersion":    devVersion,
		"Examples":      examples,
	}
	return t.Funcs(funcs).Execute(f, data)
}

func outputExampleImages() error {
	// TODO: Using cp command might not be portable.
	// Use io.Copy instead.
	const dir = "public/examples"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	return execute("cp", "-R", "../examples/_resources/images", "public/examples/_resources/images")
}

func outputExampleContent(e *example) error {
	const dir = "public/examples"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	f, err := os.Create(filepath.Join(dir, e.Name+".content.html"))
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "examplecontent.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":       license,
		"Copyright":     copyright,
		"CurrentBranch": currentBranch(),
		"Example":       e,
	}
	if err := t.Funcs(funcs).Execute(f, data); err != nil {
		return err
	}

	out := filepath.Join(dir, e.Name+".js")
	path := "github.com/hajimehoshi/ebiten/examples/" + e.Name
	if err := execute("gopherjs", "build", "-tags", "example", "-m", "-o", out, path); err != nil {
		return err
	}

	return nil
}

func outputExample(e *example) error {
	const dir = "public/examples"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	f, err := os.Create(filepath.Join(dir, e.Name+".html"))
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "example.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":   license,
		"Copyright": copyright,
		"Example":   e,
	}
	return t.Funcs(funcs).Execute(f, data)
}

func main() {
	if err := clear(); err != nil {
		log.Fatal(err)
	}
	if err := outputMain(); err != nil {
		log.Fatal(err)
	}
	if err := outputExampleImages(); err != nil {
		log.Fatal(err)
	}
	for _, e := range examples {
		if err := outputExampleContent(&e); err != nil {
			log.Fatal(err)
		}
		if err := outputExample(&e); err != nil {
			log.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"launchpad.net/mgo"
	"log"
	"os"
	"runtime/pprof"
	. "github.com/timeredbull/tsuru/api/service"
	. "github.com/timeredbull/tsuru/database"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var memprofile = flag.String("memprofile", "", "write memory profile to file")

func main() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	session, err := mgo.Dial("localhost:27017")
	if err != nil {
		panic(err)
	}
	Mdb = session.DB("tsuru")
	defer session.Close()

	sType := &ServiceType{Name: "Mysql", Charm: "mysql"}
	sType.Create()
	var s Service
	var name string
	for i := 0; i < 700; i++ {
		name = fmt.Sprintf("myService%d", i)
		s = Service{ServiceTypeId: sType.Id, Name: name}
		s.Create()
	}
	s = Service{}
	s.All()

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
		return
	}
}
<commit_msg>Panic-ing instead of loging the error<commit_after>package main

import (
	"flag"
	"fmt"
	"launchpad.net/mgo"
	"log"
	"os"
	"runtime/pprof"
	. "github.com/timeredbull/tsuru/api/service"
	. "github.com/timeredbull/tsuru/database"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var memprofile = flag.String("memprofile", "", "write memory profile to file")

func main() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	session, err := mgo.Dial("localhost:27017")
	if err != nil {
		panic(err)
	}
	Mdb = session.DB("tsuru")
	defer session.Close()

	sType := &ServiceType{Name: "Mysql", Charm: "mysql"}
	sType.Create()
	var s Service
	var name string
	for i := 0; i < 700; i++ {
		name = fmt.Sprintf("myService%d", i)
		s = Service{ServiceTypeId: sType.Id, Name: name}
		s.Create()
	}
	s = Service{}
	s.All()

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			panic(err)
			/* log.Fatal(err) */
		}
		pprof.WriteHeapProfile(f)
		f.Close()
		return
	}
}
<|endoftext|>


<commit_before>package calico

import (
	"github.com/projectcalico/libcalico-go/lib/api"
	caliconet "github.com/projectcalico/libcalico-go/lib/net"
	"github.com/projectcalico/libcalico-go/lib/numorstring"
)

// read existing Source/Destination Entity Rules into a map for easy consumption
func getEntityRuleMap(entityRule api.EntityRule) map[string]interface{} {
	resourceSourceMap := make(map[string]interface{})

	if entityRule.Net != nil {
		resourceSourceMap["net"] = entityRule.Net.String()
	}
	if len(entityRule.Selector) > 0 {
		resourceSourceMap["selector"] = entityRule.Selector
	}
	if len(entityRule.Ports) > 0 {
		portsArray := make([]string, len(entityRule.Ports))
		for i, v := range entityRule.Ports {
			val := v.String()
			portsArray[i] = val
		}
		resourceSourceMap["ports"] = portsArray
	}
	if entityRule.NotNet != nil {
		resourceSourceMap["notNet"] = entityRule.NotNet.String()
	}
	if len(entityRule.NotSelector) > 0 {
		resourceSourceMap["notSelector"] = entityRule.NotSelector
	}
	if len(entityRule.NotPorts) > 0 {
		notPortsArray := make([]string, len(entityRule.NotPorts))
		for i, v := range entityRule.NotPorts {
			val := v.String()
			notPortsArray[i] = val
		}
		resourceSourceMap["notPorts"] = notPortsArray
	}
	return resourceSourceMap
}

// convert resourceMap to an api.Rule
func resourceMapToRule(mapStruct map[string]interface{}) (api.Rule, error) {
	rule := api.Rule{}

	if val, ok := mapStruct["action"]; ok {
		rule.Action = val.(string)
	}
	if val, ok := mapStruct["protocol"]; ok {
		if len(val.(string)) > 0 {
			protocol := numorstring.ProtocolFromString(val.(string))
			rule.Protocol = &protocol
		}
	}
	if val, ok := mapStruct["notProtocol"]; ok {
		if len(val.(string)) > 0 {
			notProtocol := numorstring.ProtocolFromString(val.(string))
			rule.NotProtocol = &notProtocol
		}
	}
	if val, ok := mapStruct["icmp"]; ok {
		icmpList := val.([]interface{})
		if len(icmpList) > 0 {
			for _, v := range icmpList {
				icmpMap := v.(map[string]interface{})
				icmpType := icmpMap["type"].(int)
				icmpCode := icmpMap["code"].(int)
				icmp := api.ICMPFields{
					Type: &icmpType,
					Code: &icmpCode,
				}
				rule.ICMP = &icmp
			}
		}
	}
	if val, ok := mapStruct["notICMP"]; ok {
		icmpList := val.([]interface{})
		if len(icmpList) > 0 {
			for _, v := range icmpList {
				icmpMap := v.(map[string]interface{})
				icmpType := icmpMap["type"].(int)
				icmpCode := icmpMap["code"].(int)
				icmp := api.ICMPFields{
					Type: &icmpType,
					Code: &icmpCode,
				}
				rule.NotICMP = &icmp
			}
		}
	}
	if val, ok := mapStruct["source"]; ok {
		sourceList := val.([]interface{})

		if len(sourceList) > 0 {
			srcEntityRules, err := srcDstListToEntityRule(sourceList)
			if err != nil {
				return rule, err
			}
			rule.Source = srcEntityRules
		}
	}

	if val, ok := mapStruct["destination"]; ok {
		destinationList := val.([]interface{})

		if len(destinationList) > 0 {
			destEntityRules, err := srcDstListToEntityRule(destinationList)
			if err != nil {
				return rule, err
			}
			rule.Destination = destEntityRules
		}
	}

	return rule, nil
}

// convert resource destination/source structs to a api.EntityRule
func srcDstListToEntityRule(srcDstList []interface{}) (api.EntityRule, error) {
	entityRule := api.EntityRule{}
	resourceRuleMap := srcDstList[0].(map[string]interface{})

	if v, ok := resourceRuleMap["net"]; ok {
		_, n, err := caliconet.ParseCIDR(v.(string))
		if err != nil {
			return entityRule, err
		}
		entityRule.Net = n
	}
	if v, ok := resourceRuleMap["selector"]; ok {
		entityRule.Selector = v.(string)
	}
	if v, ok := resourceRuleMap["notSelector"]; ok {
		entityRule.NotSelector = v.(string)
	}
	if v, ok := resourceRuleMap["ports"]; ok {
		if resourcePortList, ok := v.([]interface{}); ok {
			portList, err := toPortList(resourcePortList)
			if err != nil {
				return entityRule, err
			}
			entityRule.Ports = portList
		}
	}
	if v, ok := resourceRuleMap["notPorts"]; ok {
		if resourcePortList, ok := v.([]interface{}); ok {
			portList, err := toPortList(resourcePortList)
			if err != nil {
				return entityRule, err
			}
			entityRule.NotPorts = portList
		}
	}
	return entityRule, nil
}

// create an array of Ports
func toPortList(resourcePortList []interface{}) ([]numorstring.Port, error) {
	portList := make([]numorstring.Port, len(resourcePortList))

	for i, v := range resourcePortList {
		p, err := numorstring.PortFromString(v.(string))
		if err != nil {
			return portList, err
		}
		portList[i] = p
	}
	return portList, nil
}

// check if Entity Rule is empty
func nonEmptyEntityRule(entityRule *api.EntityRule) bool {
	state := false

	if len(entityRule.Tag) > 0 {
		state = true
	}
	if entityRule.Net != nil {
		state = true
	}
	if len(entityRule.Selector) > 0 {
		state = true
	}
	if len(entityRule.Ports) > 0 {
		state = true
	}
	if len(entityRule.NotTag) > 0 {
		state = true
	}
	if entityRule.NotNet != nil {
		state = true
	}
	if len(entityRule.NotSelector) > 0 {
		state = true
	}
	if len(entityRule.NotPorts) > 0 {
		state = true
	}

	return state
}

// read []api.Rules into a map for easy consumption
func rulesToMap(calicoRules []api.Rule) []map[string]interface{} {
	resourceRules := make([]map[string]interface{}, len(calicoRules))

	for i, rule := range calicoRules {
		resourceRule := make(map[string]interface{})
		if len(rule.Action) > 0 {
			resourceRule["action"] = rule.Action
		}
		if rule.Protocol != nil {
			resourceRule["protocol"] = rule.Protocol.String()
		}
		if rule.ICMP != nil {
			resourceIcmpArray := make([]map[string]int, 1)
			resourceIcmpMap := make(map[string]int)

			resourceIcmpMap["code"] = *rule.ICMP.Code
			resourceIcmpMap["type"] = *rule.ICMP.Type

			resourceIcmpArray[0] = resourceIcmpMap
			resourceRule["icmp"] = resourceIcmpArray
		}
		if rule.NotICMP != nil {
			resourceIcmpArray := make([]map[string]int, 1)
			resourceIcmpMap := make(map[string]int)

			resourceIcmpMap["code"] = *rule.ICMP.Code
			resourceIcmpMap["type"] = *rule.ICMP.Type

			resourceIcmpArray[0] = resourceIcmpMap
			resourceRule["notICMP"] = resourceIcmpArray
		}
		if nonEmptyEntityRule(&rule.Source) {
			resourceSourceArray := make([]map[string]interface{}, 1)

			resourceSourceArray[0] = getEntityRuleMap(rule.Source)
			resourceRule["source"] = resourceSourceArray
		}
		if nonEmptyEntityRule(&rule.Destination) {
			resourceSourceArray := make([]map[string]interface{}, 1)

			resourceSourceArray[0] = getEntityRuleMap(rule.Destination)
			resourceRule["destination"] = resourceSourceArray
		}
		resourceRules[i] = resourceRule
	}

	return resourceRules

}
<commit_msg>handle empty net<commit_after>package calico

import (
	"github.com/projectcalico/libcalico-go/lib/api"
	caliconet "github.com/projectcalico/libcalico-go/lib/net"
	"github.com/projectcalico/libcalico-go/lib/numorstring"
)

// read existing Source/Destination Entity Rules into a map for easy consumption
func getEntityRuleMap(entityRule api.EntityRule) map[string]interface{} {
	resourceSourceMap := make(map[string]interface{})

	if entityRule.Net != nil {
		resourceSourceMap["net"] = entityRule.Net.String()
	}
	if len(entityRule.Selector) > 0 {
		resourceSourceMap["selector"] = entityRule.Selector
	}
	if len(entityRule.Ports) > 0 {
		portsArray := make([]string, len(entityRule.Ports))
		for i, v := range entityRule.Ports {
			val := v.String()
			portsArray[i] = val
		}
		resourceSourceMap["ports"] = portsArray
	}
	if entityRule.NotNet != nil {
		resourceSourceMap["notNet"] = entityRule.NotNet.String()
	}
	if len(entityRule.NotSelector) > 0 {
		resourceSourceMap["notSelector"] = entityRule.NotSelector
	}
	if len(entityRule.NotPorts) > 0 {
		notPortsArray := make([]string, len(entityRule.NotPorts))
		for i, v := range entityRule.NotPorts {
			val := v.String()
			notPortsArray[i] = val
		}
		resourceSourceMap["notPorts"] = notPortsArray
	}
	return resourceSourceMap
}

// convert resourceMap to an api.Rule
func resourceMapToRule(mapStruct map[string]interface{}) (api.Rule, error) {
	rule := api.Rule{}

	if val, ok := mapStruct["action"]; ok {
		rule.Action = val.(string)
	}
	if val, ok := mapStruct["protocol"]; ok {
		if len(val.(string)) > 0 {
			protocol := numorstring.ProtocolFromString(val.(string))
			rule.Protocol = &protocol
		}
	}
	if val, ok := mapStruct["notProtocol"]; ok {
		if len(val.(string)) > 0 {
			notProtocol := numorstring.ProtocolFromString(val.(string))
			rule.NotProtocol = &notProtocol
		}
	}
	if val, ok := mapStruct["icmp"]; ok {
		icmpList := val.([]interface{})
		if len(icmpList) > 0 {
			for _, v := range icmpList {
				icmpMap := v.(map[string]interface{})
				icmpType := icmpMap["type"].(int)
				icmpCode := icmpMap["code"].(int)
				icmp := api.ICMPFields{
					Type: &icmpType,
					Code: &icmpCode,
				}
				rule.ICMP = &icmp
			}
		}
	}
	if val, ok := mapStruct["notICMP"]; ok {
		icmpList := val.([]interface{})
		if len(icmpList) > 0 {
			for _, v := range icmpList {
				icmpMap := v.(map[string]interface{})
				icmpType := icmpMap["type"].(int)
				icmpCode := icmpMap["code"].(int)
				icmp := api.ICMPFields{
					Type: &icmpType,
					Code: &icmpCode,
				}
				rule.NotICMP = &icmp
			}
		}
	}
	if val, ok := mapStruct["source"]; ok {
		sourceList := val.([]interface{})

		if len(sourceList) > 0 {
			srcEntityRules, err := srcDstListToEntityRule(sourceList)
			if err != nil {
				return rule, err
			}
			rule.Source = srcEntityRules
		}
	}

	if val, ok := mapStruct["destination"]; ok {
		destinationList := val.([]interface{})

		if len(destinationList) > 0 {
			destEntityRules, err := srcDstListToEntityRule(destinationList)
			if err != nil {
				return rule, err
			}
			rule.Destination = destEntityRules
		}
	}

	return rule, nil
}

// convert resource destination/source structs to a api.EntityRule
func srcDstListToEntityRule(srcDstList []interface{}) (api.EntityRule, error) {
	entityRule := api.EntityRule{}
	resourceRuleMap := srcDstList[0].(map[string]interface{})

	if v, ok := resourceRuleMap["net"]; ok {
		if len(v.(string)) > 0 {
			_, n, err := caliconet.ParseCIDR(v.(string))
			if err != nil {
				return entityRule, err
			}
			entityRule.Net = n
		}
	}
	if v, ok := resourceRuleMap["selector"]; ok {
		entityRule.Selector = v.(string)
	}
	if v, ok := resourceRuleMap["notSelector"]; ok {
		entityRule.NotSelector = v.(string)
	}
	if v, ok := resourceRuleMap["ports"]; ok {
		if resourcePortList, ok := v.([]interface{}); ok {
			portList, err := toPortList(resourcePortList)
			if err != nil {
				return entityRule, err
			}
			entityRule.Ports = portList
		}
	}
	if v, ok := resourceRuleMap["notPorts"]; ok {
		if resourcePortList, ok := v.([]interface{}); ok {
			portList, err := toPortList(resourcePortList)
			if err != nil {
				return entityRule, err
			}
			entityRule.NotPorts = portList
		}
	}
	return entityRule, nil
}

// create an array of Ports
func toPortList(resourcePortList []interface{}) ([]numorstring.Port, error) {
	portList := make([]numorstring.Port, len(resourcePortList))

	for i, v := range resourcePortList {
		p, err := numorstring.PortFromString(v.(string))
		if err != nil {
			return portList, err
		}
		portList[i] = p
	}
	return portList, nil
}

// check if Entity Rule is empty
func nonEmptyEntityRule(entityRule *api.EntityRule) bool {
	state := false

	if len(entityRule.Tag) > 0 {
		state = true
	}
	if entityRule.Net != nil {
		state = true
	}
	if len(entityRule.Selector) > 0 {
		state = true
	}
	if len(entityRule.Ports) > 0 {
		state = true
	}
	if len(entityRule.NotTag) > 0 {
		state = true
	}
	if entityRule.NotNet != nil {
		state = true
	}
	if len(entityRule.NotSelector) > 0 {
		state = true
	}
	if len(entityRule.NotPorts) > 0 {
		state = true
	}

	return state
}

// read []api.Rules into a map for easy consumption
func rulesToMap(calicoRules []api.Rule) []map[string]interface{} {
	resourceRules := make([]map[string]interface{}, len(calicoRules))

	for i, rule := range calicoRules {
		resourceRule := make(map[string]interface{})
		if len(rule.Action) > 0 {
			resourceRule["action"] = rule.Action
		}
		if rule.Protocol != nil {
			resourceRule["protocol"] = rule.Protocol.String()
		}
		if rule.ICMP != nil {
			resourceIcmpArray := make([]map[string]int, 1)
			resourceIcmpMap := make(map[string]int)

			resourceIcmpMap["code"] = *rule.ICMP.Code
			resourceIcmpMap["type"] = *rule.ICMP.Type

			resourceIcmpArray[0] = resourceIcmpMap
			resourceRule["icmp"] = resourceIcmpArray
		}
		if rule.NotICMP != nil {
			resourceIcmpArray := make([]map[string]int, 1)
			resourceIcmpMap := make(map[string]int)

			resourceIcmpMap["code"] = *rule.ICMP.Code
			resourceIcmpMap["type"] = *rule.ICMP.Type

			resourceIcmpArray[0] = resourceIcmpMap
			resourceRule["notICMP"] = resourceIcmpArray
		}
		if nonEmptyEntityRule(&rule.Source) {
			resourceSourceArray := make([]map[string]interface{}, 1)

			resourceSourceArray[0] = getEntityRuleMap(rule.Source)
			resourceRule["source"] = resourceSourceArray
		}
		if nonEmptyEntityRule(&rule.Destination) {
			resourceSourceArray := make([]map[string]interface{}, 1)

			resourceSourceArray[0] = getEntityRuleMap(rule.Destination)
			resourceRule["destination"] = resourceSourceArray
		}
		resourceRules[i] = resourceRule
	}

	return resourceRules

}
<|endoftext|>


<commit_before>//	The MIT License (MIT)
//
//	Copyright (c) 2016, Cagatay Dogan
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//		The above copyright notice and this permission notice shall be included in
//		all copies or substantial portions of the Software.
//
//		THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//		IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//		FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//		AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//		LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//		OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//		THE SOFTWARE.

package inout

import (
	"fmt"
	"math"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"encoding/json"

	"github.com/ocdogan/fluentgo/config"
	"github.com/ocdogan/fluentgo/lib"
	"github.com/ocdogan/fluentgo/log"
)

type outFile struct {
	count int
	size  int
	file  *os.File
}

type fileRollOut struct {
	count        int
	size         int
	enabled      bool
	onEverySec   time.Duration
	lastRollTime time.Time
}

type fileOut struct {
	sync.Mutex
	outHandler
	outputDir string
	prefix    string
	extension string
	multiLog  bool
	rolling   fileRollOut
	ofile     *outFile
	lg        log.Logger
	indexer   int64
	preparing int32
}

func init() {
	RegisterOut("file", newFileOut)
	RegisterOut("fileout", newFileOut)
}

func newFileOut(manager InOutManager, params map[string]interface{}) OutSender {
	oh := newOutHandler(manager, params)
	if oh == nil {
		return nil
	}

	outputDir, ok := config.ParamAsString(params, "path")
	if !ok || outputDir == "" {
		return nil
	}
	outputDir = lib.PreparePath(outputDir)

	if exists, err := lib.PathExists(outputDir); !exists || err != nil {
		os.MkdirAll(outputDir, 0777)
	}

	prefix, ok := config.ParamAsString(params, "prefix")
	if ok && prefix != "" {
		prefix = strings.TrimSpace(prefix)
		if prefix != "" && prefix[len(prefix)-1] != '-' {
			prefix += "-"
		}
	}

	extension, ok := config.ParamAsString(params, "extension")
	if !ok {
		extension = ".log"
	} else {
		if extension != "" {
			extension = strings.TrimSpace(extension)
		}

		if extension == "" {
			extension = ".log"
		} else if extension[0] != '.' {
			extension = "." + extension
		}
	}

	multiLog, _ := config.ParamAsBool(params, "multiLog")

	rollCount, ok := config.ParamAsInt(params, "roll.count")
	if ok {
		if rollCount < 0 {
			rollCount = 0
		} else if rollCount > 1000000 {
			rollCount = 1000000
		}
	}

	rollSize, ok := config.ParamAsInt(params, "roll.size")
	if ok {
		if rollSize < 0 {
			rollSize = 0
		} else if rollSize > 100*1024*1024 {
			rollSize = 100 * 1024 * 1024
		}
	}

	rollOnEverySec, ok := config.ParamAsDuration(params, "roll.onEverySec")
	if ok {
		rollOnEverySec = lib.MinDuration(600, lib.MaxDuration(0, rollOnEverySec)) * time.Second
	}

	fo := &fileOut{
		outHandler: *oh,
		outputDir:  outputDir,
		prefix:     prefix,
		extension:  extension,
		multiLog:   multiLog,
		lg:         manager.GetLogger(),
		rolling: fileRollOut{
			count:        rollCount,
			size:         rollSize,
			onEverySec:   rollOnEverySec,
			lastRollTime: time.Now(),
			enabled:      multiLog && (rollCount > 0 || rollSize > 0),
		},
	}

	fo.iotype = "FILEOUT"

	fo.runFunc = fo.waitComplete
	fo.afterCloseFunc = fo.funcAfterClose
	fo.getDestinationFunc = fo.funcGetObjectName
	fo.sendChunkFunc = fo.funcPutMessages

	return fo
}

func (fo *fileOut) nextLogFile() string {
	start := atomic.AddInt64(&fo.indexer, int64(1))
	if start == math.MaxInt64 {
		start = 0
		atomic.StoreInt64(&fo.indexer, 0)
	}

	t := time.Now()
	prefix := fo.prefix + fmt.Sprintf("%d%02d%02dT%02dx", t.Year(), t.Month(), t.Day(), t.Hour())

	var (
		err     error
		exists  bool
		rest    string
		newName string
	)

	fileName := fo.outputDir + prefix

	for i := start; i < math.MaxInt64; i++ {
		atomic.StoreInt64(&fo.indexer, i)

		rest = fmt.Sprintf("%06d", i) + fo.extension

		newName, _ = filepath.Abs(fileName + rest)

		exists, err = lib.FileExists(newName)
		if !exists && err == nil {
			return newName
		}
	}
	return ""
}

func (fo *fileOut) prepareFile(dataLen int) {
	if !atomic.CompareAndSwapInt32(&fo.preparing, 0, 1) {
		return
	}
	defer atomic.StoreInt32(&fo.preparing, 0)

	ofile := fo.ofile
	dataLen = lib.MaxInt(0, dataLen)

	changeFile := ofile == nil || !fo.multiLog ||
		(fo.rolling.size > 0 && ofile.size+dataLen > fo.rolling.size) ||
		(fo.rolling.count > 0 && ofile.count+1 > fo.rolling.count) ||
		(time.Now().Sub(fo.rolling.lastRollTime) >= fo.rolling.onEverySec)

	if !changeFile {
		return
	}

	if fo.multiLog {
		defer func() {
			fo.rolling.lastRollTime = time.Now()
		}()
	}

	fo.ofile = nil
	if ofile != nil {
		defer func(file *os.File) {
			if file != nil {
				defer recover()
				file.Close()
			}
		}(ofile.file)
	}

	var file *os.File
	filename := fo.nextLogFile()

	if filename != "" {
		var err error
		file, err = os.OpenFile(filename, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
		if err != nil {
			if file != nil {
				f := file
				file = nil

				f.Close()
			}
		}
	}

	fo.ofile = &outFile{
		file: file,
	}
}

func (fo *fileOut) funcAfterClose() {
}

func (fo *fileOut) funcGetObjectName() string {
	return "fileout"
}

func (fo *fileOut) writeToLog(msg string) {
	if len(msg) > 0 {
		defer recover()

		fo.Lock()
		defer fo.Unlock()

		data := []byte(msg)
		ln := len(data)

		if fo.multiLog {
			hasRet := false
			for _, rn := range msg {
				if rn == '\r' || rn == '\n' {
					hasRet = true
					break
				}
			}

			if hasRet {
				var jsonMsg map[string]interface{}
				err := json.Unmarshal(data, &jsonMsg)

				if err == nil {
					data, _ = json.Marshal(jsonMsg)
				} else {
					msg = strings.Replace(msg, "\r", "", -1)
					msg = strings.Replace(msg, "\n", "", -1)

					data = []byte(msg)
				}

				ln = len(data)
				if ln == 0 {
					return
				}
			}
		}

		fo.prepareFile(ln)

		ofile := fo.ofile

		if ofile != nil {
			f := ofile.file

			if f != nil {
				defer f.Sync()
				f.Write(data)

				var nln []byte
				if fo.multiLog {
					nln = lib.NewLine()
					f.Write(nln)
				}

				ofile.size += ln + len(nln)
				ofile.count++
			}
		}
	}
}

func (fo *fileOut) funcPutMessages(messages []string, channel string) {
	if len(messages) == 0 {
		return
	}
	defer recover()

	for _, msg := range messages {
		if msg != "" {
			fo.writeToLog(msg)
		}
	}
}

func (fo *fileOut) Connect() error {
	return nil
}
<commit_msg>Added minute and seconf to file name<commit_after>//	The MIT License (MIT)
//
//	Copyright (c) 2016, Cagatay Dogan
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//		The above copyright notice and this permission notice shall be included in
//		all copies or substantial portions of the Software.
//
//		THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//		IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//		FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//		AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//		LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//		OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//		THE SOFTWARE.

package inout

import (
	"fmt"
	"math"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"encoding/json"

	"github.com/ocdogan/fluentgo/config"
	"github.com/ocdogan/fluentgo/lib"
	"github.com/ocdogan/fluentgo/log"
)

type outFile struct {
	count int
	size  int
	file  *os.File
}

type fileRollOut struct {
	count        int
	size         int
	enabled      bool
	onEverySec   time.Duration
	lastRollTime time.Time
}

type fileOut struct {
	sync.Mutex
	outHandler
	outputDir string
	prefix    string
	extension string
	multiLog  bool
	rolling   fileRollOut
	ofile     *outFile
	lg        log.Logger
	indexer   int64
	preparing int32
}

func init() {
	RegisterOut("file", newFileOut)
	RegisterOut("fileout", newFileOut)
}

func newFileOut(manager InOutManager, params map[string]interface{}) OutSender {
	oh := newOutHandler(manager, params)
	if oh == nil {
		return nil
	}

	outputDir, ok := config.ParamAsString(params, "path")
	if !ok || outputDir == "" {
		return nil
	}
	outputDir = lib.PreparePath(outputDir)

	if exists, err := lib.PathExists(outputDir); !exists || err != nil {
		os.MkdirAll(outputDir, 0777)
	}

	prefix, ok := config.ParamAsString(params, "prefix")
	if ok && prefix != "" {
		prefix = strings.TrimSpace(prefix)
		if prefix != "" && prefix[len(prefix)-1] != '-' {
			prefix += "-"
		}
	}

	extension, ok := config.ParamAsString(params, "extension")
	if !ok {
		extension = ".log"
	} else {
		if extension != "" {
			extension = strings.TrimSpace(extension)
		}

		if extension == "" {
			extension = ".log"
		} else if extension[0] != '.' {
			extension = "." + extension
		}
	}

	multiLog, _ := config.ParamAsBool(params, "multiLog")

	rollCount, ok := config.ParamAsInt(params, "roll.count")
	if ok {
		if rollCount < 0 {
			rollCount = 0
		} else if rollCount > 1000000 {
			rollCount = 1000000
		}
	}

	rollSize, ok := config.ParamAsInt(params, "roll.size")
	if ok {
		if rollSize < 0 {
			rollSize = 0
		} else if rollSize > 100*1024*1024 {
			rollSize = 100 * 1024 * 1024
		}
	}

	rollOnEverySec, ok := config.ParamAsDuration(params, "roll.onEverySec")
	if ok {
		rollOnEverySec = lib.MinDuration(600, lib.MaxDuration(0, rollOnEverySec)) * time.Second
	}

	fo := &fileOut{
		outHandler: *oh,
		outputDir:  outputDir,
		prefix:     prefix,
		extension:  extension,
		multiLog:   multiLog,
		lg:         manager.GetLogger(),
		rolling: fileRollOut{
			count:        rollCount,
			size:         rollSize,
			onEverySec:   rollOnEverySec,
			lastRollTime: time.Now(),
			enabled:      multiLog && (rollCount > 0 || rollSize > 0),
		},
	}

	fo.iotype = "FILEOUT"

	fo.runFunc = fo.waitComplete
	fo.afterCloseFunc = fo.funcAfterClose
	fo.getDestinationFunc = fo.funcGetObjectName
	fo.sendChunkFunc = fo.funcPutMessages

	return fo
}

func (fo *fileOut) nextLogFile() string {
	start := atomic.AddInt64(&fo.indexer, int64(1))
	if start == math.MaxInt64 {
		start = 0
		atomic.StoreInt64(&fo.indexer, 0)
	}

	t := time.Now()
	prefix := fo.prefix + fmt.Sprintf("%d%02d%02dT%02d%02d%02dx", t.Year(), t.Month(),
		t.Day(), t.Hour(), t.Minute(), t.Second())

	var (
		err     error
		exists  bool
		rest    string
		newName string
	)

	fileName := fo.outputDir + prefix

	for i := start; i < math.MaxInt64; i++ {
		atomic.StoreInt64(&fo.indexer, i)

		rest = fmt.Sprintf("%06d", i) + fo.extension

		newName, _ = filepath.Abs(fileName + rest)

		exists, err = lib.FileExists(newName)
		if !exists && err == nil {
			return newName
		}
	}
	return ""
}

func (fo *fileOut) prepareFile(dataLen int) {
	if !atomic.CompareAndSwapInt32(&fo.preparing, 0, 1) {
		return
	}
	defer atomic.StoreInt32(&fo.preparing, 0)

	ofile := fo.ofile
	dataLen = lib.MaxInt(0, dataLen)

	changeFile := ofile == nil || !fo.multiLog ||
		(fo.rolling.size > 0 && ofile.size+dataLen > fo.rolling.size) ||
		(fo.rolling.count > 0 && ofile.count+1 > fo.rolling.count) ||
		(time.Now().Sub(fo.rolling.lastRollTime) >= fo.rolling.onEverySec)

	if !changeFile {
		return
	}

	if fo.multiLog {
		defer func() {
			fo.rolling.lastRollTime = time.Now()
		}()
	}

	fo.ofile = nil
	if ofile != nil {
		defer func(file *os.File) {
			if file != nil {
				defer recover()
				file.Close()
			}
		}(ofile.file)
	}

	var file *os.File
	filename := fo.nextLogFile()

	if filename != "" {
		var err error
		file, err = os.OpenFile(filename, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
		if err != nil {
			if file != nil {
				f := file
				file = nil

				f.Close()
			}
		}
	}

	fo.ofile = &outFile{
		file: file,
	}
}

func (fo *fileOut) funcAfterClose() {
}

func (fo *fileOut) funcGetObjectName() string {
	return "fileout"
}

func (fo *fileOut) writeToLog(msg string) {
	if len(msg) > 0 {
		defer recover()

		fo.Lock()
		defer fo.Unlock()

		data := []byte(msg)
		ln := len(data)

		if fo.multiLog {
			hasRet := false
			for _, rn := range msg {
				if rn == '\r' || rn == '\n' {
					hasRet = true
					break
				}
			}

			if hasRet {
				var jsonMsg map[string]interface{}
				err := json.Unmarshal(data, &jsonMsg)

				if err == nil {
					data, _ = json.Marshal(jsonMsg)
				} else {
					msg = strings.Replace(msg, "\r", "", -1)
					msg = strings.Replace(msg, "\n", "", -1)

					data = []byte(msg)
				}

				ln = len(data)
				if ln == 0 {
					return
				}
			}
		}

		fo.prepareFile(ln)

		ofile := fo.ofile

		if ofile != nil {
			f := ofile.file

			if f != nil {
				defer f.Sync()
				f.Write(data)

				var nln []byte
				if fo.multiLog {
					nln = lib.NewLine()
					f.Write(nln)
				}

				ofile.size += ln + len(nln)
				ofile.count++
			}
		}
	}
}

func (fo *fileOut) funcPutMessages(messages []string, channel string) {
	if len(messages) == 0 {
		return
	}
	defer recover()

	for _, msg := range messages {
		if msg != "" {
			fo.writeToLog(msg)
		}
	}
}

func (fo *fileOut) Connect() error {
	return nil
}
<|endoftext|>


<commit_before>package build

import (
	"fmt"
	"os"
	"runtime/debug"
)

// Critical should be called if a sanity check has failed, indicating developer
// error. Critical is called with an extended message guiding the user to the
// issue tracker on Github. If the program does not panic, the call stack for
// the running goroutine is printed to help determine the error.
func Critical(v ...interface{}) {
	s := "Critical error: " + fmt.Sprintln(v...) + "Please submit a bug report here: https://github.com/NebulousLabs/Sia/issues\n"
	os.Stderr.WriteString(s)
	if DEBUG {
		panic(s)
	}
	debug.PrintStack()
}

// Severe will print a message to os.Stderr. If DEBUG has been set panic will
// be called as well. Severe should be called in situations which indicate
// significant problems for the user (such as disk failure or random number
// generation failure), but where crashing is not strictly required to preserve
// integrity.
func Severe(v ...interface{}) {
	s := "Severe error: " + fmt.Sprintln(v...)
	os.Stderr.WriteString(s)
	if DEBUG {
		panic(s)
	}
}
<commit_msg>in Critical and Severe, print stack before panic<commit_after>package build

import (
	"fmt"
	"os"
	"runtime/debug"
)

// Critical should be called if a sanity check has failed, indicating developer
// error. Critical is called with an extended message guiding the user to the
// issue tracker on Github. If the program does not panic, the call stack for
// the running goroutine is printed to help determine the error.
func Critical(v ...interface{}) {
	s := "Critical error: " + fmt.Sprintln(v...) + "Please submit a bug report here: https://github.com/NebulousLabs/Sia/issues\n"
	debug.PrintStack()
	os.Stderr.WriteString(s)
	if DEBUG {
		panic(s)
	}
}

// Severe will print a message to os.Stderr. If DEBUG has been set panic will
// be called as well. Severe should be called in situations which indicate
// significant problems for the user (such as disk failure or random number
// generation failure), but where crashing is not strictly required to preserve
// integrity.
func Severe(v ...interface{}) {
	s := "Severe error: " + fmt.Sprintln(v...)
	debug.PrintStack()
	os.Stderr.WriteString(s)
	if DEBUG {
		panic(s)
	}
}
<|endoftext|>


<commit_before>package ui

import (
	"bytes"
	"log"
	"os"
	"testing"
)

func resetUIState() {
	LoggerStdout.SetOutput(os.Stdout)
	LoggerStderr.SetOutput(os.Stderr)
	Verbosity = VerbosityLevelNormal
}

type printTestCase struct {
	name            string
	logger          *log.Logger
	printFunc       func()
	levelNoOutput   VerbosityLevel
	levelWithOutput VerbosityLevel
	expected        string
}

func testPrint(t *testing.T, tt printTestCase) {
	defer resetUIState()

	buf := new(bytes.Buffer)
	tt.logger.SetOutput(buf)

	Verbosity = tt.levelNoOutput
	tt.printFunc()
	actual := buf.String()

	if "" != actual {
		t.Errorf(
			`%s with verbosity %v: expected no output, actual: "%s"`,
			tt.name,
			tt.levelNoOutput,
			actual,
		)
	}

	buf.Reset()
	Verbosity = tt.levelWithOutput
	tt.printFunc()
	actual = buf.String()

	if tt.expected != actual {
		t.Errorf(
			`%s with verbosity %v: expected "%s", actual: "%s"`,
			tt.name,
			tt.levelWithOutput,
			tt.expected,
			actual,
		)
	}
}

var verbosityStringTests = []struct {
	level    VerbosityLevel
	expected string
}{
	{VerbosityLevelSilent, "Silent"},
	{VerbosityLevelQuiet, "Quiet"},
	{VerbosityLevelNormal, "Normal"},
	{VerbosityLevelVerbose, "Verbose"},
	{VerbosityLevel(99), "Unknown"},
}

func TestVerbosityLevel_String(t *testing.T) {
	for _, tt := range verbosityStringTests {
		actual := tt.level.String()
		if tt.expected != actual {
			t.Errorf(
				`level.String(): expected "%s", actual "%s"`,
				tt.expected, actual,
			)
		}
	}
}
<commit_msg>Mark testPrint as helper<commit_after>package ui

import (
	"bytes"
	"log"
	"os"
	"testing"
)

func resetUIState() {
	LoggerStdout.SetOutput(os.Stdout)
	LoggerStderr.SetOutput(os.Stderr)
	Verbosity = VerbosityLevelNormal
}

type printTestCase struct {
	name            string
	logger          *log.Logger
	printFunc       func()
	levelNoOutput   VerbosityLevel
	levelWithOutput VerbosityLevel
	expected        string
}

func testPrint(t *testing.T, tt printTestCase) {
	t.Helper()
	defer resetUIState()

	buf := new(bytes.Buffer)
	tt.logger.SetOutput(buf)

	Verbosity = tt.levelNoOutput
	tt.printFunc()
	actual := buf.String()

	if "" != actual {
		t.Errorf(
			`%s with verbosity %v: expected no output, actual: "%s"`,
			tt.name,
			tt.levelNoOutput,
			actual,
		)
	}

	buf.Reset()
	Verbosity = tt.levelWithOutput
	tt.printFunc()
	actual = buf.String()

	if tt.expected != actual {
		t.Errorf(
			`%s with verbosity %v: expected "%s", actual: "%s"`,
			tt.name,
			tt.levelWithOutput,
			tt.expected,
			actual,
		)
	}
}

var verbosityStringTests = []struct {
	level    VerbosityLevel
	expected string
}{
	{VerbosityLevelSilent, "Silent"},
	{VerbosityLevelQuiet, "Quiet"},
	{VerbosityLevelNormal, "Normal"},
	{VerbosityLevelVerbose, "Verbose"},
	{VerbosityLevel(99), "Unknown"},
}

func TestVerbosityLevel_String(t *testing.T) {
	for _, tt := range verbosityStringTests {
		actual := tt.level.String()
		if tt.expected != actual {
			t.Errorf(
				`level.String(): expected "%s", actual "%s"`,
				tt.expected, actual,
			)
		}
	}
}
<|endoftext|>


<commit_before>package term

import (
	"io"

	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/mouse"

	"github.com/gdamore/tcell"
	"github.com/mibk/syd/ui"
)

type UI struct {
	screen        tcell.Screen
	wasBtnPressed bool

	y      int
	width  int
	height int

	firstWin   *Window
	activeText *Text   // will receive key events
	grabbedWin *Window // index of the grabbed win or nil
}

func (t *UI) Init() error {
	sc, err := tcell.NewScreen()
	if err != nil {
		return err
	}
	if err := sc.Init(); err != nil {
		return err
	}
	sc.EnableMouse()
	t.screen = sc

	// TODO: Just for testing purposes.
	t.y = 1
	w, h := t.Size()
	t.width = w / 2
	t.height = h - 2

	go t.translateEvents()
	return nil
}

func (t *UI) Close() error {
	t.screen.Fini()
	return nil
}

func (t *UI) Size() (w, h int) { return t.screen.Size() }

func (t *UI) NewWindow() *Window {
	head := &Text{
		frame: new(Frame),
		bgstyle: tcell.StyleDefault.
			Background(tcell.GetColor("#eaffff")),
		hlstyle: tcell.StyleDefault.
			Background(tcell.GetColor("#90e0e0")),
	}
	body := &Text{
		frame: new(Frame),
		bgstyle: tcell.StyleDefault.
			Background(tcell.GetColor("#ffffea")),
		hlstyle: tcell.StyleDefault.
			Background(tcell.GetColor("#e0e090")),
	}
	win := &Window{
		y:     t.y,
		width: t.width,
		ui:    t,
		head:  head,
		body:  body,
	}
	head.win = win
	body.win = win

	if t.firstWin == nil {
		t.activeText = body
		t.firstWin = win
	} else {
		prev := t.lastWin()
		win.y = prev.y + prev.height()/2
		prev.nextWin = win
	}
	return win
}

func (t *UI) deleteWindow(todel *Window) {
	sentinel := &Window{nextWin: t.firstWin}
	win := sentinel
	for win.nextWin != nil {
		if win.nextWin == todel {
			win.nextWin = todel.nextWin
			t.firstWin = sentinel.nextWin
			if t.firstWin != nil {
				t.firstWin.y = t.y
			}
			return
		}
		win = win.nextWin
	}
	panic("window not found")
}

func (t *UI) Flush() {
	win := t.firstWin
	for win != nil {
		win.flush()
		win = win.nextWin
	}
}

// TODO: This is for temporary reasons. Remove it.
func (t *UI) Push_Mouse_Event(ev mouse.Event) {
	y := int(ev.Y)
	if t.grabbedWin != nil {
		if ev.Direction == mouse.DirRelease {
			t.moveGrabbedWin(y)
		}
		return
	}
	win := t.firstWin
	for win != nil {
		if y < win.y || y >= win.y+win.height() {
			win = win.nextWin
			continue
		}
		if y >= win.body.y {
			win.body.click(ev)
			t.activeText = win.body
		} else {
			if int(ev.X) == win.x && ev.Direction == mouse.DirPress {
				t.grabbedWin = win
				break
			}
			win.head.click(ev)
			t.activeText = win.head
		}
		break
	}
}

func (t *UI) Push_Key_Event(ev key.Event) {
	t.activeText.keyEventHandler(ev)
}

func (t *UI) lastWin() *Window {
	win := t.firstWin
	if win == nil {
		return nil
	}
	for win.nextWin != nil {
		win = win.nextWin
	}
	return win
}

func (t *UI) moveGrabbedWin(y int) {
	gw := t.grabbedWin
	t.grabbedWin = nil
	target := t.firstWin

	if target.nextWin == nil {
		// Cannot move anything if there's just one
		// window.
		return
	}

	for target != nil {
		if y >= target.y && y < target.y+target.height() {
			break
		}
		target = target.nextWin
	}

	if y == target.y {
		// TODO: If this happens, adjust position of the windows
		// to ensure at least one line of each window is shown.
		// Forbid it for now as it would cause panic otherwise.
		return
	}

	if gw == target || (target.nextWin != nil && gw == target.nextWin) {
		if gw == t.firstWin {
			return
		}
	} else {
		t.moveWin(gw, target)
	}
	gw.y = y
}

func (t *UI) moveWin(win, after *Window) {
	sentinel := &Window{nextWin: t.firstWin}
	prev := sentinel
	for prev.nextWin != nil {
		if prev.nextWin == win {
			prev.nextWin = win.nextWin
			win.nextWin = after.nextWin
			after.nextWin = win

			t.firstWin = sentinel.nextWin
			t.firstWin.y = t.y
			return
		}
		prev = prev.nextWin
	}
	panic("window not found")
}

type Window struct {
	ui *UI

	width int
	x, y  int

	head *Text
	body *Text

	dirty bool

	nextWin *Window
}

func (win *Window) Size() (w, h int) {
	return win.width, win.height()
}

func (win *Window) Head() *Text { return win.head }
func (win *Window) Body() *Text { return win.body }

func (win *Window) Clear() {
	h := win.height()
	win.head.width = win.width - 1
	win.head.height = h - 1
	win.head.clear()

	win.body.width = win.width - 1
	win.body.height = h
	win.body.clear()
}

func (win *Window) SetDirty(dirty bool) {
	win.dirty = dirty
}

func (win *Window) Delete() {
	win.ui.deleteWindow(win)
}

var dirtystyle = tcell.StyleDefault.Background(tcell.GetColor("#8888cc"))

func (win *Window) flush() {
	win.head.x = win.x + 1
	win.head.y = win.y
	win.head.flush()

	h := len(win.head.frame.lines)
	win.head.height = h

	y := 0
	for ; y < h; y++ {
		bg := win.head.bgstyle
		if y == 0 && win.dirty {
			bg = dirtystyle
		}
		win.ui.screen.SetContent(win.x, win.y+y, ' ', nil, bg)
	}
	winh := win.height()
	for ; y < winh; y++ {
		win.ui.screen.SetContent(win.x, win.y+y, ' ', nil, win.body.bgstyle)
	}

	win.body.height = winh - h
	if len(win.body.frame.lines) > win.body.height {
		// TODO: We didn't know how many lines will the head of the window
		// span. Can we do better?
		win.body.frame.lines = win.body.frame.lines[:win.body.height]
	}
	win.body.x = win.x + 1
	win.body.y = win.y + h
	win.body.flush()
	win.body.fill()

	win.ui.screen.Show()
}

func (win *Window) height() int {
	if win.nextWin == nil {
		return win.ui.y + win.ui.height - win.y
	}
	return win.nextWin.y - win.y
}

type Text struct {
	win   *Window
	frame *Frame

	width, height int
	x, y          int
	cur           struct {
		p0, p1 int // char position
		x, y   int // current position
	}

	// styles
	bgstyle tcell.Style
	hlstyle tcell.Style

	mouseEventHandler ui.MouseEventHandler
	keyEventHandler   ui.KeyEventHandler
}

func (t *Text) click(ev mouse.Event) {
	if t.mouseEventHandler == nil {
		return
	}
	p := t.frame.CharsUntilXY(int(ev.X)-t.x, int(ev.Y)-t.y)
	t.mouseEventHandler(p, ev)
}

func (t *Text) OnMouseEvent(h ui.MouseEventHandler) {
	t.mouseEventHandler = h
}

func (t *Text) OnKeyEvent(h ui.KeyEventHandler) {
	t.keyEventHandler = h
}

func (t *Text) clear() {
	*t.frame = Frame{
		lines:   make([][]rune, 1),
		wantCol: t.frame.wantCol,
	}
	t.cur.x, t.cur.y = 0, 0
	t.checkSelection()
}

func (t *Text) Select(p0, p1 int) { t.cur.p0, t.cur.p1 = p0, p1 }

func (t *Text) WriteRune(r rune) error {
	t.frame.lines[t.cur.y] = append(t.frame.lines[t.cur.y], r)
	if r == '\t' {
		t.cur.x += tabWidthForCol(t.cur.x)
	} else {
		t.cur.x++
	}

	if t.cur.x >= t.width || r == '\n' {
		t.cur.y++
		t.cur.x = 0
		t.frame.lines = append(t.frame.lines, nil)
		if t.cur.y == t.height {
			return io.EOF
		}
	}

	t.frame.nchars++
	t.checkSelection()
	return nil
}

// checkSelection tries to line0, line1, and wantCol.
func (t *Text) checkSelection() {
	if t.cur.p0 == t.frame.nchars {
		t.frame.line0 = t.cur.y
		if t.frame.wantCol == ui.ColQ0 {
			t.frame.wantCol = t.cur.x
		}
	}
	if t.cur.p1 == t.frame.nchars {
		t.frame.line1 = t.cur.y
		if t.frame.wantCol == ui.ColQ1 {
			t.frame.wantCol = t.cur.x
		}
	}
}

var reverse = tcell.StyleDefault.Reverse(true)

func (t *Text) flush() {
	style := t.bgstyle
	selStyle := func(p int) {
		if p == t.cur.p0 && t.cur.p0 == t.cur.p1 {
			style = reverse
		} else if p >= t.cur.p0 && p < t.cur.p1 {
			style = t.hlstyle
		} else {
			style = t.bgstyle
		}
	}
	p := 0
	for y, l := range t.frame.lines {
		x := 0
		for _, r := range l {
			selStyle(p)
			p++
			if r == '\n' {
				goto fill
			}
			w := 1
			if r == '\t' {
				r = ' '
				w = tabWidthForCol(x)
			}
			for i := 0; i < w && x < t.width; i++ {
				// TODO: Should the rest of the tab at the end of a
				// line span the begining of the next line?
				t.win.ui.screen.SetContent(t.x+x, t.y+y, r, nil, style)
				x++
				if style == reverse {
					style = t.bgstyle
				}
			}
		}
		selStyle(p)
	fill:
		for ; x < t.width; x++ {
			t.win.ui.screen.SetContent(t.x+x, t.y+y, ' ', nil, style)
			if style == reverse {
				style = t.bgstyle
			}
		}
	}
}

func (t *Text) fill() {
	// TODO: Using this bg color just for testing purposes.
	bg := tcell.StyleDefault.Background(tcell.GetColor("#ffe0ff"))
	for y := len(t.frame.lines); y < t.height; y++ {
		for x := 0; x < t.width; x++ {
			t.win.ui.screen.SetContent(t.x+x, t.y+y, ' ', nil, bg)
		}
	}
}

func (t *Text) Frame() *Frame { return t.frame }

type Frame struct {
	lines   [][]rune
	line0   int
	line1   int
	wantCol int
	nchars  int
}

func (f *Frame) Nchars() int                { return f.nchars }
func (f *Frame) SelectionLines() (int, int) { return f.line0, f.line1 }

func (f *Frame) CharsUntilXY(x, y int) int {
	if y >= len(f.lines) {
		return f.nchars
	}
	var p int
	for n, l := range f.lines {
		if n == y {
			return p + charsUntilX(l, x)
		}
		p += len(l)
	}
	return 0
}

func charsUntilX(s []rune, x int) int {
	if len(s) == 0 {
		return 0
	}
	var w int
	for i, r := range s {
		if r == '\t' {
			w += tabWidthForCol(w)
		} else {
			w += 1
		}
		if w > x {
			return i
		}
	}
	if s[len(s)-1] == '\n' {
		return len(s) - 1
	}
	return len(s)
}

const tabStop = 8

func tabWidthForCol(col int) int {
	w := tabStop - col%tabStop
	if w == 0 {
		return tabStop
	}
	return w
}

func (f *Frame) Lines() int         { return len(f.lines) }
func (f *Frame) WantCol() int       { return f.wantCol }
func (f *Frame) SetWantCol(col int) { f.wantCol = col }
<commit_msg>ui/term: Handle non-printable characters<commit_after>package term

import (
	"io"
	"unicode"
	"unicode/utf8"

	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/mouse"

	"github.com/gdamore/tcell"
	"github.com/mibk/syd/ui"
)

type UI struct {
	screen        tcell.Screen
	wasBtnPressed bool

	y      int
	width  int
	height int

	firstWin   *Window
	activeText *Text   // will receive key events
	grabbedWin *Window // index of the grabbed win or nil
}

func (t *UI) Init() error {
	sc, err := tcell.NewScreen()
	if err != nil {
		return err
	}
	if err := sc.Init(); err != nil {
		return err
	}
	sc.EnableMouse()
	t.screen = sc

	// TODO: Just for testing purposes.
	t.y = 1
	w, h := t.Size()
	t.width = w / 2
	t.height = h - 2

	go t.translateEvents()
	return nil
}

func (t *UI) Close() error {
	t.screen.Fini()
	return nil
}

func (t *UI) Size() (w, h int) { return t.screen.Size() }

func (t *UI) NewWindow() *Window {
	head := &Text{
		frame: new(Frame),
		bgstyle: tcell.StyleDefault.
			Background(tcell.GetColor("#eaffff")),
		hlstyle: tcell.StyleDefault.
			Background(tcell.GetColor("#90e0e0")),
	}
	body := &Text{
		frame: new(Frame),
		bgstyle: tcell.StyleDefault.
			Background(tcell.GetColor("#ffffea")),
		hlstyle: tcell.StyleDefault.
			Background(tcell.GetColor("#e0e090")),
	}
	win := &Window{
		y:     t.y,
		width: t.width,
		ui:    t,
		head:  head,
		body:  body,
	}
	head.win = win
	body.win = win

	if t.firstWin == nil {
		t.activeText = body
		t.firstWin = win
	} else {
		prev := t.lastWin()
		win.y = prev.y + prev.height()/2
		prev.nextWin = win
	}
	return win
}

func (t *UI) deleteWindow(todel *Window) {
	sentinel := &Window{nextWin: t.firstWin}
	win := sentinel
	for win.nextWin != nil {
		if win.nextWin == todel {
			win.nextWin = todel.nextWin
			t.firstWin = sentinel.nextWin
			if t.firstWin != nil {
				t.firstWin.y = t.y
			}
			return
		}
		win = win.nextWin
	}
	panic("window not found")
}

func (t *UI) Flush() {
	win := t.firstWin
	for win != nil {
		win.flush()
		win = win.nextWin
	}
}

// TODO: This is for temporary reasons. Remove it.
func (t *UI) Push_Mouse_Event(ev mouse.Event) {
	y := int(ev.Y)
	if t.grabbedWin != nil {
		if ev.Direction == mouse.DirRelease {
			t.moveGrabbedWin(y)
		}
		return
	}
	win := t.firstWin
	for win != nil {
		if y < win.y || y >= win.y+win.height() {
			win = win.nextWin
			continue
		}
		if y >= win.body.y {
			win.body.click(ev)
			t.activeText = win.body
		} else {
			if int(ev.X) == win.x && ev.Direction == mouse.DirPress {
				t.grabbedWin = win
				break
			}
			win.head.click(ev)
			t.activeText = win.head
		}
		break
	}
}

func (t *UI) Push_Key_Event(ev key.Event) {
	t.activeText.keyEventHandler(ev)
}

func (t *UI) lastWin() *Window {
	win := t.firstWin
	if win == nil {
		return nil
	}
	for win.nextWin != nil {
		win = win.nextWin
	}
	return win
}

func (t *UI) moveGrabbedWin(y int) {
	gw := t.grabbedWin
	t.grabbedWin = nil
	target := t.firstWin

	if target.nextWin == nil {
		// Cannot move anything if there's just one
		// window.
		return
	}

	for target != nil {
		if y >= target.y && y < target.y+target.height() {
			break
		}
		target = target.nextWin
	}

	if y == target.y {
		// TODO: If this happens, adjust position of the windows
		// to ensure at least one line of each window is shown.
		// Forbid it for now as it would cause panic otherwise.
		return
	}

	if gw == target || (target.nextWin != nil && gw == target.nextWin) {
		if gw == t.firstWin {
			return
		}
	} else {
		t.moveWin(gw, target)
	}
	gw.y = y
}

func (t *UI) moveWin(win, after *Window) {
	sentinel := &Window{nextWin: t.firstWin}
	prev := sentinel
	for prev.nextWin != nil {
		if prev.nextWin == win {
			prev.nextWin = win.nextWin
			win.nextWin = after.nextWin
			after.nextWin = win

			t.firstWin = sentinel.nextWin
			t.firstWin.y = t.y
			return
		}
		prev = prev.nextWin
	}
	panic("window not found")
}

type Window struct {
	ui *UI

	width int
	x, y  int

	head *Text
	body *Text

	dirty bool

	nextWin *Window
}

func (win *Window) Size() (w, h int) {
	return win.width, win.height()
}

func (win *Window) Head() *Text { return win.head }
func (win *Window) Body() *Text { return win.body }

func (win *Window) Clear() {
	h := win.height()
	win.head.width = win.width - 1
	win.head.height = h - 1
	win.head.clear()

	win.body.width = win.width - 1
	win.body.height = h
	win.body.clear()
}

func (win *Window) SetDirty(dirty bool) {
	win.dirty = dirty
}

func (win *Window) Delete() {
	win.ui.deleteWindow(win)
}

var dirtystyle = tcell.StyleDefault.Background(tcell.GetColor("#8888cc"))

func (win *Window) flush() {
	win.head.x = win.x + 1
	win.head.y = win.y
	win.head.flush()

	h := len(win.head.frame.lines)
	win.head.height = h

	y := 0
	for ; y < h; y++ {
		bg := win.head.bgstyle
		if y == 0 && win.dirty {
			bg = dirtystyle
		}
		win.ui.screen.SetContent(win.x, win.y+y, ' ', nil, bg)
	}
	winh := win.height()
	for ; y < winh; y++ {
		win.ui.screen.SetContent(win.x, win.y+y, ' ', nil, win.body.bgstyle)
	}

	win.body.height = winh - h
	if len(win.body.frame.lines) > win.body.height {
		// TODO: We didn't know how many lines will the head of the window
		// span. Can we do better?
		win.body.frame.lines = win.body.frame.lines[:win.body.height]
	}
	win.body.x = win.x + 1
	win.body.y = win.y + h
	win.body.flush()
	win.body.fill()

	win.ui.screen.Show()
}

func (win *Window) height() int {
	if win.nextWin == nil {
		return win.ui.y + win.ui.height - win.y
	}
	return win.nextWin.y - win.y
}

type Text struct {
	win   *Window
	frame *Frame

	width, height int
	x, y          int
	cur           struct {
		p0, p1 int // char position
		x, y   int // current position
	}

	// styles
	bgstyle tcell.Style
	hlstyle tcell.Style

	mouseEventHandler ui.MouseEventHandler
	keyEventHandler   ui.KeyEventHandler
}

func (t *Text) click(ev mouse.Event) {
	if t.mouseEventHandler == nil {
		return
	}
	p := t.frame.CharsUntilXY(int(ev.X)-t.x, int(ev.Y)-t.y)
	t.mouseEventHandler(p, ev)
}

func (t *Text) OnMouseEvent(h ui.MouseEventHandler) {
	t.mouseEventHandler = h
}

func (t *Text) OnKeyEvent(h ui.KeyEventHandler) {
	t.keyEventHandler = h
}

func (t *Text) clear() {
	*t.frame = Frame{
		lines:   make([][]rune, 1),
		wantCol: t.frame.wantCol,
	}
	t.cur.x, t.cur.y = 0, 0
	t.checkSelection()
}

func (t *Text) Select(p0, p1 int) { t.cur.p0, t.cur.p1 = p0, p1 }

func (t *Text) WriteRune(r rune) error {
	t.frame.lines[t.cur.y] = append(t.frame.lines[t.cur.y], r)
	if r == '\t' {
		t.cur.x += tabWidthForCol(t.cur.x)
	} else {
		t.cur.x++
	}

	if t.cur.x >= t.width || r == '\n' {
		t.cur.y++
		t.cur.x = 0
		t.frame.lines = append(t.frame.lines, nil)
		if t.cur.y == t.height {
			return io.EOF
		}
	}

	t.frame.nchars++
	t.checkSelection()
	return nil
}

// checkSelection tries to line0, line1, and wantCol.
func (t *Text) checkSelection() {
	if t.cur.p0 == t.frame.nchars {
		t.frame.line0 = t.cur.y
		if t.frame.wantCol == ui.ColQ0 {
			t.frame.wantCol = t.cur.x
		}
	}
	if t.cur.p1 == t.frame.nchars {
		t.frame.line1 = t.cur.y
		if t.frame.wantCol == ui.ColQ1 {
			t.frame.wantCol = t.cur.x
		}
	}
}

var reverse = tcell.StyleDefault.Reverse(true)

func (t *Text) flush() {
	style := t.bgstyle
	selStyle := func(p int) {
		if p == t.cur.p0 && t.cur.p0 == t.cur.p1 {
			style = reverse
		} else if p >= t.cur.p0 && p < t.cur.p1 {
			style = t.hlstyle
		} else {
			style = t.bgstyle
		}
	}
	p := 0
	for y, l := range t.frame.lines {
		x := 0
		for _, r := range l {
			selStyle(p)
			p++
			w := 1
			switch {
			case r == '\n':
				goto fill
			case r == '\t':
				r = ' '
				w = tabWidthForCol(x)
			case r == 0:
				// TODO: This is a workaround to print silently \0 that
				// separates filename and commands in the head of the window.
				r = ' '
			case !unicode.IsPrint(r):
				r = utf8.RuneError
			}
			for i := 0; i < w && x < t.width; i++ {
				// TODO: Should the rest of the tab at the end of a
				// line span the begining of the next line?
				t.win.ui.screen.SetContent(t.x+x, t.y+y, r, nil, style)
				x++
				if style == reverse {
					style = t.bgstyle
				}
			}
		}
		selStyle(p)
	fill:
		for ; x < t.width; x++ {
			t.win.ui.screen.SetContent(t.x+x, t.y+y, ' ', nil, style)
			if style == reverse {
				style = t.bgstyle
			}
		}
	}
}

func (t *Text) fill() {
	// TODO: Using this bg color just for testing purposes.
	bg := tcell.StyleDefault.Background(tcell.GetColor("#ffe0ff"))
	for y := len(t.frame.lines); y < t.height; y++ {
		for x := 0; x < t.width; x++ {
			t.win.ui.screen.SetContent(t.x+x, t.y+y, ' ', nil, bg)
		}
	}
}

func (t *Text) Frame() *Frame { return t.frame }

type Frame struct {
	lines   [][]rune
	line0   int
	line1   int
	wantCol int
	nchars  int
}

func (f *Frame) Nchars() int                { return f.nchars }
func (f *Frame) SelectionLines() (int, int) { return f.line0, f.line1 }

func (f *Frame) CharsUntilXY(x, y int) int {
	if y >= len(f.lines) {
		return f.nchars
	}
	var p int
	for n, l := range f.lines {
		if n == y {
			return p + charsUntilX(l, x)
		}
		p += len(l)
	}
	return 0
}

func charsUntilX(s []rune, x int) int {
	if len(s) == 0 {
		return 0
	}
	var w int
	for i, r := range s {
		if r == '\t' {
			w += tabWidthForCol(w)
		} else {
			w += 1
		}
		if w > x {
			return i
		}
	}
	if s[len(s)-1] == '\n' {
		return len(s) - 1
	}
	return len(s)
}

const tabStop = 8

func tabWidthForCol(col int) int {
	w := tabStop - col%tabStop
	if w == 0 {
		return tabStop
	}
	return w
}

func (f *Frame) Lines() int         { return len(f.lines) }
func (f *Frame) WantCol() int       { return f.wantCol }
func (f *Frame) SetWantCol(col int) { f.wantCol = col }
<|endoftext|>