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

package memfs

import (
	"fmt"
	"io"
	"os"
	"time"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/gcloud/syncutil"
)

// Common attributes for files and directories.
type inode struct {
	/////////////////////////
	// Dependencies
	/////////////////////////

	clock timeutil.Clock

	/////////////////////////
	// Mutable state
	/////////////////////////

	mu syncutil.InvariantMutex

	// The current attributes of this inode.
	//
	// INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0
	// INVARIANT: !(isDir() && isSymlink())
	// INVARIANT: attrs.Size == len(contents)
	attrs fuseops.InodeAttributes // GUARDED_BY(mu)

	// For directories, entries describing the children of the directory. Unused
	// entries are of type DT_Unknown.
	//
	// This array can never be shortened, nor can its elements be moved, because
	// we use its indices for Dirent.Offset, which is exposed to the user who
	// might be calling readdir in a loop while concurrently modifying the
	// directory. Unused entries can, however, be reused.
	//
	// INVARIANT: If !isDir(), len(entries) == 0
	// INVARIANT: For each i, entries[i].Offset == i+1
	// INVARIANT: Contains no duplicate names in used entries.
	entries []fuseutil.Dirent // GUARDED_BY(mu)

	// For files, the current contents of the file.
	//
	// INVARIANT: If !isFile(), len(contents) == 0
	contents []byte // GUARDED_BY(mu)

	// For symlinks, the target of the symlink.
	//
	// INVARIANT: If !isSymlink(), len(target) == 0
	//
	// GUARDED_BY(mu)
	target string
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Create a new inode with the supplied attributes, which need not contain
// time-related information (the inode object will take care of that).
func newInode(
	clock timeutil.Clock,
	attrs fuseops.InodeAttributes) (in *inode) {
	// Update time info.
	now := clock.Now()
	attrs.Mtime = now
	attrs.Crtime = now

	// Create the object.
	in = &inode{
		clock: clock,
		attrs: attrs,
	}

	in.mu = syncutil.NewInvariantMutex(in.checkInvariants)
	return
}

func (in *inode) checkInvariants() {
	// INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0
	if !(in.attrs.Mode&^(os.ModePerm|os.ModeDir|os.ModeSymlink) == 0) {
		panic(fmt.Sprintf("Unexpected mode: %v", in.attrs.Mode))
	}

	// INVARIANT: !(isDir() && isSymlink())
	if in.isDir() && in.isSymlink() {
		panic(fmt.Sprintf("Unexpected mode: %v", in.attrs.Mode))
	}

	// INVARIANT: attrs.Size == len(contents)
	if in.attrs.Size != uint64(len(in.contents)) {
		panic(fmt.Sprintf(
			"Size mismatch: %d vs. %d",
			in.attrs.Size,
			len(in.contents)))
	}

	// INVARIANT: If !isDir(), len(entries) == 0
	if !in.isDir() && len(in.entries) != 0 {
		panic(fmt.Sprintf("Unexpected entries length: %d", len(in.entries)))
	}

	// INVARIANT: For each i, entries[i].Offset == i+1
	for i, e := range in.entries {
		if !(e.Offset == fuseops.DirOffset(i+1)) {
			panic(fmt.Sprintf("Unexpected offset for index %d: %d", i, e.Offset))
		}
	}

	// INVARIANT: Contains no duplicate names in used entries.
	childNames := make(map[string]struct{})
	for i, e := range in.entries {
		if e.Type != fuseutil.DT_Unknown {
			if _, ok := childNames[e.Name]; ok {
				panic(fmt.Sprintf("Duplicate name: %s", e.Name))
			}

			childNames[e.Name] = struct{}{}
		}
	}

	// INVARIANT: If !isFile(), len(contents) == 0
	if !in.isFile() && len(in.contents) != 0 {
		panic(fmt.Sprintf("Unexpected length: %d", len(in.contents)))
	}

	// INVARIANT: If !isSymlink(), len(target) == 0
	if !in.isSymlink() && len(in.target) != 0 {
		panic(fmt.Sprintf("Unexpected target length: %d", len(in.target)))
	}

	return
}

// LOCKS_REQUIRED(in.mu)
func (in *inode) isDir() bool {
	return in.attrs.Mode&os.ModeDir != 0
}

// LOCKS_REQUIRED(in.mu)
func (in *inode) isSymlink() bool {
	return in.attrs.Mode&os.ModeSymlink != 0
}

// LOCKS_REQUIRED(in.mu)
func (in *inode) isFile() bool {
	return !(in.isDir() || in.isSymlink())
}

// Return the index of the child within in.entries, if it exists.
//
// REQUIRES: in.dir
// LOCKS_REQUIRED(in.mu)
func (in *inode) findChild(name string) (i int, ok bool) {
	if !in.isDir() {
		panic("findChild called on non-directory.")
	}

	var e fuseutil.Dirent
	for i, e = range in.entries {
		if e.Name == name {
			ok = true
			return
		}
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Public methods
////////////////////////////////////////////////////////////////////////

// Return the number of children of the directory.
//
// REQUIRES: in.isDir()
// LOCKS_REQUIRED(in.mu)
func (in *inode) Len() (n int) {
	for _, e := range in.entries {
		if e.Type != fuseutil.DT_Unknown {
			n++
		}
	}

	return
}

// Find an entry for the given child name and return its inode ID.
//
// REQUIRES: in.isDir()
// LOCKS_REQUIRED(in.mu)
func (in *inode) LookUpChild(name string) (id fuseops.InodeID, ok bool) {
	index, ok := in.findChild(name)
	if ok {
		id = in.entries[index].Inode
	}

	return
}

// Add an entry for a child.
//
// REQUIRES: in.isDir()
// REQUIRES: dt != fuseutil.DT_Unknown
// LOCKS_REQUIRED(in.mu)
func (in *inode) AddChild(
	id fuseops.InodeID,
	name string,
	dt fuseutil.DirentType) {
	var index int

	// Update the modification time.
	in.attrs.Mtime = in.clock.Now()

	// No matter where we place the entry, make sure it has the correct Offset
	// field.
	defer func() {
		in.entries[index].Offset = fuseops.DirOffset(index + 1)
	}()

	// Set up the entry.
	e := fuseutil.Dirent{
		Inode: id,
		Name:  name,
		Type:  dt,
	}

	// Look for a gap in which we can insert it.
	for index = range in.entries {
		if in.entries[index].Type == fuseutil.DT_Unknown {
			in.entries[index] = e
			return
		}
	}

	// Append it to the end.
	index = len(in.entries)
	in.entries = append(in.entries, e)
}

// Remove an entry for a child.
//
// REQUIRES: in.isDir()
// REQUIRES: An entry for the given name exists.
// LOCKS_REQUIRED(in.mu)
func (in *inode) RemoveChild(name string) {
	// Update the modification time.
	in.attrs.Mtime = in.clock.Now()

	// Find the entry.
	i, ok := in.findChild(name)
	if !ok {
		panic(fmt.Sprintf("Unknown child: %s", name))
	}

	// Mark it as unused.
	in.entries[i] = fuseutil.Dirent{
		Type:   fuseutil.DT_Unknown,
		Offset: fuseops.DirOffset(i + 1),
	}
}

// Serve a ReadDir request.
//
// REQUIRES: in.isDir()
// LOCKS_REQUIRED(in.mu)
func (in *inode) ReadDir(offset int, size int) (data []byte, err error) {
	if !in.dir {
		panic("ReadDir called on non-directory.")
	}

	for i := offset; i < len(in.entries); i++ {
		e := in.entries[i]

		// Skip unused entries.
		if e.Type == fuseutil.DT_Unknown {
			continue
		}

		data = fuseutil.AppendDirent(data, in.entries[i])

		// Trim and stop early if we've exceeded the requested size.
		if len(data) > size {
			data = data[:size]
			break
		}
	}

	return
}

// Read from the file's contents. See documentation for ioutil.ReaderAt.
//
// REQUIRES: in.isFile()
// LOCKS_REQUIRED(in.mu)
func (in *inode) ReadAt(p []byte, off int64) (n int, err error) {
	if in.dir {
		panic("ReadAt called on directory.")
	}

	// Ensure the offset is in range.
	if off > int64(len(in.contents)) {
		err = io.EOF
		return
	}

	// Read what we can.
	n = copy(p, in.contents[off:])
	if n < len(p) {
		err = io.EOF
	}

	return
}

// Write to the file's contents. See documentation for ioutil.WriterAt.
//
// REQUIRES: in.isFile()
// LOCKS_REQUIRED(in.mu)
func (in *inode) WriteAt(p []byte, off int64) (n int, err error) {
	if in.dir {
		panic("WriteAt called on directory.")
	}

	// Update the modification time.
	in.attrs.Mtime = in.clock.Now()

	// Ensure that the contents slice is long enough.
	newLen := int(off) + len(p)
	if len(in.contents) < newLen {
		padding := make([]byte, newLen-len(in.contents))
		in.contents = append(in.contents, padding...)
		in.attrs.Size = uint64(newLen)
	}

	// Copy in the data.
	n = copy(in.contents[off:], p)

	// Sanity check.
	if n != len(p) {
		panic(fmt.Sprintf("Unexpected short copy: %v", n))
	}

	return
}

// Update attributes from non-nil parameters.
//
// LOCKS_REQUIRED(in.mu)
func (in *inode) SetAttributes(
	size *uint64,
	mode *os.FileMode,
	mtime *time.Time) {
	// Update the modification time.
	in.attrs.Mtime = in.clock.Now()

	// Truncate?
	if size != nil {
		intSize := int(*size)

		// Update contents.
		if intSize <= len(in.contents) {
			in.contents = in.contents[:intSize]
		} else {
			padding := make([]byte, intSize-len(in.contents))
			in.contents = append(in.contents, padding...)
		}

		// Update attributes.
		in.attrs.Size = *size
	}

	// Change mode?
	if mode != nil {
		in.attrs.Mode = *mode
	}

	// Change mtime?
	if mtime != nil {
		in.attrs.Mtime = *mtime
	}
}
<commit_msg>Fixed more errors.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package memfs

import (
	"fmt"
	"io"
	"os"
	"time"

	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/gcloud/syncutil"
)

// Common attributes for files and directories.
type inode struct {
	/////////////////////////
	// Dependencies
	/////////////////////////

	clock timeutil.Clock

	/////////////////////////
	// Mutable state
	/////////////////////////

	mu syncutil.InvariantMutex

	// The current attributes of this inode.
	//
	// INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0
	// INVARIANT: !(isDir() && isSymlink())
	// INVARIANT: attrs.Size == len(contents)
	attrs fuseops.InodeAttributes // GUARDED_BY(mu)

	// For directories, entries describing the children of the directory. Unused
	// entries are of type DT_Unknown.
	//
	// This array can never be shortened, nor can its elements be moved, because
	// we use its indices for Dirent.Offset, which is exposed to the user who
	// might be calling readdir in a loop while concurrently modifying the
	// directory. Unused entries can, however, be reused.
	//
	// INVARIANT: If !isDir(), len(entries) == 0
	// INVARIANT: For each i, entries[i].Offset == i+1
	// INVARIANT: Contains no duplicate names in used entries.
	entries []fuseutil.Dirent // GUARDED_BY(mu)

	// For files, the current contents of the file.
	//
	// INVARIANT: If !isFile(), len(contents) == 0
	contents []byte // GUARDED_BY(mu)

	// For symlinks, the target of the symlink.
	//
	// INVARIANT: If !isSymlink(), len(target) == 0
	//
	// GUARDED_BY(mu)
	target string
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Create a new inode with the supplied attributes, which need not contain
// time-related information (the inode object will take care of that).
func newInode(
	clock timeutil.Clock,
	attrs fuseops.InodeAttributes) (in *inode) {
	// Update time info.
	now := clock.Now()
	attrs.Mtime = now
	attrs.Crtime = now

	// Create the object.
	in = &inode{
		clock: clock,
		attrs: attrs,
	}

	in.mu = syncutil.NewInvariantMutex(in.checkInvariants)
	return
}

func (in *inode) checkInvariants() {
	// INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0
	if !(in.attrs.Mode&^(os.ModePerm|os.ModeDir|os.ModeSymlink) == 0) {
		panic(fmt.Sprintf("Unexpected mode: %v", in.attrs.Mode))
	}

	// INVARIANT: !(isDir() && isSymlink())
	if in.isDir() && in.isSymlink() {
		panic(fmt.Sprintf("Unexpected mode: %v", in.attrs.Mode))
	}

	// INVARIANT: attrs.Size == len(contents)
	if in.attrs.Size != uint64(len(in.contents)) {
		panic(fmt.Sprintf(
			"Size mismatch: %d vs. %d",
			in.attrs.Size,
			len(in.contents)))
	}

	// INVARIANT: If !isDir(), len(entries) == 0
	if !in.isDir() && len(in.entries) != 0 {
		panic(fmt.Sprintf("Unexpected entries length: %d", len(in.entries)))
	}

	// INVARIANT: For each i, entries[i].Offset == i+1
	for i, e := range in.entries {
		if !(e.Offset == fuseops.DirOffset(i+1)) {
			panic(fmt.Sprintf("Unexpected offset for index %d: %d", i, e.Offset))
		}
	}

	// INVARIANT: Contains no duplicate names in used entries.
	childNames := make(map[string]struct{})
	for _, e := range in.entries {
		if e.Type != fuseutil.DT_Unknown {
			if _, ok := childNames[e.Name]; ok {
				panic(fmt.Sprintf("Duplicate name: %s", e.Name))
			}

			childNames[e.Name] = struct{}{}
		}
	}

	// INVARIANT: If !isFile(), len(contents) == 0
	if !in.isFile() && len(in.contents) != 0 {
		panic(fmt.Sprintf("Unexpected length: %d", len(in.contents)))
	}

	// INVARIANT: If !isSymlink(), len(target) == 0
	if !in.isSymlink() && len(in.target) != 0 {
		panic(fmt.Sprintf("Unexpected target length: %d", len(in.target)))
	}

	return
}

// LOCKS_REQUIRED(in.mu)
func (in *inode) isDir() bool {
	return in.attrs.Mode&os.ModeDir != 0
}

// LOCKS_REQUIRED(in.mu)
func (in *inode) isSymlink() bool {
	return in.attrs.Mode&os.ModeSymlink != 0
}

// LOCKS_REQUIRED(in.mu)
func (in *inode) isFile() bool {
	return !(in.isDir() || in.isSymlink())
}

// Return the index of the child within in.entries, if it exists.
//
// REQUIRES: in.dir
// LOCKS_REQUIRED(in.mu)
func (in *inode) findChild(name string) (i int, ok bool) {
	if !in.isDir() {
		panic("findChild called on non-directory.")
	}

	var e fuseutil.Dirent
	for i, e = range in.entries {
		if e.Name == name {
			ok = true
			return
		}
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Public methods
////////////////////////////////////////////////////////////////////////

// Return the number of children of the directory.
//
// REQUIRES: in.isDir()
// LOCKS_REQUIRED(in.mu)
func (in *inode) Len() (n int) {
	for _, e := range in.entries {
		if e.Type != fuseutil.DT_Unknown {
			n++
		}
	}

	return
}

// Find an entry for the given child name and return its inode ID.
//
// REQUIRES: in.isDir()
// LOCKS_REQUIRED(in.mu)
func (in *inode) LookUpChild(name string) (id fuseops.InodeID, ok bool) {
	index, ok := in.findChild(name)
	if ok {
		id = in.entries[index].Inode
	}

	return
}

// Add an entry for a child.
//
// REQUIRES: in.isDir()
// REQUIRES: dt != fuseutil.DT_Unknown
// LOCKS_REQUIRED(in.mu)
func (in *inode) AddChild(
	id fuseops.InodeID,
	name string,
	dt fuseutil.DirentType) {
	var index int

	// Update the modification time.
	in.attrs.Mtime = in.clock.Now()

	// No matter where we place the entry, make sure it has the correct Offset
	// field.
	defer func() {
		in.entries[index].Offset = fuseops.DirOffset(index + 1)
	}()

	// Set up the entry.
	e := fuseutil.Dirent{
		Inode: id,
		Name:  name,
		Type:  dt,
	}

	// Look for a gap in which we can insert it.
	for index = range in.entries {
		if in.entries[index].Type == fuseutil.DT_Unknown {
			in.entries[index] = e
			return
		}
	}

	// Append it to the end.
	index = len(in.entries)
	in.entries = append(in.entries, e)
}

// Remove an entry for a child.
//
// REQUIRES: in.isDir()
// REQUIRES: An entry for the given name exists.
// LOCKS_REQUIRED(in.mu)
func (in *inode) RemoveChild(name string) {
	// Update the modification time.
	in.attrs.Mtime = in.clock.Now()

	// Find the entry.
	i, ok := in.findChild(name)
	if !ok {
		panic(fmt.Sprintf("Unknown child: %s", name))
	}

	// Mark it as unused.
	in.entries[i] = fuseutil.Dirent{
		Type:   fuseutil.DT_Unknown,
		Offset: fuseops.DirOffset(i + 1),
	}
}

// Serve a ReadDir request.
//
// REQUIRES: in.isDir()
// LOCKS_REQUIRED(in.mu)
func (in *inode) ReadDir(offset int, size int) (data []byte, err error) {
	if !in.isDir() {
		panic("ReadDir called on non-directory.")
	}

	for i := offset; i < len(in.entries); i++ {
		e := in.entries[i]

		// Skip unused entries.
		if e.Type == fuseutil.DT_Unknown {
			continue
		}

		data = fuseutil.AppendDirent(data, in.entries[i])

		// Trim and stop early if we've exceeded the requested size.
		if len(data) > size {
			data = data[:size]
			break
		}
	}

	return
}

// Read from the file's contents. See documentation for ioutil.ReaderAt.
//
// REQUIRES: in.isFile()
// LOCKS_REQUIRED(in.mu)
func (in *inode) ReadAt(p []byte, off int64) (n int, err error) {
	if !in.isFile() {
		panic("ReadAt called on non-file.")
	}

	// Ensure the offset is in range.
	if off > int64(len(in.contents)) {
		err = io.EOF
		return
	}

	// Read what we can.
	n = copy(p, in.contents[off:])
	if n < len(p) {
		err = io.EOF
	}

	return
}

// Write to the file's contents. See documentation for ioutil.WriterAt.
//
// REQUIRES: in.isFile()
// LOCKS_REQUIRED(in.mu)
func (in *inode) WriteAt(p []byte, off int64) (n int, err error) {
	if !in.isFile() {
		panic("WriteAt called on non-file.")
	}

	// Update the modification time.
	in.attrs.Mtime = in.clock.Now()

	// Ensure that the contents slice is long enough.
	newLen := int(off) + len(p)
	if len(in.contents) < newLen {
		padding := make([]byte, newLen-len(in.contents))
		in.contents = append(in.contents, padding...)
		in.attrs.Size = uint64(newLen)
	}

	// Copy in the data.
	n = copy(in.contents[off:], p)

	// Sanity check.
	if n != len(p) {
		panic(fmt.Sprintf("Unexpected short copy: %v", n))
	}

	return
}

// Update attributes from non-nil parameters.
//
// LOCKS_REQUIRED(in.mu)
func (in *inode) SetAttributes(
	size *uint64,
	mode *os.FileMode,
	mtime *time.Time) {
	// Update the modification time.
	in.attrs.Mtime = in.clock.Now()

	// Truncate?
	if size != nil {
		intSize := int(*size)

		// Update contents.
		if intSize <= len(in.contents) {
			in.contents = in.contents[:intSize]
		} else {
			padding := make([]byte, intSize-len(in.contents))
			in.contents = append(in.contents, padding...)
		}

		// Update attributes.
		in.attrs.Size = *size
	}

	// Change mode?
	if mode != nil {
		in.attrs.Mode = *mode
	}

	// Change mtime?
	if mtime != nil {
		in.attrs.Mtime = *mtime
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/koding/kite"
	"github.com/koding/kite/protocol"
	"github.com/koding/kloud"
)

// Kloud represents a remote kloud instance
type Kloud struct {
	client *kite.Client
}

// Kloud returns a new connected kloud instance. The kloud is ready to use.
// It's connected and will redial if there is any disconnections.
func NewKloud(k *kite.Kite) (*Kloud, error) {
	kontrolQuery := protocol.KontrolQuery{
		Username:    "koding",
		Environment: "vagrant",
		Name:        "kloud",
	}

	timeout := time.After(time.Minute)

	k.Log.Info("Querying for Kloud: %+v", kontrolQuery)
	for {
		select {
		case <-time.Tick(time.Second * 2):
			kites, err := k.GetKites(kontrolQuery)
			if err != nil {
				// still not up, try again until the kite is ready
				continue
			}

			remoteKite := kites[0]

			connected, err := remoteKite.DialForever()
			if err != nil {
				return nil, err
			}

			select {
			case <-connected:
			case <-time.After(time.Minute):
				return nil, kloud.NewError(kloud.ErrNoKiteConnection)
			}

			// Kloud connection is ready now
			return &Kloud{
				client: remoteKite,
			}, nil
		case <-timeout:
			return nil, fmt.Errorf("timeout while connection for kite")
		}
	}
}

// Report reports machine and usage metrics to kloud instance.
func (k *Kloud) Report() error {
	// update information before we send it
	usg.Update()

	fmt.Printf("repoting usage %+v\n", usg)
	_, err := k.client.Tell("report", usg)
	return err
}
<commit_msg>go: updates from Github<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/koding/kite"
	"github.com/koding/kite/protocol"
	"github.com/koding/kloud"
)

// Kloud represents a remote kloud instance
type Kloud struct {
	client *kite.Client
}

// Kloud returns a new connected kloud instance. The kloud is ready to use.
// It's connected and will redial if there is any disconnections.
func NewKloud(k *kite.Kite) (*Kloud, error) {
	kontrolQuery := &protocol.KontrolQuery{
		Username:    "koding",
		Environment: "vagrant",
		Name:        "kloud",
	}

	timeout := time.After(time.Minute)

	k.Log.Info("Querying for Kloud: %+v", kontrolQuery)
	for {
		select {
		case <-time.Tick(time.Second * 2):
			kites, err := k.GetKites(kontrolQuery)
			if err != nil {
				// still not up, try again until the kite is ready
				continue
			}

			remoteKite := kites[0]

			connected, err := remoteKite.DialForever()
			if err != nil {
				return nil, err
			}

			select {
			case <-connected:
			case <-time.After(time.Minute):
				return nil, kloud.NewError(kloud.ErrNoKiteConnection)
			}

			// Kloud connection is ready now
			return &Kloud{
				client: remoteKite,
			}, nil
		case <-timeout:
			return nil, fmt.Errorf("timeout while connection for kite")
		}
	}
}

// Report reports machine and usage metrics to kloud instance.
func (k *Kloud) Report() error {
	// update information before we send it
	usg.Update()

	fmt.Printf("repoting usage %+v\n", usg)
	_, err := k.client.Tell("report", usg)
	return err
}
<|endoftext|>


<commit_before>package core

import (
	"context"
	"sync"

	"v2ray.com/core/common"
	"v2ray.com/core/common/uuid"
)

// Server is an instance of V2Ray. At any time, there must be at most one Server instance running.
// Deprecated. Use Instance directly.
type Server interface {
	common.Runnable
}

// Feature is the interface for V2Ray features. All features must implement this interface.
// All existing features have an implementation in app directory. These features can be replaced by third-party ones.
type Feature interface {
	common.Runnable
}

// Instance combines all functionalities in V2Ray.
type Instance struct {
	dnsClient     syncDNSClient
	policyManager syncPolicyManager
	dispatcher    syncDispatcher
	router        syncRouter
	ihm           syncInboundHandlerManager
	ohm           syncOutboundHandlerManager

	access   sync.Mutex
	features []Feature
	id       uuid.UUID
	running  bool
}

// New returns a new V2Ray instance based on given configuration.
// The instance is not started at this point.
// To make sure V2Ray instance works properly, the config must contain one Dispatcher, one InboundHandlerManager and one OutboundHandlerManager. Other features are optional.
func New(config *Config) (*Instance, error) {
	var server = &Instance{
		id: uuid.New(),
	}

	if err := config.Transport.Apply(); err != nil {
		return nil, err
	}

	for _, appSettings := range config.App {
		settings, err := appSettings.GetInstance()
		if err != nil {
			return nil, err
		}
		if _, err := server.CreateObject(settings); err != nil {
			return nil, err
		}
	}

	for _, inbound := range config.Inbound {
		rawHandler, err := server.CreateObject(inbound)
		if err != nil {
			return nil, err
		}
		handler, ok := rawHandler.(InboundHandler)
		if !ok {
			return nil, newError("not an InboundHandler")
		}
		if err := server.InboundHandlerManager().AddHandler(context.Background(), handler); err != nil {
			return nil, err
		}
	}

	for _, outbound := range config.Outbound {
		rawHandler, err := server.CreateObject(outbound)
		if err != nil {
			return nil, err
		}
		handler, ok := rawHandler.(OutboundHandler)
		if !ok {
			return nil, newError("not an OutboundHandler")
		}
		if err := server.OutboundHandlerManager().AddHandler(context.Background(), handler); err != nil {
			return nil, err
		}
	}

	return server, nil
}

func (s *Instance) CreateObject(config interface{}) (interface{}, error) {
	ctx := context.WithValue(context.Background(), v2rayKey, s)
	return common.CreateObject(ctx, config)
}

// ID returns an unique ID for this V2Ray instance.
func (s *Instance) ID() uuid.UUID {
	return s.id
}

// Close shutdown the V2Ray instance.
func (s *Instance) Close() error {
	s.access.Lock()
	defer s.access.Unlock()

	s.running = false
	for _, f := range s.allFeatures() {
		f.Close()
	}

	return nil
}

// Start starts the V2Ray instance, including all registered features. When Start returns error, the state of the instance is unknown.
// A V2Ray instance can be started only once. Upon closing, the instance is not guaranteed to start again.
func (s *Instance) Start() error {
	s.access.Lock()
	defer s.access.Unlock()

	s.running = true
	for _, f := range s.allFeatures() {
		if err := f.Start(); err != nil {
			return err
		}
	}

	newError("V2Ray ", Version(), " started").AtWarning().WriteToLog()

	return nil
}

// RegisterFeature registers the given feature into V2Ray.
// If feature is one of the following types, the corressponding feature in this Instance
// will be replaced: DNSClient, PolicyManager, Router, Dispatcher, InboundHandlerManager, OutboundHandlerManager.
func (s *Instance) RegisterFeature(feature interface{}, instance Feature) error {
	running := false

	switch feature.(type) {
	case DNSClient, *DNSClient:
		s.dnsClient.Set(instance.(DNSClient))
	case PolicyManager, *PolicyManager:
		s.policyManager.Set(instance.(PolicyManager))
	case Router, *Router:
		s.router.Set(instance.(Router))
	case Dispatcher, *Dispatcher:
		s.dispatcher.Set(instance.(Dispatcher))
	case InboundHandlerManager, *InboundHandlerManager:
		s.ihm.Set(instance.(InboundHandlerManager))
	case OutboundHandlerManager, *OutboundHandlerManager:
		s.ohm.Set(instance.(OutboundHandlerManager))
	default:
		s.access.Lock()
		s.features = append(s.features, instance)
		running = s.running
		s.access.Unlock()
	}

	if running {
		return instance.Start()
	}
	return nil
}

func (s *Instance) allFeatures() []Feature {
	return append([]Feature{s.DNSClient(), s.PolicyManager(), s.Dispatcher(), s.Router(), s.InboundHandlerManager(), s.OutboundHandlerManager()}, s.features...)
}

// GetFeature returns a feature that was registered in this Instance. Nil if not found.
// The returned Feature must implement common.HasType and whose type equals the given feature type.
func (s *Instance) GetFeature(featureType interface{}) Feature {
	for _, f := range s.features {
		if hasType, ok := f.(common.HasType); ok {
			if hasType.Type() == featureType {
				return f
			}
		}
	}
	return nil
}

// DNSClient returns the DNSClient used by this Instance. The returned DNSClient is always functional.
func (s *Instance) DNSClient() DNSClient {
	return &(s.dnsClient)
}

// PolicyManager returns the PolicyManager used by this Instance. The returned PolicyManager is always functional.
func (s *Instance) PolicyManager() PolicyManager {
	return &(s.policyManager)
}

// Router returns the Router used by this Instance. The returned Router is always functional.
func (s *Instance) Router() Router {
	return &(s.router)
}

// Dispatcher returns the Dispatcher used by this Instance. If Dispatcher was not registered before, the returned value doesn't work, although it is not nil.
func (s *Instance) Dispatcher() Dispatcher {
	return &(s.dispatcher)
}

// InboundHandlerManager returns the InboundHandlerManager used by this Instance. If InboundHandlerManager was not registered before, the returned value doesn't work.
func (s *Instance) InboundHandlerManager() InboundHandlerManager {
	return &(s.ihm)
}

// OutboundHandlerManager returns the OutboundHandlerManager used by this Instance. If OutboundHandlerManager was not registered before, the returned value doesn't work.
func (s *Instance) OutboundHandlerManager() OutboundHandlerManager {
	return &(s.ohm)
}
<commit_msg>fix typo<commit_after>package core

import (
	"context"
	"sync"

	"v2ray.com/core/common"
	"v2ray.com/core/common/uuid"
)

// Server is an instance of V2Ray. At any time, there must be at most one Server instance running.
// Deprecated. Use Instance directly.
type Server interface {
	common.Runnable
}

// Feature is the interface for V2Ray features. All features must implement this interface.
// All existing features have an implementation in app directory. These features can be replaced by third-party ones.
type Feature interface {
	common.Runnable
}

// Instance combines all functionalities in V2Ray.
type Instance struct {
	dnsClient     syncDNSClient
	policyManager syncPolicyManager
	dispatcher    syncDispatcher
	router        syncRouter
	ihm           syncInboundHandlerManager
	ohm           syncOutboundHandlerManager

	access   sync.Mutex
	features []Feature
	id       uuid.UUID
	running  bool
}

// New returns a new V2Ray instance based on given configuration.
// The instance is not started at this point.
// To make sure V2Ray instance works properly, the config must contain one Dispatcher, one InboundHandlerManager and one OutboundHandlerManager. Other features are optional.
func New(config *Config) (*Instance, error) {
	var server = &Instance{
		id: uuid.New(),
	}

	if err := config.Transport.Apply(); err != nil {
		return nil, err
	}

	for _, appSettings := range config.App {
		settings, err := appSettings.GetInstance()
		if err != nil {
			return nil, err
		}
		if _, err := server.CreateObject(settings); err != nil {
			return nil, err
		}
	}

	for _, inbound := range config.Inbound {
		rawHandler, err := server.CreateObject(inbound)
		if err != nil {
			return nil, err
		}
		handler, ok := rawHandler.(InboundHandler)
		if !ok {
			return nil, newError("not an InboundHandler")
		}
		if err := server.InboundHandlerManager().AddHandler(context.Background(), handler); err != nil {
			return nil, err
		}
	}

	for _, outbound := range config.Outbound {
		rawHandler, err := server.CreateObject(outbound)
		if err != nil {
			return nil, err
		}
		handler, ok := rawHandler.(OutboundHandler)
		if !ok {
			return nil, newError("not an OutboundHandler")
		}
		if err := server.OutboundHandlerManager().AddHandler(context.Background(), handler); err != nil {
			return nil, err
		}
	}

	return server, nil
}

func (s *Instance) CreateObject(config interface{}) (interface{}, error) {
	ctx := context.WithValue(context.Background(), v2rayKey, s)
	return common.CreateObject(ctx, config)
}

// ID returns an unique ID for this V2Ray instance.
func (s *Instance) ID() uuid.UUID {
	return s.id
}

// Close shutdown the V2Ray instance.
func (s *Instance) Close() error {
	s.access.Lock()
	defer s.access.Unlock()

	s.running = false
	for _, f := range s.allFeatures() {
		f.Close()
	}

	return nil
}

// Start starts the V2Ray instance, including all registered features. When Start returns error, the state of the instance is unknown.
// A V2Ray instance can be started only once. Upon closing, the instance is not guaranteed to start again.
func (s *Instance) Start() error {
	s.access.Lock()
	defer s.access.Unlock()

	s.running = true
	for _, f := range s.allFeatures() {
		if err := f.Start(); err != nil {
			return err
		}
	}

	newError("V2Ray ", Version(), " started").AtWarning().WriteToLog()

	return nil
}

// RegisterFeature registers the given feature into V2Ray.
// If feature is one of the following types, the corresponding feature in this Instance
// will be replaced: DNSClient, PolicyManager, Router, Dispatcher, InboundHandlerManager, OutboundHandlerManager.
func (s *Instance) RegisterFeature(feature interface{}, instance Feature) error {
	running := false

	switch feature.(type) {
	case DNSClient, *DNSClient:
		s.dnsClient.Set(instance.(DNSClient))
	case PolicyManager, *PolicyManager:
		s.policyManager.Set(instance.(PolicyManager))
	case Router, *Router:
		s.router.Set(instance.(Router))
	case Dispatcher, *Dispatcher:
		s.dispatcher.Set(instance.(Dispatcher))
	case InboundHandlerManager, *InboundHandlerManager:
		s.ihm.Set(instance.(InboundHandlerManager))
	case OutboundHandlerManager, *OutboundHandlerManager:
		s.ohm.Set(instance.(OutboundHandlerManager))
	default:
		s.access.Lock()
		s.features = append(s.features, instance)
		running = s.running
		s.access.Unlock()
	}

	if running {
		return instance.Start()
	}
	return nil
}

func (s *Instance) allFeatures() []Feature {
	return append([]Feature{s.DNSClient(), s.PolicyManager(), s.Dispatcher(), s.Router(), s.InboundHandlerManager(), s.OutboundHandlerManager()}, s.features...)
}

// GetFeature returns a feature that was registered in this Instance. Nil if not found.
// The returned Feature must implement common.HasType and whose type equals the given feature type.
func (s *Instance) GetFeature(featureType interface{}) Feature {
	for _, f := range s.features {
		if hasType, ok := f.(common.HasType); ok {
			if hasType.Type() == featureType {
				return f
			}
		}
	}
	return nil
}

// DNSClient returns the DNSClient used by this Instance. The returned DNSClient is always functional.
func (s *Instance) DNSClient() DNSClient {
	return &(s.dnsClient)
}

// PolicyManager returns the PolicyManager used by this Instance. The returned PolicyManager is always functional.
func (s *Instance) PolicyManager() PolicyManager {
	return &(s.policyManager)
}

// Router returns the Router used by this Instance. The returned Router is always functional.
func (s *Instance) Router() Router {
	return &(s.router)
}

// Dispatcher returns the Dispatcher used by this Instance. If Dispatcher was not registered before, the returned value doesn't work, although it is not nil.
func (s *Instance) Dispatcher() Dispatcher {
	return &(s.dispatcher)
}

// InboundHandlerManager returns the InboundHandlerManager used by this Instance. If InboundHandlerManager was not registered before, the returned value doesn't work.
func (s *Instance) InboundHandlerManager() InboundHandlerManager {
	return &(s.ihm)
}

// OutboundHandlerManager returns the OutboundHandlerManager used by this Instance. If OutboundHandlerManager was not registered before, the returned value doesn't work.
func (s *Instance) OutboundHandlerManager() OutboundHandlerManager {
	return &(s.ohm)
}
<|endoftext|>


<commit_before>// kvite is a simple embedded K/V store backed by SQLite
package kvite

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
)

type (
	// DB is a wrapper around the underlying SQLite database.
	DB struct {
		db *sql.DB
	}

	// Tx wraps most interactions with the datastore.
	Tx struct {
		db      *DB
		tx      *sql.Tx
		managed bool
	}

	//Bucket represents a collection of key/value pairs inside the database.
	Bucket struct {
		name        string
		tx          *Tx
		putQuery    string
		deleteQuery string
		getQuery    string
	}
)

// Open opens a KVite datastore. The returned DB is safe for concurrent use by multiple goroutines.
// It is rarely necessary to close a DB.
func Open(filename string) (*DB, error) {
	db, err := sql.Open("sqlite3", filename)
	if err != nil {
		return nil, err
	}

	return &DB{db: db}, nil
}

// Close closes the database, releasing any open resources.
// It is rare to Close a DB, as the DB handle is meant to be long-lived and shared between many goroutines.
func (db *DB) Close() error {
	return db.db.Close()
}

// Begin starts a transaction.
func (db *DB) Begin() (*Tx, error) {
	tx, err := db.db.Begin()
	if err != nil {
		return nil, err
	}
	t := &Tx{
		db: db,
		tx: tx,
	}
	return t, nil

}

// Transaction executes a function within the context of a  managed transaction.
// If no error is returned from the function then the transaction is committed.
// If an error is returned then the entire transaction is rolled back.
// Rollback and Commit cannot be used inside of the function
func (db *DB) Transaction(fn func(*Tx) error) error {
	tx, err := db.Begin()
	if err != nil {
		return err
	}

	// Make sure the transaction rolls back in the event of a panic.
	defer func() {
		if tx.db != nil {
			tx.Rollback()
		}
	}()

	tx.managed = true
	err = fn(tx)
	tx.managed = false
	if err != nil {
		_ = tx.Rollback()
		return err
	}

	return tx.Commit()
}

// Commit commits the transaction.
func (tx *Tx) Commit() error {
	if tx.managed {
		return errors.New("managed tx commit not allowed")
	}
	if tx.db == nil {
		// should we return an error here?
		return nil
	}

	err := tx.tx.Commit()
	tx.db = nil
	return err
}

// Rollback aborts the transaction.
func (tx *Tx) Rollback() error {
	if tx.managed {
		return errors.New("managed tx commit not allowed")
	}
	return tx.tx.Rollback()
}

// horrible hack to use a table per bucket and generate sql
func (tx *Tx) newBucket(name string) *Bucket {
	return &Bucket{
		tx:          tx,
		name:        name,
		getQuery:    fmt.Sprintf("SELECT value FROM '%s' where key = ?", name),
		deleteQuery: fmt.Sprintf("DELETE FROM '%s' where key = ?", name),
		putQuery:    fmt.Sprintf("INSERT OR REPLACE INTO '%s' (key, value) values (?,?)", name),
	}
}

//Bucker gets a bucket by name.
func (tx *Tx) Bucket(name string) (*Bucket, error) {
	var foo string

	if err := tx.tx.QueryRow("SELECT name FROM sqlite_master WHERE type=? AND name=?", "table", name).Scan(&foo); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		} else {
			return nil, err
		}
	}
	return tx.newBucket(name), nil
}

// CreateBucket creates a new bucket and returns the new bucket.
// Returns an error if the bucker already exists.
func (tx *Tx) CreateBucket(name string) (*Bucket, error) {
	_, err := tx.tx.Exec(fmt.Sprintf("create TABLE '%s' (key text not null primary key, value blob not null)", name))

	if err != nil {
		return nil, err
	}

	return tx.newBucket(name), nil

}

// CreateBucketIfNotExists creates a new bucket if it doesn't already exist and returns it.
// If the bucket already exists, it will return it.
func (tx *Tx) CreateBucketIfNotExists(name string) (*Bucket, error) {
	b, err := tx.Bucket(name)
	if err != nil {
		if b != nil {
			return nil, err
		}
		return tx.CreateBucket(name)
	}
	return b, nil
}

// Put sets the value for a key in the bucket. If the key exists, then its previous value will be overwritten.
func (b *Bucket) Put(key string, value []byte) error {
	_, err := b.tx.tx.Exec(b.putQuery, key, value)
	if err != nil {
		return err
	}
	return nil
}

// Delete removes a key from the bucket. If the key does not exist then nothing is done and a nil error is returned.
func (b *Bucket) Delete(key string) error {
	_, err := b.tx.tx.Exec(b.deleteQuery, key)
	if err != nil {
		return err
	}
	return nil
}

// Get retrieves the value for a key in the bucket. Returns a nil value if the key does not exist
func (b *Bucket) Get(key string) ([]byte, error) {
	var value []byte

	if err := b.tx.tx.QueryRow(b.getQuery, key).Scan(&value); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		} else {
			return nil, err
		}
	}

	return value, nil
}
<commit_msg>lint cleanup<commit_after>// Package kvite is a simple embedded K/V store backed by SQLite
package kvite

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/mattn/go-sqlite3" //import sqlite3 for driver
)

type (
	// DB is a wrapper around the underlying SQLite database.
	DB struct {
		db *sql.DB
	}

	// Tx wraps most interactions with the datastore.
	Tx struct {
		db      *DB
		tx      *sql.Tx
		managed bool
	}

	//Bucket represents a collection of key/value pairs inside the database.
	Bucket struct {
		name        string
		tx          *Tx
		putQuery    string
		deleteQuery string
		getQuery    string
	}
)

// Open opens a KVite datastore. The returned DB is safe for concurrent use by multiple goroutines.
// It is rarely necessary to close a DB.
func Open(filename string) (*DB, error) {
	db, err := sql.Open("sqlite3", filename)
	if err != nil {
		return nil, err
	}

	return &DB{db: db}, nil
}

// Close closes the database, releasing any open resources.
// It is rare to Close a DB, as the DB handle is meant to be long-lived and shared between many goroutines.
func (db *DB) Close() error {
	return db.db.Close()
}

// Begin starts a transaction.
func (db *DB) Begin() (*Tx, error) {
	tx, err := db.db.Begin()
	if err != nil {
		return nil, err
	}
	t := &Tx{
		db: db,
		tx: tx,
	}
	return t, nil

}

// Transaction executes a function within the context of a  managed transaction.
// If no error is returned from the function then the transaction is committed.
// If an error is returned then the entire transaction is rolled back.
// Rollback and Commit cannot be used inside of the function
func (db *DB) Transaction(fn func(*Tx) error) error {
	tx, err := db.Begin()
	if err != nil {
		return err
	}

	// Make sure the transaction rolls back in the event of a panic.
	defer func() {
		if tx.db != nil {
			tx.Rollback()
		}
	}()

	tx.managed = true
	err = fn(tx)
	tx.managed = false
	if err != nil {
		_ = tx.Rollback()
		return err
	}

	return tx.Commit()
}

// Commit commits the transaction.
func (tx *Tx) Commit() error {
	if tx.managed {
		return errors.New("managed tx commit not allowed")
	}
	if tx.db == nil {
		// should we return an error here?
		return nil
	}

	err := tx.tx.Commit()
	tx.db = nil
	return err
}

// Rollback aborts the transaction.
func (tx *Tx) Rollback() error {
	if tx.managed {
		return errors.New("managed tx commit not allowed")
	}
	return tx.tx.Rollback()
}

// horrible hack to use a table per bucket and generate sql
func (tx *Tx) newBucket(name string) *Bucket {
	return &Bucket{
		tx:          tx,
		name:        name,
		getQuery:    fmt.Sprintf("SELECT value FROM '%s' where key = ?", name),
		deleteQuery: fmt.Sprintf("DELETE FROM '%s' where key = ?", name),
		putQuery:    fmt.Sprintf("INSERT OR REPLACE INTO '%s' (key, value) values (?,?)", name),
	}
}

// Bucket gets a bucket by name.
func (tx *Tx) Bucket(name string) (*Bucket, error) {
	var foo string

	if err := tx.tx.QueryRow("SELECT name FROM sqlite_master WHERE type=? AND name=?", "table", name).Scan(&foo); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}
	return tx.newBucket(name), nil
}

// CreateBucket creates a new bucket and returns the new bucket.
// Returns an error if the bucker already exists.
func (tx *Tx) CreateBucket(name string) (*Bucket, error) {
	_, err := tx.tx.Exec(fmt.Sprintf("create TABLE '%s' (key text not null primary key, value blob not null)", name))

	if err != nil {
		return nil, err
	}

	return tx.newBucket(name), nil

}

// CreateBucketIfNotExists creates a new bucket if it doesn't already exist and returns it.
// If the bucket already exists, it will return it.
func (tx *Tx) CreateBucketIfNotExists(name string) (*Bucket, error) {
	b, err := tx.Bucket(name)
	if err != nil {
		if b != nil {
			return nil, err
		}
		return tx.CreateBucket(name)
	}
	return b, nil
}

// Put sets the value for a key in the bucket. If the key exists, then its previous value will be overwritten.
func (b *Bucket) Put(key string, value []byte) error {
	_, err := b.tx.tx.Exec(b.putQuery, key, value)
	if err != nil {
		return err
	}
	return nil
}

// Delete removes a key from the bucket. If the key does not exist then nothing is done and a nil error is returned.
func (b *Bucket) Delete(key string) error {
	_, err := b.tx.tx.Exec(b.deleteQuery, key)
	if err != nil {
		return err
	}
	return nil
}

// Get retrieves the value for a key in the bucket. Returns a nil value if the key does not exist
func (b *Bucket) Get(key string) ([]byte, error) {
	var value []byte

	if err := b.tx.tx.QueryRow(b.getQuery, key).Scan(&value); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	return value, nil
}
<|endoftext|>


<commit_before>package clui

import (
	xs "github.com/huandu/xstrings"
)

/*
Label is a decorative control that can display text in horizontal
or vertical direction. Other available text features are alignment
and multi-line ability. Text can be single- or multi-colored with
tags inside the text. Multi-colored strings have limited support
of alignment feature: if text is longer than Label width the text
is always left aligned
*/
type Label struct {
	BaseControl
	direction Direction
	multiline bool
}

/*
NewLabel creates a new label.
view - is a View that manages the control
parent - is container that keeps the control. The same View can be a view and a parent at the same time.
w and h - are minimal size of the control.
title - is Label title.
scale - the way of scaling the control when the parent is resized. Use DoNotScale constant if the
control should keep its original size.
*/
func CreateLabel(parent Control, w, h int, title string, scale int) *Label {
	c := new(Label)

	if w == AutoSize {
		w = xs.Len(title)
	}
	if h == AutoSize {
		h = 1
	}

	c.parent = parent

	c.SetTitle(title)
	c.SetSize(w, h)
	c.SetConstraints(w, h)
	c.SetScale(scale)
	c.tabSkip = true

	if parent != nil {
		parent.AddChild(c)
	}

	return c
}

// Direction returns direction of text output: vertical or horizontal
func (l *Label) Direction() Direction {
	return l.direction
}

// SetDirection sets the text output direction
func (l *Label) SetDirection(dir Direction) {
	l.direction = dir
}

func (l *Label) Draw() {
	if l.hidden {
		return
	}

	PushAttributes()
	defer PopAttributes()

	fg, bg := RealColor(l.fg, ColorText), RealColor(l.bg, ColorBack)
	if !l.Enabled() {
		fg = RealColor(l.fg, ColorDisabledText)
	}

	SetTextColor(fg)
	SetBackColor(bg)
	FillRect(l.x, l.y, l.width, l.height, ' ')

	if l.title == "" {
		return
	}

	if l.multiline {
		parser := NewColorParser(l.title, ColorWhite, ColorBlack)
		elem := parser.NextElement()
		xx, yy := l.x, l.y
		for elem.Type != ElemEndOfText {
			if xx >= l.x+l.width || yy >= l.y+l.height {
				break
			}

			if elem.Type == ElemLineBreak {
				xx = l.x
				yy += 1
			} else if elem.Type == ElemPrintable {
				SetTextColor(elem.Fg)
				SetBackColor(elem.Bg)
				putCharUnsafe(xx, yy, elem.Ch)

				if l.direction == Horizontal {
					xx += 1
					if xx >= l.x+l.width {
						xx = l.x
						yy += 1
					}
				} else {
					yy += 1
					if yy >= l.y+l.height {
						yy = l.y
						xx += 1
					}
				}
			}

			elem = parser.NextElement()
		}
	} else {
		if l.direction == Horizontal {
			shift, str := AlignColorizedText(l.title, l.width, l.align)
			DrawText(l.x+shift, l.y, str)
		} else {
			shift, str := AlignColorizedText(l.title, l.height, l.align)
			DrawTextVertical(l.x, l.y+shift, str)
		}
	}
}

// Multiline returns if text is displayed on several lines if the
// label title is longer than label width or title contains
// line breaks
func (l *Label) Multiline() bool {
	return l.multiline
}

// SetMultiline sets if the label should output text as one line
// or automatically display it in several lines
func (l *Label) SetMultiline(multi bool) {
	l.multiline = multi
}
<commit_msg>label: multiline<commit_after>package clui

import (
	xs "github.com/huandu/xstrings"
)

/*
Label is a decorative control that can display text in horizontal
or vertical direction. Other available text features are alignment
and multi-line ability. Text can be single- or multi-colored with
tags inside the text. Multi-colored strings have limited support
of alignment feature: if text is longer than Label width the text
is always left aligned
*/
type Label struct {
	BaseControl
	direction Direction
	multiline bool
}

/*
NewLabel creates a new label.
view - is a View that manages the control
parent - is container that keeps the control. The same View can be a view and a parent at the same time.
w and h - are minimal size of the control.
title - is Label title.
scale - the way of scaling the control when the parent is resized. Use DoNotScale constant if the
control should keep its original size.
*/
func CreateLabel(parent Control, w, h int, title string, scale int) *Label {
	c := new(Label)

	if w == AutoSize {
		w = xs.Len(title)
	}
	if h == AutoSize {
		h = 1
	}

	c.parent = parent

	c.SetTitle(title)
	c.SetSize(w, h)
	c.SetConstraints(w, h)
	c.SetScale(scale)
	c.tabSkip = true

	if parent != nil {
		parent.AddChild(c)
	}

	return c
}

// Direction returns direction of text output: vertical or horizontal
func (l *Label) Direction() Direction {
	return l.direction
}

// SetDirection sets the text output direction
func (l *Label) SetDirection(dir Direction) {
	l.direction = dir
}

func (l *Label) Draw() {
	if l.hidden {
		return
	}

	PushAttributes()
	defer PopAttributes()

	fg, bg := RealColor(l.fg, ColorText), RealColor(l.bg, ColorBack)
	if !l.Enabled() {
		fg = RealColor(l.fg, ColorDisabledText)
	}

	SetTextColor(fg)
	SetBackColor(bg)
	FillRect(l.x, l.y, l.width, l.height, ' ')

	if l.title == "" {
		return
	}

	if l.multiline {
		parser := NewColorParser(l.title, fg, bg)
		elem := parser.NextElement()
		xx, yy := l.x, l.y
		for elem.Type != ElemEndOfText {
			if xx >= l.x+l.width || yy >= l.y+l.height {
				break
			}

			if elem.Type == ElemLineBreak {
				xx = l.x
				yy += 1
			} else if elem.Type == ElemPrintable {
				SetTextColor(elem.Fg)
				SetBackColor(elem.Bg)
				putCharUnsafe(xx, yy, elem.Ch)

				if l.direction == Horizontal {
					xx += 1
					if xx >= l.x+l.width {
						xx = l.x
						yy += 1
					}
				} else {
					yy += 1
					if yy >= l.y+l.height {
						yy = l.y
						xx += 1
					}
				}
			}

			elem = parser.NextElement()
		}
	} else {
		if l.direction == Horizontal {
			shift, str := AlignColorizedText(l.title, l.width, l.align)
			DrawText(l.x+shift, l.y, str)
		} else {
			shift, str := AlignColorizedText(l.title, l.height, l.align)
			DrawTextVertical(l.x, l.y+shift, str)
		}
	}
}

// Multiline returns if text is displayed on several lines if the
// label title is longer than label width or title contains
// line breaks
func (l *Label) Multiline() bool {
	return l.multiline
}

// SetMultiline sets if the label should output text as one line
// or automatically display it in several lines
func (l *Label) SetMultiline(multi bool) {
	l.multiline = multi
}
<|endoftext|>


<commit_before>package logutils

import (
	"bytes"
	"io"
	"sync"
)

type LogLevel string

// LevelFilter is an io.Writer that can be used with a logger that
// will filter out log messages that aren't at least a certain level.
//
// Once the filter is in use somewhere, it is not safe to modify
// the structure.
type LevelFilter struct {
	// Levels is the list of log levels, in increasing order of
	// severity. Example might be: {"DEBUG", "WARN", "ERROR"}.
	Levels []LogLevel

	// MinLevel is the minimum level allowed through
	MinLevel LogLevel

	// The underlying io.Writer where log messages that pass the filter
	// will be set.
	Writer io.Writer

	badLevels map[LogLevel]struct{}
	once      sync.Once
}

// Check will check a given line if it would be included in the level
// filter.
func (f *LevelFilter) Check(line []byte) bool {
	// Check for a log level
	var level LogLevel
	x := bytes.IndexByte(line, '[')
	if x >= 0 {
		y := bytes.IndexByte(line[x:], ']')
		if y >= 0 {
			level = LogLevel(line[x+1 : y])
		}
	}

	_, ok := f.badLevels[level]
	return !ok
}

func (f *LevelFilter) Write(p []byte) (n int, err error) {
	f.once.Do(f.init)

	// Note in general that io.Writer can receive any byte sequence
	// to write, but the "log" package always guarantees that we only
	// get a single line. We use that as a slight optimization within
	// this method, assuming we're dealing with a single, complete line
	// of log data.

	if !f.Check(p) {
		return len(p), nil
	}

	return f.Writer.Write(p)
}

func (f *LevelFilter) init() {
	f.badLevels = make(map[LogLevel]struct{})
	for _, level := range f.Levels {
		if level == f.MinLevel {
			break
		}

		f.badLevels[level] = struct{}{}
	}
}
<commit_msg>move init into Check<commit_after>package logutils

import (
	"bytes"
	"io"
	"sync"
)

type LogLevel string

// LevelFilter is an io.Writer that can be used with a logger that
// will filter out log messages that aren't at least a certain level.
//
// Once the filter is in use somewhere, it is not safe to modify
// the structure.
type LevelFilter struct {
	// Levels is the list of log levels, in increasing order of
	// severity. Example might be: {"DEBUG", "WARN", "ERROR"}.
	Levels []LogLevel

	// MinLevel is the minimum level allowed through
	MinLevel LogLevel

	// The underlying io.Writer where log messages that pass the filter
	// will be set.
	Writer io.Writer

	badLevels map[LogLevel]struct{}
	once      sync.Once
}

// Check will check a given line if it would be included in the level
// filter.
func (f *LevelFilter) Check(line []byte) bool {
	f.once.Do(f.init)

	// Check for a log level
	var level LogLevel
	x := bytes.IndexByte(line, '[')
	if x >= 0 {
		y := bytes.IndexByte(line[x:], ']')
		if y >= 0 {
			level = LogLevel(line[x+1 : y])
		}
	}

	_, ok := f.badLevels[level]
	return !ok
}

func (f *LevelFilter) Write(p []byte) (n int, err error) {
	// Note in general that io.Writer can receive any byte sequence
	// to write, but the "log" package always guarantees that we only
	// get a single line. We use that as a slight optimization within
	// this method, assuming we're dealing with a single, complete line
	// of log data.

	if !f.Check(p) {
		return len(p), nil
	}

	return f.Writer.Write(p)
}

func (f *LevelFilter) init() {
	f.badLevels = make(map[LogLevel]struct{})
	for _, level := range f.Levels {
		if level == f.MinLevel {
			break
		}

		f.badLevels[level] = struct{}{}
	}
}
<|endoftext|>


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

/*  Filename:    lexer.go
 *  Author:      Bryan Matsuo <bryan.matsuo [at] gmail.com>
 *  Created:     2012-11-02 22:10:59.782356 -0700 PDT
 *  Description: Main source file in go-lexer
 */

// Package lexer provides a simple scanner and types for handrolling lexers.
// The implementation is based on Rob Pike's talk.
//	  	http://www.youtube.com/watch?v=HxaD_trXwRE
package lexer

import (
	"container/list"
	"fmt"
	"math"
	"strings"
	"unicode"
	"unicode/utf8"
)

const EOF rune = 0x04

// A state function that scans runes from the lexer's input and emits items.
// The state functions are responsible for emitting ItemEOF.
type StateFn func(*Lexer) StateFn

type Lexer struct {
	input string     // string being scanned
	start int        // start position for the current lexeme
	pos   int        // current position
	width int        // length of the last rune read
	last  rune       // the last rune read
	state StateFn    // the current state
	items *list.List // Buffer of lexed items
}

// Create a new lexer. Must be given a non-nil state.
func New(start StateFn, input string) *Lexer {
	if start == nil {
		panic("nil start state")
	}
	return &Lexer{
		input: input,
		items: list.New(),
	}
}

// The starting position of the current item.
func (l *Lexer) Start() int {
	return l.start
}

// The position following the last read rune.
func (l *Lexer) Pos() int {
	return l.pos
}

// The contents of the item currently being lexed.
func (l *Lexer) Current() string {
	return l.input[l.start:l.pos]
}

// The last rune read from the input stream.
func (l *Lexer) Last() (r rune, width int) {
	return l.last, l.width
}

// Add one rune of the input stream to the current lexeme.
func (l *Lexer) Advance() (rune, int) {
	if l.pos >= len(l.input) {
		l.width = 0
		return EOF, l.width
	}
	l.last, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
	l.pos += l.width
	return l.last, l.width
}

// Remove the last rune from the current lexeme and place back in the stream.
func (l *Lexer) Backup() {
	l.pos -= l.width
}

// Returns the next rune in the input stream without adding it to the current lexeme.
func (l *Lexer) Peek() (r rune, width int) {
	r, width = l.Advance()
	l.Backup()
	return
}

// Throw away the current lexeme (do not call Emit).
func (l *Lexer) Ignore() {
	l.start = l.pos
}

// Advance the lexer only if the next rune is in the valid string.
func (l *Lexer) Accept(valid string) (ok bool) {
	r, _ := l.Advance()
	ok = strings.IndexRune(valid, r) >= 0
	if !ok {
		l.Backup()
	}
	return
}

// Advance the lexer as long the next rune is in the valid string.
func (l *Lexer) AcceptRun(valid string) (n int) {
	for l.Accept(valid) {
		n++
	}
	return
}

// Like Advance but uses a range table for efficiency.
func (l *Lexer) AcceptRange(rangeTab *unicode.RangeTable) (ok bool) {
	r, _ := l.Advance()
	ok = unicode.Is(rangeTab, r)
	if !ok {
		l.Backup()
	}
	return
}

// Like AdvanceRun but uses a range table for efficiency.
func (l *Lexer) AcceptRangeRun(rangeTab *unicode.RangeTable) (n int) {
	for l.AcceptRange(rangeTab) {
		n++
	}
	return
}

// Emit an error from the Lexer.
func (l *Lexer) Errorf(format string, args ...interface{}) StateFn {
	l.enqueue(&Item{
		ItemError,
		l.start,
		fmt.Sprintf(format, args...),
	})
	return nil
}

// Emit the current value as an Item with the specified type.
func (l *Lexer) Emit(t ItemType) {
	l.enqueue(&Item{
		t,
		l.start,
		l.input[l.start:l.pos],
	})
	l.start = l.pos
}

// The method by which items are extracted from the input.
// Returns nil if the lexer has entered a nil state.
func (l *Lexer) Next() (i *Item) {
	for {
		if head := l.dequeue(); head != nil {
			return head
		}
		if l.state == nil {
			return nil
		}
		l.state = l.state(l)
	}
	panic("unreachable")
}

func (l *Lexer) enqueue(i *Item) {
	l.items.PushBack(i)
}

func (l *Lexer) dequeue() *Item {
	head := l.items.Front()
	if head == nil {
		return nil
	}
	return l.items.Remove(head).(*Item)
}

// A type for all the types of items in the language being lexed.
type ItemType uint16

// Special item types.
const (
	ItemEOF ItemType = math.MaxUint16 - iota
	ItemError
)

// An individual scanned item (a lexeme).
type Item struct {
	Type  ItemType
	Pos   int
	Value string
}

func (i *Item) String() string {
	switch i.Type {
	case ItemError:
		return i.Value
	case ItemEOF:
		return "EOF"
	}
	if len(i.Value) > 10 {
		return fmt.Sprintf("%.10q...", i.Value)
	}
	return i.Value
}
<commit_msg>better handling for invalid runes<commit_after>// Copyright 2012, Bryan Matsuo. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*  Filename:    lexer.go
 *  Author:      Bryan Matsuo <bryan.matsuo [at] gmail.com>
 *  Created:     2012-11-02 22:10:59.782356 -0700 PDT
 *  Description: Main source file in go-lexer
 */

// Package lexer provides a simple scanner and types for handrolling lexers.
// The implementation is based on Rob Pike's talk.
//	  	http://www.youtube.com/watch?v=HxaD_trXwRE
package lexer

import (
	"container/list"
	"fmt"
	"math"
	"strings"
	"unicode"
	"unicode/utf8"
)

const EOF rune = 0x04

// A state function that scans runes from the lexer's input and emits items.
// The state functions are responsible for emitting ItemEOF.
type StateFn func(*Lexer) StateFn

// A type for building lexers.
type Lexer struct {
	input string     // string being scanned
	start int        // start position for the current lexeme
	pos   int        // current position
	width int        // length of the last rune read
	last  rune       // the last rune read
	state StateFn    // the current state
	items *list.List // Buffer of lexed items
}

// Create a new lexer. Must be given a non-nil state.
func New(start StateFn, input string) *Lexer {
	if start == nil {
		panic("nil start state")
	}
	return &Lexer{
		input: input,
		items: list.New(),
	}
}

// The starting position of the current item.
func (l *Lexer) Start() int {
	return l.start
}

// The position following the last read rune.
func (l *Lexer) Pos() int {
	return l.pos
}

// The contents of the item currently being lexed.
func (l *Lexer) Current() string {
	return l.input[l.start:l.pos]
}

// The last rune read from the input stream.
func (l *Lexer) Last() (r rune, width int) {
	return l.last, l.width
}

// Add one rune of the input stream to the current lexeme. Invalid UTF-8
// codepoints cause the current call and all subsequent calls to return
// (unicode.RuneError, 1).
func (l *Lexer) Advance() (rune, int) {
	if l.pos >= len(l.input) {
		l.width = 0
		return EOF, l.width
	}
	l.last, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
	if l.last == unicode.RuneError && l.width == 1 {
		return l.last, l.width
	}
	l.pos += l.width
	return l.last, l.width
}

// Remove the last rune from the current lexeme and place back in the stream.
func (l *Lexer) Backup() {
	l.pos -= l.width
}

// Returns the next rune in the input stream without adding it to the current lexeme.
func (l *Lexer) Peek() (r rune, width int) {
	r, width = l.Advance()
	l.Backup()
	return
}

// Throw away the current lexeme (do not call Emit).
func (l *Lexer) Ignore() {
	l.start = l.pos
}

// Advance the lexer only if the next rune is in the valid string.
func (l *Lexer) Accept(valid string) (ok bool) {
	r, _ := l.Advance()
	ok = strings.IndexRune(valid, r) >= 0
	if !ok {
		l.Backup()
	}
	return
}

// Advance the lexer as long the next rune is in the valid string.
func (l *Lexer) AcceptRun(valid string) (n int) {
	for l.Accept(valid) {
		n++
	}
	return
}

// Like Advance but uses a range table for efficiency.
func (l *Lexer) AcceptRange(rangeTab *unicode.RangeTable) (ok bool) {
	r, _ := l.Advance()
	ok = unicode.Is(rangeTab, r)
	if !ok {
		l.Backup()
	}
	return
}

// Like AdvanceRun but uses a range table for efficiency.
func (l *Lexer) AcceptRangeRun(rangeTab *unicode.RangeTable) (n int) {
	for l.AcceptRange(rangeTab) {
		n++
	}
	return
}

// Emit an error from the Lexer.
func (l *Lexer) Errorf(format string, args ...interface{}) StateFn {
	l.enqueue(&Item{
		ItemError,
		l.start,
		fmt.Sprintf(format, args...),
	})
	return nil
}

// Emit the current value as an Item with the specified type.
func (l *Lexer) Emit(t ItemType) {
	l.enqueue(&Item{
		t,
		l.start,
		l.input[l.start:l.pos],
	})
	l.start = l.pos
}

// The method by which items are extracted from the input.
// Returns nil if the lexer has entered a nil state.
func (l *Lexer) Next() (i *Item) {
	for {
		if head := l.dequeue(); head != nil {
			return head
		}
		if l.state == nil {
			return nil
		}
		l.state = l.state(l)
	}
	panic("unreachable")
}

func (l *Lexer) enqueue(i *Item) {
	l.items.PushBack(i)
}

func (l *Lexer) dequeue() *Item {
	head := l.items.Front()
	if head == nil {
		return nil
	}
	return l.items.Remove(head).(*Item)
}

// A type for all the types of items in the language being lexed.
type ItemType uint16

// Special item types.
const (
	ItemEOF ItemType = math.MaxUint16 - iota
	ItemError
)

// An individual scanned item (a lexeme).
type Item struct {
	Type  ItemType
	Pos   int
	Value string
}

func (i *Item) String() string {
	switch i.Type {
	case ItemError:
		return i.Value
	case ItemEOF:
		return "EOF"
	}
	if len(i.Value) > 10 {
		return fmt.Sprintf("%.10q...", i.Value)
	}
	return i.Value
}
<|endoftext|>


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

// This file contains OS-specific constants and types that work on OS X (tested
// on version 10.6.8).

package serial

import "io"
import "os"
import "unsafe"

// termios types
type cc_t byte
type speed_t uint64
type tcflag_t uint64

// sys/termios.h
const (
	B9600 = 9600
	B14400 = 14400
	B19200 = 19200

	CS5 = 0x00000000
	CS6 = 0x00000100
	CS7 = 0x00000200
	CS8 = 0x00000300
	CLOCAL = 0x00008000
	CREAD = 0x00000800
	IGNPAR = 0x00000004

	NCCS = 20;

	VMIN = tcflag_t(16);
	VTIME = tcflag_t(17);
)

// sys/ttycom.h
const (
	TIOCGETA = 1078490131
	TIOCSETA = 2152231956
)

// sys/termios.h
type termios struct {
	c_iflag tcflag_t
	c_oflag tcflag_t
	c_cflag tcflag_t
	c_lflag tcflag_t
	c_cc [NCCS]cc_t
	c_ispeed speed_t
	c_ospeed speed_t
}

// setTermios updates the termios struct associated with a serial port file
// descriptor. This sets appropriate options for how the OS interacts with the
// port.
func setTermios(fd syscall.Handle, src *termios) os.Error {
	// Make the ioctl syscall that sets the termios struct.
	r1, _, errno :=
		syscall.Syscall(
			syscall.SYS_IOCTL,
			uintptr(fd),
			uintptr(TIOCSETA),
			uintptr(unsafe.Pointer(src)))

	// Did the syscall return an error?
	if err := os.NewSyscallError("SYS_IOCTL", int(errno)); err != nil {
		return err
	}

	// Just in case, check the return value as well.
	if r1 != 0 {
		return os.NewError("Unknown error from SYS_IOCTL.")
	}

	return nil
}

func openInternal(options OpenOptions) (io.ReadWriteCloser, os.Error) {
	return nil, os.NewError("Not implemented.")
}

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

// This file contains OS-specific constants and types that work on OS X (tested
// on version 10.6.8).

package serial

import "io"
import "os"
import "unsafe"

// termios types
type cc_t byte
type speed_t uint64
type tcflag_t uint64

// sys/termios.h
const (
	B9600 = 9600
	B14400 = 14400
	B19200 = 19200

	CS5 = 0x00000000
	CS6 = 0x00000100
	CS7 = 0x00000200
	CS8 = 0x00000300
	CLOCAL = 0x00008000
	CREAD = 0x00000800
	IGNPAR = 0x00000004

	NCCS = 20;

	VMIN = tcflag_t(16);
	VTIME = tcflag_t(17);
)

// sys/ttycom.h
const (
	TIOCGETA = 1078490131
	TIOCSETA = 2152231956
)

// sys/termios.h
type termios struct {
	c_iflag tcflag_t
	c_oflag tcflag_t
	c_cflag tcflag_t
	c_lflag tcflag_t
	c_cc [NCCS]cc_t
	c_ispeed speed_t
	c_ospeed speed_t
}

// setTermios updates the termios struct associated with a serial port file
// descriptor. This sets appropriate options for how the OS interacts with the
// port.
func setTermios(fd syscall.Handle, src termios) os.Error {
	// Make the ioctl syscall that sets the termios struct.
	r1, _, errno :=
		syscall.Syscall(
			syscall.SYS_IOCTL,
			uintptr(fd),
			uintptr(TIOCSETA),
			uintptr(unsafe.Pointer(&src)))

	// Did the syscall return an error?
	if err := os.NewSyscallError("SYS_IOCTL", int(errno)); err != nil {
		return err
	}

	// Just in case, check the return value as well.
	if r1 != 0 {
		return os.NewError("Unknown error from SYS_IOCTL.")
	}

	return nil
}

func openInternal(options OpenOptions) (io.ReadWriteCloser, os.Error) {
	// Open the serial port in non-blocking mode, since that seems to be required
	// for OS X for some reason (otherwise it just blocks forever).
	file, err :=
		os.OpenFile(
			options.PortName,
			os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK,
			0600)

	if err != nil {
		return nil, err
	}

	// We want to do blocking I/O, so clear the non-blocking flag set above.
	r1, _, errno :=
		syscall.Syscall(
			syscall.SYS_FCNTL,
			uintptr(file.Fd()),
			uintptr(syscall.F_SETFL),
			uintptr(0))

	if err := os.NewSyscallError("SYS_IOCTL", int(errno)); err != nil {
		return err
	}

	if r1 != 0 {
		return os.NewError("Unknown error from SYS_FCNTL.")
	}

	// Set appropriate options.
	terminalOptions := convertOptions(options)

	err = setTermios(file.Fd(), terminalOptions)
	if err != nil {
		return nil, err
	}

	// We're done.
	return file, nil
}

<|endoftext|>


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

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

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

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

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"syscall"
)

var (
	fsTypePath           = ""
	fileModePath         = ""
	readFileContentPath  = ""
	readWriteNewFilePath = ""
)

func init() {
	flag.StringVar(&fsTypePath, "fs_type", "", "Path to print the fs type for")
	flag.StringVar(&fileModePath, "file_mode", "", "Path to print the filemode of")
	flag.StringVar(&readFileContentPath, "file_content", "", "Path to read the file content from")
	flag.StringVar(&readWriteNewFilePath, "rw_new_file", "", "Path to write to and read from")
}

// This program performs some tests on the filesystem as dictated by the
// flags passed by the user.
func main() {
	flag.Parse()

	var (
		err  error
		errs = []error{}
	)

	err = fsType(fsTypePath)
	if err != nil {
		errs = append(errs, err)
	}

	err = readWriteNewFile(readWriteNewFilePath)
	if err != nil {
		errs = append(errs, err)
	}

	err = fileMode(fileModePath)
	if err != nil {
		errs = append(errs, err)
	}

	err = readFileContent(readFileContentPath)
	if err != nil {
		errs = append(errs, err)
	}

	if len(errs) != 0 {
		os.Exit(1)
	}

	os.Exit(0)
}

// Defined by Linux (sys/statfs.h) - the type number for tmpfs mounts.
const linuxTmpfsMagic = 0x01021994

func fsType(path string) error {
	if path == "" {
		return nil
	}

	buf := syscall.Statfs_t{}
	if err := syscall.Statfs(path, &buf); err != nil {
		fmt.Printf("error from statfs(%q): %v", path, err)
		return err
	}

	if buf.Type == linuxTmpfsMagic {
		fmt.Printf("mount type of %q: tmpfs\n", path)
	} else {
		fmt.Printf("mount type of %q: %v\n", path, buf.Type)
	}

	return nil
}

func fileMode(path string) error {
	if path == "" {
		return nil
	}

	fileinfo, err := os.Lstat(path)
	if err != nil {
		fmt.Printf("error from Lstat(%q): %v\n", path, err)
		return err
	}

	fmt.Printf("mode of file %q: %v\n", path, fileinfo.Mode())
	return nil
}

func readFileContent(path string) error {
	if path == "" {
		return nil
	}

	contentBytes, err := ioutil.ReadFile(path)
	if err != nil {
		fmt.Printf("error reading file content for %q: %v\n", path, err)
		return err
	}

	fmt.Printf("content of file %q: %v\n", path, string(contentBytes))

	return nil
}

func readWriteNewFile(path string) error {
	if path == "" {
		return nil
	}

	content := "mount-tester new file\n"
	err := ioutil.WriteFile(path, []byte(content), 0644)
	if err != nil {
		fmt.Printf("error writing new file %q: %v\n", path, err)
		return err
	}

	return readFileContent(path)
}
<commit_msg>Add comments in mt.go<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"syscall"
)

var (
	fsTypePath           = ""
	fileModePath         = ""
	readFileContentPath  = ""
	readWriteNewFilePath = ""
)

func init() {
	flag.StringVar(&fsTypePath, "fs_type", "", "Path to print the fs type for")
	flag.StringVar(&fileModePath, "file_mode", "", "Path to print the filemode of")
	flag.StringVar(&readFileContentPath, "file_content", "", "Path to read the file content from")
	flag.StringVar(&readWriteNewFilePath, "rw_new_file", "", "Path to write to and read from")
}

// This program performs some tests on the filesystem as dictated by the
// flags passed by the user.
func main() {
	flag.Parse()

	var (
		err  error
		errs = []error{}
	)

	// NOTE: the ordering of execution of the various command line
	// flags is intentional and allows a single command to:
	//
	// 1.  Check the fstype of a path
	// 2.  Write a new file within that path
	// 3.  Check that the file's content can be read
	//
	// Changing the ordering of the following code will break tests.

	err = fsType(fsTypePath)
	if err != nil {
		errs = append(errs, err)
	}

	err = readWriteNewFile(readWriteNewFilePath)
	if err != nil {
		errs = append(errs, err)
	}

	err = fileMode(fileModePath)
	if err != nil {
		errs = append(errs, err)
	}

	err = readFileContent(readFileContentPath)
	if err != nil {
		errs = append(errs, err)
	}

	if len(errs) != 0 {
		os.Exit(1)
	}

	os.Exit(0)
}

// Defined by Linux (sys/statfs.h) - the type number for tmpfs mounts.
const linuxTmpfsMagic = 0x01021994

func fsType(path string) error {
	if path == "" {
		return nil
	}

	buf := syscall.Statfs_t{}
	if err := syscall.Statfs(path, &buf); err != nil {
		fmt.Printf("error from statfs(%q): %v", path, err)
		return err
	}

	if buf.Type == linuxTmpfsMagic {
		fmt.Printf("mount type of %q: tmpfs\n", path)
	} else {
		fmt.Printf("mount type of %q: %v\n", path, buf.Type)
	}

	return nil
}

func fileMode(path string) error {
	if path == "" {
		return nil
	}

	fileinfo, err := os.Lstat(path)
	if err != nil {
		fmt.Printf("error from Lstat(%q): %v\n", path, err)
		return err
	}

	fmt.Printf("mode of file %q: %v\n", path, fileinfo.Mode())
	return nil
}

func readFileContent(path string) error {
	if path == "" {
		return nil
	}

	contentBytes, err := ioutil.ReadFile(path)
	if err != nil {
		fmt.Printf("error reading file content for %q: %v\n", path, err)
		return err
	}

	fmt.Printf("content of file %q: %v\n", path, string(contentBytes))

	return nil
}

func readWriteNewFile(path string) error {
	if path == "" {
		return nil
	}

	content := "mount-tester new file\n"
	err := ioutil.WriteFile(path, []byte(content), 0644)
	if err != nil {
		fmt.Printf("error writing new file %q: %v\n", path, err)
		return err
	}

	return readFileContent(path)
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

// Package activities provides the JSON handlers to get gonawin activities.
package activities

import (
	"errors"
	"net/http"

	"appengine"

	"github.com/santiaago/gonawin/extract"
	"github.com/santiaago/gonawin/helpers"
	templateshlp "github.com/santiaago/gonawin/helpers/templates"

	"github.com/santiaago/gonawin/helpers/log"
	mdl "github.com/santiaago/gonawin/models"
)

// Index activity handler, use it to get the activities of a user.
// You can pass a 'count' and a 'page' param to the http.Request to
// filter the activities that you want. default values are 20 and 1
// respectively.
//
func Index(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "GET" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	desc := "Index activity handler:"
	c := appengine.NewContext(r)
	extract := extract.NewContext(c, desc, r)

	count := extract.Count()
	page := extract.Page()

	activities := mdl.FindActivities(c, u, count, page)
	log.Infof(c, "%s activities = %v", desc, activities)

	vm := buildIndexViewModel(activities)

	return templateshlp.RenderJson(w, c, vm)
}

func buildIndexViewModel(activities []*mdl.Activity) []mdl.ActivityJson {
	fieldsToKeep := []string{"ID", "Type", "Verb", "Actor", "Object", "Target", "Published", "UserID"}
	json := make([]mdl.ActivityJson, len(activities))
	helpers.TransformFromArrayOfPointers(&activities, &json, fieldsToKeep)
	return json
}
<commit_msg>rename buildIndexViewModel<commit_after>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

// Package activities provides the JSON handlers to get gonawin activities.
package activities

import (
	"errors"
	"net/http"

	"appengine"

	"github.com/santiaago/gonawin/extract"
	"github.com/santiaago/gonawin/helpers"
	templateshlp "github.com/santiaago/gonawin/helpers/templates"

	"github.com/santiaago/gonawin/helpers/log"
	mdl "github.com/santiaago/gonawin/models"
)

// Index activity handler, use it to get the activities of a user.
// You can pass a 'count' and a 'page' param to the http.Request to
// filter the activities that you want. default values are 20 and 1
// respectively.
//
func Index(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	if r.Method != "GET" {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	desc := "Index activity handler:"
	c := appengine.NewContext(r)
	extract := extract.NewContext(c, desc, r)

	count := extract.Count()
	page := extract.Page()

	activities := mdl.FindActivities(c, u, count, page)
	log.Infof(c, "%s activities = %v", desc, activities)

	vm := buildActivitiesIndexViewModel(activities)

	return templateshlp.RenderJson(w, c, vm)
}

func buildActivitiesIndexViewModel(activities []*mdl.Activity) []mdl.ActivityJson {
	fieldsToKeep := []string{"ID", "Type", "Verb", "Actor", "Object", "Target", "Published", "UserID"}
	json := make([]mdl.ActivityJson, len(activities))
	helpers.TransformFromArrayOfPointers(&activities, &json, fieldsToKeep)
	return json
}
<|endoftext|>


<commit_before>package components

import (
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/erroneousboat/termui"

	"github.com/erroneousboat/slack-term/config"
)

var (
	COLORS = []string{
		"fg-black",
		"fg-red",
		"fg-green",
		"fg-yellow",
		"fg-blue",
		"fg-magenta",
		"fg-cyan",
		"fg-white",
	}
)

type Message struct {
	Time    time.Time
	Name    string
	Content string

	StyleTime string
	StyleName string
	StyleText string

	FormatTime string
}

func (m Message) colorizeName(styleName string) string {
	if strings.Contains(styleName, "colorize") {
		var sum int
		for _, c := range m.Name {
			sum = sum + int(c)
		}

		i := sum % len(COLORS)

		return strings.Replace(m.StyleName, "colorize", COLORS[i], -1)
	}

	return styleName
}

// Chat is the definition of a Chat component
type Chat struct {
	List     *termui.List
	Messages []Message
	Offset   int
}

// CreateChat is the constructor for the Chat struct
func CreateChatComponent(inputHeight int) *Chat {
	chat := &Chat{
		List:   termui.NewList(),
		Offset: 0,
	}

	chat.List.Height = termui.TermHeight() - inputHeight
	chat.List.Overflow = "wrap"

	return chat
}

// Buffer implements interface termui.Bufferer
func (c *Chat) Buffer() termui.Buffer {
	// Build cells. We're building parts of the message individually, or else
	// DefaultTxBuilder will interpret potential markdown usage in a message
	// as well.
	cells := make([]termui.Cell, 0)
	for i, msg := range c.Messages {

		// When msg.Time and msg.Name are empty (in the case of attachments)
		// don't add the time and name parts.
		if (msg.Time != time.Time{} && msg.Name != "") {
			// Time
			cells = append(cells, termui.DefaultTxBuilder.Build(
				fmt.Sprintf(
					"[[%s]](%s) ",
					msg.Time.Format(msg.FormatTime),
					msg.StyleTime,
				),
				termui.ColorDefault, termui.ColorDefault)...,
			)

			// Name
			cells = append(cells, termui.DefaultTxBuilder.Build(
				fmt.Sprintf("[<%s>](%s) ",
					msg.Name,
					msg.colorizeName(msg.StyleName),
				),
				termui.ColorDefault, termui.ColorDefault)...,
			)
		}

		// Hack, in order to get the correct fg and bg attributes. This is
		// because the readAttr function in termui is unexported.
		txCells := termui.DefaultTxBuilder.Build(
			fmt.Sprintf("[.](%s)", msg.StyleText),
			termui.ColorDefault, termui.ColorDefault,
		)

		// Text
		for _, r := range msg.Content {
			cells = append(
				cells,
				termui.Cell{
					Ch: r,
					Fg: txCells[0].Fg,
					Bg: txCells[0].Bg,
				},
			)
		}

		// Add a newline after every message
		if i < len(c.Messages)-1 {
			cells = append(cells, termui.Cell{Ch: '\n'})
		}
	}

	// We will create an array of Line structs, this allows us
	// to more easily render the items in a list. We will range
	// over the cells we've created and create a Line within
	// the bounds of the Chat pane
	type Line struct {
		cells []termui.Cell
	}

	lines := []Line{}
	line := Line{}

	// When we encounter a newline or are at the bounds of the chat view we
	// stop iterating over the cells and add the line to the line array
	x := 0
	for _, cell := range cells {

		// When we encounter a newline we add the line to the array
		if cell.Ch == '\n' {
			lines = append(lines, line)

			// Reset for new line
			line = Line{}
			x = 0
			continue
		}

		if x+cell.Width() > c.List.InnerBounds().Dx() {
			lines = append(lines, line)

			// Reset for new line
			line = Line{}
			x = 0
		}

		line.cells = append(line.cells, cell)
		x++
	}

	// Append the last line to the array when we didn't encounter any
	// newlines or were at the bounds of the chat view
	lines = append(lines, line)

	// We will print lines bottom up, it will loop over the lines
	// backwards and for every line it'll set the cell in that line.
	// Offset is the number which allows us to begin printing the
	// line above the last line.
	buf := c.List.Buffer()
	linesHeight := len(lines)
	paneMinY := c.List.InnerBounds().Min.Y
	paneMaxY := c.List.InnerBounds().Max.Y

	currentY := paneMaxY - 1
	for i := (linesHeight - 1) - c.Offset; i >= 0; i-- {

		if currentY < paneMinY {
			break
		}

		x := c.List.InnerBounds().Min.X
		for _, cell := range lines[i].cells {
			buf.Set(x, currentY, cell)
			x += cell.Width()
		}

		// When we're not at the end of the pane, fill it up
		// with empty characters
		for x < c.List.InnerBounds().Max.X {
			buf.Set(
				x, currentY,
				termui.Cell{
					Ch: ' ',
					Fg: c.List.ItemFgColor,
					Bg: c.List.ItemBgColor,
				},
			)
			x++
		}
		currentY--
	}

	// If the space above currentY is empty we need to fill
	// it up with blank lines, otherwise the List object will
	// render the items top down, and the result will mix.
	for currentY >= paneMinY {
		x := c.List.InnerBounds().Min.X
		for x < c.List.InnerBounds().Max.X {
			buf.Set(
				x, currentY,
				termui.Cell{
					Ch: ' ',
					Fg: c.List.ItemFgColor,
					Bg: c.List.ItemBgColor,
				},
			)
			x++
		}
		currentY--
	}

	return buf
}

// GetHeight implements interface termui.GridBufferer
func (c *Chat) GetHeight() int {
	return c.List.Block.GetHeight()
}

// SetWidth implements interface termui.GridBufferer
func (c *Chat) SetWidth(w int) {
	c.List.SetWidth(w)
}

// SetX implements interface termui.GridBufferer
func (c *Chat) SetX(x int) {
	c.List.SetX(x)
}

// SetY implements interface termui.GridBufferer
func (c *Chat) SetY(y int) {
	c.List.SetY(y)
}

// GetMaxItems return the maximal amount of items can fit in the Chat
// component
func (c *Chat) GetMaxItems() int {
	return c.List.InnerBounds().Max.Y - c.List.InnerBounds().Min.Y
}

// SetMessages will put the provided messages into the Messages field of the
// Chat view
func (c *Chat) SetMessages(messages []Message) {
	// Reset offset first, when scrolling in view and changing channels we
	// want the offset to be 0 when loading new messages
	c.Offset = 0
	c.Messages = messages
}

// AddMessage adds a single message to Messages
func (c *Chat) AddMessage(message Message) {
	c.Messages = append(c.Messages, message)
}

// ClearMessages clear the List.Items
func (c *Chat) ClearMessages() {
	c.List.Items = []string{}
}

// ScrollUp will render the chat messages based on the Offset of the Chat
// pane.
//
// Offset is 0 when scrolled down. (we loop backwards over the array, so we
// start with rendering last item in the list at the maximum y of the Chat
// pane). Increasing the Offset will thus result in substracting the offset
// from the len(Chat.List.Items).
func (c *Chat) ScrollUp() {
	c.Offset = c.Offset + 10

	// Protect overscrolling
	if c.Offset > len(c.List.Items) {
		c.Offset = len(c.List.Items)
	}
}

// ScrollDown will render the chat messages based on the Offset of the Chat
// pane.
//
// Offset is 0 when scrolled down. (we loop backwards over the array, so we
// start with rendering last item in the list at the maximum y of the Chat
// pane). Increasing the Offset will thus result in substracting the offset
// from the len(Chat.List.Items).
func (c *Chat) ScrollDown() {
	c.Offset = c.Offset - 10

	// Protect overscrolling
	if c.Offset < 0 {
		c.Offset = 0
	}
}

// SetBorderLabel will set Label of the Chat pane to the specified string
func (c *Chat) SetBorderLabel(channelName string) {
	c.List.BorderLabel = channelName
}

// Help shows the usage and key bindings in the chat pane
func (c *Chat) Help(cfg *config.Config) {
	help := []string{
		"slack-term - slack client for your terminal",
		"",
		"USAGE:",
		"    slack-term -config [path-to-config]",
		"",
		"KEY BINDINGS:",
		"",
	}

	for mode, mapping := range cfg.KeyMap {
		help = append(help, fmt.Sprintf("    %s", strings.ToUpper(mode)))
		help = append(help, "")

		var keys []string
		for k := range mapping {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		for _, k := range keys {
			help = append(help, fmt.Sprintf("    %-12s%-15s", k, mapping[k]))
		}
		help = append(help, "")
	}

	c.List.Items = help
}
<commit_msg>Fix character width calculation in chat pane<commit_after>package components

import (
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/erroneousboat/termui"
	runewidth "github.com/mattn/go-runewidth"

	"github.com/erroneousboat/slack-term/config"
)

var (
	COLORS = []string{
		"fg-black",
		"fg-red",
		"fg-green",
		"fg-yellow",
		"fg-blue",
		"fg-magenta",
		"fg-cyan",
		"fg-white",
	}
)

type Message struct {
	Time    time.Time
	Name    string
	Content string

	StyleTime string
	StyleName string
	StyleText string

	FormatTime string
}

func (m Message) colorizeName(styleName string) string {
	if strings.Contains(styleName, "colorize") {
		var sum int
		for _, c := range m.Name {
			sum = sum + int(c)
		}

		i := sum % len(COLORS)

		return strings.Replace(m.StyleName, "colorize", COLORS[i], -1)
	}

	return styleName
}

// Chat is the definition of a Chat component
type Chat struct {
	List     *termui.List
	Messages []Message
	Offset   int
}

// CreateChat is the constructor for the Chat struct
func CreateChatComponent(inputHeight int) *Chat {
	chat := &Chat{
		List:   termui.NewList(),
		Offset: 0,
	}

	chat.List.Height = termui.TermHeight() - inputHeight
	chat.List.Overflow = "wrap"

	return chat
}

// Buffer implements interface termui.Bufferer
func (c *Chat) Buffer() termui.Buffer {
	// Build cells. We're building parts of the message individually, or else
	// DefaultTxBuilder will interpret potential markdown usage in a message
	// as well.
	cells := make([]termui.Cell, 0)
	for i, msg := range c.Messages {

		// When msg.Time and msg.Name are empty (in the case of attachments)
		// don't add the time and name parts.
		if (msg.Time != time.Time{} && msg.Name != "") {
			// Time
			cells = append(cells, termui.DefaultTxBuilder.Build(
				fmt.Sprintf(
					"[[%s]](%s) ",
					msg.Time.Format(msg.FormatTime),
					msg.StyleTime,
				),
				termui.ColorDefault, termui.ColorDefault)...,
			)

			// Name
			cells = append(cells, termui.DefaultTxBuilder.Build(
				fmt.Sprintf("[<%s>](%s) ",
					msg.Name,
					msg.colorizeName(msg.StyleName),
				),
				termui.ColorDefault, termui.ColorDefault)...,
			)
		}

		// Hack, in order to get the correct fg and bg attributes. This is
		// because the readAttr function in termui is unexported.
		txCells := termui.DefaultTxBuilder.Build(
			fmt.Sprintf("[.](%s)", msg.StyleText),
			termui.ColorDefault, termui.ColorDefault,
		)

		// Text
		for _, r := range msg.Content {
			cells = append(
				cells,
				termui.Cell{
					Ch: r,
					Fg: txCells[0].Fg,
					Bg: txCells[0].Bg,
				},
			)
		}

		// Add a newline after every message
		if i < len(c.Messages)-1 {
			cells = append(cells, termui.Cell{Ch: '\n'})
		}
	}

	// We will create an array of Line structs, this allows us
	// to more easily render the items in a list. We will range
	// over the cells we've created and create a Line within
	// the bounds of the Chat pane
	type Line struct {
		cells []termui.Cell
	}

	lines := []Line{}
	line := Line{}

	// When we encounter a newline or, are at the bounds of the chat view we
	// stop iterating over the cells and add the line to the line array
	x := 0
	for _, cell := range cells {

		// When we encounter a newline we add the line to the array
		if cell.Ch == '\n' {
			lines = append(lines, line)

			// Reset for new line
			line = Line{}
			x = 0
			continue
		}

		if x+cell.Width() > c.List.InnerBounds().Dx() {
			lines = append(lines, line)

			// Reset for new line
			line = Line{}
			x = 0
		}

		line.cells = append(line.cells, cell)
		x += cell.Width()
	}

	// Append the last line to the array when we didn't encounter any
	// newlines or were at the bounds of the chat view
	lines = append(lines, line)

	// We will print lines bottom up, it will loop over the lines
	// backwards and for every line it'll set the cell in that line.
	// Offset is the number which allows us to begin printing the
	// line above the last line.
	buf := c.List.Buffer()
	linesHeight := len(lines)
	paneMinY := c.List.InnerBounds().Min.Y
	paneMaxY := c.List.InnerBounds().Max.Y

	currentY := paneMaxY - 1
	for i := (linesHeight - 1) - c.Offset; i >= 0; i-- {

		if currentY < paneMinY {
			break
		}

		x := c.List.InnerBounds().Min.X
		for _, cell := range lines[i].cells {
			buf.Set(x, currentY, cell)
			x += cell.Width()
		}

		// When we're not at the end of the pane, fill it up
		// with empty characters
		for x < c.List.InnerBounds().Max.X {
			buf.Set(
				x, currentY,
				termui.Cell{
					Ch: ' ',
					Fg: c.List.ItemFgColor,
					Bg: c.List.ItemBgColor,
				},
			)
			x += runewidth.RuneWidth(' ')
		}
		currentY--
	}

	// If the space above currentY is empty we need to fill
	// it up with blank lines, otherwise the List object will
	// render the items top down, and the result will mix.
	for currentY >= paneMinY {
		x := c.List.InnerBounds().Min.X
		for x < c.List.InnerBounds().Max.X {
			buf.Set(
				x, currentY,
				termui.Cell{
					Ch: ' ',
					Fg: c.List.ItemFgColor,
					Bg: c.List.ItemBgColor,
				},
			)
			x += runewidth.RuneWidth(' ')
		}
		currentY--
	}

	return buf
}

// GetHeight implements interface termui.GridBufferer
func (c *Chat) GetHeight() int {
	return c.List.Block.GetHeight()
}

// SetWidth implements interface termui.GridBufferer
func (c *Chat) SetWidth(w int) {
	c.List.SetWidth(w)
}

// SetX implements interface termui.GridBufferer
func (c *Chat) SetX(x int) {
	c.List.SetX(x)
}

// SetY implements interface termui.GridBufferer
func (c *Chat) SetY(y int) {
	c.List.SetY(y)
}

// GetMaxItems return the maximal amount of items can fit in the Chat
// component
func (c *Chat) GetMaxItems() int {
	return c.List.InnerBounds().Max.Y - c.List.InnerBounds().Min.Y
}

// SetMessages will put the provided messages into the Messages field of the
// Chat view
func (c *Chat) SetMessages(messages []Message) {
	// Reset offset first, when scrolling in view and changing channels we
	// want the offset to be 0 when loading new messages
	c.Offset = 0
	c.Messages = messages
}

// AddMessage adds a single message to Messages
func (c *Chat) AddMessage(message Message) {
	c.Messages = append(c.Messages, message)
}

// ClearMessages clear the List.Items
func (c *Chat) ClearMessages() {
	c.List.Items = []string{}
}

// ScrollUp will render the chat messages based on the Offset of the Chat
// pane.
//
// Offset is 0 when scrolled down. (we loop backwards over the array, so we
// start with rendering last item in the list at the maximum y of the Chat
// pane). Increasing the Offset will thus result in substracting the offset
// from the len(Chat.List.Items).
func (c *Chat) ScrollUp() {
	c.Offset = c.Offset + 10

	// Protect overscrolling
	if c.Offset > len(c.List.Items) {
		c.Offset = len(c.List.Items)
	}
}

// ScrollDown will render the chat messages based on the Offset of the Chat
// pane.
//
// Offset is 0 when scrolled down. (we loop backwards over the array, so we
// start with rendering last item in the list at the maximum y of the Chat
// pane). Increasing the Offset will thus result in substracting the offset
// from the len(Chat.List.Items).
func (c *Chat) ScrollDown() {
	c.Offset = c.Offset - 10

	// Protect overscrolling
	if c.Offset < 0 {
		c.Offset = 0
	}
}

// SetBorderLabel will set Label of the Chat pane to the specified string
func (c *Chat) SetBorderLabel(channelName string) {
	c.List.BorderLabel = channelName
}

// Help shows the usage and key bindings in the chat pane
func (c *Chat) Help(cfg *config.Config) {
	help := []string{
		"slack-term - slack client for your terminal",
		"",
		"USAGE:",
		"    slack-term -config [path-to-config]",
		"",
		"KEY BINDINGS:",
		"",
	}

	for mode, mapping := range cfg.KeyMap {
		help = append(help, fmt.Sprintf("    %s", strings.ToUpper(mode)))
		help = append(help, "")

		var keys []string
		for k := range mapping {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		for _, k := range keys {
			help = append(help, fmt.Sprintf("    %-12s%-15s", k, mapping[k]))
		}
		help = append(help, "")
	}

	c.List.Items = help
}
<|endoftext|>


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

package vmware

import (
	"os/exec"
)

// VMRun represents a vmrun command.
type VMRun struct {
	vmrunPath string
}

// NewVMRun return the new VmRun.
func NewVMRun() *VMRun {
	vmrunPath, err := exec.LookPath("vmrun")
	if err != nil {
		vmrunPath = VMRunPath // fallback the vmrun binary path
	}

	return &VMRun{
		vmrunPath: vmrunPath,
	}
}

// Usage: vmrun [AUTHENTICATION-FLAGS] COMMAND [PARAMETERS]
//
// AUTHENTICATION-FLAGS
// --------------------
// These must appear before the command and any command parameters.
//
//    -h <hostName>  (not needed for Fusion)
//    -P <hostPort>  (not needed for Fusion)
//    -T <hostType> (ws|fusion)
//    -u <userName in host OS>  (not needed for Fusion)
//    -p <password in host OS>  (not needed for Fusion)
//    -vp <password for encrypted virtual machine>
//    -gu <userName in guest OS>
//    -gp <password in guest OS>
func (v *VMRun) cmd(arg ...string) *exec.Cmd {
	cmd := exec.Command(v.vmrunPath, "-T", "fusion")
	cmd.Args = append(cmd.Args, arg...)

	return cmd
}

// Start start a VM or Team.
func (v *VMRun) Start(gui bool) error {
	cmd := v.cmd("start")

	if gui {
		cmd.Args = append(cmd.Args, "gui")
	} else {
		cmd.Args = append(cmd.Args, "nogui")
	}

	return cmd.Run()
}

// Stop stop a VM or Team.
func (v *VMRun) Stop(force bool) error {
	cmd := v.cmd("stop")

	if force {
		cmd.Args = append(cmd.Args, "hard")
	} else {
		cmd.Args = append(cmd.Args, "soft")
	}

	return cmd.Run()
}

// Reset reset a VM or Team.
func (v *VMRun) Reset(force bool) error {
	cmd := v.cmd("reset")

	if force {
		cmd.Args = append(cmd.Args, "hard")
	} else {
		cmd.Args = append(cmd.Args, "soft")
	}

	return cmd.Run()
}

// Suspend Suspend a VM or Team
func (v *VMRun) Suspend(force bool) error {
	cmd := v.cmd("suspend")

	if force {
		cmd.Args = append(cmd.Args, "hard")
	} else {
		cmd.Args = append(cmd.Args, "soft")
	}

	return cmd.Run()
}

// Pause pause a VM.
func (v *VMRun) Pause() error {
	cmd := v.cmd("unpause")

	return cmd.Run()
}

// Unpause unpause a VM.
func (v *VMRun) Unpause() error {
	cmd := v.cmd("unpause")

	return cmd.Run()
}
<commit_msg>vmrun: remove wrapper commands<commit_after>// Copyright 2017 The go-vm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vmware

import (
	"os/exec"
)

// VMRun represents a vmrun command.
type VMRun struct {
	vmrunPath string
}

// NewVMRun return the new VmRun.
func NewVMRun() *VMRun {
	vmrunPath, err := exec.LookPath("vmrun")
	if err != nil {
		vmrunPath = VMRunPath // fallback the vmrun binary path
	}

	return &VMRun{
		vmrunPath: vmrunPath,
	}
}

// Usage: vmrun [AUTHENTICATION-FLAGS] COMMAND [PARAMETERS]
//
// AUTHENTICATION-FLAGS
// --------------------
// These must appear before the command and any command parameters.
//
//    -h <hostName>  (not needed for Fusion)
//    -P <hostPort>  (not needed for Fusion)
//    -T <hostType> (ws|fusion)
//    -u <userName in host OS>  (not needed for Fusion)
//    -p <password in host OS>  (not needed for Fusion)
//    -vp <password for encrypted virtual machine>
//    -gu <userName in guest OS>
//    -gp <password in guest OS>
func (v *VMRun) Cmd(app string, arg ...string) *exec.Cmd {
	cmd := exec.Command(v.vmrunPath, "-T", app)
	cmd.Args = append(cmd.Args, arg...)

	return cmd
}
<|endoftext|>