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

package ebiten

import (
	"time"

	"github.com/hajimehoshi/ebiten/internal/ui"
)

type runContext struct {
	fps             float64
	newScreenWidth  int
	newScreenHeight int
	newScreenScale  int
	isRunningSlowly bool
}

var currentRunContext = &runContext{}

func (c *runContext) CurrentFPS() float64 {
	if c == nil {
		// TODO: Should panic here?
		return 0
	}
	return c.fps
}

func (c *runContext) IsRunningSlowly() bool {
	if c == nil {
		// TODO: Should panic here?
		return false
	}
	return c.isRunningSlowly
}

func (c *runContext) Run(f func(*Image) error, width, height, scale int, title string) error {
	if err := ui.CurrentUI().Start(width, height, scale, title); err != nil {
		return err
	}
	defer ui.CurrentUI().Terminate()

	glContext.Check()
	graphicsContext, err := newGraphicsContext(width, height, ui.CurrentUI().ActualScreenScale())
	if err != nil {
		return err
	}

	frames := 0
	now := ui.Now()
	beforeForUpdate := now
	beforeForFPS := now
	for {
		// TODO: setSize should be called after swapping buffers?
		if 0 < c.newScreenWidth || 0 < c.newScreenHeight || 0 < c.newScreenScale {
			changed := false
			if 0 < c.newScreenWidth || 0 < c.newScreenHeight {
				c := ui.CurrentUI().SetScreenSize(c.newScreenWidth, c.newScreenHeight)
				changed = changed || c
			}
			if 0 < c.newScreenScale {
				c := ui.CurrentUI().SetScreenScale(c.newScreenScale)
				changed = changed || c
			}
			if changed {
				w, h := c.newScreenWidth, c.newScreenHeight
				if err := graphicsContext.setSize(w, h, ui.CurrentUI().ActualScreenScale()); err != nil {
					return err
				}
			}
		}
		c.newScreenWidth = 0
		c.newScreenHeight = 0
		c.newScreenScale = 0

		if err := ui.CurrentUI().DoEvents(); err != nil {
			return err
		}
		if ui.CurrentUI().IsClosed() {
			return nil
		}
		now := ui.Now()
		// If beforeForUpdate is too old, we assume that screen is not shown.
		c.isRunningSlowly = false
		if int64(5*time.Second/FPS) < now-beforeForUpdate {
			beforeForUpdate = now
		} else {
			t := float64(now-beforeForUpdate) * FPS / float64(time.Second)
			c.isRunningSlowly = t >= 2.5
			for i := 0; i < int(t); i++ {
				if err := ui.CurrentUI().DoEvents(); err != nil {
					return err
				}
				if ui.CurrentUI().IsClosed() {
					return nil
				}
				if err := graphicsContext.update(f); err != nil {
					return err
				}
			}
			beforeForUpdate += int64(t) * int64(time.Second/FPS)
			ui.CurrentUI().SwapBuffers()
		}

		// Calc the current FPS.
		now = ui.Now()
		frames++
		if time.Second <= time.Duration(now-beforeForFPS) {
			c.fps = float64(frames) * float64(time.Second) / float64(now-beforeForFPS)
			beforeForFPS = now
			frames = 0
		}
	}
}

func (c *runContext) SetScreenSize(width, height int) {
	if c == nil {
		panic("ebiten: SetScreenSize must be called during Run")
	}
	if width <= 0 || height <= 0 {
		panic("ebiten: width and height must be positive")
	}
	c.newScreenWidth = width
	c.newScreenHeight = height
}

func (c *runContext) SetScreenScale(scale int) {
	if c == nil {
		panic("ebiten: SetScreenScale must be called during Run")
	}
	if scale <= 0 {
		panic("ebiten: scale must be positive")
	}
	c.newScreenScale = scale
}

// FPS represents how many times game updating happens in a second.
const FPS = 60

// CurrentFPS returns the current number of frames per second of rendering.
//
// This value represents how many times rendering happens in 1/60 second and
// NOT how many times logical game updating (a passed function to Run) happens.
// Note that logical game updating is assured to happen 60 times in a second
// as long as the screen is active.
func CurrentFPS() float64 {
	return currentRunContext.CurrentFPS()
}

// IsRunningSlowly returns true if the game is running too slowly to keep 60 FPS of rendering.
// The game screen is not updated when IsRunningSlowly is true.
// It is recommended to skip heavy processing, especially drawing, when IsRunningSlowly is true.
func IsRunningSlowly() bool {
	return currentRunContext.IsRunningSlowly()
}

// Run runs the game.
// f is a function which is called at every frame.
// The argument (*Image) is the render target that represents the screen.
//
// This function must be called from the main thread.
// Note that ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
//
// The given function f is guaranteed to be called 60 times a second
// even if a rendering frame is skipped.
// f is not called when the screen is not shown.
func Run(f func(*Image) error, width, height, scale int, title string) error {
	currentRunContext = &runContext{}
	defer func() {
		currentRunContext = nil
	}()
	return currentRunContext.Run(f, width, height, scale, title)
}

// SetScreenSize changes the (logical) size of the screen.
// This doesn't affect the current scale of the screen.
func SetScreenSize(width, height int) {
	currentRunContext.SetScreenSize(width, height)
}

// SetScreenSize changes the scale of the screen.
func SetScreenScale(scale int) {
	currentRunContext.SetScreenScale(scale)
}

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

package ebiten

import (
	"time"

	"github.com/hajimehoshi/ebiten/internal/ui"
)

type runContext struct {
	fps             float64
	newScreenWidth  int
	newScreenHeight int
	newScreenScale  int
	isRunningSlowly bool
}

var currentRunContext = &runContext{}

func (c *runContext) CurrentFPS() float64 {
	if c == nil {
		// TODO: Should panic here?
		return 0
	}
	return c.fps
}

func (c *runContext) IsRunningSlowly() bool {
	if c == nil {
		// TODO: Should panic here?
		return false
	}
	return c.isRunningSlowly
}

func (c *runContext) updateScreenSize(g *graphicsContext) error {
	if c.newScreenWidth == 0 && c.newScreenHeight == 0 && c.newScreenScale == 0 {
		return nil
	}
	changed := false
	if 0 < c.newScreenWidth || 0 < c.newScreenHeight {
		c := ui.CurrentUI().SetScreenSize(c.newScreenWidth, c.newScreenHeight)
		changed = changed || c
	}
	if 0 < c.newScreenScale {
		c := ui.CurrentUI().SetScreenScale(c.newScreenScale)
		changed = changed || c
	}
	if changed {
		w, h := c.newScreenWidth, c.newScreenHeight
		if err := g.setSize(w, h, ui.CurrentUI().ActualScreenScale()); err != nil {
			return err
		}
	}
	c.newScreenWidth = 0
	c.newScreenHeight = 0
	c.newScreenScale = 0
	return nil
}

func (c *runContext) Run(f func(*Image) error, width, height, scale int, title string) error {
	if err := ui.CurrentUI().Start(width, height, scale, title); err != nil {
		return err
	}
	defer ui.CurrentUI().Terminate()

	glContext.Check()
	graphicsContext, err := newGraphicsContext(width, height, ui.CurrentUI().ActualScreenScale())
	if err != nil {
		return err
	}

	frames := 0
	now := ui.Now()
	beforeForUpdate := now
	beforeForFPS := now
	for {
		// TODO: setSize should be called after swapping buffers?
		if err := c.updateScreenSize(graphicsContext); err != nil {
			return err
		}
		if err := ui.CurrentUI().DoEvents(); err != nil {
			return err
		}
		if ui.CurrentUI().IsClosed() {
			return nil
		}
		now := ui.Now()
		// If beforeForUpdate is too old, we assume that screen is not shown.
		c.isRunningSlowly = false
		if int64(5*time.Second/FPS) < now-beforeForUpdate {
			beforeForUpdate = now
		} else {
			t := float64(now-beforeForUpdate) * FPS / float64(time.Second)
			c.isRunningSlowly = t >= 2.5
			for i := 0; i < int(t); i++ {
				if err := ui.CurrentUI().DoEvents(); err != nil {
					return err
				}
				if ui.CurrentUI().IsClosed() {
					return nil
				}
				if err := graphicsContext.update(f); err != nil {
					return err
				}
			}
			beforeForUpdate += int64(t) * int64(time.Second/FPS)
			ui.CurrentUI().SwapBuffers()
		}

		// Calc the current FPS.
		now = ui.Now()
		frames++
		if time.Second <= time.Duration(now-beforeForFPS) {
			c.fps = float64(frames) * float64(time.Second) / float64(now-beforeForFPS)
			beforeForFPS = now
			frames = 0
		}
	}
}

func (c *runContext) SetScreenSize(width, height int) {
	if c == nil {
		panic("ebiten: SetScreenSize must be called during Run")
	}
	if width <= 0 || height <= 0 {
		panic("ebiten: width and height must be positive")
	}
	c.newScreenWidth = width
	c.newScreenHeight = height
}

func (c *runContext) SetScreenScale(scale int) {
	if c == nil {
		panic("ebiten: SetScreenScale must be called during Run")
	}
	if scale <= 0 {
		panic("ebiten: scale must be positive")
	}
	c.newScreenScale = scale
}

// FPS represents how many times game updating happens in a second.
const FPS = 60

// CurrentFPS returns the current number of frames per second of rendering.
//
// This value represents how many times rendering happens in 1/60 second and
// NOT how many times logical game updating (a passed function to Run) happens.
// Note that logical game updating is assured to happen 60 times in a second
// as long as the screen is active.
func CurrentFPS() float64 {
	return currentRunContext.CurrentFPS()
}

// IsRunningSlowly returns true if the game is running too slowly to keep 60 FPS of rendering.
// The game screen is not updated when IsRunningSlowly is true.
// It is recommended to skip heavy processing, especially drawing, when IsRunningSlowly is true.
func IsRunningSlowly() bool {
	return currentRunContext.IsRunningSlowly()
}

// Run runs the game.
// f is a function which is called at every frame.
// The argument (*Image) is the render target that represents the screen.
//
// This function must be called from the main thread.
// Note that ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
//
// The given function f is guaranteed to be called 60 times a second
// even if a rendering frame is skipped.
// f is not called when the screen is not shown.
func Run(f func(*Image) error, width, height, scale int, title string) error {
	currentRunContext = &runContext{}
	defer func() {
		currentRunContext = nil
	}()
	return currentRunContext.Run(f, width, height, scale, title)
}

// SetScreenSize changes the (logical) size of the screen.
// This doesn't affect the current scale of the screen.
func SetScreenSize(width, height int) {
	currentRunContext.SetScreenSize(width, height)
}

// SetScreenSize changes the scale of the screen.
func SetScreenScale(scale int) {
	currentRunContext.SetScreenScale(scale)
}

// ScreenScale returns the current screen scale.
func ScreenScale() int {
	return ui.CurrentUI().ScreenScale()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	docker "github.com/fsouza/go-dockerclient"
)

type Run struct {
	Id         string
	VolumePath string
	Container  *docker.Container
	Client     *docker.Client
	Request    *Request
}

type RunResult struct {
	ExitCode int    `json:"exit_code"`
	Output   string `json:"output"`
	Duration string `json:"-"`
}

func NewRun(config *Config, client *docker.Client, req *Request) *Run {
	id, _ := randomHex(20)

	return &Run{
		Id:         id,
		Client:     client,
		VolumePath: fmt.Sprintf("%s/%s", config.SharedPath, id),
		Request:    req,
	}
}

func (run *Run) Setup() error {
	fullPath := fmt.Sprintf("%s/%s", run.VolumePath, run.Request.Filename)

	if err := os.Mkdir(run.VolumePath, 0777); err != nil {
		return err
	}

	if err := ioutil.WriteFile(fullPath, []byte(run.Request.Content), 0666); err != nil {
		return err
	}

	opts := docker.CreateContainerOptions{
		HostConfig: &docker.HostConfig{
			Binds: []string{
				run.VolumePath + ":/code",
				run.VolumePath + ":/tmp",
			},
			ReadonlyRootfs: true,
			Memory:         33554432, // 32 mb
			MemorySwap:     0,
		},
		Config: &docker.Config{
			Hostname:        "bitrun",
			Image:           run.Request.Image,
			AttachStdout:    true,
			AttachStderr:    true,
			AttachStdin:     false,
			OpenStdin:       false,
			Tty:             true,
			NetworkDisabled: true,
			WorkingDir:      "/code",
			Cmd:             []string{"bash", "-c", run.Request.Command},
		},
	}

	container, err := run.Client.CreateContainer(opts)
	if err != nil {
		return nil
	}

	run.Container = container
	return nil
}

func (run *Run) Start() (*RunResult, error) {
	ts := time.Now()

	err := run.Client.StartContainer(run.Container.ID, run.Container.HostConfig)
	if err != nil {
		return nil, err
	}

	result := RunResult{}

	exitCode, err := run.Client.WaitContainer(run.Container.ID)
	if err != nil {
		return nil, err
	}

	result.Duration = time.Now().Sub(ts).String()
	result.ExitCode = exitCode

	buff := bytes.NewBuffer([]byte{})

	err = run.Client.Logs(docker.LogsOptions{
		Container:    run.Container.ID,
		Stdout:       true,
		Stderr:       true,
		OutputStream: buff,
		ErrorStream:  buff,
		RawTerminal:  true,
	})

	if err != nil {
		return nil, err
	}

	result.Output = buff.String()
	return &result, nil
}

func (run *Run) Destroy() error {
	run.Client.RemoveContainer(docker.RemoveContainerOptions{
		ID:            run.Container.ID,
		RemoveVolumes: true,
		Force:         true,
	})

	return os.RemoveAll(run.VolumePath)
}
<commit_msg>Only delete container if it was created<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	docker "github.com/fsouza/go-dockerclient"
)

type Run struct {
	Id         string
	VolumePath string
	Container  *docker.Container
	Client     *docker.Client
	Request    *Request
}

type RunResult struct {
	ExitCode int    `json:"exit_code"`
	Output   string `json:"output"`
	Duration string `json:"-"`
}

func NewRun(config *Config, client *docker.Client, req *Request) *Run {
	id, _ := randomHex(20)

	return &Run{
		Id:         id,
		Client:     client,
		VolumePath: fmt.Sprintf("%s/%s", config.SharedPath, id),
		Request:    req,
	}
}

func (run *Run) Setup() error {
	fullPath := fmt.Sprintf("%s/%s", run.VolumePath, run.Request.Filename)

	if err := os.Mkdir(run.VolumePath, 0777); err != nil {
		return err
	}

	if err := ioutil.WriteFile(fullPath, []byte(run.Request.Content), 0666); err != nil {
		return err
	}

	opts := docker.CreateContainerOptions{
		HostConfig: &docker.HostConfig{
			Binds: []string{
				run.VolumePath + ":/code",
				run.VolumePath + ":/tmp",
			},
			ReadonlyRootfs: true,
			Memory:         33554432, // 32 mb
			MemorySwap:     0,
		},
		Config: &docker.Config{
			Hostname:        "bitrun",
			Image:           run.Request.Image,
			AttachStdout:    true,
			AttachStderr:    true,
			AttachStdin:     false,
			OpenStdin:       false,
			Tty:             true,
			NetworkDisabled: true,
			WorkingDir:      "/code",
			Cmd:             []string{"bash", "-c", run.Request.Command},
		},
	}

	container, err := run.Client.CreateContainer(opts)
	if err != nil {
		return nil
	}

	run.Container = container
	return nil
}

func (run *Run) Start() (*RunResult, error) {
	ts := time.Now()

	err := run.Client.StartContainer(run.Container.ID, run.Container.HostConfig)
	if err != nil {
		return nil, err
	}

	result := RunResult{}

	exitCode, err := run.Client.WaitContainer(run.Container.ID)
	if err != nil {
		return nil, err
	}

	result.Duration = time.Now().Sub(ts).String()
	result.ExitCode = exitCode

	buff := bytes.NewBuffer([]byte{})

	err = run.Client.Logs(docker.LogsOptions{
		Container:    run.Container.ID,
		Stdout:       true,
		Stderr:       true,
		OutputStream: buff,
		ErrorStream:  buff,
		RawTerminal:  true,
	})

	if err != nil {
		return nil, err
	}

	result.Output = buff.String()
	return &result, nil
}

func (run *Run) Destroy() error {
	if run.Container != nil {
		run.Client.RemoveContainer(docker.RemoveContainerOptions{
			ID:            run.Container.ID,
			RemoveVolumes: true,
			Force:         true,
		})
	}

	return os.RemoveAll(run.VolumePath)
}
<|endoftext|>


<commit_before>package openzwave

// #cgo LDFLAGS: -lopenzwave -Lgo/src/github.com/ninjasphere/go-openzwave/openzwave
// #cgo CPPFLAGS: -Iopenzwave/cpp/src/platform -Iopenzwave/cpp/src -Iopenzwave/cpp/src/value_classes
// #include "api.h"
import "C"

import (
	"os"
	"os/signal"
	"time"
	"unsafe"
)

const (
	EXIT_REMOVE_DRIVER_BLOCKED = 127
	EXIT_DEVICE_MONITOR_QUIT   = 126
	EXIT_INTERRUPT             = 125
	EXIT_EVENT_LOOP_BLOCKED    = 124
)

var defaultEventLoop = func(api API) int {
	for {
		select {
		case quitNow := <-api.QuitSignal():
			_ = quitNow
			api.Logger().Debugf("terminating event loop in response to quit.\n")
			return 0
		}
	}
}

//
// Run the supplied event loop
//
// The intent of the complexity is to gracefully handle device insertion and removal events and to
// deal with unexpected (but observed) lockups during the driver removal processing.
//
// The function will only return if a signal is received or if there was an unexpected
// lockup during driver removal processing. The exit code identifies which path
// caused the exit to occur.
//
func (self api) Run() int {

	// lock the options object, now we are done configuring it

	C.endOptions()

	// allocate various channels we need

	signals := make(chan os.Signal, 1)        // used to receive OS signals
	startQuit := make(chan Signal, 2)         // used to indicate we need to quit the event loop
	quitDeviceMonitor := make(chan Signal, 1) // used to indicate to outer loop that it should exit
	exit := make(chan int, 1)                 // used to indicate we are ready to exit

	// indicate that we want to wait for these signals

	signal.Notify(signals, os.Interrupt, os.Kill)
	go func() {
		// Block until a signal is received.

		signal := <-signals
		// once we receive a signal, exit of the process is inevitable
		self.logger.Infof("received %v signal - commencing shutdown\n", signal)

		// try a graceful shutdown of the event loop
		startQuit <- Signal{}
		// and the device monitor loop
		quitDeviceMonitor <- Signal{}

		// but, just in case this doesn't happen, set up an abort timer.
		time.AfterFunc(time.Second*5, func() {
			self.logger.Errorf("timed out while waiting for event loop to quit - aborting now\n")
			exit <- EXIT_EVENT_LOOP_BLOCKED
		})

		// the user is impatient - just die now
		signal = <-signals
		self.logger.Errorf("received 2nd %v signal - aborting now\n", signal)
		exit <- EXIT_INTERRUPT
	}()

	//
	// This goroutine does the following
	//    starts the manager
	//    starts a device monitoroing loop which
	//       waits for the device to be available
	// 	 starts a device removal goroutine which raises a startQuit signal when removal of the device is detected
	//   	 starts the driver
	//	 starts a go routine that that waits until a startQuit is signaled, then initiates the removal of the driver and quit of the event loop
	//	 runs the event loop
	//
	// It does not exit until either an OS Interrupt or Kill signal is received or driver removal or event loop blocks for some reason.
	//
	// If the device is removed, the monitoring go routine will send a signal via the startQuit channel. The intent is to allow the
	// event loop to exit and have the driver removed.
	//
	// The driver removal goroutine waits for the startQuit signal, then attempts to remove the driver. If this completes successfully
	// it propagates a quit signal to the event loop. It also sets up an abort timer which will exit the process if either
	// the driver removal or quit signal propagation blocks for some reason.
	//
	// If an OS signal is received, the main go routine will send signals to the startQuit and to the quitDeviceMonitor channels.
	// It then waits for another signal, for the outer loop to exit or for a 5 second timeout. When one of these occurs, the
	// process will exit.
	//

	go func() {
		cSelf := unsafe.Pointer(&self) // a reference to self

		C.startManager(cSelf) // start the manager
		defer C.stopManager(cSelf)

		cDevice := C.CString(self.device) // allocate a C string for device
		defer C.free(unsafe.Pointer(cDevice))

		// a function which returns true if the device exists
		deviceExists := func() bool {
			if _, err := os.Stat(self.device); err == nil {
				return true
			} else {
				if os.IsNotExist(err) {
					return false
				} else {
					return true
				}
			}
		}

		// waits until the state matches the desired state.
		pollUntilDeviceExistsStateEquals := func(comparand bool) {
			for deviceExists() != comparand {
				time.Sleep(time.Second)
			}
		}

		// there is one iteration of this loop for each device insertion/removal cycle
		done := false
		for !done {
			select {
			case doneSignal := <-quitDeviceMonitor: // we received a signal, allow us to quit
				_ = doneSignal
				done = true
			default:
				// one iteration of a device insert/removal cycle

				// wait until device present
				self.logger.Infof("waiting until %s is available\n", self.device)
				pollUntilDeviceExistsStateEquals(true)

				go func() {

					// wait until device absent
					pollUntilDeviceExistsStateEquals(false)
					self.logger.Infof("device %s removed\n", self.device)

					// start the removal of the driver
					startQuit <- Signal{}
				}()

				C.addDriver(cDevice)

				go func() {
					// wait until something (OS signal handler or device existence monitor) decides we need to terminate
					<-startQuit

					// we start an abort timer, because if the driver blocks, we need to restart the driver process
					// to guarantee successful operation.
					abortTimer := time.AfterFunc(5*time.Second, func() {
						self.logger.Errorf("failed to remove driver - exiting driver process\n")
						exit <- EXIT_REMOVE_DRIVER_BLOCKED
					})

					// try to remove the driver
					if C.removeDriver(cDevice) {
						self.quit <- Signal{}
						abortTimer.Stop() // if we get to here in a timely fashion we can stop the abort timer
					} else {
						// this is unexpected, if we get to here, let the abort timer do its thing
						self.logger.Errorf("removeDriver call failed - waiting for abort\n")
					}
				}()

				rc := self.loop(self) // run the event loop
				if rc != 0 {
					done = true
					exit <- rc
				}
			}
		}

		exit <- EXIT_DEVICE_MONITOR_QUIT
	}()

	return <-exit
}

//export onNotificationWrapper
func onNotificationWrapper(cNotification *C.Notification, context unsafe.Pointer) {
	self := (*api)(context)
	goNotification := (*Notification)(cNotification.goRef)
	if self.callback != nil {
		self.callback(self, goNotification)
	}
	goNotification.free()
}
<commit_msg>fix: better signal names.<commit_after>package openzwave

// #cgo LDFLAGS: -lopenzwave -Lgo/src/github.com/ninjasphere/go-openzwave/openzwave
// #cgo CPPFLAGS: -Iopenzwave/cpp/src/platform -Iopenzwave/cpp/src -Iopenzwave/cpp/src/value_classes
// #include "api.h"
import "C"

import (
	"os"
	"os/signal"
	"time"
	"unsafe"
)

const (
	EXIT_QUIT_FAILED       = 127 // the event loop did not exit
	EXIT_INTERRUPTED       = 126 // something interrupted the current process
	EXIT_INTERRUPTED_AGAIN = 125 // something interrupted the current process (twice)
	EXIT_INTERRUPT_FAILED  = 124 // something interrupted the current process, but something took too long to clean up
)

var defaultEventLoop = func(api API) int {
	for {
		select {
		case quitNow := <-api.QuitSignal():
			_ = quitNow
			api.Logger().Debugf("terminating event loop in response to quit.\n")
			return 0
		}
	}
}

//
// Run the supplied event loop
//
// The intent of the complexity is to gracefully handle device insertion and removal events and to
// deal with unexpected (but observed) lockups during the driver removal processing.
//
// The function will only return if a signal is received or if there was an unexpected
// lockup during driver removal processing. The exit code identifies which path
// caused the exit to occur.
//
func (self api) Run() int {

	// lock the options object, now we are done configuring it

	C.endOptions()

	// allocate various channels we need

	signals := make(chan os.Signal, 1)        // used to receive OS signals
	startQuit := make(chan Signal, 2)         // used to indicate we need to quit the event loop
	quitDeviceMonitor := make(chan Signal, 1) // used to indicate to outer loop that it should exit
	exit := make(chan int, 1)                 // used to indicate we are ready to exit

	// indicate that we want to wait for these signals

	signal.Notify(signals, os.Interrupt, os.Kill)
	go func() {
		// Block until a signal is received.

		signal := <-signals
		// once we receive a signal, exit of the process is inevitable
		self.logger.Infof("received %v signal - commencing shutdown\n", signal)

		// try a graceful shutdown of the event loop
		startQuit <- Signal{}
		// and the device monitor loop
		quitDeviceMonitor <- Signal{}

		// but, just in case this doesn't happen, set up an abort timer.
		time.AfterFunc(time.Second*5, func() {
			self.logger.Errorf("timed out while waiting for event loop to quit - aborting now\n")
			exit <- EXIT_INTERRUPT_FAILED
		})

		// the user is impatient - just die now
		signal = <-signals
		self.logger.Errorf("received 2nd %v signal - aborting now\n", signal)
		exit <- EXIT_INTERRUPTED_AGAIN
	}()

	//
	// This goroutine does the following
	//    starts the manager
	//    starts a device monitoroing loop which
	//       waits for the device to be available
	// 	 starts a device removal goroutine which raises a startQuit signal when removal of the device is detected
	//   	 starts the driver
	//	 starts a go routine that that waits until a startQuit is signaled, then initiates the removal of the driver and quit of the event loop
	//	 runs the event loop
	//
	// It does not exit until either an OS Interrupt or Kill signal is received or driver removal or event loop blocks for some reason.
	//
	// If the device is removed, the monitoring go routine will send a signal via the startQuit channel. The intent is to allow the
	// event loop to exit and have the driver removed.
	//
	// The driver removal goroutine waits for the startQuit signal, then attempts to remove the driver. If this completes successfully
	// it propagates a quit signal to the event loop. It also sets up an abort timer which will exit the process if either
	// the driver removal or quit signal propagation blocks for some reason.
	//
	// If an OS signal is received, the main go routine will send signals to the startQuit and to the quitDeviceMonitor channels.
	// It then waits for another signal, for the outer loop to exit or for a 5 second timeout. When one of these occurs, the
	// process will exit.
	//

	go func() {
		cSelf := unsafe.Pointer(&self) // a reference to self

		C.startManager(cSelf) // start the manager
		defer C.stopManager(cSelf)

		cDevice := C.CString(self.device) // allocate a C string for device
		defer C.free(unsafe.Pointer(cDevice))

		// a function which returns true if the device exists
		deviceExists := func() bool {
			if _, err := os.Stat(self.device); err == nil {
				return true
			} else {
				if os.IsNotExist(err) {
					return false
				} else {
					return true
				}
			}
		}

		// waits until the state matches the desired state.
		pollUntilDeviceExistsStateEquals := func(comparand bool) {
			for deviceExists() != comparand {
				time.Sleep(time.Second)
			}
		}

		// there is one iteration of this loop for each device insertion/removal cycle
		done := false
		for !done {
			select {
			case doneSignal := <-quitDeviceMonitor: // we received a signal, allow us to quit
				_ = doneSignal
				done = true
			default:
				// one iteration of a device insert/removal cycle

				// wait until device present
				self.logger.Infof("waiting until %s is available\n", self.device)
				pollUntilDeviceExistsStateEquals(true)

				go func() {

					// wait until device absent
					pollUntilDeviceExistsStateEquals(false)
					self.logger.Infof("device %s removed\n", self.device)

					// start the removal of the driver
					startQuit <- Signal{}
				}()

				C.addDriver(cDevice)

				go func() {
					// wait until something (OS signal handler or device existence monitor) decides we need to terminate
					<-startQuit

					// we start an abort timer, because if the driver blocks, we need to restart the driver process
					// to guarantee successful operation.
					abortTimer := time.AfterFunc(5*time.Second, func() {
						self.logger.Errorf("failed to remove driver - exiting driver process\n")
						exit <- EXIT_QUIT_FAILED
					})

					// try to remove the driver
					if C.removeDriver(cDevice) {
						self.quit <- Signal{}
						abortTimer.Stop() // if we get to here in a timely fashion we can stop the abort timer
					} else {
						// this is unexpected, if we get to here, let the abort timer do its thing
						self.logger.Errorf("removeDriver call failed - waiting for abort\n")
					}
				}()

				rc := self.loop(self) // run the event loop
				if rc != 0 {
					done = true
					exit <- rc
				}
			}
		}

		exit <- EXIT_INTERRUPTED
	}()

	return <-exit
}

//export onNotificationWrapper
func onNotificationWrapper(cNotification *C.Notification, context unsafe.Pointer) {
	self := (*api)(context)
	goNotification := (*Notification)(cNotification.goRef)
	if self.callback != nil {
		self.callback(self, goNotification)
	}
	goNotification.free()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"os"
)

const (
	programName = "sdb"
)

func main() {
	t := tool{
		stdin:  os.Stdin,
		stdout: os.Stdout,
		stderr: os.Stderr,
	}
	if err := t.run(os.Args); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

type format int

const (
	formatHex format = iota
	formatText
)

const (
	formatHexString  = "hex"
	formatTextString = "text"
)

func (f *format) String() string {
	switch *f {
	case formatHex:
		return formatHexString
	case formatText:
		return formatTextString
	default:
		panic("Invalid format")
	}
}

func (f *format) Set(s string) error {
	switch s {
	case formatHexString:
		*f = formatHex
	case formatTextString:
		*f = formatText
	default:
		return fmt.Errorf("Invalid format '%s'", s)
	}
	return nil
}

type tool struct {
	stdin  *os.File
	stdout *os.File
	stderr *os.File
	flags  *flag.FlagSet
}

func (t *tool) run(args []string) error {
	if len(args) < 2 {
		t.commands("No command specified")
		return nil
	}
	cmd, args := args[1], args[2:]
	switch cmd {
	case "tars":
		return t.tars(args)
	case "entries":
		return t.entries(args)
	case "segments":
		return t.segments(args)
	case "segment":
		return t.segment(args)
	case "index":
		return t.index(args)
	case "graph":
		return t.graph(args)
	case "binaries":
		return t.binaries(args)
	default:
		t.commands(fmt.Sprintf("Invalid command '%s'", cmd))
	}
	return nil
}

func (t *tool) commands(reason string) {
	fmt.Fprintf(t.stderr, "%s. Available commands:\n", reason)
	fmt.Fprintf(t.stderr, "    tars        List active and inactive TAR files\n")
	fmt.Fprintf(t.stderr, "    entries     List the entries of a TAR file\n")
	fmt.Fprintf(t.stderr, "    segments    List the IDs of the segments in a TAR file\n")
	fmt.Fprintf(t.stderr, "    segment     Print the content of a segment\n")
	fmt.Fprintf(t.stderr, "    index       Print the content of a TAR index\n")
	fmt.Fprintf(t.stderr, "    graph       Print the content of a TAR graph\n")
	fmt.Fprintf(t.stderr, "    binaries    Print the content of a TAR binary index\n")
}

func (t *tool) tars(args []string) error {
	t.initFlags("tars", "[-all] [directory]")
	all := t.boolFlag("all", false, "List active and non-active TAR files")
	t.parseFlags(args)
	directory, err := os.Getwd()
	if err != nil {
		return err
	}
	if t.nArgs() > 0 {
		directory = t.arg(0)
	}
	return printTars(directory, *all, t.stdout)
}

func (t *tool) entries(args []string) error {
	t.initFlags("entries", "file")
	t.parseFlags(args)
	if t.nArgs() != 1 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printEntries(t.arg(0), t.stdout)
}

func (t *tool) segments(args []string) error {
	t.initFlags("segments", "file")
	t.parseFlags(args)
	if t.nArgs() != 1 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printSegments(t.arg(0), t.stdout)
}

func (t *tool) segment(args []string) error {
	t.initFlags("segment", "[-format] file")
	f := t.formatFlag("format", "Output format (hex, text)")
	t.parseFlags(args)
	if t.nArgs() != 2 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printSegment(t.arg(0), t.arg(1), *f, t.stdout)
}

func (t *tool) index(args []string) error {
	t.initFlags("index", "[-format] file")
	f := t.formatFlag("format", "Output format (hex, text)")
	t.parseFlags(args)
	if t.nArgs() != 1 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printIndex(t.arg(0), *f, t.stdout)
}

func (t *tool) graph(args []string) error {
	t.initFlags("graph", "[-format] file")
	f := t.formatFlag("format", "Output format (hex, text)")
	t.parseFlags(args)
	if t.nArgs() != 1 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printGraph(t.arg(0), *f, t.stdout)
}

func (t *tool) binaries(args []string) error {
	t.initFlags("binaries", "[-format] file")
	f := t.formatFlag("format", "Output format (hex, text)")
	t.parseFlags(args)
	if t.nArgs() != 1 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printBinaries(t.arg(0), *f, t.stdout)
}

func (t *tool) initFlags(cmd, usage string) {
	t.flags = flag.NewFlagSet(cmd, flag.ContinueOnError)
	t.flags.SetOutput(t.stderr)
	t.flags.Usage = func() {
		fmt.Fprintf(t.stderr, "Usage: %s %s [-help] %s\n", programName, cmd, usage)
		t.flags.PrintDefaults()
	}
}

func (t *tool) boolFlag(name string, value bool, usage string) *bool {
	return t.flags.Bool(name, value, usage)
}

func (t *tool) formatFlag(name, usage string) *format {
	f := new(format)
	t.flags.Var(f, name, usage)
	return f
}

func (t *tool) parseFlags(args []string) {
	if err := t.flags.Parse(args); err != nil {
		os.Exit(1)
	}
}

func (t *tool) nArgs() int {
	return t.flags.NArg()
}

func (t *tool) arg(i int) string {
	return t.flags.Arg(i)
}

func printTars(d string, all bool, w io.Writer) error {
	return forEachTarFile(d, all, func(n string) {
		fmt.Fprintln(w, n)
	})
}

func printBinaries(p string, f format, w io.Writer) error {
	return onMatchingEntry(p, isBinary, doPrintBinaries(f, w))
}

func printGraph(p string, f format, w io.Writer) error {
	return onMatchingEntry(p, isGraph, doPrintGraph(f, w))
}

func printIndex(p string, f format, w io.Writer) error {
	return onMatchingEntry(p, isIndex, doPrintIndex(f, w))
}

func printSegments(p string, w io.Writer) error {
	return forEachMatchingEntry(p, isAnySegment, doPrintSegmentNameTo(w))
}

func printSegment(p string, id string, f format, w io.Writer) error {
	return onMatchingEntry(p, isSegment(id), doPrintSegment(f, w))
}

func printEntries(p string, w io.Writer) error {
	return forEachEntry(p, doPrintNameTo(w))
}
<commit_msg>Fix the description of the 'segment' command<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"os"
)

const (
	programName = "sdb"
)

func main() {
	t := tool{
		stdin:  os.Stdin,
		stdout: os.Stdout,
		stderr: os.Stderr,
	}
	if err := t.run(os.Args); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

type format int

const (
	formatHex format = iota
	formatText
)

const (
	formatHexString  = "hex"
	formatTextString = "text"
)

func (f *format) String() string {
	switch *f {
	case formatHex:
		return formatHexString
	case formatText:
		return formatTextString
	default:
		panic("Invalid format")
	}
}

func (f *format) Set(s string) error {
	switch s {
	case formatHexString:
		*f = formatHex
	case formatTextString:
		*f = formatText
	default:
		return fmt.Errorf("Invalid format '%s'", s)
	}
	return nil
}

type tool struct {
	stdin  *os.File
	stdout *os.File
	stderr *os.File
	flags  *flag.FlagSet
}

func (t *tool) run(args []string) error {
	if len(args) < 2 {
		t.commands("No command specified")
		return nil
	}
	cmd, args := args[1], args[2:]
	switch cmd {
	case "tars":
		return t.tars(args)
	case "entries":
		return t.entries(args)
	case "segments":
		return t.segments(args)
	case "segment":
		return t.segment(args)
	case "index":
		return t.index(args)
	case "graph":
		return t.graph(args)
	case "binaries":
		return t.binaries(args)
	default:
		t.commands(fmt.Sprintf("Invalid command '%s'", cmd))
	}
	return nil
}

func (t *tool) commands(reason string) {
	fmt.Fprintf(t.stderr, "%s. Available commands:\n", reason)
	fmt.Fprintf(t.stderr, "    tars        List active and inactive TAR files\n")
	fmt.Fprintf(t.stderr, "    entries     List the entries of a TAR file\n")
	fmt.Fprintf(t.stderr, "    segments    List the IDs of the segments in a TAR file\n")
	fmt.Fprintf(t.stderr, "    segment     Print the content of a segment\n")
	fmt.Fprintf(t.stderr, "    index       Print the content of a TAR index\n")
	fmt.Fprintf(t.stderr, "    graph       Print the content of a TAR graph\n")
	fmt.Fprintf(t.stderr, "    binaries    Print the content of a TAR binary index\n")
}

func (t *tool) tars(args []string) error {
	t.initFlags("tars", "[-all] [directory]")
	all := t.boolFlag("all", false, "List active and non-active TAR files")
	t.parseFlags(args)
	directory, err := os.Getwd()
	if err != nil {
		return err
	}
	if t.nArgs() > 0 {
		directory = t.arg(0)
	}
	return printTars(directory, *all, t.stdout)
}

func (t *tool) entries(args []string) error {
	t.initFlags("entries", "file")
	t.parseFlags(args)
	if t.nArgs() != 1 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printEntries(t.arg(0), t.stdout)
}

func (t *tool) segments(args []string) error {
	t.initFlags("segments", "file")
	t.parseFlags(args)
	if t.nArgs() != 1 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printSegments(t.arg(0), t.stdout)
}

func (t *tool) segment(args []string) error {
	t.initFlags("segment", "[-format] file segment")
	f := t.formatFlag("format", "Output format (hex, text)")
	t.parseFlags(args)
	if t.nArgs() != 2 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printSegment(t.arg(0), t.arg(1), *f, t.stdout)
}

func (t *tool) index(args []string) error {
	t.initFlags("index", "[-format] file")
	f := t.formatFlag("format", "Output format (hex, text)")
	t.parseFlags(args)
	if t.nArgs() != 1 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printIndex(t.arg(0), *f, t.stdout)
}

func (t *tool) graph(args []string) error {
	t.initFlags("graph", "[-format] file")
	f := t.formatFlag("format", "Output format (hex, text)")
	t.parseFlags(args)
	if t.nArgs() != 1 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printGraph(t.arg(0), *f, t.stdout)
}

func (t *tool) binaries(args []string) error {
	t.initFlags("binaries", "[-format] file")
	f := t.formatFlag("format", "Output format (hex, text)")
	t.parseFlags(args)
	if t.nArgs() != 1 {
		fmt.Fprintln(t.stderr, "Invalid number of arguments")
		return nil
	}
	return printBinaries(t.arg(0), *f, t.stdout)
}

func (t *tool) initFlags(cmd, usage string) {
	t.flags = flag.NewFlagSet(cmd, flag.ContinueOnError)
	t.flags.SetOutput(t.stderr)
	t.flags.Usage = func() {
		fmt.Fprintf(t.stderr, "Usage: %s %s [-help] %s\n", programName, cmd, usage)
		t.flags.PrintDefaults()
	}
}

func (t *tool) boolFlag(name string, value bool, usage string) *bool {
	return t.flags.Bool(name, value, usage)
}

func (t *tool) formatFlag(name, usage string) *format {
	f := new(format)
	t.flags.Var(f, name, usage)
	return f
}

func (t *tool) parseFlags(args []string) {
	if err := t.flags.Parse(args); err != nil {
		os.Exit(1)
	}
}

func (t *tool) nArgs() int {
	return t.flags.NArg()
}

func (t *tool) arg(i int) string {
	return t.flags.Arg(i)
}

func printTars(d string, all bool, w io.Writer) error {
	return forEachTarFile(d, all, func(n string) {
		fmt.Fprintln(w, n)
	})
}

func printBinaries(p string, f format, w io.Writer) error {
	return onMatchingEntry(p, isBinary, doPrintBinaries(f, w))
}

func printGraph(p string, f format, w io.Writer) error {
	return onMatchingEntry(p, isGraph, doPrintGraph(f, w))
}

func printIndex(p string, f format, w io.Writer) error {
	return onMatchingEntry(p, isIndex, doPrintIndex(f, w))
}

func printSegments(p string, w io.Writer) error {
	return forEachMatchingEntry(p, isAnySegment, doPrintSegmentNameTo(w))
}

func printSegment(p string, id string, f format, w io.Writer) error {
	return onMatchingEntry(p, isSegment(id), doPrintSegment(f, w))
}

func printEntries(p string, w io.Writer) error {
	return forEachEntry(p, doPrintNameTo(w))
}
<|endoftext|>


<commit_before>package suffix

import (
	"bufio"
	"fmt"
	"io"
	"sort"
	"strings"
)

// Set defines set of suffixes
type Set struct {
	names     map[string]struct{}
	maxLabels int
}

// Len returns number of entries in Set
func (set *Set) Len() int {
	return len(set.names)
}

// Add suffix to the set
func (set *Set) Add(suffix string) {
	if set.names == nil {
		set.names = make(map[string]struct{})
	}

	suffix = strings.Trim(suffix, ".")
	set.names[suffix] = struct{}{}
	// Find max number of lables
	// TODO: handle double dot (*..*)
	labels := strings.Count(suffix, ".") + 1
	if labels > set.maxLabels {
		set.maxLabels = labels
	}
}

// Has returns true iff suffix was added to set.
func (set *Set) Has(suffix string) bool {
	_, ok := set.names[suffix]
	return ok
}

// Match returns the longest matching suffix.
// If nothing matches empty string is returned.
func (set *Set) Match(name string) string {
	if len(set.names) == 0 {
		return ""
	}

	// Shrink to longest suffix
	dot := len(name)
	for n := set.maxLabels; n > 0 && dot > 0; n-- {
		dot = strings.LastIndexByte(name[:dot], '.')
	}
	s := name[dot+1:]

	// Find matching suffix
	for len(s) > 0 {
		if _, ok := set.names[s]; ok {
			return s
		}
		dot := strings.IndexByte(s, '.')
		if dot < 0 {
			return ""
		}
		s = s[dot+1:]
	}

	return ""
}

// Matches checks if passed name matches any suffix.
// Equivalent to Match(name) != ""
func (set *Set) Matches(name string) bool {
	return set.Match(name) != ""
}

// Split splits name into prefix and suffix where suffix is longest matching
// suffix from the set. If no suffix matches empty strings are returned.
func (set *Set) Split(name string) (pre string, suf string) {
	suf = set.Match(name)
	if suf != "" && len(name) > len(suf) {
		pre = name[:len(name)-len(suf)-1]
	}
	return
}

// ReadFrom reads set from the stream. Each non-empty line of stream is
// considered a suffix, except from lines beginning with '#' or '//', which
// are treated as comments and skipped.
func (set *Set) ReadFrom(r io.Reader) (n int64, err error) {
	cnt := &counter{}
	scanner := bufio.NewScanner(io.TeeReader(r, cnt))
	for scanner.Scan() {
		line := strings.Trim(scanner.Text(), " \t")
		if strings.HasPrefix(line, "#") || strings.HasPrefix(line, "//") {
			continue
		}
		set.Add(line)
	}

	return cnt.N, scanner.Err()
}

// WriteTo serialises set into the writer.
// Data is serialised in plain text, each suffix in a separate line.
// Suffixes are written in lexicographical order.
func (set *Set) WriteTo(w io.Writer) (n int64, err error) {
	suffs := make([]string, 0, len(set.names))
	for s := range set.names {
		suffs = append(suffs, s)
	}
	sort.Strings(suffs)
	c := &counter{W: w}
	for n := range suffs {
		_, err = fmt.Fprintln(c, suffs[n])
		if err != nil {
			break
		}
	}
	return c.N, err
}

type counter struct {
	W io.Writer
	N int64
}

func (c *counter) Write(p []byte) (n int, err error) {
	if c.W != nil {
		n, err = c.W.Write(p)
	} else {
		n = len(p)
	}
	c.N += int64(n)
	return
}

// PlusOne returns matching suffix plus one label from the name.
// For example if set containt 'com' and name is 'www.blog.com',
// this function would return 'blog.com'. Returned string is empty if there
// is no matching suffix in the set or an additional label is missing.
func PlusOne(set *Set, name string) string {
	pre, suf := set.Split(name)
	if suf == "" || pre == "" {
		return ""
	}
	return pre[strings.LastIndexByte(pre, '.')+1:] + "." + suf
}
<commit_msg>Fix panic on passing empty names<commit_after>package suffix

import (
	"bufio"
	"fmt"
	"io"
	"sort"
	"strings"
)

// Set defines set of suffixes
type Set struct {
	names     map[string]struct{}
	maxLabels int
}

// Len returns number of entries in Set
func (set *Set) Len() int {
	return len(set.names)
}

// Add suffix to the set
func (set *Set) Add(suffix string) {
	if set.names == nil {
		set.names = make(map[string]struct{})
	}

	suffix = strings.Trim(suffix, ".")
	set.names[suffix] = struct{}{}
	// Find max number of lables
	// TODO: handle double dot (*..*)
	labels := strings.Count(suffix, ".") + 1
	if labels > set.maxLabels {
		set.maxLabels = labels
	}
}

// Has returns true iff suffix was added to set.
func (set *Set) Has(suffix string) bool {
	_, ok := set.names[suffix]
	return ok
}

// Match returns the longest matching suffix.
// If nothing matches empty string is returned.
func (set *Set) Match(name string) string {
	if len(set.names) == 0 || len(name) == 0 {
		return ""
	}

	// Shrink to longest suffix
	dot := len(name)
	for n := set.maxLabels; n > 0 && dot > 0; n-- {
		dot = strings.LastIndexByte(name[:dot], '.')
	}
	s := name[dot+1:]

	// Find matching suffix
	for len(s) > 0 {
		if _, ok := set.names[s]; ok {
			return s
		}
		dot := strings.IndexByte(s, '.')
		if dot < 0 {
			return ""
		}
		s = s[dot+1:]
	}

	return ""
}

// Matches checks if passed name matches any suffix.
// Equivalent to Match(name) != ""
func (set *Set) Matches(name string) bool {
	return set.Match(name) != ""
}

// Split splits name into prefix and suffix where suffix is longest matching
// suffix from the set. If no suffix matches empty strings are returned.
func (set *Set) Split(name string) (pre string, suf string) {
	suf = set.Match(name)
	if suf != "" && len(name) > len(suf) {
		pre = name[:len(name)-len(suf)-1]
	}
	return
}

// ReadFrom reads set from the stream. Each non-empty line of stream is
// considered a suffix, except from lines beginning with '#' or '//', which
// are treated as comments and skipped.
func (set *Set) ReadFrom(r io.Reader) (n int64, err error) {
	cnt := &counter{}
	scanner := bufio.NewScanner(io.TeeReader(r, cnt))
	for scanner.Scan() {
		line := strings.Trim(scanner.Text(), " \t")
		if strings.HasPrefix(line, "#") || strings.HasPrefix(line, "//") {
			continue
		}
		set.Add(line)
	}

	return cnt.N, scanner.Err()
}

// WriteTo serialises set into the writer.
// Data is serialised in plain text, each suffix in a separate line.
// Suffixes are written in lexicographical order.
func (set *Set) WriteTo(w io.Writer) (n int64, err error) {
	suffs := make([]string, 0, len(set.names))
	for s := range set.names {
		suffs = append(suffs, s)
	}
	sort.Strings(suffs)
	c := &counter{W: w}
	for n := range suffs {
		_, err = fmt.Fprintln(c, suffs[n])
		if err != nil {
			break
		}
	}
	return c.N, err
}

type counter struct {
	W io.Writer
	N int64
}

func (c *counter) Write(p []byte) (n int, err error) {
	if c.W != nil {
		n, err = c.W.Write(p)
	} else {
		n = len(p)
	}
	c.N += int64(n)
	return
}

// PlusOne returns matching suffix plus one label from the name.
// For example if set containt 'com' and name is 'www.blog.com',
// this function would return 'blog.com'. Returned string is empty if there
// is no matching suffix in the set or an additional label is missing.
func PlusOne(set *Set, name string) string {
	pre, suf := set.Split(name)
	if suf == "" || pre == "" {
		return ""
	}
	return pre[strings.LastIndexByte(pre, '.')+1:] + "." + suf
}
<|endoftext|>


<commit_before>package k8sclient

import (
	"k8s.io/client-go/pkg/api/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/validation"
	"github.com/pkg/errors"
	"log"
	"k8s.io/client-go/pkg/apis/rbac/v1beta1"
	"time"
	"os"
)

type ServiceAccountInfo struct {
	Name 		string
	Namespace	string
	Token		string
}

// CreateServiceAccountAndRoleBinding creates a ServiceAccount and a matching secret to use it.
func CreateServiceAccountAndRoleBinding(fullProjectPath string) (ServiceAccountInfo, string, error) {
	name := getServiceAccountName()
	namespace := GetActualNameSpaceNameByGitlabName(fullProjectPath)

	client := getK8sClient()

	sa := &v1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}}

	serviceAccount, err := client.ServiceAccounts(namespace).Create(sa)

	if k8serrors.IsAlreadyExists(err) {
		// ServiceAccount already exists, so retrieve and use it
		serviceAccount, err = client.ServiceAccounts(namespace).Get(name, metav1.GetOptions{})
		if err != nil {
			return ServiceAccountInfo{},"", err
		}
	} else if err != nil {
		return ServiceAccountInfo{}, "", err
	}

	// try to retrieve ServiceAccount once as the newly created one won't have the secret set
	serviceAccount, err = client.ServiceAccounts(namespace).Get(name, metav1.GetOptions{})
	// The secret in the ServiceAccount is not created and linked immediately, so we have to wait for it
	// to not wait indefinitely we use a timeout
	timeout := time.After(30 * time.Second)
	tick := time.Tick(500 * time.Millisecond)
	// Keep trying until we're timed out or got a result or got an error
	for k8serrors.IsNotFound(err) || len(serviceAccount.Secrets) < 1 {
		select {
		// Got a timeout! fail with a timeout error
		case <-timeout:
			return ServiceAccountInfo{}, "", errors.New("ServiceAccount was created, but Secrets were empty!")

		case <-tick:
			serviceAccount, err = client.ServiceAccounts(namespace).Get(name, metav1.GetOptions{})
			if err != nil && !k8serrors.IsNotFound(err) {
				return ServiceAccountInfo{},"", err
			}
		}
	}

	secretName := serviceAccount.Secrets[0].Name
	saSecret, err := client.Secrets(namespace).Get(secretName, metav1.GetOptions{})
	token := saSecret.Data["token"]
	if len(token) <= 0 {
		return ServiceAccountInfo{}, "", errors.New("The token field in the Secret's data was empty!")
	}

	tokenAsString := string(token[:])

	sAI := ServiceAccountInfo{Namespace: namespace, Name: name, Token: tokenAsString}
	rbName := createServiceAccountRoleBinding(name, fullProjectPath)
	return sAI, rbName, nil
}

func createServiceAccountRoleBinding(saName, path string) string {
	ns := GetActualNameSpaceNameByGitlabName(path)
	if ns == "" {
		CreateNamespace(path)
		ns = GetActualNameSpaceNameByGitlabName(path)
	}
	// ServiceAccounts are always bound to Master roles
	rolename := GetProjectRoleName("Master")

	rB := v1beta1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: saName, Namespace: ns},
		Subjects: []v1beta1.Subject{{Name: saName, Kind: "ServiceAccount", Namespace: ns}},
		RoleRef:  v1beta1.RoleRef{Kind: "ClusterRole", Name: rolename, APIGroup: "rbac.authorization.k8s.io"}}

	rb, err := getK8sClient().RbacV1beta1().RoleBindings(ns).Create(&rB)
	if k8serrors.IsNotFound(err) {
		CreateNamespace(path)
		_, err = getK8sClient().RbacV1beta1().RoleBindings(ns).Create(&rB)
	}
	if check(err) {
		log.Fatal("Communication with K8s Server threw error, while creating ServiceAccount RoleBinding. Err: " + err.Error())
	}
	return rb.Name
}

func getServiceAccountName() string {
	name := os.Getenv("GITLAB_SERVICEACCOUNT_NAME")
	if name == "" {
		name = "gitlab-serviceaccount"
	} else if errs := validation.IsDNS1123Label(name) ; len(errs) != 0 {
		log.Fatalf("The provided value for GITLAB_SERVICEACCOUNT_NAME is not a DNS-1123 compliant name!")
	}
	return name
}<commit_msg>fixed error being thrown when rolebinding already existed<commit_after>package k8sclient

import (
	"k8s.io/client-go/pkg/api/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/validation"
	"github.com/pkg/errors"
	"log"
	"k8s.io/client-go/pkg/apis/rbac/v1beta1"
	"time"
	"os"
)

type ServiceAccountInfo struct {
	Name 		string
	Namespace	string
	Token		string
}

// CreateServiceAccountAndRoleBinding creates a ServiceAccount and a matching secret to use it.
func CreateServiceAccountAndRoleBinding(fullProjectPath string) (ServiceAccountInfo, string, error) {
	name := getServiceAccountName()
	namespace := GetActualNameSpaceNameByGitlabName(fullProjectPath)

	client := getK8sClient()

	sa := &v1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}}

	serviceAccount, err := client.ServiceAccounts(namespace).Create(sa)

	if k8serrors.IsAlreadyExists(err) {
		// ServiceAccount already exists, so retrieve and use it
		serviceAccount, err = client.ServiceAccounts(namespace).Get(name, metav1.GetOptions{})
		if err != nil {
			return ServiceAccountInfo{},"", err
		}
	} else if err != nil {
		return ServiceAccountInfo{}, "", err
	}

	// try to retrieve ServiceAccount once as the newly created one won't have the secret set
	serviceAccount, err = client.ServiceAccounts(namespace).Get(name, metav1.GetOptions{})
	// The secret in the ServiceAccount is not created and linked immediately, so we have to wait for it
	// to not wait indefinitely we use a timeout
	timeout := time.After(30 * time.Second)
	tick := time.Tick(500 * time.Millisecond)
	// Keep trying until we're timed out or got a result or got an error
	for k8serrors.IsNotFound(err) || len(serviceAccount.Secrets) < 1 {
		select {
		// Got a timeout! fail with a timeout error
		case <-timeout:
			return ServiceAccountInfo{}, "", errors.New("ServiceAccount was created, but Secrets were empty!")

		case <-tick:
			serviceAccount, err = client.ServiceAccounts(namespace).Get(name, metav1.GetOptions{})
			if err != nil && !k8serrors.IsNotFound(err) {
				return ServiceAccountInfo{},"", err
			}
		}
	}

	secretName := serviceAccount.Secrets[0].Name
	saSecret, err := client.Secrets(namespace).Get(secretName, metav1.GetOptions{})
	token := saSecret.Data["token"]
	if len(token) <= 0 {
		return ServiceAccountInfo{}, "", errors.New("The token field in the Secret's data was empty!")
	}

	tokenAsString := string(token[:])

	sAI := ServiceAccountInfo{Namespace: namespace, Name: name, Token: tokenAsString}
	rbName := createServiceAccountRoleBinding(name, fullProjectPath)
	return sAI, rbName, nil
}

func createServiceAccountRoleBinding(saName, path string) string {
	ns := GetActualNameSpaceNameByGitlabName(path)
	if ns == "" {
		CreateNamespace(path)
		ns = GetActualNameSpaceNameByGitlabName(path)
	}
	// ServiceAccounts are always bound to Master roles
	rolename := GetProjectRoleName("Master")

	rB := v1beta1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: saName, Namespace: ns},
		Subjects: []v1beta1.Subject{{Name: saName, Kind: "ServiceAccount", Namespace: ns}},
		RoleRef:  v1beta1.RoleRef{Kind: "ClusterRole", Name: rolename, APIGroup: "rbac.authorization.k8s.io"}}

	rb, err := getK8sClient().RbacV1beta1().RoleBindings(ns).Create(&rB)
	if err != nil && k8serrors.IsNotFound(err) {
		CreateNamespace(path)
		_, err = getK8sClient().RbacV1beta1().RoleBindings(ns).Create(&rB)
	}
	if err != nil && k8serrors.IsAlreadyExists(err) {
		_, err = getK8sClient().RbacV1beta1().RoleBindings(ns).Update(&rB)
		if err != nil {
			log.Fatal("Communication with K8s Server threw error, while creating ServiceAccount RoleBinding. Err: " + err.Error())
		}
	}
	return rb.Name
}

func getServiceAccountName() string {
	name := os.Getenv("GITLAB_SERVICEACCOUNT_NAME")
	if name == "" {
		name = "gitlab-serviceaccount"
	} else if errs := validation.IsDNS1123Label(name) ; len(errs) != 0 {
		log.Fatalf("The provided value for GITLAB_SERVICEACCOUNT_NAME is not a DNS-1123 compliant name!")
	}
	return name
}<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package containerd

import (
	"github.com/pkg/errors"
	"os"
	"os/exec"

	log "github.com/sirupsen/logrus"

	"k8s.io/kubeadm/kinder/pkg/build/bits"
)

// GetAlterContainerArgs returns arguments for the alter container for containerd
func GetAlterContainerArgs() ([]string, []string) {
	runArgs := []string{
		// privileged is required for "ctr image pull" permissions
		"--privileged",
		// the snapshot storage must be a volume.
		// see the info in Commit()
		"-v=/var/lib/containerd",
		// enable the actual entry point in the kind base image
		"--entrypoint=/usr/local/bin/entrypoint",
	}
	runCommands := []string{
		// pass the init binary to the entrypoint
		"/sbin/init",
	}
	return runArgs, runCommands
}

// StartRuntime starts the runtime
func StartRuntime(bc *bits.BuildContext) error {
	log.Info("starting containerd")
	go func() {
		bc.RunInContainer("containerd")
		log.Info("containerd stopped")
	}()
	return nil
}

// StopRuntime stops the runtime
func StopRuntime(bc *bits.BuildContext) error {
	return bc.RunInContainer("pkill", "-f", "containerd")
}

// PullImages pulls a set of images using ctr
func PullImages(bc *bits.BuildContext, images []string, targetPath string) error {
	// Supposedly this should be enough for containerd to snapshot the images, but it does not work.
	// TODO: commit pre-pulled images for containerd.
	for _, image := range images {
		if err := bc.RunInContainer("bash", "-c", "ctr image pull "+image+" > /dev/null"); err != nil {
			return errors.Wrapf(err, "could not pull image: %s", image)
		}
	}
	return nil
}

// Commit a kind(er) node image that uses the containerd runtime internally
func Commit(containerID, targetImage string) error {
	// NB. this code is an extract from "sigs.k8s.io/kind/pkg/build/node"

	// Save the image changes to a new image
	cmd := exec.Command("docker", "commit",
		/*
			The snapshot storage must be a volume to avoid overlay on overlay

			NOTE: we do this last because changing a volume with a docker image
			must occur before defining it.

			See: https://docs.docker.com/engine/reference/builder/#volume
		*/
		"--change", `VOLUME [ "/var/lib/containerd" ]`,
		// we need to put this back after changing it when running the image
		"--change", `ENTRYPOINT [ "/usr/local/bin/entrypoint", "/sbin/init" ]`,
		containerID, targetImage)

	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}
<commit_msg>kinder: don't use /usr/local/bin/entrypoint for alter<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package containerd

import (
	"github.com/pkg/errors"
	"os"
	"os/exec"

	log "github.com/sirupsen/logrus"

	"k8s.io/kubeadm/kinder/pkg/build/bits"
)

// GetAlterContainerArgs returns arguments for the alter container for containerd
func GetAlterContainerArgs() ([]string, []string) {
	// NB. using /usr/local/bin/entrypoint or /sbin/init both throw errors
	// for base image "kindest/base:v20191105-ee880e9b".
	// Use "sleep infinity" instead, but still make sure containerd can run.
	runArgs := []string{
		// privileged is required for "ctr image pull" permissions
		"--privileged",
		// the snapshot storage must be a volume.
		// see the info in Commit()
		"-v=/var/lib/containerd",
		// override the entrypoint
		"--entrypoint=/bin/sleep",
	}
	runCommands := []string{
		// pass this to the entrypoint
		"infinity",
	}
	return runArgs, runCommands
}

// StartRuntime starts the runtime
func StartRuntime(bc *bits.BuildContext) error {
	log.Info("starting containerd")
	go func() {
		bc.RunInContainer("containerd")
		log.Info("containerd stopped")
	}()
	return nil
}

// StopRuntime stops the runtime
func StopRuntime(bc *bits.BuildContext) error {
	return bc.RunInContainer("pkill", "-f", "containerd")
}

// PullImages pulls a set of images using ctr
func PullImages(bc *bits.BuildContext, images []string, targetPath string) error {
	// Supposedly this should be enough for containerd to snapshot the images, but it does not work.
	// TODO: commit pre-pulled images for containerd.
	for _, image := range images {
		if err := bc.RunInContainer("bash", "-c", "ctr image pull "+image+" > /dev/null"); err != nil {
			return errors.Wrapf(err, "could not pull image: %s", image)
		}
	}
	return nil
}

// Commit a kind(er) node image that uses the containerd runtime internally
func Commit(containerID, targetImage string) error {
	// NB. this code is an extract from "sigs.k8s.io/kind/pkg/build/node"

	// Save the image changes to a new image
	cmd := exec.Command("docker", "commit",
		/*
			The snapshot storage must be a volume to avoid overlay on overlay

			NOTE: we do this last because changing a volume with a docker image
			must occur before defining it.

			See: https://docs.docker.com/engine/reference/builder/#volume
		*/
		"--change", `VOLUME [ "/var/lib/containerd" ]`,
		// we need to put this back after changing it when running the image
		"--change", `ENTRYPOINT [ "/usr/local/bin/entrypoint", "/sbin/init" ]`,
		containerID, targetImage)

	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}
<|endoftext|>


<commit_before>package encoders

import (
	"fmt"
	//"github.com/cznic/mathutil"
	//"github.com/zacg/floats"
	"github.com/zacg/htm"
	"github.com/zacg/htm/utils"
	"math"
)

/*
 n -- The number of bits in the output. Must be greater than or equal to w

radius -- Two inputs separated by more than the radius have non-overlapping
representations. Two inputs separated by less than the radius will
in general overlap in at least some of their bits. You can think
of this as the radius of the input.

resolution -- Two inputs separated by greater than, or equal to the resolution are guaranteed
to have different representations.
*/
type ScalerOutputType int

const (
	N          ScalerOutputType = 1
	Radius     ScalerOutputType = 2
	Resolution ScalerOutputType = 3
)

type ScalerEncoderParams struct {
	Width      int
	MinVal     float64
	MaxVal     float64
	Periodic   bool
	OutputType ScalerOutputType
	Range      float64
	Resolution float64
	Name       string
	Radius     float64
	ClipInput  bool
	Verbosity  int
	N          int
}

func NewScalerEncoderParams(width int, minVal float64, maxVal float64) *ScalerEncoderParams {
	p := new(ScalerEncoderParams)

	p.Width = width
	p.MinVal = minVal
	p.MaxVal = maxVal
	p.N = 0
	p.Radius = 0
	p.Resolution = 0
	p.Name = ""
	p.Verbosity = 0
	p.ClipInput = false

	return p
}

/*
 A scalar encoder encodes a numeric (floating point) value into an array
of bits. The output is 0's except for a contiguous block of 1's. The
location of this contiguous block varies continuously with the input value.

The encoding is linear. If you want a nonlinear encoding, just transform
the scalar (e.g. by applying a logarithm function) before encoding.
It is not recommended to bin the data as a pre-processing step, e.g.
"1" = $0 - $.20, "2" = $.21-$0.80, "3" = $.81-$1.20, etc. as this
removes a lot of information and prevents nearby values from overlapping
in the output. Instead, use a continuous transformation that scales
the data (a piecewise transformation is fine).
*/
type ScalerEncoder struct {
	params          *ScalerEncoderParams
	padding         int
	halfWidth       int
	rangeInternal   float64
	topDownMappingM *htm.SparseBinaryMatrix
	topDownValues   []float64

	//nInternal represents the output area excluding the possible padding on each
	nInternal int
}

func NewScalerEncoder(params *ScalerEncoderParams) *ScalerEncoder {
	se := new(ScalerEncoder)
	se.params = params

	if params.Width%2 == 0 {
		panic("Width must be an odd number.")
	}

	se.halfWidth = (params.Width - 1) / 2

	/* For non-periodic inputs, padding is the number of bits "outside" the range,
	 on each side. I.e. the representation of minval is centered on some bit, and
	there are "padding" bits to the left of that centered bit; similarly with
	bits to the right of the center bit of maxval*/
	if !params.Periodic {
		se.padding = se.halfWidth
	}

	if params.MinVal >= params.MaxVal {
		panic("MinVal must be less than MaxVal")
	}

	se.rangeInternal = float64(params.MaxVal - params.MinVal)

	// There are three different ways of thinking about the representation. Handle
	// each case here.
	se.initEncoder(params.Width, params.MinVal, params.MaxVal, params.N,
		params.Radius, params.Resolution)

	// nInternal represents the output area excluding the possible padding on each
	// side
	se.nInternal = params.N - 2*se.padding

	// Our name
	if len(params.Name) == 0 {
		params.Name = fmt.Sprintf("[%v:%v]", params.MinVal, params.MaxVal)
	}

	if params.Width < 21 {
		fmt.Println("Number of bits in the SDR must be greater than 21")
	}

	return se
}

/*
	helper used to inititalize the encoder
*/
func (se *ScalerEncoder) initEncoder(width int, minval float64, maxval float64, n int,
	radius float64, resolution float64) {
	//handle 3 diff ways of representation

	if n != 0 {
		//crutches ;(
		if radius != 0 {
			panic("radius is not 0")
		}
		if resolution != 0 {
			panic("resolution is not 0")
		}
		if n <= width {
			panic("n less than width")
		}

		se.params.N = n

		//if (minval is not None and maxval is not None){

		if !se.params.Periodic {
			se.params.Resolution = se.rangeInternal / float64(se.params.N-se.params.Width)
		} else {
			se.params.Resolution = se.rangeInternal / float64(se.params.N)
		}

		se.params.Radius = float64(se.params.Width) * se.params.Resolution

		if se.params.Periodic {
			se.params.Range = se.rangeInternal
		} else {
			se.params.Range = se.rangeInternal + se.params.Resolution
		}

	} else { //n == 0
		if radius != 0 {
			if resolution != 0 {
				panic("resolution not 0")
			}
			se.params.Radius = radius
			se.params.Resolution = se.params.Radius / float64(width)
		} else if resolution != 0 {
			se.params.Resolution = resolution
			se.params.Radius = se.params.Resolution * float64(se.params.Width)
		} else {
			panic("One of n, radius, resolution must be set")
		}

		if se.params.Periodic {
			se.params.Range = se.rangeInternal
		} else {
			se.params.Range = se.rangeInternal + se.params.Resolution
		}

		nfloat := float64(se.params.Width)*(se.params.Range/se.params.Radius) + 2*float64(se.padding)
		se.params.N = int(math.Ceil(nfloat))

	}

}

/*
	recalculate encoder parameters and name
*/
func (se *ScalerEncoder) recalcParams() {
	se.rangeInternal = se.params.MaxVal - se.params.MinVal

	if !se.params.Periodic {
		se.params.Resolution = se.rangeInternal/float64(se.params.N) - float64(se.params.Width)
	} else {
		se.params.Resolution = se.rangeInternal / float64(se.params.N)
	}

	se.params.Radius = float64(se.params.Width) * se.params.Resolution

	if se.params.Periodic {
		se.params.Range = se.rangeInternal
	} else {
		se.params.Range = se.rangeInternal + se.params.Resolution
	}

	se.params.Name = fmt.Sprintf("[%v:%v]", se.params.MinVal, se.params.MaxVal)

}

/* Return the bit offset of the first bit to be set in the encoder output.
For periodic encoders, this can be a negative number when the encoded output
wraps around. */
func (se *ScalerEncoder) getFirstOnBit(input float64) int {

	//if input == SENTINEL_VALUE_FOR_MISSING_DATA:
	//	return [None]
	//else:

	if input < se.params.MinVal {
		//Don't clip periodic inputs. Out-of-range input is always an error
		if se.params.ClipInput && !se.params.Periodic {

			if se.params.Verbosity > 0 {
				fmt.Printf("Clipped input %v=%d to minval %d", se.params.Name, input, se.params.MinVal)
			}
			input = se.params.MinVal
		} else {
			panic(fmt.Sprintf("Input %v less than range %v - %v", input, se.params.MinVal, se.params.MaxVal))
		}

		if se.params.Periodic {

			// Don't clip periodic inputs. Out-of-range input is always an error
			if input >= se.params.MaxVal {
				panic(fmt.Sprintf("input %v greater than periodic range %v - %v", input, se.params.MinVal, se.params.MaxVal))
			}

		} else {

			if input > se.params.MaxVal {
				if se.params.ClipInput {
					if se.params.Verbosity > 0 {
						fmt.Printf("Clipped input %v=%v to maxval %v", se.params.Name, input, se.params.MaxVal)
					}
					input = se.params.MaxVal
				} else {
					panic(fmt.Sprintf("input %v greater than range (%v - %v)", input, se.params.MinVal, se.params.MaxVal))
				}
			}
		}
	}

	centerbin := 0

	if se.params.Periodic {
		centerbin = int((input-se.params.MinVal)*float64(se.nInternal)/se.params.Range) + se.padding
	} else {
		centerbin = int(((input-se.params.MinVal)+se.params.Resolution/2)/se.params.Resolution) + se.padding
	}

	// We use the first bit to be set in the encoded output as the bucket index
	minbin := centerbin - se.halfWidth
	return minbin
}

/*
 Returns bucket index for given input
*/
func (se *ScalerEncoder) getBucketIndices(input float64) []int {

	minbin := se.getFirstOnBit(input)
	var bucketIdx int

	// For periodic encoders, the bucket index is the index of the center bit
	if se.params.Periodic {
		bucketIdx = minbin + se.halfWidth
		if bucketIdx < 0 {
			bucketIdx += se.params.N
		}
	} else {
		// for non-periodic encoders, the bucket index is the index of the left bit
		bucketIdx = minbin
	}

	return []int{bucketIdx}
}

func (se *ScalerEncoder) Encode(input float64, learn bool) (output []bool) {

	// Get the bucket index to use
	bucketIdx := se.getFirstOnBit(input)

	//if len(bucketIdx) {
	//This shouldn't get hit
	//	panic("Missing input value")
	//TODO output[0:self.n] = 0 TODO: should all 1s, or random SDR be returned instead?
	//} else {
	// The bucket index is the index of the first bit to set in the output
	output = make([]bool, se.params.N)
	minbin := bucketIdx
	maxbin := minbin + 2*se.halfWidth

	if se.params.Periodic {

		// Handle the edges by computing wrap-around
		if maxbin >= se.params.N {
			bottombins := maxbin - se.params.N + 1
			utils.FillSliceRangeBool(output, true, 0, bottombins)
			maxbin = se.params.N - 1
		}
		if minbin < 0 {
			topbins := -minbin
			utils.FillSliceRangeBool(output, true, se.params.N-topbins, (se.params.N - (se.params.N - topbins)))
			minbin = 0
		}

	}

	if minbin < 0 {
		panic("invalid minbin")
	}
	if maxbin >= se.params.N {
		panic("invalid maxbin")
	}

	fmt.Println("prefill")
	fmt.Println(utils.Bool2Int(output))
	// set the output (except for periodic wraparound)
	utils.FillSliceRangeBool(output, true, minbin, (maxbin+1)-minbin)

	if se.params.Verbosity >= 2 {
		fmt.Println("input:", input)
		fmt.Printf("half width:%v \n", se.params.Width)
		fmt.Printf("range: %v - %v \n", se.params.MinVal, se.params.MaxVal)
		fmt.Printf("n: %v width: %v resolution: %v \n", se.params.N, se.params.Width, se.params.Resolution)
		fmt.Printf("radius: %v periodic: %v \n", se.params.Radius, se.params.Periodic)
		fmt.Printf("output: %v \n", output)
	}

	//}

	return output
}

/*
	Return the interal topDownMappingM matrix used for handling the
	bucketInfo() and topDownCompute() methods. This is a matrix, one row per
	category (bucket) where each row contains the encoded output for that
	category.
*/
func (se *ScalerEncoder) getTopDownMapping() *htm.SparseBinaryMatrix {

	//if already calculated return
	if se.topDownMappingM != nil {
		return se.topDownMappingM
	}

	// The input scalar value corresponding to each possible output encoding
	if se.params.Periodic {
		se.topDownValues = make([]float64, 0, int(se.params.MaxVal-se.params.MinVal))
		start := se.params.MinVal + se.params.Resolution/2.0
		idx := 0
		for i := start; i <= se.params.MaxVal; i += se.params.Resolution {
			se.topDownValues[idx] = i
			idx++
		}
	} else {
		//Number of values is (max-min)/resolution
		se.topDownValues = make([]float64, int(math.Ceil((se.params.MaxVal-se.params.MinVal)/se.params.Resolution)))
		end := se.params.MaxVal + se.params.Resolution/2.0
		idx := 0
		for i := se.params.MinVal; i <= end; i += se.params.Resolution {
			se.topDownValues[idx] = i
			idx++
		}
	}

	// Each row represents an encoded output pattern
	numCategories := len(se.topDownValues)

	se.topDownMappingM = htm.NewSparseBinaryMatrix(numCategories, se.params.N)

	for i := 0; i < numCategories; i++ {
		value := se.topDownValues[i]
		value = math.Max(value, se.params.MinVal)
		value = math.Min(value, se.params.MaxVal)

		outputSpace := se.Encode(value, false)
		se.topDownMappingM.SetRowFromDense(i, outputSpace)
	}

	return se.topDownMappingM

}

/*
	Returns input description for bucket. Numenta implementations iface returns
	set of tuples to support diff encoder types.
*/
func (se *ScalerEncoder) getBucketInfo(buckets []int) (value float64, encoding []bool) {

	//ensure topdownmapping matrix is calculated
	se.getTopDownMapping()

	// The "category" is simply the bucket index
	category := buckets[0]
	encoding = se.topDownMappingM.GetDenseRow(category)

	if se.params.Periodic {
		value = (se.params.MinVal + (se.params.Resolution / 2.0) + (float64(category) * se.params.Resolution))
	} else {
		value = se.params.MinVal + (float64(category) * se.params.Resolution)
	}

	return value, encoding

}
<commit_msg>implementing getBucketValues()<commit_after>package encoders

import (
	"fmt"
	//"github.com/cznic/mathutil"
	//"github.com/zacg/floats"
	"github.com/zacg/htm"
	"github.com/zacg/htm/utils"
	"math"
)

/*
 n -- The number of bits in the output. Must be greater than or equal to w

radius -- Two inputs separated by more than the radius have non-overlapping
representations. Two inputs separated by less than the radius will
in general overlap in at least some of their bits. You can think
of this as the radius of the input.

resolution -- Two inputs separated by greater than, or equal to the resolution are guaranteed
to have different representations.
*/
type ScalerOutputType int

const (
	N          ScalerOutputType = 1
	Radius     ScalerOutputType = 2
	Resolution ScalerOutputType = 3
)

type ScalerEncoderParams struct {
	Width      int
	MinVal     float64
	MaxVal     float64
	Periodic   bool
	OutputType ScalerOutputType
	Range      float64
	Resolution float64
	Name       string
	Radius     float64
	ClipInput  bool
	Verbosity  int
	N          int
}

func NewScalerEncoderParams(width int, minVal float64, maxVal float64) *ScalerEncoderParams {
	p := new(ScalerEncoderParams)

	p.Width = width
	p.MinVal = minVal
	p.MaxVal = maxVal
	p.N = 0
	p.Radius = 0
	p.Resolution = 0
	p.Name = ""
	p.Verbosity = 0
	p.ClipInput = false

	return p
}

/*
 A scalar encoder encodes a numeric (floating point) value into an array
of bits. The output is 0's except for a contiguous block of 1's. The
location of this contiguous block varies continuously with the input value.

The encoding is linear. If you want a nonlinear encoding, just transform
the scalar (e.g. by applying a logarithm function) before encoding.
It is not recommended to bin the data as a pre-processing step, e.g.
"1" = $0 - $.20, "2" = $.21-$0.80, "3" = $.81-$1.20, etc. as this
removes a lot of information and prevents nearby values from overlapping
in the output. Instead, use a continuous transformation that scales
the data (a piecewise transformation is fine).
*/
type ScalerEncoder struct {
	params          *ScalerEncoderParams
	padding         int
	halfWidth       int
	rangeInternal   float64
	topDownMappingM *htm.SparseBinaryMatrix
	topDownValues   []float64
	bucketValues    []float64
	//nInternal represents the output area excluding the possible padding on each
	nInternal int
}

func NewScalerEncoder(params *ScalerEncoderParams) *ScalerEncoder {
	se := new(ScalerEncoder)
	se.params = params

	if params.Width%2 == 0 {
		panic("Width must be an odd number.")
	}

	se.halfWidth = (params.Width - 1) / 2

	/* For non-periodic inputs, padding is the number of bits "outside" the range,
	 on each side. I.e. the representation of minval is centered on some bit, and
	there are "padding" bits to the left of that centered bit; similarly with
	bits to the right of the center bit of maxval*/
	if !params.Periodic {
		se.padding = se.halfWidth
	}

	if params.MinVal >= params.MaxVal {
		panic("MinVal must be less than MaxVal")
	}

	se.rangeInternal = float64(params.MaxVal - params.MinVal)

	// There are three different ways of thinking about the representation. Handle
	// each case here.
	se.initEncoder(params.Width, params.MinVal, params.MaxVal, params.N,
		params.Radius, params.Resolution)

	// nInternal represents the output area excluding the possible padding on each
	// side
	se.nInternal = params.N - 2*se.padding

	// Our name
	if len(params.Name) == 0 {
		params.Name = fmt.Sprintf("[%v:%v]", params.MinVal, params.MaxVal)
	}

	if params.Width < 21 {
		fmt.Println("Number of bits in the SDR must be greater than 21")
	}

	return se
}

/*
	helper used to inititalize the encoder
*/
func (se *ScalerEncoder) initEncoder(width int, minval float64, maxval float64, n int,
	radius float64, resolution float64) {
	//handle 3 diff ways of representation

	if n != 0 {
		//crutches ;(
		if radius != 0 {
			panic("radius is not 0")
		}
		if resolution != 0 {
			panic("resolution is not 0")
		}
		if n <= width {
			panic("n less than width")
		}

		se.params.N = n

		//if (minval is not None and maxval is not None){

		if !se.params.Periodic {
			se.params.Resolution = se.rangeInternal / float64(se.params.N-se.params.Width)
		} else {
			se.params.Resolution = se.rangeInternal / float64(se.params.N)
		}

		se.params.Radius = float64(se.params.Width) * se.params.Resolution

		if se.params.Periodic {
			se.params.Range = se.rangeInternal
		} else {
			se.params.Range = se.rangeInternal + se.params.Resolution
		}

	} else { //n == 0
		if radius != 0 {
			if resolution != 0 {
				panic("resolution not 0")
			}
			se.params.Radius = radius
			se.params.Resolution = se.params.Radius / float64(width)
		} else if resolution != 0 {
			se.params.Resolution = resolution
			se.params.Radius = se.params.Resolution * float64(se.params.Width)
		} else {
			panic("One of n, radius, resolution must be set")
		}

		if se.params.Periodic {
			se.params.Range = se.rangeInternal
		} else {
			se.params.Range = se.rangeInternal + se.params.Resolution
		}

		nfloat := float64(se.params.Width)*(se.params.Range/se.params.Radius) + 2*float64(se.padding)
		se.params.N = int(math.Ceil(nfloat))

	}

}

/*
	recalculate encoder parameters and name
*/
func (se *ScalerEncoder) recalcParams() {
	se.rangeInternal = se.params.MaxVal - se.params.MinVal

	if !se.params.Periodic {
		se.params.Resolution = se.rangeInternal/float64(se.params.N) - float64(se.params.Width)
	} else {
		se.params.Resolution = se.rangeInternal / float64(se.params.N)
	}

	se.params.Radius = float64(se.params.Width) * se.params.Resolution

	if se.params.Periodic {
		se.params.Range = se.rangeInternal
	} else {
		se.params.Range = se.rangeInternal + se.params.Resolution
	}

	se.params.Name = fmt.Sprintf("[%v:%v]", se.params.MinVal, se.params.MaxVal)

}

/* Return the bit offset of the first bit to be set in the encoder output.
For periodic encoders, this can be a negative number when the encoded output
wraps around. */
func (se *ScalerEncoder) getFirstOnBit(input float64) int {

	//if input == SENTINEL_VALUE_FOR_MISSING_DATA:
	//	return [None]
	//else:

	if input < se.params.MinVal {
		//Don't clip periodic inputs. Out-of-range input is always an error
		if se.params.ClipInput && !se.params.Periodic {

			if se.params.Verbosity > 0 {
				fmt.Printf("Clipped input %v=%d to minval %d", se.params.Name, input, se.params.MinVal)
			}
			input = se.params.MinVal
		} else {
			panic(fmt.Sprintf("Input %v less than range %v - %v", input, se.params.MinVal, se.params.MaxVal))
		}

		if se.params.Periodic {

			// Don't clip periodic inputs. Out-of-range input is always an error
			if input >= se.params.MaxVal {
				panic(fmt.Sprintf("input %v greater than periodic range %v - %v", input, se.params.MinVal, se.params.MaxVal))
			}

		} else {

			if input > se.params.MaxVal {
				if se.params.ClipInput {
					if se.params.Verbosity > 0 {
						fmt.Printf("Clipped input %v=%v to maxval %v", se.params.Name, input, se.params.MaxVal)
					}
					input = se.params.MaxVal
				} else {
					panic(fmt.Sprintf("input %v greater than range (%v - %v)", input, se.params.MinVal, se.params.MaxVal))
				}
			}
		}
	}

	centerbin := 0

	if se.params.Periodic {
		centerbin = int((input-se.params.MinVal)*float64(se.nInternal)/se.params.Range) + se.padding
	} else {
		centerbin = int(((input-se.params.MinVal)+se.params.Resolution/2)/se.params.Resolution) + se.padding
	}

	// We use the first bit to be set in the encoded output as the bucket index
	minbin := centerbin - se.halfWidth
	return minbin
}

/*
 Returns bucket index for given input
*/
func (se *ScalerEncoder) getBucketIndices(input float64) []int {

	minbin := se.getFirstOnBit(input)
	var bucketIdx int

	// For periodic encoders, the bucket index is the index of the center bit
	if se.params.Periodic {
		bucketIdx = minbin + se.halfWidth
		if bucketIdx < 0 {
			bucketIdx += se.params.N
		}
	} else {
		// for non-periodic encoders, the bucket index is the index of the left bit
		bucketIdx = minbin
	}

	return []int{bucketIdx}
}

func (se *ScalerEncoder) Encode(input float64, learn bool) (output []bool) {

	// Get the bucket index to use
	bucketIdx := se.getFirstOnBit(input)

	//if len(bucketIdx) {
	//This shouldn't get hit
	//	panic("Missing input value")
	//TODO output[0:self.n] = 0 TODO: should all 1s, or random SDR be returned instead?
	//} else {
	// The bucket index is the index of the first bit to set in the output
	output = make([]bool, se.params.N)
	minbin := bucketIdx
	maxbin := minbin + 2*se.halfWidth

	if se.params.Periodic {

		// Handle the edges by computing wrap-around
		if maxbin >= se.params.N {
			bottombins := maxbin - se.params.N + 1
			utils.FillSliceRangeBool(output, true, 0, bottombins)
			maxbin = se.params.N - 1
		}
		if minbin < 0 {
			topbins := -minbin
			utils.FillSliceRangeBool(output, true, se.params.N-topbins, (se.params.N - (se.params.N - topbins)))
			minbin = 0
		}

	}

	if minbin < 0 {
		panic("invalid minbin")
	}
	if maxbin >= se.params.N {
		panic("invalid maxbin")
	}

	fmt.Println("prefill")
	fmt.Println(utils.Bool2Int(output))
	// set the output (except for periodic wraparound)
	utils.FillSliceRangeBool(output, true, minbin, (maxbin+1)-minbin)

	if se.params.Verbosity >= 2 {
		fmt.Println("input:", input)
		fmt.Printf("half width:%v \n", se.params.Width)
		fmt.Printf("range: %v - %v \n", se.params.MinVal, se.params.MaxVal)
		fmt.Printf("n: %v width: %v resolution: %v \n", se.params.N, se.params.Width, se.params.Resolution)
		fmt.Printf("radius: %v periodic: %v \n", se.params.Radius, se.params.Periodic)
		fmt.Printf("output: %v \n", output)
	}

	//}

	return output
}

/*
	Return the interal topDownMappingM matrix used for handling the
	bucketInfo() and topDownCompute() methods. This is a matrix, one row per
	category (bucket) where each row contains the encoded output for that
	category.
*/
func (se *ScalerEncoder) getTopDownMapping() *htm.SparseBinaryMatrix {

	//if already calculated return
	if se.topDownMappingM != nil {
		return se.topDownMappingM
	}

	// The input scalar value corresponding to each possible output encoding
	if se.params.Periodic {
		se.topDownValues = make([]float64, 0, int(se.params.MaxVal-se.params.MinVal))
		start := se.params.MinVal + se.params.Resolution/2.0
		idx := 0
		for i := start; i <= se.params.MaxVal; i += se.params.Resolution {
			se.topDownValues[idx] = i
			idx++
		}
	} else {
		//Number of values is (max-min)/resolution
		se.topDownValues = make([]float64, int(math.Ceil((se.params.MaxVal-se.params.MinVal)/se.params.Resolution)))
		end := se.params.MaxVal + se.params.Resolution/2.0
		idx := 0
		for i := se.params.MinVal; i <= end; i += se.params.Resolution {
			se.topDownValues[idx] = i
			idx++
		}
	}

	// Each row represents an encoded output pattern
	numCategories := len(se.topDownValues)

	se.topDownMappingM = htm.NewSparseBinaryMatrix(numCategories, se.params.N)

	for i := 0; i < numCategories; i++ {
		value := se.topDownValues[i]
		value = math.Max(value, se.params.MinVal)
		value = math.Min(value, se.params.MaxVal)

		outputSpace := se.Encode(value, false)
		se.topDownMappingM.SetRowFromDense(i, outputSpace)
	}

	return se.topDownMappingM

}

/*
	Returns input description for bucket. Numenta implementations iface returns
	set of tuples to support diff encoder types.
*/
func (se *ScalerEncoder) getBucketInfo(buckets []int) (value float64, encoding []bool) {

	//ensure topdownmapping matrix is calculated
	se.getTopDownMapping()

	// The "category" is simply the bucket index
	category := buckets[0]
	encoding = se.topDownMappingM.GetDenseRow(category)

	if se.params.Periodic {
		value = (se.params.MinVal + (se.params.Resolution / 2.0) + (float64(category) * se.params.Resolution))
	} else {
		value = se.params.MinVal + (float64(category) * se.params.Resolution)
	}

	return value, encoding

}

/*
	Returns the value for each bucket defined by the encoder
*/
func (se *ScalerEncoder) getBucketValues() []float64 {

	if se.bucketValues == nil {
		topDownMappingM := se.getTopDownMapping()
		numBuckets := topDownMappingM.Height
		se.bucketValues = make([]float64, numBuckets)
		for i := 0; i < numBuckets; i++ {
			val, _ := se.getBucketInfo([]int{i})
			se.bucketValues[i] = val
		}
	}

	return se.bucketValues
}
<|endoftext|>


<commit_before>package grpcutil

import (
	"bytes"
	"io"

	"github.com/gogo/protobuf/types"
)

var (
	// MaxMsgSize is used to define the GRPC frame size
	MaxMsgSize = 20 * 1024 * 1024
)

// Chunk
func Chunk(data []byte, chunkSize int) [][]byte {
	var result [][]byte
	for i := 0; i < len(data); i += chunkSize {
		end := i + chunkSize
		if end > len(data) {
			end = len(data)
		}
		result = append(result, data[i:end])
	}
	return result
}

// StreamingBytesServer represents a server for an rpc method of the form:
//   rpc Foo(Bar) returns (stream google.protobuf.BytesValue) {}
type StreamingBytesServer interface {
	Send(bytesValue *types.BytesValue) error
}

// StreamingBytesClient represents a client for an rpc method of the form:
//   rpc Foo(Bar) returns (stream google.protobuf.BytesValue) {}
type StreamingBytesClient interface {
	Recv() (*types.BytesValue, error)
}

// NewStreamingBytesReader returns an io.Reader for a StreamingBytesClient.
func NewStreamingBytesReader(streamingBytesClient StreamingBytesClient) io.Reader {
	return &streamingBytesReader{streamingBytesClient: streamingBytesClient}
}

type streamingBytesReader struct {
	streamingBytesClient StreamingBytesClient
	buffer               bytes.Buffer
}

func (s *streamingBytesReader) Read(p []byte) (int, error) {
	// TODO this is doing an unneeded copy (unless go is smarter than I think it is)
	if s.buffer.Len() == 0 {
		value, err := s.streamingBytesClient.Recv()
		if err != nil {
			return 0, err
		}
		if _, err := s.buffer.Write(value.Value); err != nil {
			return 0, err
		}
	}
	return s.buffer.Read(p)
}

// NewStreamingBytesWriter returns an io.Writer for a StreamingBytesServer.
func NewStreamingBytesWriter(streamingBytesServer StreamingBytesServer) io.Writer {
	return &streamingBytesWriter{streamingBytesServer}
}

type streamingBytesWriter struct {
	streamingBytesServer StreamingBytesServer
}

func (s *streamingBytesWriter) Write(p []byte) (int, error) {
	if len(p) == 0 {
		return 0, nil
	}
	if err := s.streamingBytesServer.Send(&types.BytesValue{Value: p}); err != nil {
		return 0, err
	}
	return len(p), nil
}

// WriteToStreamingBytesServer writes the data from the io.Reader to the StreamingBytesServer.
func WriteToStreamingBytesServer(reader io.Reader, streamingBytesServer StreamingBytesServer) error {
	_, err := io.CopyBuffer(NewStreamingBytesWriter(streamingBytesServer), reader, make([]byte, MaxMsgSize/2))
	return err
}

// WriteFromStreamingBytesClient writes from the StreamingBytesClient to the io.Writer.
func WriteFromStreamingBytesClient(streamingBytesClient StreamingBytesClient, writer io.Writer) error {
	for bytesValue, err := streamingBytesClient.Recv(); err != io.EOF; bytesValue, err = streamingBytesClient.Recv() {
		if err != nil {
			return err
		}
		if _, err = writer.Write(bytesValue.Value); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Make linter happy.<commit_after>package grpcutil

import (
	"bytes"
	"io"

	"github.com/gogo/protobuf/types"
)

var (
	// MaxMsgSize is used to define the GRPC frame size
	MaxMsgSize = 20 * 1024 * 1024
)

// Chunk splits a piece of data up, this is useful for splitting up data that's
// bigger than MaxMsgSize
func Chunk(data []byte, chunkSize int) [][]byte {
	var result [][]byte
	for i := 0; i < len(data); i += chunkSize {
		end := i + chunkSize
		if end > len(data) {
			end = len(data)
		}
		result = append(result, data[i:end])
	}
	return result
}

// StreamingBytesServer represents a server for an rpc method of the form:
//   rpc Foo(Bar) returns (stream google.protobuf.BytesValue) {}
type StreamingBytesServer interface {
	Send(bytesValue *types.BytesValue) error
}

// StreamingBytesClient represents a client for an rpc method of the form:
//   rpc Foo(Bar) returns (stream google.protobuf.BytesValue) {}
type StreamingBytesClient interface {
	Recv() (*types.BytesValue, error)
}

// NewStreamingBytesReader returns an io.Reader for a StreamingBytesClient.
func NewStreamingBytesReader(streamingBytesClient StreamingBytesClient) io.Reader {
	return &streamingBytesReader{streamingBytesClient: streamingBytesClient}
}

type streamingBytesReader struct {
	streamingBytesClient StreamingBytesClient
	buffer               bytes.Buffer
}

func (s *streamingBytesReader) Read(p []byte) (int, error) {
	// TODO this is doing an unneeded copy (unless go is smarter than I think it is)
	if s.buffer.Len() == 0 {
		value, err := s.streamingBytesClient.Recv()
		if err != nil {
			return 0, err
		}
		if _, err := s.buffer.Write(value.Value); err != nil {
			return 0, err
		}
	}
	return s.buffer.Read(p)
}

// NewStreamingBytesWriter returns an io.Writer for a StreamingBytesServer.
func NewStreamingBytesWriter(streamingBytesServer StreamingBytesServer) io.Writer {
	return &streamingBytesWriter{streamingBytesServer}
}

type streamingBytesWriter struct {
	streamingBytesServer StreamingBytesServer
}

func (s *streamingBytesWriter) Write(p []byte) (int, error) {
	if len(p) == 0 {
		return 0, nil
	}
	if err := s.streamingBytesServer.Send(&types.BytesValue{Value: p}); err != nil {
		return 0, err
	}
	return len(p), nil
}

// WriteToStreamingBytesServer writes the data from the io.Reader to the StreamingBytesServer.
func WriteToStreamingBytesServer(reader io.Reader, streamingBytesServer StreamingBytesServer) error {
	_, err := io.CopyBuffer(NewStreamingBytesWriter(streamingBytesServer), reader, make([]byte, MaxMsgSize/2))
	return err
}

// WriteFromStreamingBytesClient writes from the StreamingBytesClient to the io.Writer.
func WriteFromStreamingBytesClient(streamingBytesClient StreamingBytesClient, writer io.Writer) error {
	for bytesValue, err := streamingBytesClient.Recv(); err != io.EOF; bytesValue, err = streamingBytesClient.Recv() {
		if err != nil {
			return err
		}
		if _, err = writer.Write(bytesValue.Value); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>