<commit_before>// Copyright 2018 Authors of Cilium
//
// 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 k8sTest

import (
	. "github.com/cilium/cilium/test/ginkgo-ext"
	"github.com/cilium/cilium/test/helpers"

	. "github.com/onsi/gomega"
	"github.com/sirupsen/logrus"
)

var (
	microscopeTestName = "K8sValidatedMicroscope"
)

var _ = Describe(microscopeTestName, func() {

	var (
		kubectl *helpers.Kubectl
		logger  *logrus.Entry
	)

	BeforeAll(func() {
		logger = log.WithFields(logrus.Fields{"testName": microscopeTestName})
		logger.Info("Starting")
		kubectl = helpers.CreateKubectl(helpers.K8s1VMName(), logger)

		err := kubectl.CiliumInstall(helpers.CiliumDSPath)
		Expect(err).To(BeNil(), "Cilium cannot be installed")

		ExpectCiliumReady(kubectl)
	})

	AfterFailed(func() {
		kubectl.CiliumReport(helpers.KubeSystemNamespace,
			"cilium endpoint list")
	})

	It("Runs microscope", func() {
		microscopeErr, microscopeCancel := kubectl.MicroscopeStart()
		Expect(microscopeErr).To(BeNil(), "Microscope cannot be started")

		err := helpers.WithTimeout(func() bool {
			res := kubectl.ExecPodCmd("kube-system", "microscope", "pgrep -f microscope")
			return res.WasSuccessful()
		}, "running microscope processes not found",
			&helpers.TimeoutConfig{
				Ticker:  5,
				Timeout: 120,
			})

		Expect(err).To(BeNil())

		kubectl.ValidateNoErrorsOnLogs(CurrentGinkgoTestDescription().Duration)
		Expect(microscopeCancel()).To(BeNil(), "cannot stop microscope")

		err = helpers.WithTimeout(func() bool {
			res := kubectl.ExecPodCmd("kube-system", "microscope", "pgrep -f microscope")
			return !res.WasSuccessful()
		}, "found running microscope processes; no microscope processes should be running",
			&helpers.TimeoutConfig{
				Ticker:  5,
				Timeout: 120,
			})
		Expect(err).To(BeNil())
	})
})
<commit_msg>Test: Microscope waiting until pods terminates.<commit_after>// Copyright 2018 Authors of Cilium
//
// 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 k8sTest

import (
	. "github.com/cilium/cilium/test/ginkgo-ext"
	"github.com/cilium/cilium/test/helpers"

	. "github.com/onsi/gomega"
	"github.com/sirupsen/logrus"
)

var (
	microscopeTestName = "K8sValidatedMicroscope"
)

var _ = Describe(microscopeTestName, func() {

	var (
		kubectl *helpers.Kubectl
		logger  *logrus.Entry
	)

	BeforeAll(func() {
		logger = log.WithFields(logrus.Fields{"testName": microscopeTestName})
		logger.Info("Starting")
		kubectl = helpers.CreateKubectl(helpers.K8s1VMName(), logger)

		err := kubectl.CiliumInstall(helpers.CiliumDSPath)
		Expect(err).To(BeNil(), "Cilium cannot be installed")

		ExpectCiliumReady(kubectl)
	})

	AfterFailed(func() {
		kubectl.CiliumReport(helpers.KubeSystemNamespace,
			"cilium endpoint list")
	})

	AfterAll(func() {
		ExpectAllPodsTerminated(kubectl)
	})

	It("Runs microscope", func() {
		microscopeErr, microscopeCancel := kubectl.MicroscopeStart()
		Expect(microscopeErr).To(BeNil(), "Microscope cannot be started")

		err := helpers.WithTimeout(func() bool {
			res := kubectl.ExecPodCmd("kube-system", "microscope", "pgrep -f microscope")
			return res.WasSuccessful()
		}, "running microscope processes not found",
			&helpers.TimeoutConfig{
				Ticker:  5,
				Timeout: 120,
			})

		Expect(err).To(BeNil())

		kubectl.ValidateNoErrorsOnLogs(CurrentGinkgoTestDescription().Duration)
		Expect(microscopeCancel()).To(BeNil(), "cannot stop microscope")

		err = helpers.WithTimeout(func() bool {
			res := kubectl.ExecPodCmd("kube-system", "microscope", "pgrep -f microscope")
			return !res.WasSuccessful()
		}, "found running microscope processes; no microscope processes should be running",
			&helpers.TimeoutConfig{
				Ticker:  5,
				Timeout: 120,
			})
		Expect(err).To(BeNil())
	})
})
<|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.

package runtime

import "unsafe"

// Note: the MemStats struct should be kept in sync with
// struct MStats in malloc.h

// A MemStats records statistics about the memory allocator.
type MemStats struct {
	// General statistics.
	Alloc      uint64 // bytes allocated and still in use
	TotalAlloc uint64 // bytes allocated (even if freed)
	Sys        uint64 // bytes obtained from system (sum of XxxSys below)
	Lookups    uint64 // number of pointer lookups
	Mallocs    uint64 // number of mallocs
	Frees      uint64 // number of frees

	// Main allocation heap statistics.
	HeapAlloc    uint64 // bytes allocated and still in use
	HeapSys      uint64 // bytes obtained from system
	HeapIdle     uint64 // bytes in idle spans
	HeapInuse    uint64 // bytes in non-idle span
	HeapReleased uint64 // bytes released to the OS
	HeapObjects  uint64 // total number of allocated objects

	// Low-level fixed-size structure allocator statistics.
	//	Inuse is bytes used now.
	//	Sys is bytes obtained from system.
	StackInuse  uint64 // bytes used by stack allocator
	StackSys    uint64
	MSpanInuse  uint64 // mspan structures
	MSpanSys    uint64
	MCacheInuse uint64 // mcache structures
	MCacheSys   uint64
	BuckHashSys uint64 // profiling bucket hash table
	GCSys       uint64 // GC metadata
	OtherSys    uint64 // other system allocations

	// Garbage collector statistics.
	NextGC       uint64 // next run in HeapAlloc time (bytes)
	LastGC       uint64 // last run in absolute time (ns)
	PauseTotalNs uint64
	PauseNs      [256]uint64 // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
	NumGC        uint32
	EnableGC     bool
	DebugGC      bool

	// Per-size allocation statistics.
	// 61 is NumSizeClasses in the C code.
	BySize [61]struct {
		Size    uint32
		Mallocs uint64
		Frees   uint64
	}
}

var sizeof_C_MStats uintptr // filled in by malloc.goc

func init() {
	var memStats MemStats
	if sizeof_C_MStats != unsafe.Sizeof(memStats) {
		println(sizeof_C_MStats, unsafe.Sizeof(memStats))
		gothrow("MStats vs MemStatsType size mismatch")
	}
}

// ReadMemStats populates m with memory allocator statistics.
func ReadMemStats(m *MemStats) {
	// Have to acquire worldsema to stop the world,
	// because stoptheworld can only be used by
	// one goroutine at a time, and there might be
	// a pending garbage collection already calling it.
	semacquire(&worldsema, false)
	gp := getg()
	gp.m.gcing = 1
	onM(stoptheworld)

	gp.m.ptrarg[0] = noescape(unsafe.Pointer(m))
	onM(readmemstats_m)

	gp.m.gcing = 0
	gp.m.locks++
	semrelease(&worldsema)
	onM(starttheworld)
	gp.m.locks--
}

// Implementation of runtime/debug.WriteHeapDump
func writeHeapDump(fd uintptr) {
	semacquire(&worldsema, false)
	gp := getg()
	gp.m.gcing = 1
	onM(stoptheworld)

	gp.m.scalararg[0] = fd
	onM(writeheapdump_m)

	gp.m.gcing = 0
	gp.m.locks++
	semrelease(&worldsema)
	onM(starttheworld)
	gp.m.locks--
}
<commit_msg>runtime: fix LastGC comment<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.

package runtime

import "unsafe"

// Note: the MemStats struct should be kept in sync with
// struct MStats in malloc.h

// A MemStats records statistics about the memory allocator.
type MemStats struct {
	// General statistics.
	Alloc      uint64 // bytes allocated and still in use
	TotalAlloc uint64 // bytes allocated (even if freed)
	Sys        uint64 // bytes obtained from system (sum of XxxSys below)
	Lookups    uint64 // number of pointer lookups
	Mallocs    uint64 // number of mallocs
	Frees      uint64 // number of frees

	// Main allocation heap statistics.
	HeapAlloc    uint64 // bytes allocated and still in use
	HeapSys      uint64 // bytes obtained from system
	HeapIdle     uint64 // bytes in idle spans
	HeapInuse    uint64 // bytes in non-idle span
	HeapReleased uint64 // bytes released to the OS
	HeapObjects  uint64 // total number of allocated objects

	// Low-level fixed-size structure allocator statistics.
	//	Inuse is bytes used now.
	//	Sys is bytes obtained from system.
	StackInuse  uint64 // bytes used by stack allocator
	StackSys    uint64
	MSpanInuse  uint64 // mspan structures
	MSpanSys    uint64
	MCacheInuse uint64 // mcache structures
	MCacheSys   uint64
	BuckHashSys uint64 // profiling bucket hash table
	GCSys       uint64 // GC metadata
	OtherSys    uint64 // other system allocations

	// Garbage collector statistics.
	NextGC       uint64 // next collection will happen when HeapAlloc ≥ this amount
	LastGC       uint64 // end time of last collection (nanoseconds since 1970)
	PauseTotalNs uint64
	PauseNs      [256]uint64 // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
	NumGC        uint32
	EnableGC     bool
	DebugGC      bool

	// Per-size allocation statistics.
	// 61 is NumSizeClasses in the C code.
	BySize [61]struct {
		Size    uint32
		Mallocs uint64
		Frees   uint64
	}
}

var sizeof_C_MStats uintptr // filled in by malloc.goc

func init() {
	var memStats MemStats
	if sizeof_C_MStats != unsafe.Sizeof(memStats) {
		println(sizeof_C_MStats, unsafe.Sizeof(memStats))
		gothrow("MStats vs MemStatsType size mismatch")
	}
}

// ReadMemStats populates m with memory allocator statistics.
func ReadMemStats(m *MemStats) {
	// Have to acquire worldsema to stop the world,
	// because stoptheworld can only be used by
	// one goroutine at a time, and there might be
	// a pending garbage collection already calling it.
	semacquire(&worldsema, false)
	gp := getg()
	gp.m.gcing = 1
	onM(stoptheworld)

	gp.m.ptrarg[0] = noescape(unsafe.Pointer(m))
	onM(readmemstats_m)

	gp.m.gcing = 0
	gp.m.locks++
	semrelease(&worldsema)
	onM(starttheworld)
	gp.m.locks--
}

// Implementation of runtime/debug.WriteHeapDump
func writeHeapDump(fd uintptr) {
	semacquire(&worldsema, false)
	gp := getg()
	gp.m.gcing = 1
	onM(stoptheworld)

	gp.m.scalararg[0] = fd
	onM(writeheapdump_m)

	gp.m.gcing = 0
	gp.m.locks++
	semrelease(&worldsema)
	onM(starttheworld)
	gp.m.locks--
}
<|endoftext|>


<commit_before>
package main

import (
    "fmt"
    "regexp"
)

func main() {
    matched, err := regexp.MatchString("(?i)add\\s+(a\\s+)?ticket\\s+for\\s.*", "Add a ticket for @godzilla ")
    fmt.Println(matched, err)
    matched, err = regexp.MatchString("(?i)respond\\s+to\\s.*", "Respond  to @bigfoot")
    fmt.Println(matched, err)
    matched, err = regexp.MatchString("a(b", "seafood")
    fmt.Println(matched, err)

    addTicketRE := regexp.MustCompile(`(?i)add\s+(a\s+)?ticket\s+for\s.*`)
    matched := addTicketRE.MatchString("Add a ticket for @godzilla ")
    fmt.Println(matched)
    matched, err := regexp.MatchString("(?i)respond\\s+to\\s.*", "Respond  to @bigfoot")
    fmt.Println(matched, err)
    matched, err = regexp.MatchString("a(b", "seafood")
    fmt.Println(matched, err)

    re := regexp.MustCompile("a(x*)b(y|z)c")
    fmt.Printf("%q\n", re.FindStringSubmatch("-axxxbyc-"))
    fmt.Printf("%q\n", re.FindStringSubmatch("-abzc-"))

    myText := "Add a  TickeT for @bruce Are you the batman?"
    ticketOnBehalfRegex := regexp.MustCompile(`(?i)add\s+(?:a\s+)?ticket\s+for\s+(.*)`)
    matches := ticketOnBehalfRegex.FindStringSubmatch(myText)
    fmt.Printf("ticketOnBehalfRegex ~=? %s:\n\t  %#v\n", myText, matches)

    myText = "ResPond to @alfred Where's Bruce?"
    questionOnBehalfRegex := regexp.MustCompile(`(?i)respond\s+to\s+(?-i)((<@[^|]{5,}\|[a-z0-9][a-z0-9._-]*>)|@[a-z0-9][a-z0-9._-]*)\s+(.*)`)
    matches = questionOnBehalfRegex.FindStringSubmatch(myText)
    fmt.Printf("questionOnBehalfRegex ~=? %s:\n\t  %#v\n", myText, matches)

    myText = "ResPond to <@U54321ABC|rosencrantz> Where's Guildenstern?"
    matches = questionOnBehalfRegex.FindStringSubmatch(myText)
    fmt.Printf("questionOnBehalfRegex ~=? %s:\n\t  %#v\n", myText, matches)

}

<commit_msg>regex<commit_after>
package main

import (
    "fmt"
    "regexp"
)

func main() {
    matched, err := regexp.MatchString("(?i)add\\s+(a\\s+)?ticket\\s+for\\s.*", "Add a ticket for @godzilla ")
    fmt.Println(matched, err)
    matched, err = regexp.MatchString("(?i)respond\\s+to\\s.*", "Respond  to @bigfoot")
    fmt.Println(matched, err)
    matched, err = regexp.MatchString("a(b", "seafood")
    fmt.Println(matched, err)

    addTicketRE := regexp.MustCompile(`(?i)add\s+(a\s+)?ticket\s+for\s.*`)
    matched := addTicketRE.MatchString("Add a ticket for @godzilla ")
    fmt.Println(matched)
    matched, err := regexp.MatchString("(?i)respond\\s+to\\s.*", "Respond  to @bigfoot")
    fmt.Println(matched, err)
    matched, err = regexp.MatchString("a(b", "seafood")
    fmt.Println(matched, err)

    re := regexp.MustCompile("a(x*)b(y|z)c")
    fmt.Printf("%q\n", re.FindStringSubmatch("-axxxbyc-"))
    fmt.Printf("%q\n", re.FindStringSubmatch("-abzc-"))

    myText := "Add a  TickeT for @bruce Are you the batman?"
    ticketOnBehalfRegex := regexp.MustCompile(`(?i)add\s+(?:a\s+)?ticket\s+for\s+(.*)`)
    matches := ticketOnBehalfRegex.FindStringSubmatch(myText)
    fmt.Printf("ticketOnBehalfRegex ~=? %s:\n\t  %#v\n", myText, matches)

    myText = "ResPond to @alfred Where's Bruce?"
    questionOnBehalfRegex := regexp.MustCompile(`(?i)respond\s+to\s+(?-i)((<@[^|]{5,}\|[a-z0-9][a-z0-9._-]*>)|@[a-z0-9][a-z0-9._-]*)\s+(.*)`)
    matches = questionOnBehalfRegex.FindStringSubmatch(myText)
    fmt.Printf("questionOnBehalfRegex ~=? %s:\n\t  %#v\n", myText, matches)

    myText = "ResPond to <@U54321ABC|rosencrantz> Where's Guildenstern?"
    matches = questionOnBehalfRegex.FindStringSubmatch(myText)
    fmt.Printf("questionOnBehalfRegex ~=? %s:\n\t  %#v\n", myText, matches)

    myText = "ResPond to <@U54321ABC|rosencrantz> Where's Guildenstern?"
    matches = questionOnBehalfRegex.FindStringSubmatch(myText)
    fmt.Printf("questionOnBehalfRegex ~=? %s:\n\t  %#v\n", myText, matches)

    myText = "ResPond <@U54321ABC|rosencrantz> Where's Rosencrantz?"
    matches = questionOnBehalfRegex.FindStringSubmatch(myText)
    fmt.Printf("questionOnBehalfRegex ~=? %s:\n\t  %#v\n", myText, matches)
    if (matches != nil && ) {
        fmt.Println("matches is true!  ", matches)
    } else {
        fmt.Println("matches is false!  ", matches)
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2015 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
// resty source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

// Package resty provides simple HTTP and REST client for Go inspired by Ruby rest-client.
package resty

// Version # of go-resty
var Version = "0.6"
<commit_msg>Bump version to v0.7<commit_after>// Copyright (c) 2015 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
// resty source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

// Package resty provides simple HTTP and REST client for Go inspired by Ruby rest-client.
package resty

// Version # of go-resty
var Version = "0.7"
<|endoftext|>


<commit_before>// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
// resty source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

// Package resty provides simple HTTP and REST client for Go inspired by Ruby rest-client.
package resty

// Version # of resty
const Version = "1.1"
<commit_msg>version update for next dev iteration<commit_after>// Copyright (c) 2015-2018 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
// resty source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

// Package resty provides simple HTTP and REST client for Go inspired by Ruby rest-client.
package resty

// Version # of resty
const Version = "1.2-edge"
<|endoftext|>


<commit_before>package rounding

import (
	"math/big"
)

// RoundingMode describes how to round a given number.
// n is the integer that should be rounded such that the last digit is zero.
// l is the current last digit of n. For most cases you shouldn't need to
// implement this yourself, use one of the provided implementations in the
// rounding package.
type RoundingMode func(n, l *big.Int)

func roundUp(n, l *big.Int) {
	li := l.Int64()
	if li != 0 {
		if n.Sign() > 0 {
			n.Add(n, l.SetInt64(10-li))
		} else {
			n.Sub(n, l.SetInt64(10-li))
		}
	}
}

func roundDown(n, l *big.Int) {
	if n.Sign() > 0 {
		n.Sub(n, l)
	} else {
		n.Add(n, l)
	}
}

func roundCeil(n, l *big.Int) {
	li := l.Int64()
	if n.Sign() > 0 {
		if li != 0 {
			n.Add(n, l.SetInt64(10-li))
		}
	} else {
		n.Add(n, l)
	}
}

func roundFloor(n, l *big.Int) {
	if n.Sign() > 0 {
		n.Sub(n, l)
	} else {
		li := l.Int64()
		if li != 0 {
			n.Sub(n, l.SetInt64(10-li))
		}
	}
}

func roundHalfUp(n, l *big.Int) {
	if l.Int64() >= 5 {
		roundUp(n, l)
	} else {
		roundDown(n, l)
	}
}

func roundHalfDown(n, l *big.Int) {
	if l.Int64() > 5 {
		roundUp(n, l)
	} else {
		roundDown(n, l)
	}
}

func roundHalfEven(n, l *big.Int) {
	li := l.Int64()
	if li == 5 {
		k := new(big.Int).Rem(n, big100)
		ki := k.Int64() / 10
		if ki%2 == 0 {
			roundDown(n, l)
		} else {
			roundUp(n, l)
		}
	} else if li > 5 {
		roundUp(n, l)
	} else {
		roundDown(n, l)
	}
}

var (
	// Up rounds away from zero.
	Up RoundingMode = roundUp

	// Down rounds towards zero.
	Down RoundingMode = roundDown

	// Ceil rounds towards positive infinity.
	Ceil RoundingMode = roundCeil

	// Floor rounds towards negative infinity.
	Floor RoundingMode = roundFloor

	// HalfUp rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
	HalfUp RoundingMode = roundHalfUp

	// HalfDown rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
	HalfDown RoundingMode = roundHalfDown

	// HalfEven rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.
	HalfEven RoundingMode = roundHalfEven
)

// Round sets x to its value rounded to the given precision using the given rounding mode.
// Returns x, which was modified in place.
func Round(x *big.Rat, prec int, method RoundingMode) *big.Rat {
	trunc(x, prec+1)
	n, d := x.Num(), x.Denom()
	l := new(big.Int).Rem(n, big10)
	l.Abs(l)

	method(n, l)

	// To force renormalization
	return x.SetFrac(n, d)
}
<commit_msg>need to pass the sign to RoundingMode<commit_after>package rounding

import (
	"math/big"
)

// RoundingMode describes how to round a given number.
// sign is the sign of the number (needed when n is zero)
// n is the integer that should be rounded such that the last digit is zero.
// l is the current last digit of n. For most cases you shouldn't need to
// implement this yourself, use one of the provided implementations in the
// rounding package.
type RoundingMode func(sign int, n, l *big.Int)

func roundUp(sign int, n, l *big.Int) {
	li := l.Int64()
	if li != 0 {
		if sign > 0 {
			n.Add(n, l.SetInt64(10-li))
		} else {
			n.Sub(n, l.SetInt64(10-li))
		}
	}
}

func roundDown(sign int, n, l *big.Int) {
	if sign > 0 {
		n.Sub(n, l)
	} else {
		n.Add(n, l)
	}
}

func roundCeil(sign int, n, l *big.Int) {
	li := l.Int64()
	if sign > 0 {
		if li != 0 {
			n.Add(n, l.SetInt64(10-li))
		}
	} else {
		n.Add(n, l)
	}
}

func roundFloor(sign int, n, l *big.Int) {
	if sign > 0 {
		n.Sub(n, l)
	} else {
		li := l.Int64()
		if li != 0 {
			n.Sub(n, l.SetInt64(10-li))
		}
	}
}

func roundHalfUp(sign int, n, l *big.Int) {
	if l.Int64() >= 5 {
		roundUp(sign, n, l)
	} else {
		roundDown(sign, n, l)
	}
}

func roundHalfDown(sign int, n, l *big.Int) {
	if l.Int64() > 5 {
		roundUp(sign, n, l)
	} else {
		roundDown(sign, n, l)
	}
}

func roundHalfEven(sign int, n, l *big.Int) {
	li := l.Int64()
	if li == 5 {
		k := new(big.Int).Rem(n, big100)
		ki := k.Int64() / 10
		if ki%2 == 0 {
			roundDown(sign, n, l)
		} else {
			roundUp(sign, n, l)
		}
	} else if li > 5 {
		roundUp(sign, n, l)
	} else {
		roundDown(sign, n, l)
	}
}

var (
	// Up rounds away from zero.
	Up RoundingMode = roundUp

	// Down rounds towards zero.
	Down RoundingMode = roundDown

	// Ceil rounds towards positive infinity.
	Ceil RoundingMode = roundCeil

	// Floor rounds towards negative infinity.
	Floor RoundingMode = roundFloor

	// HalfUp rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
	HalfUp RoundingMode = roundHalfUp

	// HalfDown rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
	HalfDown RoundingMode = roundHalfDown

	// HalfEven rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.
	HalfEven RoundingMode = roundHalfEven
)

// Round sets x to its value rounded to the given precision using the given rounding mode.
// Returns x, which was modified in place.
func Round(x *big.Rat, prec int, method RoundingMode) *big.Rat {
	sign := x.Sign()
	trunc(x, prec+1)
	n, d := x.Num(), x.Denom()
	l := new(big.Int).Rem(n, big10)
	l.Abs(l)

	method(sign, n, l)

	// To force renormalization
	return x.SetFrac(n, d)
}
<|endoftext|>


<commit_before>package route

// See http://golang.org/pkg/go/build/

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"os/exec"
	"strconv"
	"strings"

	"rib/util"
)

type Route struct {
	Net       net.IP
	PrefixLen int
	NextHop   net.IP
	//InterfaceAddr net.IP
	Metric int
}

func (r1 Route) Match(r2 Route) bool {
	return r1.PrefixLen == r2.PrefixLen && r1.Net.Equal(r2.Net) && r1.NextHop.Equal(r2.NextHop)
}

func (r1 Route) Equal(r2 Route) bool {
	return r1.Match(r2) && r1.Metric == r2.Metric
}

var (
	routeAdd = make(chan Route)
	routeDel = make(chan Route)
)

func parseRoute(cols []string, route *Route) error {
	//log.Printf("parseRoute: cols=[%v]", cols)

	route.Net = net.ParseIP(cols[0])
	if route.Net == nil {
		return nil
	}

	//log.Printf("parseRoute: dest=%v", dest)

	if util.IpIsIPv4(route.Net) {
		// IPv4

		mask := net.ParseIP(cols[1])
		if mask == nil {
			return nil
		}

		m := mask.To4()
		ipmask := net.IPv4Mask(m[0], m[1], m[2], m[3])

		route.PrefixLen, _ = ipmask.Size()

		route.NextHop = net.ParseIP(cols[2])
		if route.NextHop == nil {
			// may be a non-address string "On-link"
			route.NextHop = net.IPv4zero
		}

		//route.InterfaceAddr = net.ParseIP(cols[3])

		var err error
		route.Metric, err = strconv.Atoi(cols[4])
		if err != nil {
			route.Metric = -1
		}

		//log.Printf("parse: [%v] => [%v]", cols, route)

		return nil
	}

	// IPv6

	return fmt.Errorf("parse IPv6")
}

func addRoute(routeTable *[]Route, route Route) {
	for _, r := range *routeTable {
		if route.Match(r) {
			// found
			if route.Equal(r) {
				// nothing to do
				return
			}
			// update
			return
		}
	}
	*routeTable = append(*routeTable, route)
}

func scanLines(input io.ReadCloser) error {

	scanningIPv4 := false

	scanner := bufio.NewScanner(input)
	for scanner.Scan() {
		line := scanner.Text()
		//log.Printf("scanLines: line=[%v]\n", line)

		if line == "IPv4 Route Table" {
			scanningIPv4 = true
			continue
		}

		if line == "IPv6 Route Table" {
			scanningIPv4 = false
			continue
		}

		if line == "Persistent Routes:" {
			if scanningIPv4 {
				log.Printf("send IPv4 table updates")
			} else {
				log.Printf("send IPv6 table updates")
			}
			continue
		}

		cols := strings.Fields(line)

		n := len(cols)
		//log.Printf("cols=%d [%v]", n, cols)
		if n < 4 {
			continue
		}

		var route Route

		if err := parseRoute(cols, &route); err != nil {
			log.Printf("parse error: %v", err)
			continue
		}

		if route.Net == nil {
			continue
		}

		log.Printf("route: [%v]", route)
	}

	return scanner.Err()
}

func scanRoutes() {
	cmd := exec.Command("netstat", "-nvr", "5")
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Printf("scanRoutes: cmd: %v", err)
		return
	}
	if err := cmd.Start(); err != nil {
		log.Printf("scanRoutes: start: %v", err)
		return
	}

	if err := scanLines(stdout); err != nil {
		log.Printf("scanRoutes: scan lines: %v", err)
	}

	log.Printf("scanLines: unexpected end")

	close(routeAdd)

	if err := cmd.Wait(); err != nil {
		log.Printf("scanRoutes: wait: %v", err)
	}
}

func Routes() {
	log.Printf("compile-time operating system: windows")

	go scanRoutes()

	log.Printf("Routes: scanning route table")

	for {
		select {
		case r, ok := <-routeAdd:
			if !ok {
				break
			}
			log.Printf("route add: %v", r)
		case r := <-routeDel:
			log.Printf("route del: %v", r)
		}
	}

	log.Printf("Routes: quit")
}
<commit_msg>Route maintenance.<commit_after>package route

// See http://golang.org/pkg/go/build/

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"os/exec"
	"strconv"
	"strings"

	"rib/util"
)

type Route struct {
	Net           net.IP
	PrefixLen     int
	NextHop       net.IP
	InterfaceAddr net.IP
	Metric        int
	erased        bool
}

func (r1 Route) Equal(r2 Route) bool {
	return r1.PrefixLen == r2.PrefixLen &&
		r1.Metric == r2.Metric &&
		r1.Net.Equal(r2.Net) &&
		r1.NextHop.Equal(r2.NextHop) &&
		r1.InterfaceAddr.Equal(r2.InterfaceAddr)
}

var (
	routeAdd = make(chan Route)
	routeDel = make(chan Route)
)

func parseRoute(cols []string, route *Route) error {
	//log.Printf("parseRoute: cols=[%v]", cols)

	route.Net = net.ParseIP(cols[0])
	if route.Net == nil {
		return nil
	}

	//log.Printf("parseRoute: dest=%v", dest)

	if util.IpIsIPv4(route.Net) {
		// IPv4

		mask := net.ParseIP(cols[1])
		if mask == nil {
			return nil
		}

		m := mask.To4()
		ipmask := net.IPv4Mask(m[0], m[1], m[2], m[3])

		route.PrefixLen, _ = ipmask.Size()

		route.NextHop = net.ParseIP(cols[2])
		if route.NextHop == nil {
			// may be a non-address string "On-link"
			route.NextHop = net.IPv4zero
		}

		route.InterfaceAddr = net.ParseIP(cols[3])

		var err error
		route.Metric, err = strconv.Atoi(cols[4])
		if err != nil {
			route.Metric = -1
		}

		//log.Printf("parse: [%v] => [%v]", cols, route)

		return nil
	}

	// IPv6

	return fmt.Errorf("parse IPv6")
}

func sendDeleted(routeTable []Route) {
	for _, r := range routeTable {
		if r.erased {
			log.Printf("sendDeleted: [%v]", r)
			routeDel <- r
		}
	}
}

func markToDelete(routeTable []Route) {
	for _, r := range routeTable {
		r.erased = true
	}
}

func refreshRoute(routeTable *[]Route, route Route) {
	for _, r := range *routeTable {
		if route.Equal(r) {
			log.Printf("refreshed: [%v]", r)
			r.erased = false // refresh route
			return
		}
	}
	*routeTable = append(*routeTable, route)
	log.Printf("new: [%v]", route)
}

func scanLines(input io.ReadCloser) error {

	routeTable := []Route{}

	scanningIPv4 := false

	scanner := bufio.NewScanner(input)
	for scanner.Scan() {
		line := scanner.Text()
		//log.Printf("scanLines: line=[%v]\n", line)

		if line == "IPv4 Route Table" {
			scanningIPv4 = true
			markToDelete(routeTable)
			continue
		}

		if line == "IPv6 Route Table" {
			scanningIPv4 = false
			continue
		}

		if line == "Persistent Routes:" {
			if !scanningIPv4 {
				log.Printf("send table updates")
				sendDeleted(routeTable)
			}
			continue
		}

		cols := strings.Fields(line)

		n := len(cols)
		//log.Printf("cols=%d [%v]", n, cols)
		if n < 4 {
			continue
		}

		route := Route{erased: false}

		if err := parseRoute(cols, &route); err != nil {
			log.Printf("parse error: %v", err)
			continue
		}

		if route.Net == nil {
			continue
		}

		log.Printf("route: [%v]", route)

		refreshRoute(&routeTable, route)
	}

	return scanner.Err()
}

func scanRoutes() {
	cmd := exec.Command("netstat", "-nvr", "5")
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Printf("scanRoutes: cmd: %v", err)
		return
	}
	if err := cmd.Start(); err != nil {
		log.Printf("scanRoutes: start: %v", err)
		return
	}

	if err := scanLines(stdout); err != nil {
		log.Printf("scanRoutes: scan lines: %v", err)
	}

	log.Printf("scanLines: unexpected end")

	close(routeAdd)

	if err := cmd.Wait(); err != nil {
		log.Printf("scanRoutes: wait: %v", err)
	}
}

func Routes() {
	log.Printf("compile-time operating system: windows")

	go scanRoutes()

	log.Printf("Routes: scanning route table")

	for {
		select {
		case r, ok := <-routeAdd:
			if !ok {
				break
			}
			log.Printf("route add: %v", r)
		case r := <-routeDel:
			log.Printf("route del: %v", r)
		}
	}

	log.Printf("Routes: quit")
}
<|endoftext|>


<commit_before>package request

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"time"
)

// GetCookies gets []*http.Cookie by domain
func (c *Client) GetCookies(domain string) (cookies []*http.Cookie, err error) {
	debug(domain)

	u, err := url.Parse(domain)
	if err != nil {
		debug("ERR(parse)", err)
		return
	}

	cookies = c.httpClient.Jar.Cookies(u)
	return
}

// SetCookies sets cookies by domain
func (c *Client) SetCookies(domain string, cookies []*http.Cookie) (err error) {
	debug(domain)
	debug(cookies)

	u, err := url.Parse(domain)
	if err != nil {
		debug("ERR(parse)", err)
		return
	}

	c.httpClient.Jar.SetCookies(u, cookies)
	return
}

// GetCookie gets cookie value by domain and cookie name
func (c *Client) GetCookie(domain, name string) (value string, err error) {
	debug(domain, name)

	u, err := url.Parse(domain)
	if err != nil {
		debug("ERR(parse)", err)
		return
	}

	cookies := c.httpClient.Jar.Cookies(u)

	for i := 0; i < len(cookies); i++ {
		if cookies[i].Name == name {
			value = cookies[i].Value

			debug("DONE", value)
			return
		}
	}

	debug("EMPTY")
	return
}

// cookie is a duplicate of http.Cookie but with json parser
type cookie struct {
	Name  string `json:"name"`
	Value string `json:"value"`

	Path       string `json:"path"`
	Domain     string `json:"domain"`
	Expires    time.Time
	RawExpires string `json:"expires"` // for reading cookies only

	MaxAge   int  `json:"expiry"`
	Secure   bool `json:"secure"`
	HttpOnly bool `json:"httponly"`
}

// debug purpose
func (c cookie) String() string {
	return fmt.Sprintf("\nName\t\t:%s\nValue\t\t:%s\nPath\t\t:%s\nDomain\t\t:%s\nExpires\t\t:%v\nRawExpires\t:%s\nMaxAge\t\t:%v\nSecure\t\t:%v\nHttpOnly\t:%v\n-------------\n", c.Name, c.Value, c.Path, c.Domain, c.Expires, c.RawExpires, c.MaxAge, c.Secure, c.HttpOnly)
}

// ImportCookie imports cookie from json
func (c *Client) ImportCookie(domain, jsonStr string) (err error) {
	debug("domain:", domain)

	var cookies []cookie

	err = json.Unmarshal([]byte(jsonStr), &cookies)
	if err != nil {
		debug("ERR(json.Unmarshal)", err)
		return
	}

	// debug(cookies)

	httpCookies := tohttpCookie(cookies)

	err = c.SetCookies(domain, httpCookies)
	if err != nil {
		return
	}
	return
}

func tohttpCookie(cookies []cookie) (httpCookies []*http.Cookie) {
	debug()

	var expires time.Time
	var err error

	for i := 0; i < len(cookies); i++ {
		// .Expires
		expires, err = time.Parse(time.RFC1123, cookies[i].RawExpires)
		if err == nil {
			cookies[i].Expires = expires
		}

		// new httpCookie
		httpCookies = append(httpCookies, &http.Cookie{
			Name:       cookies[i].Name,
			Value:      cookies[i].Value,
			Path:       cookies[i].Path,
			Domain:     cookies[i].Domain,
			Expires:    cookies[i].Expires,
			RawExpires: cookies[i].RawExpires,
			MaxAge:     cookies[i].MaxAge,
			Secure:     cookies[i].Secure,
			HttpOnly:   cookies[i].HttpOnly,
		})
	}

	return
}

func toCookie(httpCookies []*http.Cookie) (cookies []cookie) {
	debug()

	for i := 0; i < len(httpCookies); i++ {
		// new cookie
		cookies = append(cookies, cookie{
			Name:       httpCookies[i].Name,
			Value:      httpCookies[i].Value,
			Path:       httpCookies[i].Path,
			Domain:     httpCookies[i].Domain,
			Expires:    httpCookies[i].Expires,
			RawExpires: httpCookies[i].RawExpires,
			MaxAge:     httpCookies[i].MaxAge,
			Secure:     httpCookies[i].Secure,
			HttpOnly:   httpCookies[i].HttpOnly,
		})
	}

	return
}

// ExportCookie exports client cookies as json
func (c *Client) ExportCookie(domain string) (jsonStr string, err error) {
	debug("domain:", domain)

	httpCookies, err := c.GetCookies(domain)
	if err != nil {
		return
	}
	debug(httpCookies)

	cookies := toCookie(httpCookies)
	// debug(cookies)

	jsonByte, err := json.Marshal(cookies)
	if err != nil {
		debug("ERR(json.Marshal)", err)
		return
	}

	jsonStr = string(jsonByte)
	return
}
<commit_msg>refactor<commit_after>package request

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"time"
)

// GetCookies gets []*http.Cookie by domain
func (c *Client) GetCookies(domain string) (cookies []*http.Cookie, err error) {
	debug(domain)

	u, err := url.Parse(domain)
	if err != nil {
		debug("ERR(parse)", err)
		return
	}

	cookies = c.httpClient.Jar.Cookies(u)
	return
}

// SetCookies sets cookies by domain
func (c *Client) SetCookies(domain string, cookies []*http.Cookie) (err error) {
	debug(domain)
	debug(cookies)

	u, err := url.Parse(domain)
	if err != nil {
		debug("ERR(parse)", err)
		return
	}

	c.httpClient.Jar.SetCookies(u, cookies)
	return
}

// GetCookie gets cookie value by domain and cookie name
func (c *Client) GetCookie(domain, name string) (value string, err error) {
	debug(domain, name)

	u, err := url.Parse(domain)
	if err != nil {
		debug("ERR(parse)", err)
		return
	}

	cookies := c.httpClient.Jar.Cookies(u)

	for i := 0; i < len(cookies); i++ {
		if cookies[i].Name == name {
			value = cookies[i].Value

			debug("DONE", value)
			return
		}
	}

	debug("EMPTY")
	return
}

// cookie is a duplicate of http.Cookie but with json parser
type cookie struct {
	Name  string `json:"name"`
	Value string `json:"value"`

	Path       string `json:"path"`
	Domain     string `json:"domain"`
	Expires    time.Time
	RawExpires string `json:"expires"` // for reading cookies only

	MaxAge   int  `json:"expiry"`
	Secure   bool `json:"secure"`
	HttpOnly bool `json:"httponly"`
}

// debug purpose
func (c cookie) String() string {
	return fmt.Sprintf("\nName\t\t:%s\nValue\t\t:%s\nPath\t\t:%s\nDomain\t\t:%s\nExpires\t\t:%v\nRawExpires\t:%s\nMaxAge\t\t:%v\nSecure\t\t:%v\nHttpOnly\t:%v\n-------------\n", c.Name, c.Value, c.Path, c.Domain, c.Expires, c.RawExpires, c.MaxAge, c.Secure, c.HttpOnly)
}

func tohttpCookie(cookies []cookie) (httpCookies []*http.Cookie) {
	debug()

	var expires time.Time
	var err error

	for i := 0; i < len(cookies); i++ {
		// .Expires
		expires, err = time.Parse(time.RFC1123, cookies[i].RawExpires)
		if err == nil {
			cookies[i].Expires = expires
		}

		// new httpCookie
		httpCookies = append(httpCookies, &http.Cookie{
			Name:       cookies[i].Name,
			Value:      cookies[i].Value,
			Path:       cookies[i].Path,
			Domain:     cookies[i].Domain,
			Expires:    cookies[i].Expires,
			RawExpires: cookies[i].RawExpires,
			MaxAge:     cookies[i].MaxAge,
			Secure:     cookies[i].Secure,
			HttpOnly:   cookies[i].HttpOnly,
		})
	}

	return
}

func toCookie(httpCookies []*http.Cookie) (cookies []cookie) {
	debug()

	for i := 0; i < len(httpCookies); i++ {
		// new cookie
		cookies = append(cookies, cookie{
			Name:       httpCookies[i].Name,
			Value:      httpCookies[i].Value,
			Path:       httpCookies[i].Path,
			Domain:     httpCookies[i].Domain,
			Expires:    httpCookies[i].Expires,
			RawExpires: httpCookies[i].RawExpires,
			MaxAge:     httpCookies[i].MaxAge,
			Secure:     httpCookies[i].Secure,
			HttpOnly:   httpCookies[i].HttpOnly,
		})
	}

	return
}

// ImportCookie imports cookie from json
func (c *Client) ImportCookie(domain, jsonStr string) (err error) {
	debug("domain:", domain)

	var cookies []cookie

	err = json.Unmarshal([]byte(jsonStr), &cookies)
	if err != nil {
		debug("ERR(json.Unmarshal)", err)
		return
	}
	// debug(cookies)

	httpCookies := tohttpCookie(cookies)

	err = c.SetCookies(domain, httpCookies)
	if err != nil {
		return
	}
	return
}

// ExportCookie exports client cookies as json
func (c *Client) ExportCookie(domain string) (jsonStr string, err error) {
	debug("domain:", domain)

	httpCookies, err := c.GetCookies(domain)
	if err != nil {
		return
	}

	cookies := toCookie(httpCookies)
	// debug(cookies)

	jsonByte, err := json.Marshal(cookies)
	if err != nil {
		debug("ERR(json.Marshal)", err)
		return
	}

	jsonStr = string(jsonByte)
	return
}

// TODO: should map Expires?
// TODO: defer res.Body.Close() in tests
<|endoftext|>


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

package main

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

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

// TODO: use x/tools/go/ssa?

// uses interface{} instead of ast.Node for node slices
func (r *reducer) reduceNode(v interface{}) bool {
	if r.didChange {
		return false
	}
	switch x := v.(type) {
	case *ast.ImportSpec:
		return false
	case *[]ast.Stmt:
		r.removeStmt(x)
		r.inlineBlock(x)
	case *ast.IfStmt:
		undo := r.afterDelete(x.Init, x.Cond, x.Else)
		if r.changeStmt(x.Body) {
			r.logChange(x, "if a { b } -> b")
			break
		}
		undo()
		if x.Else != nil {
			undo := r.afterDelete(x.Init, x.Cond, x.Body)
			if r.changeStmt(x.Else) {
				r.logChange(x, "if a { ... } else { c } -> c")
				break
			}
			undo()
		}
	case *ast.BasicLit:
		r.reduceLit(x)
	case *ast.SliceExpr:
		r.reduceSlice(x)
	case *ast.CompositeLit:
		if len(x.Elts) == 0 {
			break
		}
		orig := x.Elts
		undo := r.afterDeleteExprs(x.Elts)
		if x.Elts = nil; r.okChange() {
			t := "T"
			switch x.Type.(type) {
			case *ast.ArrayType:
				t = "[]" + t
			}
			r.logChange(x, "%s{a, b} -> %s{}", t, t)
			break
		}
		undo()
		x.Elts = orig
	case *ast.BinaryExpr:
		undo := r.afterDelete(x.Y)
		if r.changeExpr(x.X) {
			r.logChange(x, "a %v b -> a", x.Op)
			break
		}
		undo()
		undo = r.afterDelete(x.X)
		if r.changeExpr(x.Y) {
			r.logChange(x, "a %v b -> b", x.Op)
			break
		}
		undo()
	case *ast.ParenExpr:
		if r.changeExpr(x.X) {
			r.logChange(x, "(a) -> a")
		}
	case *ast.IndexExpr:
		undo := r.afterDelete(x.Index)
		if r.changeExpr(x.X) {
			r.logChange(x, "a[b] -> a")
			break
		}
		undo()
	case *ast.StarExpr:
		if r.changeExpr(x.X) {
			r.logChange(x, "*a -> a")
		}
	case *ast.UnaryExpr:
		if r.changeExpr(x.X) {
			r.logChange(x, "%va -> a", x.Op)
		}
	case *ast.GoStmt:
		if r.changeStmt(&ast.ExprStmt{X: x.Call}) {
			r.logChange(x, "go a() -> a()")
		}
	case *ast.DeferStmt:
		if r.changeStmt(&ast.ExprStmt{X: x.Call}) {
			r.logChange(x, "defer a() -> a()")
		}
	}
	return true
}

func (r *reducer) removeStmt(list *[]ast.Stmt) {
	orig := *list
	l := make([]ast.Stmt, len(orig)-1)
stmtLoop:
	for i, stmt := range orig {
		// discard those that will likely break compilation
		switch x := stmt.(type) {
		case *ast.DeclStmt:
			// TODO: support more complex decls
			gd := x.Decl.(*ast.GenDecl)
			if len(gd.Specs) != 1 {
				continue
			}
			vs, ok := gd.Specs[0].(*ast.ValueSpec)
			if !ok {
				continue
			}
			for _, name := range vs.Names {
				if name.Name != "_" {
					continue stmtLoop
				}
			}
		case *ast.AssignStmt:
			if x.Tok == token.DEFINE { // :=
				continue
			}
		}
		undo := r.afterDelete(stmt)
		copy(l, orig[:i])
		copy(l[i:], orig[i+1:])
		*list = l
		if r.okChange() {
			r.mergeLinesNode(stmt)
			r.logChange(stmt, "%s removed", nodeType(stmt))
			return
		}
		undo()
	}
	*list = orig
}

func nodeType(n ast.Node) string {
	s := fmt.Sprintf("%T", n)
	if i := strings.IndexByte(s, '.'); i >= 0 {
		s = s[i+1:]
	}
	return s
}

func (r *reducer) mergeLinesNode(node ast.Node) {
	r.mergeLines(node.Pos(), node.End()+1)
}

func (r *reducer) mergeLines(start, end token.Pos) {
	file := r.fset.File(start)
	l1 := file.Line(start)
	l2 := file.Line(end)
	for l1 < l2 {
		file.MergeLine(l1)
		l1++
	}
}

// TODO: name collisions, move to cleanup once 100% sure it will work
func (r *reducer) inlineBlock(list *[]ast.Stmt) {
	orig := *list
	for i, stmt := range orig {
		bl, ok := stmt.(*ast.BlockStmt)
		if !ok {
			continue
		}
		var l []ast.Stmt
		l = append(l, orig[:i]...)
		l = append(l, bl.List...)
		l = append(l, orig[i+1:]...)
		*list = l
		if r.okChange() {
			r.mergeLines(bl.Pos(), bl.List[0].Pos())
			r.mergeLines(bl.List[len(bl.List)-1].End(), bl.End())
			r.logChange(stmt, "block inlined")
			return
		}
	}
	*list = orig
}

func (r *reducer) afterDeleteExprs(exprs []ast.Expr) (undo func()) {
	nodes := make([]ast.Node, len(exprs))
	for i, expr := range exprs {
		nodes[i] = expr
	}
	return r.afterDelete(nodes...)
}

func (r *reducer) afterDelete(nodes ...ast.Node) (undo func()) {
	type redoImp struct {
		name, path string
	}
	var imps []redoImp
	type redoVar struct {
		id   *ast.Ident
		name string
		asgn *ast.AssignStmt
	}
	var vars []redoVar

	for _, obj := range r.unusedAfterDelete(nodes...) {
		switch x := obj.(type) {
		case *types.PkgName:
			name := x.Name()
			if x.Imported().Name() == name {
				// import wasn't named
				name = ""
			}
			path := x.Imported().Path()
			astutil.DeleteNamedImport(r.fset, r.file, name, path)
			imps = append(imps, redoImp{name, path})
		case *types.Var:
			ast.Inspect(r.file, func(node ast.Node) bool {
				switch x := node.(type) {
				case *ast.Ident:
					vars = append(vars, redoVar{x, x.Name, nil})
					if r.info.Defs[x] == obj {
						x.Name = "_"
					}
				case *ast.AssignStmt:
					// TODO: support more complex assigns
					if len(x.Lhs) != 1 {
						return false
					}
					id, ok := x.Lhs[0].(*ast.Ident)
					if !ok {
						return false
					}
					if r.info.Defs[id] != obj {
						return false
					}
					vars = append(vars, redoVar{id, id.Name, x})
					id.Name, x.Tok = "_", token.ASSIGN
					return false
				}
				return true
			})
		}
	}
	return func() {
		for _, imp := range imps {
			astutil.AddNamedImport(r.fset, r.file, imp.name, imp.path)
		}
		for _, rvar := range vars {
			rvar.id.Name = rvar.name
			if rvar.asgn != nil {
				rvar.asgn.Tok = token.DEFINE
			}
		}
	}
}

func (r *reducer) unusedAfterDelete(nodes ...ast.Node) (objs []types.Object) {
	remaining := make(map[types.Object]int)
	for _, node := range nodes {
		if node == nil {
			// for convenience
			continue
		}
		ast.Inspect(node, func(node ast.Node) bool {
			id, ok := node.(*ast.Ident)
			if !ok {
				return true
			}
			obj := r.info.Uses[id]
			if obj == nil {
				return true
			}
			if num, e := remaining[obj]; e {
				if num == 1 {
					objs = append(objs, obj)
				} else {
					remaining[obj]--
				}
			}
			if num, e := r.numUses[obj]; e {
				if num == 1 {
					objs = append(objs, obj)
				} else {
					remaining[obj] = num - 1
				}
			}
			return true
		})
	}
	return
}

func (r *reducer) changeStmt(stmt ast.Stmt) bool {
	orig := *r.stmt
	if *r.stmt = stmt; r.okChange() {
		return true
	}
	*r.stmt = orig
	return false
}

func (r *reducer) changeExpr(expr ast.Expr) bool {
	orig := *r.expr
	if *r.expr = expr; r.okChange() {
		return true
	}
	*r.expr = orig
	return false
}

func (r *reducer) reduceLit(l *ast.BasicLit) {
	orig := l.Value
	changeValue := func(val string) bool {
		if l.Value == val {
			return false
		}
		if l.Value = val; r.okChange() {
			return true
		}
		l.Value = orig
		return false
	}
	switch l.Kind {
	case token.STRING:
		if changeValue(`""`) {
			if len(orig) > 10 {
				orig = fmt.Sprintf(`%s..."`, orig[:7])
			}
			r.logChange(l, `%s -> ""`, orig)
		}
	case token.INT:
		if changeValue(`0`) {
			if len(orig) > 10 {
				orig = fmt.Sprintf(`%s...`, orig[:7])
			}
			r.logChange(l, `%s -> 0`, orig)
		}
	}
}

func (r *reducer) reduceSlice(sl *ast.SliceExpr) {
	if r.changeExpr(sl.X) {
		r.logChange(sl, "a[b:] -> a")
		return
	}
	for i, expr := range [...]*ast.Expr{
		&sl.Max,
		&sl.High,
		&sl.Low,
	} {
		orig := *expr
		if orig == nil {
			continue
		}
		if i == 0 {
			sl.Slice3 = false
		}
		if *expr = nil; r.okChange() {
			switch i {
			case 0:
				r.logChange(orig, "a[b:c:d] -> a[b:c]")
			case 1:
				r.logChange(orig, "a[b:c] -> a[b:]")
			case 2:
				r.logChange(orig, "a[b:c] -> a[:c]")
			}
			return
		}
		if i == 0 {
			sl.Slice3 = true
		}
		*expr = orig
	}
}
<commit_msg>Support removing more complex var/const stmts<commit_after>// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

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

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

// TODO: use x/tools/go/ssa?

// uses interface{} instead of ast.Node for node slices
func (r *reducer) reduceNode(v interface{}) bool {
	if r.didChange {
		return false
	}
	switch x := v.(type) {
	case *ast.ImportSpec:
		return false
	case *[]ast.Stmt:
		r.removeStmt(x)
		r.inlineBlock(x)
	case *ast.IfStmt:
		undo := r.afterDelete(x.Init, x.Cond, x.Else)
		if r.changeStmt(x.Body) {
			r.logChange(x, "if a { b } -> b")
			break
		}
		undo()
		if x.Else != nil {
			undo := r.afterDelete(x.Init, x.Cond, x.Body)
			if r.changeStmt(x.Else) {
				r.logChange(x, "if a { ... } else { c } -> c")
				break
			}
			undo()
		}
	case *ast.BasicLit:
		r.reduceLit(x)
	case *ast.SliceExpr:
		r.reduceSlice(x)
	case *ast.CompositeLit:
		if len(x.Elts) == 0 {
			break
		}
		orig := x.Elts
		undo := r.afterDeleteExprs(x.Elts)
		if x.Elts = nil; r.okChange() {
			t := "T"
			switch x.Type.(type) {
			case *ast.ArrayType:
				t = "[]" + t
			}
			r.logChange(x, "%s{a, b} -> %s{}", t, t)
			break
		}
		undo()
		x.Elts = orig
	case *ast.BinaryExpr:
		undo := r.afterDelete(x.Y)
		if r.changeExpr(x.X) {
			r.logChange(x, "a %v b -> a", x.Op)
			break
		}
		undo()
		undo = r.afterDelete(x.X)
		if r.changeExpr(x.Y) {
			r.logChange(x, "a %v b -> b", x.Op)
			break
		}
		undo()
	case *ast.ParenExpr:
		if r.changeExpr(x.X) {
			r.logChange(x, "(a) -> a")
		}
	case *ast.IndexExpr:
		undo := r.afterDelete(x.Index)
		if r.changeExpr(x.X) {
			r.logChange(x, "a[b] -> a")
			break
		}
		undo()
	case *ast.StarExpr:
		if r.changeExpr(x.X) {
			r.logChange(x, "*a -> a")
		}
	case *ast.UnaryExpr:
		if r.changeExpr(x.X) {
			r.logChange(x, "%va -> a", x.Op)
		}
	case *ast.GoStmt:
		if r.changeStmt(&ast.ExprStmt{X: x.Call}) {
			r.logChange(x, "go a() -> a()")
		}
	case *ast.DeferStmt:
		if r.changeStmt(&ast.ExprStmt{X: x.Call}) {
			r.logChange(x, "defer a() -> a()")
		}
	}
	return true
}

func (r *reducer) removeStmt(list *[]ast.Stmt) {
	orig := *list
	l := make([]ast.Stmt, len(orig)-1)
	for i, stmt := range orig {
		// discard those that will likely break compilation
		switch x := stmt.(type) {
		case *ast.DeclStmt:
			gd := x.Decl.(*ast.GenDecl)
			if !allEmptyNames(gd) { // var _ = ...
				continue
			}
		case *ast.AssignStmt:
			if x.Tok == token.DEFINE { // :=
				continue
			}
		}
		undo := r.afterDelete(stmt)
		copy(l, orig[:i])
		copy(l[i:], orig[i+1:])
		*list = l
		if r.okChange() {
			r.mergeLinesNode(stmt)
			r.logChange(stmt, "%s removed", nodeType(stmt))
			return
		}
		undo()
	}
	*list = orig
}

// allEmptyNames reports whether all delcs in a GenDecl are vars or
// consts with empty (underscore) names.
func allEmptyNames(gd *ast.GenDecl) bool {
	for _, spec := range gd.Specs {
		vs, ok := spec.(*ast.ValueSpec)
		if !ok {
			return false
		}
		for _, name := range vs.Names {
			if name.Name != "_" {
				return false
			}
		}
	}
	return true
}

func nodeType(n ast.Node) string {
	s := fmt.Sprintf("%T", n)
	if i := strings.IndexByte(s, '.'); i >= 0 {
		s = s[i+1:]
	}
	return s
}

func (r *reducer) mergeLinesNode(node ast.Node) {
	r.mergeLines(node.Pos(), node.End()+1)
}

func (r *reducer) mergeLines(start, end token.Pos) {
	file := r.fset.File(start)
	l1 := file.Line(start)
	l2 := file.Line(end)
	for l1 < l2 {
		file.MergeLine(l1)
		l1++
	}
}

// TODO: name collisions, move to cleanup once 100% sure it will work
func (r *reducer) inlineBlock(list *[]ast.Stmt) {
	orig := *list
	for i, stmt := range orig {
		bl, ok := stmt.(*ast.BlockStmt)
		if !ok {
			continue
		}
		var l []ast.Stmt
		l = append(l, orig[:i]...)
		l = append(l, bl.List...)
		l = append(l, orig[i+1:]...)
		*list = l
		if r.okChange() {
			r.mergeLines(bl.Pos(), bl.List[0].Pos())
			r.mergeLines(bl.List[len(bl.List)-1].End(), bl.End())
			r.logChange(stmt, "block inlined")
			return
		}
	}
	*list = orig
}

func (r *reducer) afterDeleteExprs(exprs []ast.Expr) (undo func()) {
	nodes := make([]ast.Node, len(exprs))
	for i, expr := range exprs {
		nodes[i] = expr
	}
	return r.afterDelete(nodes...)
}

func (r *reducer) afterDelete(nodes ...ast.Node) (undo func()) {
	type redoImp struct {
		name, path string
	}
	var imps []redoImp
	type redoVar struct {
		id   *ast.Ident
		name string
		asgn *ast.AssignStmt
	}
	var vars []redoVar

	for _, obj := range r.unusedAfterDelete(nodes...) {
		switch x := obj.(type) {
		case *types.PkgName:
			name := x.Name()
			if x.Imported().Name() == name {
				// import wasn't named
				name = ""
			}
			path := x.Imported().Path()
			astutil.DeleteNamedImport(r.fset, r.file, name, path)
			imps = append(imps, redoImp{name, path})
		case *types.Var:
			ast.Inspect(r.file, func(node ast.Node) bool {
				switch x := node.(type) {
				case *ast.Ident:
					vars = append(vars, redoVar{x, x.Name, nil})
					if r.info.Defs[x] == obj {
						x.Name = "_"
					}
				case *ast.AssignStmt:
					// TODO: support more complex assigns
					if len(x.Lhs) != 1 {
						return false
					}
					id, ok := x.Lhs[0].(*ast.Ident)
					if !ok {
						return false
					}
					if r.info.Defs[id] != obj {
						return false
					}
					vars = append(vars, redoVar{id, id.Name, x})
					id.Name, x.Tok = "_", token.ASSIGN
					return false
				}
				return true
			})
		}
	}
	return func() {
		for _, imp := range imps {
			astutil.AddNamedImport(r.fset, r.file, imp.name, imp.path)
		}
		for _, rvar := range vars {
			rvar.id.Name = rvar.name
			if rvar.asgn != nil {
				rvar.asgn.Tok = token.DEFINE
			}
		}
	}
}

func (r *reducer) unusedAfterDelete(nodes ...ast.Node) (objs []types.Object) {
	remaining := make(map[types.Object]int)
	for _, node := range nodes {
		if node == nil {
			// for convenience
			continue
		}
		ast.Inspect(node, func(node ast.Node) bool {
			id, ok := node.(*ast.Ident)
			if !ok {
				return true
			}
			obj := r.info.Uses[id]
			if obj == nil {
				return true
			}
			if num, e := remaining[obj]; e {
				if num == 1 {
					objs = append(objs, obj)
				} else {
					remaining[obj]--
				}
			}
			if num, e := r.numUses[obj]; e {
				if num == 1 {
					objs = append(objs, obj)
				} else {
					remaining[obj] = num - 1
				}
			}
			return true
		})
	}
	return
}

func (r *reducer) changeStmt(stmt ast.Stmt) bool {
	orig := *r.stmt
	if *r.stmt = stmt; r.okChange() {
		return true
	}
	*r.stmt = orig
	return false
}

func (r *reducer) changeExpr(expr ast.Expr) bool {
	orig := *r.expr
	if *r.expr = expr; r.okChange() {
		return true
	}
	*r.expr = orig
	return false
}

func (r *reducer) reduceLit(l *ast.BasicLit) {
	orig := l.Value
	changeValue := func(val string) bool {
		if l.Value == val {
			return false
		}
		if l.Value = val; r.okChange() {
			return true
		}
		l.Value = orig
		return false
	}
	switch l.Kind {
	case token.STRING:
		if changeValue(`""`) {
			if len(orig) > 10 {
				orig = fmt.Sprintf(`%s..."`, orig[:7])
			}
			r.logChange(l, `%s -> ""`, orig)
		}
	case token.INT:
		if changeValue(`0`) {
			if len(orig) > 10 {
				orig = fmt.Sprintf(`%s...`, orig[:7])
			}
			r.logChange(l, `%s -> 0`, orig)
		}
	}
}

func (r *reducer) reduceSlice(sl *ast.SliceExpr) {
	if r.changeExpr(sl.X) {
		r.logChange(sl, "a[b:] -> a")
		return
	}
	for i, expr := range [...]*ast.Expr{
		&sl.Max,
		&sl.High,
		&sl.Low,
	} {
		orig := *expr
		if orig == nil {
			continue
		}
		if i == 0 {
			sl.Slice3 = false
		}
		if *expr = nil; r.okChange() {
			switch i {
			case 0:
				r.logChange(orig, "a[b:c:d] -> a[b:c]")
			case 1:
				r.logChange(orig, "a[b:c] -> a[b:]")
			case 2:
				r.logChange(orig, "a[b:c] -> a[:c]")
			}
			return
		}
		if i == 0 {
			sl.Slice3 = true
		}
		*expr = orig
	}
}
<|endoftext|>


<commit_before>// Copyright © 2015-2017 Hilko Bengen <bengen@hilluzination.de>
// All rights reserved.
//
// Use of this source code is governed by the license that can be
// found in the LICENSE file.

// Package yara provides bindings to the YARA library.
package yara

/*
#include <yara.h>

int stdScanCallback(int, void*, void*);
*/
import "C"
import (
	"errors"
	"reflect"
	"runtime"
	"time"
	"unsafe"
)

// Rules contains a compiled YARA ruleset.
type Rules struct {
	*rules
}

type rules struct {
	cptr *C.YR_RULES
}

var dummy *[]MatchRule

// A MatchRule represents a rule successfully matched against a block
// of data.
type MatchRule struct {
	Rule      string
	Namespace string
	Tags      []string
	Meta      map[string]interface{}
	Strings   []MatchString
}

// A MatchString represents a string declared and matched in a rule.
type MatchString struct {
	Name   string
	Offset uint64
	Data   []byte
}

func init() {
	_ = C.yr_initialize()
}

//export newMatch
func newMatch(userData unsafe.Pointer, namespace, identifier *C.char) {
	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	*matches = append(*matches, MatchRule{
		Rule:      C.GoString(identifier),
		Namespace: C.GoString(namespace),
		Tags:      []string{},
		Meta:      map[string]interface{}{},
		Strings:   []MatchString{},
	})
}

//export addMetaInt
func addMetaInt(userData unsafe.Pointer, identifier *C.char, value C.int) {
	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	i := len(*matches) - 1
	(*matches)[i].Meta[C.GoString(identifier)] = int32(value)
}

//export addMetaString
func addMetaString(userData unsafe.Pointer, identifier *C.char, value *C.char) {
	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	i := len(*matches) - 1
	(*matches)[i].Meta[C.GoString(identifier)] = C.GoString(value)
}

//export addMetaBool
func addMetaBool(userData unsafe.Pointer, identifier *C.char, value C.int) {
	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	i := len(*matches) - 1
	(*matches)[i].Meta[C.GoString(identifier)] = bool(value != 0)
}

//export addTag
func addTag(userData unsafe.Pointer, tag *C.char) {
	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	i := len(*matches) - 1
	(*matches)[i].Tags = append((*matches)[i].Tags, C.GoString(tag))
}

//export addString
func addString(userData unsafe.Pointer, identifier *C.char, offset C.uint64_t, data unsafe.Pointer, length C.int) {
	ms := MatchString{
		Name:   C.GoString(identifier),
		Offset: uint64(offset),
		Data:   make([]byte, int(length)),
	}

	var tmpSlice []byte
	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&tmpSlice))
	hdr.Data = uintptr(data)
	hdr.Len = int(length)
	copy(ms.Data, tmpSlice)

	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	i := len(*matches) - 1
	(*matches)[i].Strings = append((*matches)[i].Strings, ms)
}

// ScanFlags are used to tweak the behavior of Scan* functions.
type ScanFlags int

const (
	// ScanFlagsFastMode avoids multiple matches of the same string
	// when not necessary.
	ScanFlagsFastMode = C.SCAN_FLAGS_FAST_MODE
	// ScanFlagsProcessMemory causes the scanned data to be
	// interpreted like live, in-prcess memory rather than an on-disk
	// file.
	ScanFlagsProcessMemory = C.SCAN_FLAGS_PROCESS_MEMORY
)

// ScanMem scans an in-memory buffer using the ruleset.
func (r *Rules) ScanMem(buf []byte, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	var ptr *C.uint8_t
	if len(buf) > 0 {
		ptr = (*C.uint8_t)(unsafe.Pointer(&(buf[0])))
	}
	id := callbackData.Put(&matches)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_mem(
		r.cptr,
		ptr,
		C.size_t(len(buf)),
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.stdScanCallback),
		unsafe.Pointer(&id),
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// ScanFile scans a file using the ruleset.
func (r *Rules) ScanFile(filename string, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	id := callbackData.Put(&matches)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_file(
		r.cptr,
		cfilename,
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.stdScanCallback),
		unsafe.Pointer(&id),
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// ScanProc scans a live process using the ruleset.
func (r *Rules) ScanProc(pid int, flags int, timeout time.Duration) (matches []MatchRule, err error) {
	id := callbackData.Put(&matches)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_proc(
		r.cptr,
		C.int(pid),
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.stdScanCallback),
		unsafe.Pointer(&id),
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// Save writes a compiled ruleset to filename.
func (r *Rules) Save(filename string) (err error) {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	err = newError(C.yr_rules_save(r.cptr, cfilename))
	keepAlive(r)
	return
}

// LoadRules retrieves a compiled ruleset from filename.
func LoadRules(filename string) (*Rules, error) {
	r := &Rules{rules: &rules{}}
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	if err := newError(C.yr_rules_load(cfilename,
		&(r.rules.cptr))); err != nil {
		return nil, err
	}
	runtime.SetFinalizer(r.rules, (*rules).finalize)
	return r, nil
}

func (r *rules) finalize() {
	C.yr_rules_destroy(r.cptr)
	runtime.SetFinalizer(r, nil)
}

// Destroy destroys the YARA data structure representing a ruleset.
// Since a Finalizer for the underlying YR_RULES structure is
// automatically set up on creation, it should not be necessary to
// explicitly call this method.
func (r *Rules) Destroy() {
	if r.rules != nil {
		r.rules.finalize()
		r.rules = nil
	}
}

// DefineVariable defines a named variable for use by the compiler.
// Boolean, int64, float64, and string types are supported.
func (r *Rules) DefineVariable(name string, value interface{}) (err error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))
	switch value.(type) {
	case bool:
		var v int
		if value.(bool) {
			v = 1
		}
		err = newError(C.yr_rules_define_boolean_variable(
			r.cptr, cname, C.int(v)))
	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
		value := toint64(value)
		err = newError(C.yr_rules_define_integer_variable(
			r.cptr, cname, C.int64_t(value)))
	case float64:
		err = newError(C.yr_rules_define_float_variable(
			r.cptr, cname, C.double(value.(float64))))
	case string:
		cvalue := C.CString(value.(string))
		defer C.free(unsafe.Pointer(cvalue))
		err = newError(C.yr_rules_define_string_variable(
			r.cptr, cname, cvalue))
	default:
		err = errors.New("wrong value type passed to DefineVariable; bool, int64, float64, string are accepted")
	}
	keepAlive(r)
	return
}

// GetRules returns a slice of rule objects that are part of the
// ruleset
func (r *Rules) GetRules() (rv []Rule) {
	for p := unsafe.Pointer(r.cptr.rules_list_head); (*C.YR_RULE)(p).g_flags&C.RULE_GFLAGS_NULL == 0; p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(*r.cptr.rules_list_head)) {
		rv = append(rv, Rule{(*C.YR_RULE)(p)})
	}
	return
}
<commit_msg>Make flags parameter to ScanProc a ScanFlags (not int)<commit_after>// Copyright © 2015-2017 Hilko Bengen <bengen@hilluzination.de>
// All rights reserved.
//
// Use of this source code is governed by the license that can be
// found in the LICENSE file.

// Package yara provides bindings to the YARA library.
package yara

/*
#include <yara.h>

int stdScanCallback(int, void*, void*);
*/
import "C"
import (
	"errors"
	"reflect"
	"runtime"
	"time"
	"unsafe"
)

// Rules contains a compiled YARA ruleset.
type Rules struct {
	*rules
}

type rules struct {
	cptr *C.YR_RULES
}

var dummy *[]MatchRule

// A MatchRule represents a rule successfully matched against a block
// of data.
type MatchRule struct {
	Rule      string
	Namespace string
	Tags      []string
	Meta      map[string]interface{}
	Strings   []MatchString
}

// A MatchString represents a string declared and matched in a rule.
type MatchString struct {
	Name   string
	Offset uint64
	Data   []byte
}

func init() {
	_ = C.yr_initialize()
}

//export newMatch
func newMatch(userData unsafe.Pointer, namespace, identifier *C.char) {
	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	*matches = append(*matches, MatchRule{
		Rule:      C.GoString(identifier),
		Namespace: C.GoString(namespace),
		Tags:      []string{},
		Meta:      map[string]interface{}{},
		Strings:   []MatchString{},
	})
}

//export addMetaInt
func addMetaInt(userData unsafe.Pointer, identifier *C.char, value C.int) {
	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	i := len(*matches) - 1
	(*matches)[i].Meta[C.GoString(identifier)] = int32(value)
}

//export addMetaString
func addMetaString(userData unsafe.Pointer, identifier *C.char, value *C.char) {
	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	i := len(*matches) - 1
	(*matches)[i].Meta[C.GoString(identifier)] = C.GoString(value)
}

//export addMetaBool
func addMetaBool(userData unsafe.Pointer, identifier *C.char, value C.int) {
	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	i := len(*matches) - 1
	(*matches)[i].Meta[C.GoString(identifier)] = bool(value != 0)
}

//export addTag
func addTag(userData unsafe.Pointer, tag *C.char) {
	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	i := len(*matches) - 1
	(*matches)[i].Tags = append((*matches)[i].Tags, C.GoString(tag))
}

//export addString
func addString(userData unsafe.Pointer, identifier *C.char, offset C.uint64_t, data unsafe.Pointer, length C.int) {
	ms := MatchString{
		Name:   C.GoString(identifier),
		Offset: uint64(offset),
		Data:   make([]byte, int(length)),
	}

	var tmpSlice []byte
	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&tmpSlice))
	hdr.Data = uintptr(data)
	hdr.Len = int(length)
	copy(ms.Data, tmpSlice)

	matches := callbackData.Get(*(*uintptr)(userData)).(*[]MatchRule)
	i := len(*matches) - 1
	(*matches)[i].Strings = append((*matches)[i].Strings, ms)
}

// ScanFlags are used to tweak the behavior of Scan* functions.
type ScanFlags int

const (
	// ScanFlagsFastMode avoids multiple matches of the same string
	// when not necessary.
	ScanFlagsFastMode = C.SCAN_FLAGS_FAST_MODE
	// ScanFlagsProcessMemory causes the scanned data to be
	// interpreted like live, in-prcess memory rather than an on-disk
	// file.
	ScanFlagsProcessMemory = C.SCAN_FLAGS_PROCESS_MEMORY
)

// ScanMem scans an in-memory buffer using the ruleset.
func (r *Rules) ScanMem(buf []byte, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	var ptr *C.uint8_t
	if len(buf) > 0 {
		ptr = (*C.uint8_t)(unsafe.Pointer(&(buf[0])))
	}
	id := callbackData.Put(&matches)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_mem(
		r.cptr,
		ptr,
		C.size_t(len(buf)),
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.stdScanCallback),
		unsafe.Pointer(&id),
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// ScanFile scans a file using the ruleset.
func (r *Rules) ScanFile(filename string, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	id := callbackData.Put(&matches)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_file(
		r.cptr,
		cfilename,
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.stdScanCallback),
		unsafe.Pointer(&id),
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// ScanProc scans a live process using the ruleset.
func (r *Rules) ScanProc(pid int, flags ScanFlags, timeout time.Duration) (matches []MatchRule, err error) {
	id := callbackData.Put(&matches)
	defer callbackData.Delete(id)
	err = newError(C.yr_rules_scan_proc(
		r.cptr,
		C.int(pid),
		C.int(flags),
		C.YR_CALLBACK_FUNC(C.stdScanCallback),
		unsafe.Pointer(&id),
		C.int(timeout/time.Second)))
	keepAlive(r)
	return
}

// Save writes a compiled ruleset to filename.
func (r *Rules) Save(filename string) (err error) {
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	err = newError(C.yr_rules_save(r.cptr, cfilename))
	keepAlive(r)
	return
}

// LoadRules retrieves a compiled ruleset from filename.
func LoadRules(filename string) (*Rules, error) {
	r := &Rules{rules: &rules{}}
	cfilename := C.CString(filename)
	defer C.free(unsafe.Pointer(cfilename))
	if err := newError(C.yr_rules_load(cfilename,
		&(r.rules.cptr))); err != nil {
		return nil, err
	}
	runtime.SetFinalizer(r.rules, (*rules).finalize)
	return r, nil
}

func (r *rules) finalize() {
	C.yr_rules_destroy(r.cptr)
	runtime.SetFinalizer(r, nil)
}

// Destroy destroys the YARA data structure representing a ruleset.
// Since a Finalizer for the underlying YR_RULES structure is
// automatically set up on creation, it should not be necessary to
// explicitly call this method.
func (r *Rules) Destroy() {
	if r.rules != nil {
		r.rules.finalize()
		r.rules = nil
	}
}

// DefineVariable defines a named variable for use by the compiler.
// Boolean, int64, float64, and string types are supported.
func (r *Rules) DefineVariable(name string, value interface{}) (err error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))
	switch value.(type) {
	case bool:
		var v int
		if value.(bool) {
			v = 1
		}
		err = newError(C.yr_rules_define_boolean_variable(
			r.cptr, cname, C.int(v)))
	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
		value := toint64(value)
		err = newError(C.yr_rules_define_integer_variable(
			r.cptr, cname, C.int64_t(value)))
	case float64:
		err = newError(C.yr_rules_define_float_variable(
			r.cptr, cname, C.double(value.(float64))))
	case string:
		cvalue := C.CString(value.(string))
		defer C.free(unsafe.Pointer(cvalue))
		err = newError(C.yr_rules_define_string_variable(
			r.cptr, cname, cvalue))
	default:
		err = errors.New("wrong value type passed to DefineVariable; bool, int64, float64, string are accepted")
	}
	keepAlive(r)
	return
}

// GetRules returns a slice of rule objects that are part of the
// ruleset
func (r *Rules) GetRules() (rv []Rule) {
	for p := unsafe.Pointer(r.cptr.rules_list_head); (*C.YR_RULE)(p).g_flags&C.RULE_GFLAGS_NULL == 0; p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(*r.cptr.rules_list_head)) {
		rv = append(rv, Rule{(*C.YR_RULE)(p)})
	}
	return
}
<|endoftext|>


<commit_before>package cruncy

// VERSION of the application
const VERSION = "0.7.1"
<commit_msg>0.7.2<commit_after>package cruncy

// VERSION of the application
const VERSION = "0.7.2"
<|endoftext|>


<commit_before>package satan

import (
	"fmt"
	"log"
	"runtime/debug"
	"sync"
	"time"
)

// Satan is the master daemon.
type Satan struct {
	SubscribeFunc SubscribeFunc
	Publisher     Publisher

	daemons []Daemon
	queue   chan *task
	latency *statistics

	wgWorkers       sync.WaitGroup
	wgSystem        sync.WaitGroup
	shutdownWorkers chan struct{}
	shutdownSystem  chan struct{}
}

// Actor is a function that could be executed by daemon workers.
type Actor func()

// SubscribeFunc is a function that is used by daemons to subscribe to messages.
type SubscribeFunc func(consumer, topic string) Streamer

// Streamer is the interface that wraps message consumers. Error handling
// should be provided by the implementation. Feel free to panic.
type Streamer interface {
	Messages() <-chan []byte
	Close()
}

// Publisher is the interface that wraps message publishers. Error handling
// should be provided by the implementation. Feel free to panic.
type Publisher interface {
	Publish(msg []byte)
	Close()
}

type task struct {
	daemon    Daemon
	actor     Actor
	createdAt time.Time
	system    bool
	name      string
}

const (
	defaultNumWorkers = 10
)

// Summon creates a new instance of Satan.
func Summon() *Satan {
	return &Satan{
		queue:           make(chan *task),
		latency:         newStatistics(),
		shutdownWorkers: make(chan struct{}),
		shutdownSystem:  make(chan struct{}),
	}
}

// AddDaemon adds a new daemon.
func (s *Satan) AddDaemon(d Daemon) {
	base := d.base()
	base.self = d
	base.subscribeFunc = s.SubscribeFunc
	base.publisher = s.Publisher
	base.queue = s.queue
	base.shutdown = s.shutdownSystem
	base.stats = newStatistics()

	go d.Startup()
	s.daemons = append(s.daemons, d)
}

// StartDaemons starts all registered daemons.
func (s *Satan) StartDaemons() {
	for i := 0; i < defaultNumWorkers; i++ {
		go func(i int) {
			s.runWorker(i)
		}(i)
	}
}

// StopDaemons stops all running daemons.
func (s *Satan) StopDaemons() {
	close(s.shutdownSystem)
	for _, d := range s.daemons {
		d.Shutdown()
	}

	s.wgSystem.Wait()
	close(s.shutdownWorkers)
	s.wgWorkers.Wait()
	close(s.queue)

	for _, d := range s.daemons {
		stats := d.base().stats.snapshot()
		log.Printf("%s daemon performace statistics:\n%s\n", d.base(), stats)
	}
	log.Printf("Task processing latency statistics:\n%s\n", s.latency.snapshot())
}

func (s *Satan) runWorker(i int) {
	s.wgWorkers.Add(1)
	defer s.wgWorkers.Done()
	log.Printf("Starting worker #%d", i+1)
	defer log.Printf("Worker #%d has stopped", i+1)

	for {
		select {
		case t := <-s.queue:
			s.processTask(t)
		case <-s.shutdownWorkers:
			return
		}
	}
}

func (s *Satan) processTask(t *task) {
	dur := time.Now().UnixNano() - t.createdAt.UnixNano()
	s.latency.add(time.Duration(dur))

	if t.system {
		s.processSystemTask(t)
	} else {
		s.processGeneralTask(t)
	}
}

func (s *Satan) processSystemTask(t *task) {
	s.wgSystem.Add(1)
	defer s.wgSystem.Done()
	defer func() {
		if err := recover(); err != nil {
			log.Printf("System task %s recovered from a panic\nError: %v\n", t, err)
			debug.PrintStack()

			t.createdAt = time.Now()
			s.queue <- t // Restarting task
		} else {
			log.Printf("System task %s has stopped\n", t)
		}
	}()

	log.Printf("Starting system task %s\n", t)
	t.actor() // <--- THE ACTION HAPPENS HERE
}

func (s *Satan) processGeneralTask(t *task) {
	defer t.daemon.base().handlePanic()
	defer func(start time.Time) {
		dur := time.Now().UnixNano() - start.UnixNano()
		t.daemon.base().stats.add(time.Duration(dur))
	}(time.Now())

	t.actor() // <--- THE ACTION HAPPENS HERE
}

func (t *task) String() string {
	if t.name == "" {
		return fmt.Sprintf("[unnamed %s process]", t.daemon.base())
	}

	return fmt.Sprintf("%s[%s]", t.daemon.base(), t.name)
}
<commit_msg>Use auto increment value as worker index<commit_after>package satan

import (
	"fmt"
	"log"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"time"
)

// Satan is the master daemon.
type Satan struct {
	SubscribeFunc SubscribeFunc
	Publisher     Publisher

	daemons []Daemon
	queue   chan *task
	latency *statistics

	wgWorkers       sync.WaitGroup
	wgSystem        sync.WaitGroup
	shutdownWorkers chan struct{}
	shutdownSystem  chan struct{}
}

// Actor is a function that could be executed by daemon workers.
type Actor func()

// SubscribeFunc is a function that is used by daemons to subscribe to messages.
type SubscribeFunc func(consumer, topic string) Streamer

// Streamer is the interface that wraps message consumers. Error handling
// should be provided by the implementation. Feel free to panic.
type Streamer interface {
	Messages() <-chan []byte
	Close()
}

// Publisher is the interface that wraps message publishers. Error handling
// should be provided by the implementation. Feel free to panic.
type Publisher interface {
	Publish(msg []byte)
	Close()
}

type task struct {
	daemon    Daemon
	actor     Actor
	createdAt time.Time
	system    bool
	name      string
}

const (
	defaultNumWorkers = 10
)

var (
	workerIndex uint64
)

// Summon creates a new instance of Satan.
func Summon() *Satan {
	return &Satan{
		queue:           make(chan *task),
		latency:         newStatistics(),
		shutdownWorkers: make(chan struct{}),
		shutdownSystem:  make(chan struct{}),
	}
}

// AddDaemon adds a new daemon.
func (s *Satan) AddDaemon(d Daemon) {
	base := d.base()
	base.self = d
	base.subscribeFunc = s.SubscribeFunc
	base.publisher = s.Publisher
	base.queue = s.queue
	base.shutdown = s.shutdownSystem
	base.stats = newStatistics()

	go d.Startup()
	s.daemons = append(s.daemons, d)
}

// StartDaemons starts all registered daemons.
func (s *Satan) StartDaemons() {
	s.addWorkers(defaultNumWorkers)
}

// StopDaemons stops all running daemons.
func (s *Satan) StopDaemons() {
	close(s.shutdownSystem)
	for _, d := range s.daemons {
		d.Shutdown()
	}

	s.wgSystem.Wait()
	close(s.shutdownWorkers)
	s.wgWorkers.Wait()
	close(s.queue)

	for _, d := range s.daemons {
		stats := d.base().stats.snapshot()
		log.Printf("%s daemon performace statistics:\n%s\n", d.base(), stats)
	}
	log.Printf("Task processing latency statistics:\n%s\n", s.latency.snapshot())
}

func (s *Satan) addWorkers(num int) {
	for i := 0; i < num; i++ {
		go s.runWorker()
	}
}

func (s *Satan) stopWorkers(num int) {
	for i := 0; i < num; i++ {
		s.shutdownWorkers <- struct{}{}
	}
}

func (s *Satan) runWorker() {
	s.wgWorkers.Add(1)
	defer s.wgWorkers.Done()

	i := atomic.AddUint64(&workerIndex, 1)
	log.Printf("Starting worker #%d", i+1)
	defer log.Printf("Worker #%d has stopped", i+1)

	for {
		select {
		case t := <-s.queue:
			s.processTask(t)
		case <-s.shutdownWorkers:
			return
		}
	}
}

func (s *Satan) processTask(t *task) {
	dur := time.Now().UnixNano() - t.createdAt.UnixNano()
	s.latency.add(time.Duration(dur))

	if t.system {
		s.processSystemTask(t)
	} else {
		s.processGeneralTask(t)
	}
}

func (s *Satan) processSystemTask(t *task) {
	s.wgSystem.Add(1)
	defer s.wgSystem.Done()
	defer func() {
		if err := recover(); err != nil {
			log.Printf("System task %s recovered from a panic\nError: %v\n", t, err)
			debug.PrintStack()

			t.createdAt = time.Now()
			s.queue <- t // Restarting task
		} else {
			log.Printf("System task %s has stopped\n", t)
		}
	}()

	log.Printf("Starting system task %s\n", t)
	t.actor() // <--- THE ACTION HAPPENS HERE
}

func (s *Satan) processGeneralTask(t *task) {
	defer t.daemon.base().handlePanic()
	defer func(start time.Time) {
		dur := time.Now().UnixNano() - start.UnixNano()
		t.daemon.base().stats.add(time.Duration(dur))
	}(time.Now())

	t.actor() // <--- THE ACTION HAPPENS HERE
}

func (t *task) String() string {
	if t.name == "" {
		return fmt.Sprintf("[unnamed %s process]", t.daemon.base())
	}

	return fmt.Sprintf("%s[%s]", t.daemon.base(), t.name)
}
<|endoftext|>


<commit_before>package trompe

import (
	"bytes"
	"fmt"
	"math"
)

func ModulePervasives() *Module {
	m := NewModule("Pervasives")

	m.SetTycon("list", TcList)
	m.SetTycon("option", TcOption)
	m.SetTycon("result", TcResult)

	m.SetFieldType("=",
		TPoly(Tyvars("a"),
			TApp(
				TcTyFun(Tyvars("a"),
					TApp(TcArrow, TArgs(TVar("a"), TVar("a"), TBool))),
				TArgs(TVar("a")))))
	m.SetPrim("=", Pervasives_eq)

	m.SetFieldType("min",
		TPoly(Tyvars("a"),
			TApp(
				TcTyFun(Tyvars("a"),
					TApp(TcArrow, TArgs(TVar("a"), TVar("a"), TVar("a")))),
				TArgs(TVar("a")))))
	m.SetPrim("min", Pervasives_min)

	m.SetFieldType("max",
		TPoly(Tyvars("a"),
			TApp(
				TcTyFun(Tyvars("a"),
					TApp(TcArrow, TArgs(TVar("a"), TVar("a"), TVar("a")))),
				TArgs(TVar("a")))))
	m.SetPrim("max", Pervasives_max)

	m.SetFieldType("show",
		TPoly(Tyvars("a"),
			TApp(
				TcTyFun(Tyvars("a"),
					TApp(TcArrow, TArgs(TVar("a"), TUnit))),
				TArgs(TVar("a")))))
	m.SetPrim("show", Pervasives_show)

	m.SetFieldType("print_string", TApp(TcArrow, TArgs(TString, TUnit)))
	m.SetPrim("print_string", Pervasives_print_string)

	m.SetFieldType("print_char", TApp(TcArrow, TArgs(TChar, TUnit)))
	m.SetPrim("print_char", Pervasives_print_char)

	m.SetFieldType("print_int", TApp(TcArrow, TArgs(TInt, TUnit)))
	m.SetPrim("print_int", Pervasives_print_int)

	m.SetFieldType("print_float", TApp(TcArrow, TArgs(TFloat, TUnit)))
	m.SetPrim("print_float", Pervasives_print_float)

	m.SetFieldType("print_nl", TApp(TcArrow, TArgs(TUnit, TUnit)))
	m.SetPrim("print_nl", Pervasives_print_nl)

	m.SetFieldType("printf",
		TApp(TcArrow, TArgs(
			TApp(TcFormat, TArgs(TUnit, TUnit)),
			TApp(TcFormatter, TArgs(TUnit, TUnit)))))
	m.SetPrim("printf", Pervasives_printf)

	m.SetFieldType("sprintf",
		TApp(TcArrow, TArgs(
			TApp(TcFormat, TArgs(TUnit, TUnit)),
			TApp(TcFormatter, TArgs(TUnit, TString)))))
	m.SetPrim("sprintf", Pervasives_sprintf)

	m.SetFieldType("raise",
		TPoly(Tyvars("a"),
			TApp(
				TcTyFun(Tyvars("a"),
					TApp(TcArrow, TArgs(TExn, TVar("a")))),
				TArgs(TVar("a")))))

	return m
}

/*
external printf : (unit, unit) format -> (unit, unit) formatter = "printf"
external sprintf : (unit, string) format -> (unit, string) formatter = "sprintf"
external raise : exn -> 'a = "raise"
*/

// val (=) : 'a -> 'a -> bool
func Pervasives_eq(state *State, parent *Context, args []Value) (Value, error) {
	// TODO
	x := args[0]
	y := args[1]
	return x == y, nil
}

// val min : 'a -> 'a -> 'a
func Pervasives_min(state *State, parent *Context, args []Value) (Value, error) {
	// TODO
	x := args[0]
	y := args[1]
	if xv, ok := x.(int64); ok {
		if yv, ok := y.(int64); ok {
			if xv < yv {
				return xv, nil
			} else {
				return yv, nil
			}
		}
	} else if xv, ok := x.(float64); ok {
		if yv, ok := y.(float64); ok {
			return math.Min(xv, yv), nil
		}
	}
	return x, nil
}

// val max : 'a -> 'a -> 'a
func Pervasives_max(state *State, parent *Context, args []Value) (Value, error) {
	// TODO
	x := args[0]
	y := args[1]
	if xv, ok := x.(int64); ok {
		if yv, ok := y.(int64); ok {
			if xv > yv {
				return xv, nil
			} else {
				return yv, nil
			}
		}
	} else if xv, ok := x.(float64); ok {
		if yv, ok := y.(float64); ok {
			return math.Max(xv, yv), nil
		}
	}
	return x, nil
}

func Pervasives_show(state *State, parent *Context, args []Value) (Value, error) {
	switch v := args[0].(type) {
	case int64:
		fmt.Printf("%d", v)
	case float64:
		fmt.Printf("%f", v)
	case string:
		fmt.Printf("%s", v)
	default:
		fmt.Printf("%s", v)
	}
	fmt.Printf("\n")
	return UnitValue, nil
}

func Pervasives_print_char(state *State, parent *Context, args []Value) (Value, error) {
	fmt.Printf("%s", args[0].(string))
	return UnitValue, nil
}

func Pervasives_print_string(state *State, parent *Context, args []Value) (Value, error) {
	fmt.Printf("%s", args[0].(string))
	return UnitValue, nil
}

func Pervasives_print_int(state *State, parent *Context, args []Value) (Value, error) {
	fmt.Printf("%d", args[0].(int64))
	return UnitValue, nil
}

func Pervasives_print_float(state *State, parent *Context, args []Value) (Value, error) {
	fmt.Printf("%f", args[0].(float64))
	return UnitValue, nil
}

func Pervasives_print_nl(state *State, parent *Context, args []Value) (Value, error) {
	fmt.Printf("\n")
	return UnitValue, nil
}

func Pervasives_printf(state *State, parent *Context, args []Value) (Value, error) {
	s, err := Pervasives_sprintf(state, parent, args)
	if err != nil {
		return nil, err
	}
	fmt.Printf("%s", s)
	return UnitValue, nil
}

func Pervasives_sprintf(state *State, parent *Context, args []Value) (Value, error) {
	return FormatString(args)
}

func FormatString(args []Value) (string, error) {
	s := args[0].(string)
	f, err := NewFormat(s)
	if err != nil {
		return "", err
	}

	buf := bytes.NewBufferString("")
	i := 1
	for _, comp := range f.Comps {
		switch comp.Type {
		case FormatTypeNone:
			buf.WriteString(comp.String)
			continue
		case FormatTypeBool:
			if args[i].(bool) {
				buf.WriteString("true")
			} else {
				buf.WriteString("false")
			}
		case FormatTypeInt:
			buf.WriteString(fmt.Sprintf("%d", args[i].(int64)))
		case FormatTypeFloat:
			buf.WriteString(fmt.Sprintf("%f", args[i].(float64)))
		case FormatTypeString:
			buf.WriteString(args[i].(string))
		case FormatTypeChar:
			buf.WriteString(fmt.Sprintf("%c", args[i].(string)))
		default:
			Panicf("unsupported format type %d", comp.Type)
		}
		i++
	}
	return buf.String(), nil
}
<commit_msg>print newline<commit_after>package trompe

import (
	"bytes"
	"fmt"
	"math"
)

func ModulePervasives() *Module {
	m := NewModule("Pervasives")

	m.SetTycon("list", TcList)
	m.SetTycon("option", TcOption)
	m.SetTycon("result", TcResult)

	m.SetFieldType("=",
		TPoly(Tyvars("a"),
			TApp(
				TcTyFun(Tyvars("a"),
					TApp(TcArrow, TArgs(TVar("a"), TVar("a"), TBool))),
				TArgs(TVar("a")))))
	m.SetPrim("=", Pervasives_eq)

	m.SetFieldType("min",
		TPoly(Tyvars("a"),
			TApp(
				TcTyFun(Tyvars("a"),
					TApp(TcArrow, TArgs(TVar("a"), TVar("a"), TVar("a")))),
				TArgs(TVar("a")))))
	m.SetPrim("min", Pervasives_min)

	m.SetFieldType("max",
		TPoly(Tyvars("a"),
			TApp(
				TcTyFun(Tyvars("a"),
					TApp(TcArrow, TArgs(TVar("a"), TVar("a"), TVar("a")))),
				TArgs(TVar("a")))))
	m.SetPrim("max", Pervasives_max)

	m.SetFieldType("show",
		TPoly(Tyvars("a"),
			TApp(
				TcTyFun(Tyvars("a"),
					TApp(TcArrow, TArgs(TVar("a"), TUnit))),
				TArgs(TVar("a")))))
	m.SetPrim("show", Pervasives_show)

	m.SetFieldType("print_string", TApp(TcArrow, TArgs(TString, TUnit)))
	m.SetPrim("print_string", Pervasives_print_string)

	m.SetFieldType("print_char", TApp(TcArrow, TArgs(TChar, TUnit)))
	m.SetPrim("print_char", Pervasives_print_char)

	m.SetFieldType("print_int", TApp(TcArrow, TArgs(TInt, TUnit)))
	m.SetPrim("print_int", Pervasives_print_int)

	m.SetFieldType("print_float", TApp(TcArrow, TArgs(TFloat, TUnit)))
	m.SetPrim("print_float", Pervasives_print_float)

	m.SetFieldType("print_nl", TApp(TcArrow, TArgs(TUnit, TUnit)))
	m.SetPrim("print_nl", Pervasives_print_nl)

	m.SetFieldType("printf",
		TApp(TcArrow, TArgs(
			TApp(TcFormat, TArgs(TUnit, TUnit)),
			TApp(TcFormatter, TArgs(TUnit, TUnit)))))
	m.SetPrim("printf", Pervasives_printf)

	m.SetFieldType("sprintf",
		TApp(TcArrow, TArgs(
			TApp(TcFormat, TArgs(TUnit, TUnit)),
			TApp(TcFormatter, TArgs(TUnit, TString)))))
	m.SetPrim("sprintf", Pervasives_sprintf)

	m.SetFieldType("raise",
		TPoly(Tyvars("a"),
			TApp(
				TcTyFun(Tyvars("a"),
					TApp(TcArrow, TArgs(TExn, TVar("a")))),
				TArgs(TVar("a")))))

	return m
}

/*
external printf : (unit, unit) format -> (unit, unit) formatter = "printf"
external sprintf : (unit, string) format -> (unit, string) formatter = "sprintf"
external raise : exn -> 'a = "raise"
*/

// val (=) : 'a -> 'a -> bool
func Pervasives_eq(state *State, parent *Context, args []Value) (Value, error) {
	// TODO
	x := args[0]
	y := args[1]
	return x == y, nil
}

// val min : 'a -> 'a -> 'a
func Pervasives_min(state *State, parent *Context, args []Value) (Value, error) {
	// TODO
	x := args[0]
	y := args[1]
	if xv, ok := x.(int64); ok {
		if yv, ok := y.(int64); ok {
			if xv < yv {
				return xv, nil
			} else {
				return yv, nil
			}
		}
	} else if xv, ok := x.(float64); ok {
		if yv, ok := y.(float64); ok {
			return math.Min(xv, yv), nil
		}
	}
	return x, nil
}

// val max : 'a -> 'a -> 'a
func Pervasives_max(state *State, parent *Context, args []Value) (Value, error) {
	// TODO
	x := args[0]
	y := args[1]
	if xv, ok := x.(int64); ok {
		if yv, ok := y.(int64); ok {
			if xv > yv {
				return xv, nil
			} else {
				return yv, nil
			}
		}
	} else if xv, ok := x.(float64); ok {
		if yv, ok := y.(float64); ok {
			return math.Max(xv, yv), nil
		}
	}
	return x, nil
}

func Pervasives_show(state *State, parent *Context, args []Value) (Value, error) {
	switch v := args[0].(type) {
	case int64:
		fmt.Printf("%d", v)
	case float64:
		fmt.Printf("%f", v)
	case string:
		fmt.Printf("%s", v)
	default:
		fmt.Printf("%s", v)
	}
	fmt.Printf("\n")
	return UnitValue, nil
}

func Pervasives_print_char(state *State, parent *Context, args []Value) (Value, error) {
	fmt.Printf("%s\n", args[0].(string))
	return UnitValue, nil
}

func Pervasives_print_string(state *State, parent *Context, args []Value) (Value, error) {
	fmt.Printf("%s\n", args[0].(string))
	return UnitValue, nil
}

func Pervasives_print_int(state *State, parent *Context, args []Value) (Value, error) {
	fmt.Printf("%d\n", args[0].(int64))
	return UnitValue, nil
}

func Pervasives_print_float(state *State, parent *Context, args []Value) (Value, error) {
	fmt.Printf("%f\n", args[0].(float64))
	return UnitValue, nil
}

func Pervasives_print_nl(state *State, parent *Context, args []Value) (Value, error) {
	fmt.Printf("\n")
	return UnitValue, nil
}

func Pervasives_printf(state *State, parent *Context, args []Value) (Value, error) {
	s, err := Pervasives_sprintf(state, parent, args)
	if err != nil {
		return nil, err
	}
	fmt.Printf("%s", s)
	return UnitValue, nil
}

func Pervasives_sprintf(state *State, parent *Context, args []Value) (Value, error) {
	return FormatString(args)
}

func FormatString(args []Value) (string, error) {
	s := args[0].(string)
	f, err := NewFormat(s)
	if err != nil {
		return "", err
	}

	buf := bytes.NewBufferString("")
	i := 1
	for _, comp := range f.Comps {
		switch comp.Type {
		case FormatTypeNone:
			buf.WriteString(comp.String)
			continue
		case FormatTypeBool:
			if args[i].(bool) {
				buf.WriteString("true")
			} else {
				buf.WriteString("false")
			}
		case FormatTypeInt:
			buf.WriteString(fmt.Sprintf("%d", args[i].(int64)))
		case FormatTypeFloat:
			buf.WriteString(fmt.Sprintf("%f", args[i].(float64)))
		case FormatTypeString:
			buf.WriteString(args[i].(string))
		case FormatTypeChar:
			buf.WriteString(fmt.Sprintf("%c", args[i].(string)))
		default:
			Panicf("unsupported format type %d", comp.Type)
		}
		i++
	}
	return buf.String(), nil
}
<|endoftext|>


<commit_before>package BloomFilter

import (
	"github.com/6xiao/go/BitMapCache"
)

type BloomFilter struct {
	haskKey []uint64
	capa    uint64
	cache   *BitMapCache.Bit1Cache
}

func NewBloomFilter(keys []uint64, cache *BitMapCache.Bit1Cache) *BloomFilter {
	return &BloomFilter{keys, uint64(cache.Capacity()), cache}
}

func NewDefaultBloomFilter() *BloomFilter {
	var primes = []uint64{61, 163, 233, 347, 401, 521, 661, 809}
	return NewBloomFilter(primes, BitMapCache.NewBit1Cache(1<<32))
}

func (this *BloomFilter) Keys() []uint64 {
	return this.haskKey
}

func (this *BloomFilter) KeySize() int {
	return len(this.haskKey)
}

func (this *BloomFilter) Capacity() int {
	return int(this.capa)
}

func (this *BloomFilter) Set(data []byte) {
	for _, key := range this.haskKey {
		hash := key
		for _, b := range data {
			hash = (hash << 5) + hash + uint64(b)
		}
		this.cache.SetLastBit(int(hash % this.capa))
	}
}

func (this *BloomFilter) Hits(data []byte) int {
	res := uint64(0)
	for _, key := range this.haskKey {
		hash := key
		for _, b := range data {
			hash = (hash << 5) + hash + uint64(b)
		}
		res += this.cache.GetIndex(int(hash % this.capa))
	}
	return int(res)
}

func (this *BloomFilter) IsSet(data []byte) bool {
	return this.Hits(data) == len(this.haskKey)
}
<commit_msg>remove redundancy function<commit_after>package BloomFilter

import (
	"github.com/6xiao/go/BitMapCache"
)

type BloomFilter struct {
	haskKey []uint64
	mod     uint64
	cache   *BitMapCache.Bit1Cache
}

func NewBloomFilter(keys []uint64, cache *BitMapCache.Bit1Cache) *BloomFilter {
	return &BloomFilter{keys, uint64(cache.Capacity()), cache}
}

func NewDefaultBloomFilter() *BloomFilter {
	var primes = []uint64{61, 163, 233, 347, 401, 521, 661, 809}
	return NewBloomFilter(primes, BitMapCache.NewBit1Cache(1<<32))
}

func (this *BloomFilter) Keys() []uint64 {
	return this.haskKey
}

func (this *BloomFilter) Set(data []byte) {
	for _, key := range this.haskKey {
		hash := key
		for _, b := range data {
			hash = (hash << 5) + hash + uint64(b)
		}
		this.cache.SetLastBit(int(hash % this.mod))
	}
}

func (this *BloomFilter) Hits(data []byte) int {
	res := uint64(0)
	for _, key := range this.haskKey {
		hash := key
		for _, b := range data {
			hash = (hash << 5) + hash + uint64(b)
		}
		res += this.cache.GetIndex(int(hash % this.mod))
	}
	return int(res)
}

func (this *BloomFilter) IsSet(data []byte) bool {
	return this.Hits(data) == len(this.haskKey)
}
<|endoftext|>


<commit_before>package reader

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"

	loghttp "github.com/grafana/loki/pkg/loghttp/legacy"
	"github.com/grafana/loki/pkg/logproto"
)

var (
	reconnects = promauto.NewCounter(prometheus.CounterOpts{
		Namespace: "loki_canary",
		Name:      "ws_reconnects",
		Help:      "counts every time the websocket connection has to reconnect",
	})
)

type LokiReader interface {
	Query(start time.Time, end time.Time) ([]time.Time, error)
}

type Reader struct {
	header       http.Header
	tls          bool
	addr         string
	user         string
	pass         string
	lName        string
	lVal         string
	conn         *websocket.Conn
	w            io.Writer
	recv         chan time.Time
	quit         chan struct{}
	shuttingDown bool
	done         chan struct{}
}

func NewReader(writer io.Writer, receivedChan chan time.Time, tls bool,
	address string, user string, pass string, labelName string, labelVal string) *Reader {
	h := http.Header{}
	if user != "" {
		h = http.Header{"Authorization": {"Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+pass))}}
	}

	rd := Reader{
		header:       h,
		tls:          tls,
		addr:         address,
		user:         user,
		pass:         pass,
		lName:        labelName,
		lVal:         labelVal,
		w:            writer,
		recv:         receivedChan,
		quit:         make(chan struct{}),
		done:         make(chan struct{}),
		shuttingDown: false,
	}

	go rd.run()

	go func() {
		<-rd.quit
		if rd.conn != nil {
			_, _ = fmt.Fprintf(rd.w, "shutting down reader\n")
			rd.shuttingDown = true
			_ = rd.conn.Close()
		}
	}()

	return &rd
}

func (r *Reader) Stop() {
	if r.quit != nil {
		close(r.quit)
		<-r.done
		r.quit = nil
	}
}

func (r *Reader) Query(start time.Time, end time.Time) ([]time.Time, error) {
	scheme := "http"
	if r.tls {
		scheme = "https"
	}
	u := url.URL{
		Scheme: scheme,
		Host:   r.addr,
		Path:   "/api/prom/query",
		RawQuery: fmt.Sprintf("start=%d&end=%d", start.UnixNano(), end.UnixNano()) +
			"&query=" + url.QueryEscape(fmt.Sprintf("{stream=\"stdout\",%v=\"%v\"}", r.lName, r.lVal)) +
			"&limit=1000",
	}
	_, _ = fmt.Fprintf(r.w, "Querying loki for missing values with query: %v\n", u.String())

	client := &http.Client{}

	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, err
	}

	req.SetBasicAuth(r.user, r.pass)

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			log.Println("error closing body", err)
		}
	}()

	if resp.StatusCode/100 != 2 {
		buf, _ := ioutil.ReadAll(resp.Body)
		return nil, fmt.Errorf("error response from server: %s (%v)", string(buf), err)
	}
	var decoded logproto.QueryResponse
	err = json.NewDecoder(resp.Body).Decode(&decoded)
	if err != nil {
		return nil, err
	}

	tss := []time.Time{}

	for _, stream := range decoded.Streams {
		for _, entry := range stream.Entries {
			ts, err := parseResponse(&entry)
			if err != nil {
				_, _ = fmt.Fprint(r.w, err)
				continue
			}
			tss = append(tss, *ts)
		}

	}

	return tss, nil
}

func (r *Reader) run() {

	r.closeAndReconnect()

	tailResponse := &loghttp.TailResponse{}

	for {
		err := r.conn.ReadJSON(tailResponse)
		if err != nil {
			if r.shuttingDown {
				close(r.done)
				return
			}
			_, _ = fmt.Fprintf(r.w, "error reading websocket: %s\n", err)
			r.closeAndReconnect()
			continue
		}
		for _, stream := range tailResponse.Streams {
			for _, entry := range stream.Entries {
				ts, err := parseResponse(&entry)
				if err != nil {
					_, _ = fmt.Fprint(r.w, err)
					continue
				}
				r.recv <- *ts
			}
		}
	}
}

func (r *Reader) closeAndReconnect() {
	if r.conn != nil {
		_ = r.conn.Close()
		r.conn = nil
		// By incrementing reconnects here we should only count a failure followed by a successful reconnect.
		// Initial connections and reconnections from failed tries will not be counted.
		reconnects.Inc()
	}
	for r.conn == nil {
		scheme := "ws"
		if r.tls {
			scheme = "wss"
		}
		u := url.URL{
			Scheme:   scheme,
			Host:     r.addr,
			Path:     "/api/prom/tail",
			RawQuery: "query=" + url.QueryEscape(fmt.Sprintf("{stream=\"stdout\",%v=\"%v\"}", r.lName, r.lVal)),
		}

		_, _ = fmt.Fprintf(r.w, "Connecting to loki at %v, querying for label '%v' with value '%v'\n", u.String(), r.lName, r.lVal)

		c, _, err := websocket.DefaultDialer.Dial(u.String(), r.header)
		if err != nil {
			_, _ = fmt.Fprintf(r.w, "failed to connect to %s with err %s\n", u.String(), err)
			<-time.After(5 * time.Second)
			continue
		}
		r.conn = c
	}
}

func parseResponse(entry *logproto.Entry) (*time.Time, error) {
	sp := strings.Split(entry.Line, " ")
	if len(sp) != 2 {
		return nil, errors.Errorf("received invalid entry: %s\n", entry.Line)
	}
	ts, err := strconv.ParseInt(sp[0], 10, 64)
	if err != nil {
		return nil, errors.Errorf("failed to parse timestamp: %s\n", sp[0])
	}
	t := time.Unix(0, ts)
	return &t, nil
}
<commit_msg>pkg/canary: use default HTTP client when reading from Loki<commit_after>package reader

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"

	loghttp "github.com/grafana/loki/pkg/loghttp/legacy"
	"github.com/grafana/loki/pkg/logproto"
)

var (
	reconnects = promauto.NewCounter(prometheus.CounterOpts{
		Namespace: "loki_canary",
		Name:      "ws_reconnects",
		Help:      "counts every time the websocket connection has to reconnect",
	})
)

type LokiReader interface {
	Query(start time.Time, end time.Time) ([]time.Time, error)
}

type Reader struct {
	header       http.Header
	tls          bool
	addr         string
	user         string
	pass         string
	lName        string
	lVal         string
	conn         *websocket.Conn
	w            io.Writer
	recv         chan time.Time
	quit         chan struct{}
	shuttingDown bool
	done         chan struct{}
}

func NewReader(writer io.Writer, receivedChan chan time.Time, tls bool,
	address string, user string, pass string, labelName string, labelVal string) *Reader {
	h := http.Header{}
	if user != "" {
		h = http.Header{"Authorization": {"Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+pass))}}
	}

	rd := Reader{
		header:       h,
		tls:          tls,
		addr:         address,
		user:         user,
		pass:         pass,
		lName:        labelName,
		lVal:         labelVal,
		w:            writer,
		recv:         receivedChan,
		quit:         make(chan struct{}),
		done:         make(chan struct{}),
		shuttingDown: false,
	}

	go rd.run()

	go func() {
		<-rd.quit
		if rd.conn != nil {
			_, _ = fmt.Fprintf(rd.w, "shutting down reader\n")
			rd.shuttingDown = true
			_ = rd.conn.Close()
		}
	}()

	return &rd
}

func (r *Reader) Stop() {
	if r.quit != nil {
		close(r.quit)
		<-r.done
		r.quit = nil
	}
}

func (r *Reader) Query(start time.Time, end time.Time) ([]time.Time, error) {
	scheme := "http"
	if r.tls {
		scheme = "https"
	}
	u := url.URL{
		Scheme: scheme,
		Host:   r.addr,
		Path:   "/api/prom/query",
		RawQuery: fmt.Sprintf("start=%d&end=%d", start.UnixNano(), end.UnixNano()) +
			"&query=" + url.QueryEscape(fmt.Sprintf("{stream=\"stdout\",%v=\"%v\"}", r.lName, r.lVal)) +
			"&limit=1000",
	}
	_, _ = fmt.Fprintf(r.w, "Querying loki for missing values with query: %v\n", u.String())

	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, err
	}

	req.SetBasicAuth(r.user, r.pass)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			log.Println("error closing body", err)
		}
	}()

	if resp.StatusCode/100 != 2 {
		buf, _ := ioutil.ReadAll(resp.Body)
		return nil, fmt.Errorf("error response from server: %s (%v)", string(buf), err)
	}
	var decoded logproto.QueryResponse
	err = json.NewDecoder(resp.Body).Decode(&decoded)
	if err != nil {
		return nil, err
	}

	tss := []time.Time{}

	for _, stream := range decoded.Streams {
		for _, entry := range stream.Entries {
			ts, err := parseResponse(&entry)
			if err != nil {
				_, _ = fmt.Fprint(r.w, err)
				continue
			}
			tss = append(tss, *ts)
		}

	}

	return tss, nil
}

func (r *Reader) run() {

	r.closeAndReconnect()

	tailResponse := &loghttp.TailResponse{}

	for {
		err := r.conn.ReadJSON(tailResponse)
		if err != nil {
			if r.shuttingDown {
				close(r.done)
				return
			}
			_, _ = fmt.Fprintf(r.w, "error reading websocket: %s\n", err)
			r.closeAndReconnect()
			continue
		}
		for _, stream := range tailResponse.Streams {
			for _, entry := range stream.Entries {
				ts, err := parseResponse(&entry)
				if err != nil {
					_, _ = fmt.Fprint(r.w, err)
					continue
				}
				r.recv <- *ts
			}
		}
	}
}

func (r *Reader) closeAndReconnect() {
	if r.conn != nil {
		_ = r.conn.Close()
		r.conn = nil
		// By incrementing reconnects here we should only count a failure followed by a successful reconnect.
		// Initial connections and reconnections from failed tries will not be counted.
		reconnects.Inc()
	}
	for r.conn == nil {
		scheme := "ws"
		if r.tls {
			scheme = "wss"
		}
		u := url.URL{
			Scheme:   scheme,
			Host:     r.addr,
			Path:     "/api/prom/tail",
			RawQuery: "query=" + url.QueryEscape(fmt.Sprintf("{stream=\"stdout\",%v=\"%v\"}", r.lName, r.lVal)),
		}

		_, _ = fmt.Fprintf(r.w, "Connecting to loki at %v, querying for label '%v' with value '%v'\n", u.String(), r.lName, r.lVal)

		c, _, err := websocket.DefaultDialer.Dial(u.String(), r.header)
		if err != nil {
			_, _ = fmt.Fprintf(r.w, "failed to connect to %s with err %s\n", u.String(), err)
			<-time.After(5 * time.Second)
			continue
		}
		r.conn = c
	}
}

func parseResponse(entry *logproto.Entry) (*time.Time, error) {
	sp := strings.Split(entry.Line, " ")
	if len(sp) != 2 {
		return nil, errors.Errorf("received invalid entry: %s\n", entry.Line)
	}
	ts, err := strconv.ParseInt(sp[0], 10, 64)
	if err != nil {
		return nil, errors.Errorf("failed to parse timestamp: %s\n", sp[0])
	}
	t := time.Unix(0, ts)
	return &t, nil
}
<|endoftext|>