<commit_before>// Implementation of MQTT V3.1 encoding and decoding.
//
// See http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html
// for the MQTT protocol specification. This package does not implement the
// semantics of MQTT, but purely the encoding and decoding of its messages.
//
// Decoding Messages:
//
// Use the DecodeOneMessage function to read a Message from an io.Reader, it
// will return a Message value. The function can be implemented using the public
// API of this package if more control is required. For example:
//
//   for {
//     msg, err := mqtt.DecodeOneMessage(conn, nil)
//     if err != nil {
//       // handle err
//     }
//     switch msg := msg.(type) {
//     case *Connect:
//       // ...
//     case *Publish:
//       // ...
//       // etc.
//     }
//   }
//
// Encoding Messages:
//
// Create a message value, and use its Encode method to write it to an
// io.Writer. For example:
//
//   msg := &Publish{
//     Header: {
//       DupFlag: false,
//       QosLevel: QosAtLeastOnce,
//       Retain: false,
//     },
//     TopicName: "a/b",
//     MessageId: 10,
//     Payload: BytesPayload(someBytesData),
//   }
//   if err := msg.Encode(conn); err != nil {
//     // handle err
//   }
//
// Advanced PUBLISH payload handling:
//
// The default behaviour for decoding PUBLISH payloads, and most common way to
// supply payloads for encoding, is the BytesPayload, which is a []byte
// derivative, i.e someData := []byte{1, 2, 3}; BytesPayload(someData) is
// valid.
//
// More complex handling is possible by implementing the Payload interface,
// which can be injected into DecodeOneMessage via the `config` parameter, or
// into an outgoing Publish message via its Payload field.  Potential benefits
// of this include:
//
// * Data can be (un)marshalled directly on a connection, without an unecessary
// round-trip via bytes.Buffer.
//
// * Data can be streamed directly on readers/writers (e.g files, other
// connections, pipes) without the requirement to buffer an entire message
// payload in memory at once.
//
// The limitations of these streaming features are:
//
// * When encoding a payload, the encoded size of the payload must be known and
// declared upfront.
//
// * The payload size (and PUBLISH variable header) can be no more than 256MiB
// minus 1 byte. This is a specified limitation of MQTT v3.1 itself.
package mqtt

import (
	"errors"
	"io"
)

var (
	badMsgTypeError        = errors.New("mqtt: message type is invalid")
	badQosError            = errors.New("mqtt: QoS is invalid")
	badWillQosError        = errors.New("mqtt: will QoS is invalid")
	badLengthEncodingError = errors.New("mqtt: remaining length field exceeded maximum of 4 bytes")
	badReturnCodeError     = errors.New("mqtt: is invalid")
	dataExceedsPacketError = errors.New("mqtt: data exceeds packet length")
	msgTooLongError        = errors.New("mqtt: message is too long")
)

const (
	QosAtMostOnce = QosLevel(iota)
	QosAtLeastOnce
	QosExactlyOnce

	qosFirstInvalid
)

type QosLevel uint8

func (qos QosLevel) IsValid() bool {
	return qos < qosFirstInvalid
}

func (qos QosLevel) HasId() bool {
	return qos == QosAtLeastOnce || qos == QosExactlyOnce
}

const (
	RetCodeAccepted = ReturnCode(iota)
	RetCodeUnacceptableProtocolVersion
	RetCodeIdentifierRejected
	RetCodeServerUnavailable
	RetCodeBadUsernameOrPassword
	RetCodeNotAuthorized

	retCodeFirstInvalid
)

type ReturnCode uint8

func (rc ReturnCode) IsValid() bool {
	return rc >= RetCodeAccepted && rc < retCodeFirstInvalid
}

// DecoderConfig provides configuration for decoding messages.
type DecoderConfig interface {
	// MakePayload returns a Payload for the given Publish message. r is a Reader
	// that will read the payload data, and n is the number of bytes in the
	// payload. The Payload.ReadPayload method is called on the returned payload
	// by the decoding process.
	MakePayload(msg *Publish, r io.Reader, n int) (Payload, error)
}

type DefaultDecoderConfig struct{}

func (c DefaultDecoderConfig) MakePayload(msg *Publish, r io.Reader, n int) (Payload, error) {
	return make(BytesPayload, n), nil
}

// ValueConfig always returns the given Payload when MakePayload is called.
type ValueConfig struct {
	Payload Payload
}

func (c *ValueConfig) MakePayload(msg *Publish, r io.Reader, n int) (Payload, error) {
	return c.Payload, nil
}

// DecodeOneMessage decodes one message from r. config provides specifics on
// how to decode messages, nil indicates that the DefaultDecoderConfig should
// be used.
func DecodeOneMessage(r io.Reader, config DecoderConfig) (msg Message, err error) {
	var hdr Header
	var msgType MessageType
	var packetRemaining int32
	msgType, packetRemaining, err = hdr.Decode(r)

	msg, err = NewMessage(msgType)
	if err != nil {
		return
	}

	if config == nil {
		config = DefaultDecoderConfig{}
	}

	return msg, msg.Decode(r, hdr, packetRemaining, config)
}

// NewMessage creates an instance of a Message value for the given message
// type. An error is returned if msgType is invalid.
func NewMessage(msgType MessageType) (msg Message, err error) {
	switch msgType {
	case MsgConnect:
		msg = new(Connect)
	case MsgConnAck:
		msg = new(ConnAck)
	case MsgPublish:
		msg = new(Publish)
	case MsgPubAck:
		msg = new(PubAck)
	case MsgPubRec:
		msg = new(PubRec)
	case MsgPubRel:
		msg = new(PubRel)
	case MsgPubComp:
		msg = new(PubComp)
	case MsgSubscribe:
		msg = new(Subscribe)
	case MsgUnsubAck:
		msg = new(UnsubAck)
	case MsgSubAck:
		msg = new(SubAck)
	case MsgUnsubscribe:
		msg = new(Unsubscribe)
	case MsgPingReq:
		msg = new(PingReq)
	case MsgPingResp:
		msg = new(PingResp)
	case MsgDisconnect:
		msg = new(Disconnect)
	default:
		return nil, badMsgTypeError
	}

	return
}

// panicErr wraps an error that caused a problem that needs to bail out of the
// API, such that errors can be recovered and returned as errors from the
// public API.
type panicErr struct {
	err error
}

func (p panicErr) Error() string {
	return p.err.Error()
}

func raiseError(err error) {
	panic(panicErr{err})
}

// recoverError recovers any panic in flight and, iff it's an error from
// raiseError, will return the error. Otherwise re-raises the panic value.
// If no panic is in flight, it returns existingErr.
//
// This must be used in combination with a defer in all public API entry
// points where raiseError could be called.
func recoverError(existingErr error, recovered interface{}) error {
	if recovered != nil {
		if pErr, ok := recovered.(panicErr); ok {
			return pErr.err
		} else {
			panic(recovered)
		}
	}
	return existingErr
}
<commit_msg>Clear up a slightly redundant point in the docs.<commit_after>// Implementation of MQTT V3.1 encoding and decoding.
//
// See http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html
// for the MQTT protocol specification. This package does not implement the
// semantics of MQTT, but purely the encoding and decoding of its messages.
//
// Decoding Messages:
//
// Use the DecodeOneMessage function to read a Message from an io.Reader, it
// will return a Message value. The function can be implemented using the public
// API of this package if more control is required. For example:
//
//   for {
//     msg, err := mqtt.DecodeOneMessage(conn, nil)
//     if err != nil {
//       // handle err
//     }
//     switch msg := msg.(type) {
//     case *Connect:
//       // ...
//     case *Publish:
//       // ...
//       // etc.
//     }
//   }
//
// Encoding Messages:
//
// Create a message value, and use its Encode method to write it to an
// io.Writer. For example:
//
//   someData := []byte{1, 2, 3}
//   msg := &Publish{
//     Header: {
//       DupFlag: false,
//       QosLevel: QosAtLeastOnce,
//       Retain: false,
//     },
//     TopicName: "a/b",
//     MessageId: 10,
//     Payload: BytesPayload(someData),
//   }
//   if err := msg.Encode(conn); err != nil {
//     // handle err
//   }
//
// Advanced PUBLISH payload handling:
//
// The default behaviour for decoding PUBLISH payloads, and most common way to
// supply payloads for encoding, is the BytesPayload, which is a []byte
// derivative.
//
// More complex handling is possible by implementing the Payload interface,
// which can be injected into DecodeOneMessage via the `config` parameter, or
// into an outgoing Publish message via its Payload field.  Potential benefits
// of this include:
//
// * Data can be (un)marshalled directly on a connection, without an unecessary
// round-trip via bytes.Buffer.
//
// * Data can be streamed directly on readers/writers (e.g files, other
// connections, pipes) without the requirement to buffer an entire message
// payload in memory at once.
//
// The limitations of these streaming features are:
//
// * When encoding a payload, the encoded size of the payload must be known and
// declared upfront.
//
// * The payload size (and PUBLISH variable header) can be no more than 256MiB
// minus 1 byte. This is a specified limitation of MQTT v3.1 itself.
package mqtt

import (
	"errors"
	"io"
)

var (
	badMsgTypeError        = errors.New("mqtt: message type is invalid")
	badQosError            = errors.New("mqtt: QoS is invalid")
	badWillQosError        = errors.New("mqtt: will QoS is invalid")
	badLengthEncodingError = errors.New("mqtt: remaining length field exceeded maximum of 4 bytes")
	badReturnCodeError     = errors.New("mqtt: is invalid")
	dataExceedsPacketError = errors.New("mqtt: data exceeds packet length")
	msgTooLongError        = errors.New("mqtt: message is too long")
)

const (
	QosAtMostOnce = QosLevel(iota)
	QosAtLeastOnce
	QosExactlyOnce

	qosFirstInvalid
)

type QosLevel uint8

func (qos QosLevel) IsValid() bool {
	return qos < qosFirstInvalid
}

func (qos QosLevel) HasId() bool {
	return qos == QosAtLeastOnce || qos == QosExactlyOnce
}

const (
	RetCodeAccepted = ReturnCode(iota)
	RetCodeUnacceptableProtocolVersion
	RetCodeIdentifierRejected
	RetCodeServerUnavailable
	RetCodeBadUsernameOrPassword
	RetCodeNotAuthorized

	retCodeFirstInvalid
)

type ReturnCode uint8

func (rc ReturnCode) IsValid() bool {
	return rc >= RetCodeAccepted && rc < retCodeFirstInvalid
}

// DecoderConfig provides configuration for decoding messages.
type DecoderConfig interface {
	// MakePayload returns a Payload for the given Publish message. r is a Reader
	// that will read the payload data, and n is the number of bytes in the
	// payload. The Payload.ReadPayload method is called on the returned payload
	// by the decoding process.
	MakePayload(msg *Publish, r io.Reader, n int) (Payload, error)
}

type DefaultDecoderConfig struct{}

func (c DefaultDecoderConfig) MakePayload(msg *Publish, r io.Reader, n int) (Payload, error) {
	return make(BytesPayload, n), nil
}

// ValueConfig always returns the given Payload when MakePayload is called.
type ValueConfig struct {
	Payload Payload
}

func (c *ValueConfig) MakePayload(msg *Publish, r io.Reader, n int) (Payload, error) {
	return c.Payload, nil
}

// DecodeOneMessage decodes one message from r. config provides specifics on
// how to decode messages, nil indicates that the DefaultDecoderConfig should
// be used.
func DecodeOneMessage(r io.Reader, config DecoderConfig) (msg Message, err error) {
	var hdr Header
	var msgType MessageType
	var packetRemaining int32
	msgType, packetRemaining, err = hdr.Decode(r)

	msg, err = NewMessage(msgType)
	if err != nil {
		return
	}

	if config == nil {
		config = DefaultDecoderConfig{}
	}

	return msg, msg.Decode(r, hdr, packetRemaining, config)
}

// NewMessage creates an instance of a Message value for the given message
// type. An error is returned if msgType is invalid.
func NewMessage(msgType MessageType) (msg Message, err error) {
	switch msgType {
	case MsgConnect:
		msg = new(Connect)
	case MsgConnAck:
		msg = new(ConnAck)
	case MsgPublish:
		msg = new(Publish)
	case MsgPubAck:
		msg = new(PubAck)
	case MsgPubRec:
		msg = new(PubRec)
	case MsgPubRel:
		msg = new(PubRel)
	case MsgPubComp:
		msg = new(PubComp)
	case MsgSubscribe:
		msg = new(Subscribe)
	case MsgUnsubAck:
		msg = new(UnsubAck)
	case MsgSubAck:
		msg = new(SubAck)
	case MsgUnsubscribe:
		msg = new(Unsubscribe)
	case MsgPingReq:
		msg = new(PingReq)
	case MsgPingResp:
		msg = new(PingResp)
	case MsgDisconnect:
		msg = new(Disconnect)
	default:
		return nil, badMsgTypeError
	}

	return
}

// panicErr wraps an error that caused a problem that needs to bail out of the
// API, such that errors can be recovered and returned as errors from the
// public API.
type panicErr struct {
	err error
}

func (p panicErr) Error() string {
	return p.err.Error()
}

func raiseError(err error) {
	panic(panicErr{err})
}

// recoverError recovers any panic in flight and, iff it's an error from
// raiseError, will return the error. Otherwise re-raises the panic value.
// If no panic is in flight, it returns existingErr.
//
// This must be used in combination with a defer in all public API entry
// points where raiseError could be called.
func recoverError(existingErr error, recovered interface{}) error {
	if recovered != nil {
		if pErr, ok := recovered.(panicErr); ok {
			return pErr.err
		} else {
			panic(recovered)
		}
	}
	return existingErr
}
<|endoftext|>


<commit_before>package buildpackrunner

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"code.cloudfoundry.org/archiver/extractor"
	"code.cloudfoundry.org/cacheddownloader"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/systemcerts"
)

type ZipDownloader struct {
	downloader *cacheddownloader.Downloader
}

func IsZipFile(filename string) bool {
	return strings.HasSuffix(filename, ".zip")
}

func NewZipDownloader(skipSSLVerification bool) *ZipDownloader {
	tlsConfig := &tls.Config{
		RootCAs:            systemcerts.SystemRootsPool().AsX509CertPool(),
		InsecureSkipVerify: skipSSLVerification,
	}

	return &ZipDownloader{
		downloader: cacheddownloader.NewDownloader(DOWNLOAD_TIMEOUT, 1, tlsConfig),
	}
}

func (z *ZipDownloader) DownloadAndExtract(u *url.URL, destination string) (uint64, error) {
	zipFile, err := ioutil.TempFile("", filepath.Base(u.Path))
	if err != nil {
		return 0, fmt.Errorf("Could not create zip file: %s", err.Error())
	}
	defer os.Remove(zipFile.Name())

	_, _, err = z.downloader.Download(
		lager.NewLogger("noop"),
		u,
		func() (*os.File, error) {
			return os.OpenFile(zipFile.Name(), os.O_WRONLY, 0666)
		},
		cacheddownloader.CachingInfoType{},
		cacheddownloader.ChecksumInfoType{},
		make(chan struct{}),
	)
	if err != nil {
		return 0, fmt.Errorf("Failed to download buildpack '%s': %s", u.String(), err.Error())
	}

	fi, err := zipFile.Stat()
	if err != nil {
		return 0, fmt.Errorf("Failed to obtain the size of the buildpack '%s': %s", u.String(), err.Error())
	}

	err = extractor.NewZip().Extract(zipFile.Name(), destination)
	if err != nil {
		return 0, fmt.Errorf("Failed to extract buildpack '%s': %s", u.String(), err.Error())
	}

	return uint64(fi.Size()), nil
}
<commit_msg>replace cloudfoundry/systemcerts -> crypto/x509<commit_after>package buildpackrunner

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"code.cloudfoundry.org/archiver/extractor"
	"code.cloudfoundry.org/cacheddownloader"
	"code.cloudfoundry.org/lager"
)

type ZipDownloader struct {
	downloader *cacheddownloader.Downloader
}

func IsZipFile(filename string) bool {
	return strings.HasSuffix(filename, ".zip")
}

func SystemCerts() *x509.CertPool {
	caCertPool, err := x509.SystemCertPool()
	if err != nil {
		caCertPool = x509.NewCertPool()
	}
	return caCertPool
}

func NewZipDownloader(skipSSLVerification bool) *ZipDownloader {
	tlsConfig := &tls.Config{
		RootCAs:            SystemCerts(),
		InsecureSkipVerify: skipSSLVerification,
	}

	return &ZipDownloader{
		downloader: cacheddownloader.NewDownloader(DOWNLOAD_TIMEOUT, 1, tlsConfig),
	}
}

func (z *ZipDownloader) DownloadAndExtract(u *url.URL, destination string) (uint64, error) {
	zipFile, err := ioutil.TempFile("", filepath.Base(u.Path))
	if err != nil {
		return 0, fmt.Errorf("Could not create zip file: %s", err.Error())
	}
	defer os.Remove(zipFile.Name())

	_, _, err = z.downloader.Download(
		lager.NewLogger("noop"),
		u,
		func() (*os.File, error) {
			return os.OpenFile(zipFile.Name(), os.O_WRONLY, 0666)
		},
		cacheddownloader.CachingInfoType{},
		cacheddownloader.ChecksumInfoType{},
		make(chan struct{}),
	)
	if err != nil {
		return 0, fmt.Errorf("Failed to download buildpack '%s': %s", u.String(), err.Error())
	}

	fi, err := zipFile.Stat()
	if err != nil {
		return 0, fmt.Errorf("Failed to obtain the size of the buildpack '%s': %s", u.String(), err.Error())
	}

	err = extractor.NewZip().Extract(zipFile.Name(), destination)
	if err != nil {
		return 0, fmt.Errorf("Failed to extract buildpack '%s': %s", u.String(), err.Error())
	}

	return uint64(fi.Size()), nil
}
<|endoftext|>


<commit_before>package backup

import (
	"context"
	"fmt"
	"io"

	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"

	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
)

// Info represents exported backup information.
type Info struct {
	Project          string           `json:"-" yaml:"-"` // Project is set during import based on current project.
	Name             string           `json:"name" yaml:"name"`
	Backend          string           `json:"backend" yaml:"backend"`
	Pool             string           `json:"pool" yaml:"pool"`
	Snapshots        []string         `json:"snapshots,omitempty" yaml:"snapshots,omitempty"`
	OptimizedStorage *bool            `json:"optimized,omitempty" yaml:"optimized,omitempty"`               // Optional field to handle older optimized backups that don't have this field.
	OptimizedHeader  *bool            `json:"optimized_header,omitempty" yaml:"optimized_header,omitempty"` // Optional field to handle older optimized backups that don't have this field.
	Type             api.InstanceType `json:"type" yaml:"type"`
}

// GetInfo extracts backup information from a given ReadSeeker.
func GetInfo(r io.ReadSeeker) (*Info, error) {
	result := Info{}
	hasIndexFile := false

	// Define some bools used to create points for OptimizedStorage field.
	optimizedStorageFalse := false
	optimizedHeaderFalse := false

	// Extract
	r.Seek(0, 0)
	_, _, unpacker, err := shared.DetectCompressionFile(r)
	if err != nil {
		return nil, err
	}

	if unpacker == nil {
		return nil, fmt.Errorf("Unsupported backup compression")
	}

	tr, cancelFunc, err := shared.CompressedTarReader(context.Background(), r, unpacker)
	if err != nil {
		return nil, err
	}
	defer cancelFunc()

	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break // End of archive
		}
		if err != nil {
			return nil, errors.Wrapf(err, "Error reading backup file info")
		}

		if hdr.Name == "backup/index.yaml" {
			err = yaml.NewDecoder(tr).Decode(&result)
			if err != nil {
				return nil, err
			}

			hasIndexFile = true

			// Default to container if index doesn't specify instance type.
			if result.Type == api.InstanceTypeAny {
				result.Type = api.InstanceTypeContainer
			}

			// Default to no optimized header if not specified.
			if result.OptimizedHeader == nil {
				result.OptimizedHeader = &optimizedHeaderFalse
			}

			if result.OptimizedStorage != nil {
				// No need to continue looking for optimized storage hint using the presence of the
				// container.bin file below, as the index.yaml file tells us directly.
				cancelFunc()
				break
			} else {
				// Default to non-optimized if not specified and continue reading to see if
				// optimized container.bin file present.
				result.OptimizedStorage = &optimizedStorageFalse
			}
		}

		// If the tarball contains a binary dump of the container, then this is an optimized backup.
		if hdr.Name == "backup/container.bin" {
			optimizedStorageTrue := true
			result.OptimizedStorage = &optimizedStorageTrue

			// Stop read loop if index.yaml already parsed.
			if hasIndexFile {
				cancelFunc()
				break
			}
		}
	}

	if !hasIndexFile {
		return nil, fmt.Errorf("Backup is missing index.yaml")
	}

	return &result, nil
}
<commit_msg>lxd/backup/backup/info: Changes Type field from api.InstanceType to Type<commit_after>package backup

import (
	"fmt"
	"io"

	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"

	"github.com/lxc/lxd/shared/api"
)

// Type indicates the type of backup.
type Type string

// TypeUnknown defines the backup type value for unknown backups.
const TypeUnknown = Type("")

// TypeContainer defines the backup type value for a container.
const TypeContainer = Type("container")

// TypeVM defines the backup type value for a virtual-machine.
const TypeVM = Type("virtual-machine")

// InstanceTypeToBackupType converts instance type to backup type.
func InstanceTypeToBackupType(instanceType api.InstanceType) Type {
	switch instanceType {
	case api.InstanceTypeContainer:
		return TypeContainer
	case api.InstanceTypeVM:
		return TypeVM
	}

	return TypeUnknown
}

// Info represents exported backup information.
type Info struct {
	Project          string   `json:"-" yaml:"-"` // Project is set during import based on current project.
	Name             string   `json:"name" yaml:"name"`
	Backend          string   `json:"backend" yaml:"backend"`
	Pool             string   `json:"pool" yaml:"pool"`
	Snapshots        []string `json:"snapshots,omitempty" yaml:"snapshots,omitempty"`
	OptimizedStorage *bool    `json:"optimized,omitempty" yaml:"optimized,omitempty"`               // Optional field to handle older optimized backups that don't have this field.
	OptimizedHeader  *bool    `json:"optimized_header,omitempty" yaml:"optimized_header,omitempty"` // Optional field to handle older optimized backups that don't have this field.
	Type             Type     `json:"type,omitempty" yaml:"type,omitempty"`                         // Type of backup.
}

// GetInfo extracts backup information from a given ReadSeeker.
func GetInfo(r io.ReadSeeker) (*Info, error) {
	result := Info{}
	hasIndexFile := false

	// Define some bools used to create points for OptimizedStorage field.
	optimizedStorageFalse := false
	optimizedHeaderFalse := false

	// Extract
	r.Seek(0, 0)
	_, _, unpacker, err := shared.DetectCompressionFile(r)
	if err != nil {
		return nil, err
	}

	if unpacker == nil {
		return nil, fmt.Errorf("Unsupported backup compression")
	}

	tr, cancelFunc, err := shared.CompressedTarReader(context.Background(), r, unpacker)
	if err != nil {
		return nil, err
	}
	defer cancelFunc()

	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			break // End of archive
		}
		if err != nil {
			return nil, errors.Wrapf(err, "Error reading backup file info")
		}

		if hdr.Name == "backup/index.yaml" {
			err = yaml.NewDecoder(tr).Decode(&result)
			if err != nil {
				return nil, err
			}

			hasIndexFile = true

			// Default to container if index doesn't specify instance type.
			if result.Type == api.InstanceTypeAny {
				result.Type = api.InstanceTypeContainer
			}

			// Default to no optimized header if not specified.
			if result.OptimizedHeader == nil {
				result.OptimizedHeader = &optimizedHeaderFalse
			}

			if result.OptimizedStorage != nil {
				// No need to continue looking for optimized storage hint using the presence of the
				// container.bin file below, as the index.yaml file tells us directly.
				cancelFunc()
				break
			} else {
				// Default to non-optimized if not specified and continue reading to see if
				// optimized container.bin file present.
				result.OptimizedStorage = &optimizedStorageFalse
			}
		}

		// If the tarball contains a binary dump of the container, then this is an optimized backup.
		if hdr.Name == "backup/container.bin" {
			optimizedStorageTrue := true
			result.OptimizedStorage = &optimizedStorageTrue

			// Stop read loop if index.yaml already parsed.
			if hasIndexFile {
				cancelFunc()
				break
			}
		}
	}

	if !hasIndexFile {
		return nil, fmt.Errorf("Backup is missing index.yaml")
	}

	return &result, nil
}
<|endoftext|>


<commit_before>package userprint

import (
	"fmt"

	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/plugin/models"
)

type UserPrinter interface {
	PrintUsers(guid string, username string)
}

type spaceUsersPluginPrinter struct {
	UserPrinter
	roles       []string
	userLister  func(spaceGuid string, role string) ([]models.UserFields, error)
	pluginModel *[]plugin_models.GetSpaceUsers_Model
	users       users
}

type orgUsersPluginPrinter struct {
	UserPrinter
	roles       []string
	userLister  func(orgGuid string, role string) ([]models.UserFields, error)
	pluginModel *[]plugin_models.GetOrgUsers_Model
	users       users
}

type SpaceUsersUiPrinter struct {
	UserPrinter
	Ui               terminal.UI
	UserLister       func(spaceGuid string, role string) ([]models.UserFields, error)
	Roles            []string
	RoleDisplayNames map[string]string
}

type OrgUsersUiPrinter struct {
	UserPrinter
	Roles            []string
	RoleDisplayNames map[string]string
	UserLister       func(orgGuid string, role string) ([]models.UserFields, error)
	Ui               terminal.UI
}

type userWithRoles struct {
	models.UserFields
	roles []string
}

type users struct {
	db map[string]userWithRoles
}

func NewOrgUsersPluginPrinter(
	pluginModel *[]plugin_models.GetOrgUsers_Model,
	userLister func(guid string, role string) ([]models.UserFields, error),
	roles []string,
) (printer *orgUsersPluginPrinter) {
	return &orgUsersPluginPrinter{
		pluginModel: pluginModel,
		users:       users{db: make(map[string]userWithRoles)},
		userLister:  userLister,
		roles:       roles,
	}
}

func NewSpaceUsersPluginPrinter(
	pluginModel *[]plugin_models.GetSpaceUsers_Model,
	userLister func(guid string, role string) ([]models.UserFields, error),
	roles []string,
) (printer *spaceUsersPluginPrinter) {
	return &spaceUsersPluginPrinter{
		pluginModel: pluginModel,
		users:       users{db: make(map[string]userWithRoles)},
		userLister:  userLister,
		roles:       roles,
	}
}

func (p *orgUsersPluginPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.roles {
		users, _ := p.userLister(guid, role)
		for _, user := range users {
			p.users.storeAppendingRole(role, user.Username, user.Guid, user.IsAdmin)
		}
	}
	*(p.pluginModel) = p.users.asOrgUsers()
}

func (p *spaceUsersPluginPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.roles {
		users, _ := p.userLister(guid, role)
		for _, user := range users {
			p.users.storeAppendingRole(role, user.Username, user.Guid, user.IsAdmin)
		}
	}
	*(p.pluginModel) = p.users.asSpaceUsers()
}

func (p *OrgUsersUiPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		displayName := p.RoleDisplayNames[role]
		users, err := p.UserLister(guid, role)
		if err != nil {
			p.Ui.Failed(T("Failed fetching org-users for role {{.OrgRoleToDisplayName}}.\n{{.Error}}",
				map[string]interface{}{
					"Error":                err.Error(),
					"OrgRoleToDisplayName": displayName,
				}))
			return
		}
		p.Ui.Say("")
		p.Ui.Say("%s", terminal.HeaderColor(displayName))

		if len(users) == 0 {
			p.Ui.Say(fmt.Sprintf("  "+T("No %s found"), displayName))
		} else {
			for _, user := range users {
				p.Ui.Say("  %s", user.Username)
			}
		}
	}
}

func (p *SpaceUsersUiPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		displayName := p.RoleDisplayNames[role]
		users, err := p.UserLister(guid, role)
		if err != nil {
			p.Ui.Failed(T("Failed fetching space-users for role {{.SpaceRoleToDisplayName}}.\n{{.Error}}",
				map[string]interface{}{
					"Error":                  err.Error(),
					"SpaceRoleToDisplayName": displayName,
				}))
			return
		}
		p.Ui.Say("")
		p.Ui.Say("%s", terminal.HeaderColor(displayName))

		if len(users) == 0 {
			p.Ui.Say(fmt.Sprintf("  "+T("No %s found"), displayName))
		} else {
			for _, user := range users {
				p.Ui.Say("  %s", user.Username)
			}
		}
	}
}

func (c *users) storeAppendingRole(role string, username string, guid string, isAdmin bool) {
	u := c.db[username]
	u.roles = append(u.roles, role)
	u.Username = username
	u.Guid = guid
	u.IsAdmin = isAdmin
	c.db[username] = u
}

func (c *users) asOrgUsers() (coll []plugin_models.GetOrgUsers_Model) {
	for _, u := range c.db {
		coll = append(coll, plugin_models.GetOrgUsers_Model{
			Guid:     u.Guid,
			Username: u.Username,
			IsAdmin:  u.IsAdmin,
			Roles:    u.roles,
		})
	}
	return coll
}

func (c *users) asSpaceUsers() (coll []plugin_models.GetSpaceUsers_Model) {
	for _, u := range c.db {
		coll = append(coll, plugin_models.GetSpaceUsers_Model{
			Guid:     u.Guid,
			Username: u.Username,
			IsAdmin:  u.IsAdmin,
			Roles:    u.roles,
		})
	}
	return coll
}
<commit_msg>Remove meaningless 'implements'-style lines<commit_after>package userprint

import (
	"fmt"

	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/plugin/models"
)

type UserPrinter interface {
	PrintUsers(guid string, username string)
}

type spaceUsersPluginPrinter struct {
	roles       []string
	userLister  func(spaceGuid string, role string) ([]models.UserFields, error)
	pluginModel *[]plugin_models.GetSpaceUsers_Model
	users       users
}

type orgUsersPluginPrinter struct {
	roles       []string
	userLister  func(orgGuid string, role string) ([]models.UserFields, error)
	pluginModel *[]plugin_models.GetOrgUsers_Model
	users       users
}

type SpaceUsersUiPrinter struct {
	Ui               terminal.UI
	UserLister       func(spaceGuid string, role string) ([]models.UserFields, error)
	Roles            []string
	RoleDisplayNames map[string]string
}

type OrgUsersUiPrinter struct {
	Roles            []string
	RoleDisplayNames map[string]string
	UserLister       func(orgGuid string, role string) ([]models.UserFields, error)
	Ui               terminal.UI
}

type userWithRoles struct {
	models.UserFields
	roles []string
}

type users struct {
	db map[string]userWithRoles
}

func NewOrgUsersPluginPrinter(
	pluginModel *[]plugin_models.GetOrgUsers_Model,
	userLister func(guid string, role string) ([]models.UserFields, error),
	roles []string,
) (printer *orgUsersPluginPrinter) {
	return &orgUsersPluginPrinter{
		pluginModel: pluginModel,
		users:       users{db: make(map[string]userWithRoles)},
		userLister:  userLister,
		roles:       roles,
	}
}

func NewSpaceUsersPluginPrinter(
	pluginModel *[]plugin_models.GetSpaceUsers_Model,
	userLister func(guid string, role string) ([]models.UserFields, error),
	roles []string,
) (printer *spaceUsersPluginPrinter) {
	return &spaceUsersPluginPrinter{
		pluginModel: pluginModel,
		users:       users{db: make(map[string]userWithRoles)},
		userLister:  userLister,
		roles:       roles,
	}
}

func (p *orgUsersPluginPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.roles {
		users, _ := p.userLister(guid, role)
		for _, user := range users {
			p.users.storeAppendingRole(role, user.Username, user.Guid, user.IsAdmin)
		}
	}
	*(p.pluginModel) = p.users.asOrgUsers()
}

func (p *spaceUsersPluginPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.roles {
		users, _ := p.userLister(guid, role)
		for _, user := range users {
			p.users.storeAppendingRole(role, user.Username, user.Guid, user.IsAdmin)
		}
	}
	*(p.pluginModel) = p.users.asSpaceUsers()
}

func (p *OrgUsersUiPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		displayName := p.RoleDisplayNames[role]
		users, err := p.UserLister(guid, role)
		if err != nil {
			p.Ui.Failed(T("Failed fetching org-users for role {{.OrgRoleToDisplayName}}.\n{{.Error}}",
				map[string]interface{}{
					"Error":                err.Error(),
					"OrgRoleToDisplayName": displayName,
				}))
			return
		}
		p.Ui.Say("")
		p.Ui.Say("%s", terminal.HeaderColor(displayName))

		if len(users) == 0 {
			p.Ui.Say(fmt.Sprintf("  "+T("No %s found"), displayName))
		} else {
			for _, user := range users {
				p.Ui.Say("  %s", user.Username)
			}
		}
	}
}

func (p *SpaceUsersUiPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		displayName := p.RoleDisplayNames[role]
		users, err := p.UserLister(guid, role)
		if err != nil {
			p.Ui.Failed(T("Failed fetching space-users for role {{.SpaceRoleToDisplayName}}.\n{{.Error}}",
				map[string]interface{}{
					"Error":                  err.Error(),
					"SpaceRoleToDisplayName": displayName,
				}))
			return
		}
		p.Ui.Say("")
		p.Ui.Say("%s", terminal.HeaderColor(displayName))

		if len(users) == 0 {
			p.Ui.Say(fmt.Sprintf("  "+T("No %s found"), displayName))
		} else {
			for _, user := range users {
				p.Ui.Say("  %s", user.Username)
			}
		}
	}
}

func (c *users) storeAppendingRole(role string, username string, guid string, isAdmin bool) {
	u := c.db[username]
	u.roles = append(u.roles, role)
	u.Username = username
	u.Guid = guid
	u.IsAdmin = isAdmin
	c.db[username] = u
}

func (c *users) asOrgUsers() (coll []plugin_models.GetOrgUsers_Model) {
	for _, u := range c.db {
		coll = append(coll, plugin_models.GetOrgUsers_Model{
			Guid:     u.Guid,
			Username: u.Username,
			IsAdmin:  u.IsAdmin,
			Roles:    u.roles,
		})
	}
	return coll
}

func (c *users) asSpaceUsers() (coll []plugin_models.GetSpaceUsers_Model) {
	for _, u := range c.db {
		coll = append(coll, plugin_models.GetSpaceUsers_Model{
			Guid:     u.Guid,
			Username: u.Username,
			IsAdmin:  u.IsAdmin,
			Roles:    u.roles,
		})
	}
	return coll
}
<|endoftext|>


<commit_before>package v1

import (
	"encoding/json"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/ieee0824/cryptex"
	"github.com/ieee0824/cryptex/kms"
	"github.com/jobtalk/pnzr/subcmd/vault/edit/util"
	"os"
)

type Editor struct {
	c          *cryptex.Cryptex
	editorName string
}

func New(s *session.Session, keyID string) *Editor {
	return &Editor{
		cryptex.New(kms.New(s).SetKey(keyID)),
		util.GetEditor(),
	}
}

func (e *Editor) Edit(fileName string) error {
	cryptex.SetEditor(e.editorName)
	var container = &cryptex.Container{}

	f, err := os.Open(fileName)
	if err != nil {
		return err
	}
	if err := json.NewDecoder(f).Decode(container); err != nil {
		return err
	}
	result, err := e.c.Edit(container)
	if err != nil {
		return err
	}

	w, err := os.OpenFile(fileName, os.O_WRONLY, 0644)
	if err != nil {
		return err
	}

	encoder := json.NewEncoder(w)
	encoder.SetIndent("", "    ")

	if err := encoder.Encode(result); err != nil {
		return err
	}

	return nil
}
<commit_msg>fix edit bug (#101)<commit_after>package v1

import (
	"encoding/json"
	"os"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/ieee0824/cryptex"
	"github.com/ieee0824/cryptex/kms"
	"github.com/jobtalk/pnzr/subcmd/vault/edit/util"
)

type Editor struct {
	c          *cryptex.Cryptex
	editorName string
}

func New(s *session.Session, keyID string) *Editor {
	return &Editor{
		cryptex.New(kms.New(s).SetKey(keyID)),
		util.GetEditor(),
	}
}

func (e *Editor) Edit(fileName string) error {
	cryptex.SetEditor(e.editorName)
	var container = &cryptex.Container{}

	f, err := os.Open(fileName)
	if err != nil {
		return err
	}
	if err := json.NewDecoder(f).Decode(container); err != nil {
		return err
	}
	result, err := e.c.Edit(container)
	if err != nil {
		return err
	}

	w, err := os.OpenFile(fileName, os.O_TRUNC|os.O_WRONLY, 0644)
	if err != nil {
		return err
	}

	encoder := json.NewEncoder(w)
	encoder.SetIndent("", "    ")

	if err := encoder.Encode(result); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package nnmc

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"regexp"
	"strconv"
	"strings"

	"golang.org/x/net/html/charset"
)

// NNMc values:
// client http.Client with cookie
type NNMc struct {
	client http.Client
}

// Topic from forum
type Topic struct {
	href    string
	text    string
	year    string
	quality string
}

// Film all values
// ID            id
// Name          Название
// EngName       Английское название
// Href          Ссылка
// Year          Год
// Genre         Жанр
// Country       Производство
// Director      Режиссер
// Producer      Продюсер
// Actors        Актеры
// Description   Описание
// Age           Возраст
// ReleaseDate   Дата мировой премьеры
// RussianDate   Дата премьеры в России
// Duration      Продолжительность
// Quality       Качество видео
// Translation   Перевод
// SubtitlesType Вид субтитров
// Subtitles     Субтитры
// Video         Видео
// Audio         Аудио
// Kinopoisk     Рейтинг кинопоиска
// Imdb          Рейтинг IMDb
// NNM           Рейтинг nnm-club
// Sound         Звук
// Size          Размер
// DateCreate    Дата создания раздачи
// Torrent       Ссылка на torrent
// Poster        Ссылка на постер
// Hide          Скрывать в общем списке
type Film struct {
	ID            int64
	Name          string
	EngName       string
	Href          string
	Year          int64
	Genre         string
	Country       string
	Director      string
	Producer      string
	Actors        string
	Description   string
	Age           string
	ReleaseDate   string
	RussianDate   string
	Duration      int64
	Quality       string
	Translation   string
	SubtitlesType string
	Subtitles     string
	Video         string
	Audio         string
	Kinopoisk     float64
	Imdb          float64
	NNM           float64
	Sound         string
	Size          int64
	DateCreate    string
	Torrent       string
	Poster        string
	Hide          bool
}

// Init nnmc with login password
func Init(login string, password string) (*NNMc, error) {
	var client http.Client
	cookieJar, _ := cookiejar.New(nil)
	client.Jar = cookieJar
	urlPost := "http://nnm-club.me/forum/login.php"
	form := url.Values{}
	form.Set("username", login)
	form.Add("password", password)
	form.Add("redirect", "")
	form.Add("login", "âõîä")
	req, _ := http.NewRequest("POST", urlPost, bytes.NewBufferString(form.Encode()))
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode())))
	_, err := client.Do(req)
	return &NNMc{client: client}, err
}

// getHTML get body from url
func getHTML(url string, n *NNMc) ([]byte, error) {
	resp, err := n.client.Get(url)
	if err != nil {
		log.Println("client Get error:", err)
		return nil, err
	}
	defer resp.Body.Close()
	utf8body, err := charset.NewReader(resp.Body, resp.Header.Get("Content-Type"))
	if err != nil {
		log.Println("Encoding error:", err)
		return nil, err
	}
	doc, err := ioutil.ReadAll(utf8body)
	if err != nil {
		log.Println("ioutil.ReadAll error:", err)
	}
	doc = replaceAll(doc, " ", " ")
	doc = replaceAll(doc, "&", "&")
	return doc, nil
}

// ParseForumTree get topics from forumTree
func (n *NNMc) ParseForumTree(url string) ([]Topic, error) {
	var (
		topics []Topic
		reTree = regexp.MustCompile(`<a href="(viewtopic.php\?t=\d+)"class="topictitle">(.+?)\s\((\d{4})\)\s(.+?)</a>`)
	)
	body, err := getHTML(url, n)
	if err != nil {
		return topics, err
	}
	if reTree.Match(body) == false {
		return topics, fmt.Errorf("No topic in body")
	}
	findResult := reTree.FindAllSubmatch(body, -1)
	for _, v := range findResult {
		var t Topic
		t.href = string(v[1])
		t.text = string(v[2])
		t.year = string(v[3])
		t.quality = string(v[4])
		topics = append(topics, t)
	}

	return topics, nil
}

// ParseTopic get film from topic
func (n *NNMc) ParseTopic(url string) (Film, error) {
	var (
		film     Film
		reTopic  = regexp.MustCompile(`(Производство|Жанр|Режиссер|Продюсер|Актеры|Описание|Возраст|Дата мировой премьеры|Дата премьеры в России|Продолжительность|Качество видео|Перевод|Вид субтитров|Субтитры|Видео|Аудио):<\/span>(.+?)<`)
		reDate   = regexp.MustCompile(`> (\d{1,2} .{3} \d{4}).{9}<`)
		reSize   = regexp.MustCompile(`Размер блока: \d{1,2} MB"> (\d{1,2},\d{1,2}|\d{3,4})`)
		reRating = regexp.MustCompile(`>(\d,\d)<\/span`)
		reDl     = regexp.MustCompile(`<a href="download\.php\?id=(\d{5,7})" rel="nofollow">Скачать<`)
	)
	body, err := getHTML(url, n)
	film.Href = url
	if err != nil {
		return film, err
	}
	if reTopic.Match(body) == false {
		return film, fmt.Errorf("No topic in body")
	}
	findAttrs := reTopic.FindAllSubmatch(body, -1)
	for _, v := range findAttrs {
		one := strings.Trim(string(v[1]), " ")
		two := strings.Trim(string(v[2]), " ")
		switch one {
		case "Производство":
			film.Country = two
		case "Жанр":
			film.Genre = two
		case "Режиссер":
			film.Director = two
		case "Продюсер":
			film.Producer = two
		case "Актеры":
			film.Actors = two
		case "Описание":
			film.Description = two
		case "Возраст":
			film.Age = two
		case "Дата мировой премьеры":
			film.ReleaseDate = two
		case "Дата премьеры в России":
			film.RussianDate = two
		case "Продолжительность":
			if i64, err := strconv.ParseInt(two, 10, 64); err == nil {
				film.Duration = i64
			}
		case "Качество видео":
			film.Quality = two
		case "Перевод":
			film.Translation = two
		case "Вид субтитров":
			film.SubtitlesType = two
		case "Субтитры":
			film.Subtitles = two
		case "Видео":
			film.Video = two
		case "Аудио":
			film.Audio = two
		}
	}
	if reDate.Match(body) == true {
		film.DateCreate = string(reDate.FindSubmatch(body)[1])
	}
	if reSize.Match(body) == true {
		size := string(reSize.FindSubmatch(body)[1])
		size = strings.Replace(size, ",", ".", -1)
		if s64, err := strconv.ParseFloat(size, 64); err == nil {
			if s64 < 100 {
				s64 = s64 * 1000
			}
			film.Size = int64(s64)
		}
	}
	if reRating.Match(body) == true {
		rating := string(reRating.FindSubmatch(body)[1])
		rating = strings.Replace(rating, ",", ".", -1)
		if r64, err := strconv.ParseFloat(rating, 64); err == nil {
			film.NNM = r64
		}
	}
	if reDl.Match(body) == false {
		return film, fmt.Errorf("No torrent url in body")
	}
	findDl := reDl.FindAllSubmatch(body, -1)
	film.Torrent = "http://nnm-club.me/forum/download.php?id=" + string(findDl[0][1])
	return film, nil
}

func replaceAll(body []byte, from string, to string) []byte {
	var reStr = regexp.MustCompile(from)
	result := reStr.ReplaceAll(body, []byte(to))
	return result
}
<commit_msg>fix for gorm<commit_after>package nnmc

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"regexp"
	"strconv"
	"strings"

	"golang.org/x/net/html/charset"
)

// NNMc values:
// client http.Client with cookie
type NNMc struct {
	client http.Client
}

// Topic from forum
type Topic struct {
	Href    string
	Text    string
	Year    string
	Quality string
}

// Film all values
// ID            id
// Name          Название
// EngName       Английское название
// Href          Ссылка
// Year          Год
// Genre         Жанр
// Country       Производство
// Director      Режиссер
// Producer      Продюсер
// Actors        Актеры
// Description   Описание
// Age           Возраст
// ReleaseDate   Дата мировой премьеры
// RussianDate   Дата премьеры в России
// Duration      Продолжительность
// Quality       Качество видео
// Translation   Перевод
// SubtitlesType Вид субтитров
// Subtitles     Субтитры
// Video         Видео
// Audio         Аудио
// Kinopoisk     Рейтинг кинопоиска
// Imdb          Рейтинг IMDb
// NNM           Рейтинг nnm-club
// Sound         Звук
// Size          Размер
// DateCreate    Дата создания раздачи
// Torrent       Ссылка на torrent
// Poster        Ссылка на постер
// Hide          Скрывать в общем списке
type Film struct {
	ID            int64   `gorm:"column:id" sql:"AUTO_INCREMENT"`
	Name          string  `gorm:"column:name"`
	EngName       string  `gorm:"column:eng_name"`
	Href          string  `gorm:"column:href"`
	Year          int64   `gorm:"column:year"`
	Genre         string  `gorm:"column:genre"`
	Country       string  `gorm:"column:country"`
	Director      string  `gorm:"column:director"`
	Producer      string  `gorm:"column:producer"`
	Actors        string  `gorm:"column:actors"`
	Description   string  `gorm:"column:description"`
	Age           string  `gorm:"column:age"`
	ReleaseDate   string  `gorm:"column:release_date"`
	RussianDate   string  `gorm:"column:russian_date"`
	Duration      int64   `gorm:"column:duration"`
	Quality       string  `gorm:"column:quality"`
	Translation   string  `gorm:"column:translation"`
	SubtitlesType string  `gorm:"column:subtitles_type"`
	Subtitles     string  `gorm:"column:subtitles"`
	Video         string  `gorm:"column:video"`
	Audio         string  `gorm:"column:audio"`
	Kinopoisk     float64 `gorm:"column:kinopoisk"`
	IMDb          float64 `gorm:"column:imdb"`
	NNM           float64 `gorm:"column:nnm"`
	Sound         string  `gorm:"column:sound"`
	Size          int64   `gorm:"column:size"`
	DateCreate    string  `gorm:"column:date_create"`
	Torrent       string  `gorm:"column:torrent"`
	Poster        string  `gorm:"column:poster"`
	Hide          bool    `gorm:"column:hide" sql:"default:0"`
}

// Init nnmc with login password
func Init(login string, password string) (*NNMc, error) {
	var client http.Client
	cookieJar, _ := cookiejar.New(nil)
	client.Jar = cookieJar
	urlPost := "http://nnm-club.me/forum/login.php"
	form := url.Values{}
	form.Set("username", login)
	form.Add("password", password)
	form.Add("redirect", "")
	form.Add("login", "âõîä")
	req, _ := http.NewRequest("POST", urlPost, bytes.NewBufferString(form.Encode()))
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode())))
	_, err := client.Do(req)
	return &NNMc{client: client}, err
}

// getHTML get body from url
func getHTML(url string, n *NNMc) ([]byte, error) {
	resp, err := n.client.Get(url)
	if err != nil {
		log.Println("client Get error:", err)
		return nil, err
	}
	defer resp.Body.Close()
	utf8body, err := charset.NewReader(resp.Body, resp.Header.Get("Content-Type"))
	if err != nil {
		log.Println("Encoding error:", err)
		return nil, err
	}
	doc, err := ioutil.ReadAll(utf8body)
	if err != nil {
		log.Println("ioutil.ReadAll error:", err)
	}
	doc = replaceAll(doc, " ", " ")
	doc = replaceAll(doc, "&", "&")
	return doc, nil
}

// ParseForumTree get topics from forumTree
func (n *NNMc) ParseForumTree(url string) ([]Topic, error) {
	var (
		topics []Topic
		reTree = regexp.MustCompile(`<a href="(viewtopic.php\?t=\d+)"class="topictitle">(.+?)\s\((\d{4})\)\s(.+?)</a>`)
	)
	body, err := getHTML(url, n)
	if err != nil {
		return topics, err
	}
	if reTree.Match(body) == false {
		return topics, fmt.Errorf("No topic in body")
	}
	findResult := reTree.FindAllSubmatch(body, -1)
	for _, v := range findResult {
		var t Topic
		t.Href = "http://nnm-club.me/forum/" + string(v[1])
		t.Text = string(v[2])
		t.Year = string(v[3])
		t.Quality = string(v[4])
		topics = append(topics, t)
	}

	return topics, nil
}

// ParseTopic get film from topic
func (n *NNMc) ParseTopic(url string) (Film, error) {
	var (
		film     Film
		reTopic  = regexp.MustCompile(`(Производство|Жанр|Режиссер|Продюсер|Актеры|Описание|Возраст|Дата мировой премьеры|Дата премьеры в России|Продолжительность|Качество видео|Перевод|Вид субтитров|Субтитры|Видео|Аудио):<\/span>(.+?)<`)
		reDate   = regexp.MustCompile(`> (\d{1,2} .{3} \d{4}).{9}<`)
		reSize   = regexp.MustCompile(`Размер блока: \d{1,2} MB"> (\d{1,2},\d{1,2}|\d{3,4})`)
		reRating = regexp.MustCompile(`>(\d,\d)<\/span`)
		reDl     = regexp.MustCompile(`<a href="download\.php\?id=(\d{5,7})" rel="nofollow">Скачать<`)
	)
	body, err := getHTML(url, n)
	film.Href = url
	if err != nil {
		return film, err
	}
	if reTopic.Match(body) == false {
		return film, fmt.Errorf("No topic in body")
	}
	findAttrs := reTopic.FindAllSubmatch(body, -1)
	for _, v := range findAttrs {
		one := strings.Trim(string(v[1]), " ")
		two := strings.Trim(string(v[2]), " ")
		switch one {
		case "Производство":
			film.Country = two
		case "Жанр":
			film.Genre = strings.ToLower(two)
		case "Режиссер":
			film.Director = two
		case "Продюсер":
			film.Producer = two
		case "Актеры":
			film.Actors = two
		case "Описание":
			film.Description = two
		case "Возраст":
			film.Age = two
		case "Дата мировой премьеры":
			film.ReleaseDate = two
		case "Дата премьеры в России":
			film.RussianDate = two
		case "Продолжительность":
			if i64, err := strconv.ParseInt(two, 10, 64); err == nil {
				film.Duration = i64
			}
		case "Качество видео":
			film.Quality = two
		case "Перевод":
			film.Translation = two
		case "Вид субтитров":
			film.SubtitlesType = two
		case "Субтитры":
			film.Subtitles = two
		case "Видео":
			film.Video = two
		case "Аудио":
			film.Audio = two
		}
	}
	if reDate.Match(body) == true {
		film.DateCreate = string(reDate.FindSubmatch(body)[1])
	}
	if reSize.Match(body) == true {
		size := string(reSize.FindSubmatch(body)[1])
		size = strings.Replace(size, ",", ".", -1)
		if s64, err := strconv.ParseFloat(size, 64); err == nil {
			if s64 < 100 {
				s64 = s64 * 1000
			}
			film.Size = int64(s64)
		}
	}
	if reRating.Match(body) == true {
		rating := string(reRating.FindSubmatch(body)[1])
		rating = strings.Replace(rating, ",", ".", -1)
		if r64, err := strconv.ParseFloat(rating, 64); err == nil {
			film.NNM = r64
		}
	}
	if reDl.Match(body) == false {
		return film, fmt.Errorf("No torrent url in body")
	}
	findDl := reDl.FindAllSubmatch(body, -1)
	film.Torrent = "http://nnm-club.me/forum/download.php?id=" + string(findDl[0][1])
	return film, nil
}

func replaceAll(body []byte, from string, to string) []byte {
	var reStr = regexp.MustCompile(from)
	result := reStr.ReplaceAll(body, []byte(to))
	return result
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2015 The Notify Authors. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

package notify

import (
	"errors"
	"io/ioutil"
	"os"
	"path/filepath"
)

var errSkip = errors.New("notify: skip")

type walkPathFunc func(nd node, isbase bool) error

type walkFunc func(node) error

func errnotexist(name string) error {
	return &os.PathError{
		Op:   "Node",
		Path: name,
		Err:  os.ErrNotExist,
	}
}

type node struct {
	Name  string
	Watch watchpoint
	Child map[string]node
}

func newnode(name string) node {
	return node{
		Name:  name,
		Watch: make(watchpoint),
		Child: make(map[string]node),
	}
}

func (nd node) addchild(name, base string) node {
	child, ok := nd.Child[base]
	if !ok {
		child = newnode(name)
		nd.Child[base] = child
	}
	return child
}

func (nd node) Add(name string) node {
	i := indexbase(nd.Name, name)
	if i == -1 {
		return node{}
	}
	for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) {
		nd = nd.addchild(name[:i+j], name[i:i+j])
		i += j + 1
	}
	return nd.addchild(name, name[i:])
}

func (nd node) AddDir(fn walkFunc) error {
	stack := []node{nd}
Traverse:
	for n := len(stack); n != 0; n = len(stack) {
		nd, stack = stack[n-1], stack[:n-1]
		switch err := fn(nd); err {
		case nil:
		case errSkip:
			continue Traverse
		default:
			return err
		}
		// TODO(rjeczalik): tolerate open failures - add failed names to
		// AddDirError and notify users which names are not added to the tree.
		fi, err := ioutil.ReadDir(nd.Name)
		if err != nil {
			return err
		}
		for _, fi := range fi {
			if fi.Mode()&(os.ModeSymlink|os.ModeDir) == os.ModeDir {
				name := filepath.Join(nd.Name, fi.Name())
				stack = append(stack, nd.addchild(name, name[len(nd.Name)+1:]))
			}
		}
	}
	return nil
}

func (nd node) Get(name string) (node, error) {
	i := indexbase(nd.Name, name)
	if i == -1 {
		return node{}, errnotexist(name)
	}
	ok := false
	for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) {
		if nd, ok = nd.Child[name[i:i+j]]; !ok {
			return node{}, errnotexist(name)
		}
		i += j + 1
	}
	if nd, ok = nd.Child[name[i:]]; !ok {
		return node{}, errnotexist(name)
	}
	return nd, nil
}

func (nd node) Del(name string) error {
	i := indexbase(nd.Name, name)
	if i == -1 {
		return errnotexist(name)
	}
	stack := []node{nd}
	ok := false
	for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) {
		if nd, ok = nd.Child[name[i:i+j]]; !ok {
			return errnotexist(name[:i+j])
		}
		stack = append(stack, nd)
	}
	if nd, ok = nd.Child[name[i:]]; !ok {
		return errnotexist(name)
	}
	nd.Child = nil
	nd.Watch = nil
	for name, i = base(nd.Name), len(stack); i != 0; name, i = base(nd.Name), i-1 {
		nd = stack[i-1]
		if nd := nd.Child[name]; len(nd.Watch) > 1 || len(nd.Child) != 0 {
			break
		} else {
			nd.Child = nil
			nd.Watch = nil
		}
		delete(nd.Child, name)
	}
	return nil
}

func (nd node) Walk(fn walkFunc) error {
	stack := []node{nd}
Traverse:
	for n := len(stack); n != 0; n = len(stack) {
		nd, stack = stack[n-1], stack[:n-1]
		switch err := fn(nd); err {
		case nil:
		case errSkip:
			continue Traverse
		default:
			return err
		}
		for name, nd := range nd.Child {
			if name == "" {
				// Node storing inactive watchpoints has empty name, skip it
				// form traversing. Root node has also an empty name, but it
				// never has a parent node.
				continue
			}
			stack = append(stack, nd)
		}
	}
	return nil
}

func (nd node) WalkPath(name string, fn walkPathFunc) error {
	i := indexbase(nd.Name, name)
	if i == -1 {
		return errnotexist(name)
	}
	ok := false
	for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) {
		switch err := fn(nd, false); err {
		case nil:
		case errSkip:
			return nil
		default:
			return err
		}
		if nd, ok = nd.Child[name[i:i+j]]; !ok {
			return errnotexist(name[:i+j])
		}
		i += j + 1
	}
	switch err := fn(nd, false); err {
	case nil:
	case errSkip:
		return nil
	default:
		return err
	}
	if nd, ok = nd.Child[name[i:]]; !ok {
		return errnotexist(name)
	}
	switch err := fn(nd, true); err {
	case nil, errSkip:
		return nil
	default:
		return err
	}
}

type root struct {
	nd node
}

func (r root) addroot(name string) node {
	if vol := filepath.VolumeName(name); vol != "" {
		root, ok := r.nd.Child[vol]
		if !ok {
			root = r.nd.addchild(vol, vol)
		}
		return root
	}
	return r.nd
}

func (r root) root(name string) (node, error) {
	if vol := filepath.VolumeName(name); vol != "" {
		nd, ok := r.nd.Child[vol]
		if !ok {
			return node{}, errnotexist(name)
		}
		return nd, nil
	}
	return r.nd, nil
}

func (r root) Add(name string) node {
	return r.addroot(name).Add(name)
}

func (r root) AddDir(dir string, fn walkFunc) error {
	return r.Add(dir).AddDir(fn)
}

func (r root) Del(name string) error {
	nd, err := r.root(name)
	if err != nil {
		return err
	}
	return nd.Del(name)
}

func (r root) Get(name string) (node, error) {
	nd, err := r.root(name)
	if err != nil {
		return node{}, err
	}
	if nd.Name != name {
		if nd, err = nd.Get(name); err != nil {
			return node{}, err
		}
	}
	return nd, nil
}

func (r root) Walk(name string, fn walkFunc) error {
	nd, err := r.Get(name)
	if err != nil {
		return err
	}
	return nd.Walk(fn)
}

func (r root) WalkPath(name string, fn walkPathFunc) error {
	nd, err := r.root(name)
	if err != nil {
		return err
	}
	return nd.WalkPath(name, fn)
}
<commit_msg>include node name in error when traversing fails<commit_after>// Copyright (c) 2014-2015 The Notify Authors. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

package notify

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
)

var errSkip = errors.New("notify: skip")

type walkPathFunc func(nd node, isbase bool) error

type walkFunc func(node) error

func errnotexist(name string) error {
	return &os.PathError{
		Op:   "Node",
		Path: name,
		Err:  os.ErrNotExist,
	}
}

type node struct {
	Name  string
	Watch watchpoint
	Child map[string]node
}

func newnode(name string) node {
	return node{
		Name:  name,
		Watch: make(watchpoint),
		Child: make(map[string]node),
	}
}

func (nd node) addchild(name, base string) node {
	child, ok := nd.Child[base]
	if !ok {
		child = newnode(name)
		nd.Child[base] = child
	}
	return child
}

func (nd node) Add(name string) node {
	i := indexbase(nd.Name, name)
	if i == -1 {
		return node{}
	}
	for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) {
		nd = nd.addchild(name[:i+j], name[i:i+j])
		i += j + 1
	}
	return nd.addchild(name, name[i:])
}

func (nd node) AddDir(fn walkFunc) error {
	stack := []node{nd}
Traverse:
	for n := len(stack); n != 0; n = len(stack) {
		nd, stack = stack[n-1], stack[:n-1]
		switch err := fn(nd); err {
		case nil:
		case errSkip:
			continue Traverse
		default:
			return fmt.Errorf("error while traversing %q: %v", nd.Name, err)
		}
		// TODO(rjeczalik): tolerate open failures - add failed names to
		// AddDirError and notify users which names are not added to the tree.
		fi, err := ioutil.ReadDir(nd.Name)
		if err != nil {
			return err
		}
		for _, fi := range fi {
			if fi.Mode()&(os.ModeSymlink|os.ModeDir) == os.ModeDir {
				name := filepath.Join(nd.Name, fi.Name())
				stack = append(stack, nd.addchild(name, name[len(nd.Name)+1:]))
			}
		}
	}
	return nil
}

func (nd node) Get(name string) (node, error) {
	i := indexbase(nd.Name, name)
	if i == -1 {
		return node{}, errnotexist(name)
	}
	ok := false
	for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) {
		if nd, ok = nd.Child[name[i:i+j]]; !ok {
			return node{}, errnotexist(name)
		}
		i += j + 1
	}
	if nd, ok = nd.Child[name[i:]]; !ok {
		return node{}, errnotexist(name)
	}
	return nd, nil
}

func (nd node) Del(name string) error {
	i := indexbase(nd.Name, name)
	if i == -1 {
		return errnotexist(name)
	}
	stack := []node{nd}
	ok := false
	for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) {
		if nd, ok = nd.Child[name[i:i+j]]; !ok {
			return errnotexist(name[:i+j])
		}
		stack = append(stack, nd)
	}
	if nd, ok = nd.Child[name[i:]]; !ok {
		return errnotexist(name)
	}
	nd.Child = nil
	nd.Watch = nil
	for name, i = base(nd.Name), len(stack); i != 0; name, i = base(nd.Name), i-1 {
		nd = stack[i-1]
		if nd := nd.Child[name]; len(nd.Watch) > 1 || len(nd.Child) != 0 {
			break
		} else {
			nd.Child = nil
			nd.Watch = nil
		}
		delete(nd.Child, name)
	}
	return nil
}

func (nd node) Walk(fn walkFunc) error {
	stack := []node{nd}
Traverse:
	for n := len(stack); n != 0; n = len(stack) {
		nd, stack = stack[n-1], stack[:n-1]
		switch err := fn(nd); err {
		case nil:
		case errSkip:
			continue Traverse
		default:
			return err
		}
		for name, nd := range nd.Child {
			if name == "" {
				// Node storing inactive watchpoints has empty name, skip it
				// form traversing. Root node has also an empty name, but it
				// never has a parent node.
				continue
			}
			stack = append(stack, nd)
		}
	}
	return nil
}

func (nd node) WalkPath(name string, fn walkPathFunc) error {
	i := indexbase(nd.Name, name)
	if i == -1 {
		return errnotexist(name)
	}
	ok := false
	for j := indexSep(name[i:]); j != -1; j = indexSep(name[i:]) {
		switch err := fn(nd, false); err {
		case nil:
		case errSkip:
			return nil
		default:
			return err
		}
		if nd, ok = nd.Child[name[i:i+j]]; !ok {
			return errnotexist(name[:i+j])
		}
		i += j + 1
	}
	switch err := fn(nd, false); err {
	case nil:
	case errSkip:
		return nil
	default:
		return err
	}
	if nd, ok = nd.Child[name[i:]]; !ok {
		return errnotexist(name)
	}
	switch err := fn(nd, true); err {
	case nil, errSkip:
		return nil
	default:
		return err
	}
}

type root struct {
	nd node
}

func (r root) addroot(name string) node {
	if vol := filepath.VolumeName(name); vol != "" {
		root, ok := r.nd.Child[vol]
		if !ok {
			root = r.nd.addchild(vol, vol)
		}
		return root
	}
	return r.nd
}

func (r root) root(name string) (node, error) {
	if vol := filepath.VolumeName(name); vol != "" {
		nd, ok := r.nd.Child[vol]
		if !ok {
			return node{}, errnotexist(name)
		}
		return nd, nil
	}
	return r.nd, nil
}

func (r root) Add(name string) node {
	return r.addroot(name).Add(name)
}

func (r root) AddDir(dir string, fn walkFunc) error {
	return r.Add(dir).AddDir(fn)
}

func (r root) Del(name string) error {
	nd, err := r.root(name)
	if err != nil {
		return err
	}
	return nd.Del(name)
}

func (r root) Get(name string) (node, error) {
	nd, err := r.root(name)
	if err != nil {
		return node{}, err
	}
	if nd.Name != name {
		if nd, err = nd.Get(name); err != nil {
			return node{}, err
		}
	}
	return nd, nil
}

func (r root) Walk(name string, fn walkFunc) error {
	nd, err := r.Get(name)
	if err != nil {
		return err
	}
	return nd.Walk(fn)
}

func (r root) WalkPath(name string, fn walkPathFunc) error {
	nd, err := r.root(name)
	if err != nil {
		return err
	}
	return nd.WalkPath(name, fn)
}
<|endoftext|>


<commit_before>// Copyright 2015 Vadim Kravcenko
//
// 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 gojenkins

import "errors"

// Nodes

type Computers struct {
	BusyExecutors  int            `json:"busyExecutors"`
	Computers      []nodeResponse `json:"computer"`
	DisplayName    string         `json:"displayName"`
	TotalExecutors int            `json:"totalExecutors"`
}

type Node struct {
	Raw     *nodeResponse
	Jenkins *Jenkins
	Base    string
}

type nodeResponse struct {
	Actions             []interface{} `json:"actions"`
	DisplayName         string        `json:"displayName"`
	Executors           []struct{}    `json:"executors"`
	Icon                string        `json:"icon"`
	IconClassName       string        `json:"iconClassName"`
	Idle                bool          `json:"idle"`
	JnlpAgent           bool          `json:"jnlpAgent"`
	LaunchSupported     bool          `json:"launchSupported"`
	LoadStatistics      struct{}      `json:"loadStatistics"`
	ManualLaunchAllowed bool          `json:"manualLaunchAllowed"`
	MonitorData         struct {
		Hudson_NodeMonitors_ArchitectureMonitor interface{} `json:"hudson.node_monitors.ArchitectureMonitor"`
		Hudson_NodeMonitors_ClockMonitor        interface{} `json:"hudson.node_monitors.ClockMonitor"`
		Hudson_NodeMonitors_DiskSpaceMonitor    interface{} `json:"hudson.node_monitors.DiskSpaceMonitor"`
		Hudson_NodeMonitors_ResponseTimeMonitor struct {
			Average int64 `json:"average"`
		} `json:"hudson.node_monitors.ResponseTimeMonitor"`
		Hudson_NodeMonitors_SwapSpaceMonitor      interface{} `json:"hudson.node_monitors.SwapSpaceMonitor"`
		Hudson_NodeMonitors_TemporarySpaceMonitor interface{} `json:"hudson.node_monitors.TemporarySpaceMonitor"`
	} `json:"monitorData"`
	NumExecutors       int64         `json:"numExecutors"`
	Offline            bool          `json:"offline"`
	OfflineCause       struct{}      `json:"offlineCause"`
	OfflineCauseReason string        `json:"offlineCauseReason"`
	OneOffExecutors    []interface{} `json:"oneOffExecutors"`
	TemporarilyOffline bool          `json:"temporarilyOffline"`
}

func (n *Node) Info() (*nodeResponse, error) {
	_, err := n.Poll()
	if err != nil {
		return nil, err
	}
	return n.Raw, nil
}

func (n *Node) GetName() string {
	return n.Raw.DisplayName
}

func (n *Node) Delete() (bool, error) {
	resp, err := n.Jenkins.Requester.Post(n.Base+"/doDelete", nil, nil, nil)
	if err != nil {
		return false, err
	}
	return resp.StatusCode == 200, nil
}

func (n *Node) IsOnline() (bool, error) {
	_, err := n.Poll()
	if err != nil {
		return false, err
	}
	return !n.Raw.Offline, nil
}

func (n *Node) IsTemporarilyOffline() (bool, error) {
	_, err := n.Poll()
	if err != nil {
		return false, err
	}
	return n.Raw.TemporarilyOffline, nil
}

func (n *Node) IsIdle() (bool, error) {
	_, err := n.Poll()
	if err != nil {
		return false, err
	}
	return n.Raw.Idle, nil
}

func (n *Node) IsJnlpAgent() (bool, error) {
	_, err := n.Poll()
	if err != nil {
		return false, err
	}
	return n.Raw.JnlpAgent, nil
}

func (n *Node) SetOnline() (bool, error) {
	_, err := n.Poll()

	if err != nil {
		return false, err
	}

	if n.Raw.Offline && !n.Raw.TemporarilyOffline {
		return false, errors.New("Node is Permanently offline, can't bring it up")
	}

	if n.Raw.Offline && n.Raw.TemporarilyOffline {
		return n.ToggleTemporarilyOffline()
	}

	return false, nil
}

func (n *Node) SetOffline() (bool, error) {
	if !n.Raw.Offline {
		return n.ToggleTemporarilyOffline()
	}
	return false, errors.New("Node already Offline")
}

func (n *Node) ToggleTemporarilyOffline(options ...interface{}) (bool, error) {
	state_before, err := n.IsTemporarilyOffline()
	if err != nil {
		return false, err
	}
	qr := map[string]string{"offlineMessage": "requested from gojenkins"}
	if len(options) > 0 {
		qr["offlineMessage"] = options[0].(string)
	}
	_, err = n.Jenkins.Requester.GetJSON(n.Base+"/toggleOffline", nil, qr)
	if err != nil {
		return false, err
	}
	new_state, err := n.IsTemporarilyOffline()
	if err != nil {
		return false, err
	}
	if state_before == new_state {
		return false, errors.New("Node state not changed")
	}
	return false, nil
}

func (n *Node) Poll() (int, error) {
	_, err := n.Jenkins.Requester.GetJSON(n.Base, n.Raw, nil)
	if err != nil {
		return 0, err
	}
	return n.Jenkins.Requester.LastResponse.StatusCode, nil
}
<commit_msg>fix(node): Ust Post request for toggleTemporaryOffline<commit_after>// Copyright 2015 Vadim Kravcenko
//
// 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 gojenkins

import "errors"

// Nodes

type Computers struct {
	BusyExecutors  int            `json:"busyExecutors"`
	Computers      []nodeResponse `json:"computer"`
	DisplayName    string         `json:"displayName"`
	TotalExecutors int            `json:"totalExecutors"`
}

type Node struct {
	Raw     *nodeResponse
	Jenkins *Jenkins
	Base    string
}

type nodeResponse struct {
	Actions             []interface{} `json:"actions"`
	DisplayName         string        `json:"displayName"`
	Executors           []struct{}    `json:"executors"`
	Icon                string        `json:"icon"`
	IconClassName       string        `json:"iconClassName"`
	Idle                bool          `json:"idle"`
	JnlpAgent           bool          `json:"jnlpAgent"`
	LaunchSupported     bool          `json:"launchSupported"`
	LoadStatistics      struct{}      `json:"loadStatistics"`
	ManualLaunchAllowed bool          `json:"manualLaunchAllowed"`
	MonitorData         struct {
		Hudson_NodeMonitors_ArchitectureMonitor interface{} `json:"hudson.node_monitors.ArchitectureMonitor"`
		Hudson_NodeMonitors_ClockMonitor        interface{} `json:"hudson.node_monitors.ClockMonitor"`
		Hudson_NodeMonitors_DiskSpaceMonitor    interface{} `json:"hudson.node_monitors.DiskSpaceMonitor"`
		Hudson_NodeMonitors_ResponseTimeMonitor struct {
			Average int64 `json:"average"`
		} `json:"hudson.node_monitors.ResponseTimeMonitor"`
		Hudson_NodeMonitors_SwapSpaceMonitor      interface{} `json:"hudson.node_monitors.SwapSpaceMonitor"`
		Hudson_NodeMonitors_TemporarySpaceMonitor interface{} `json:"hudson.node_monitors.TemporarySpaceMonitor"`
	} `json:"monitorData"`
	NumExecutors       int64         `json:"numExecutors"`
	Offline            bool          `json:"offline"`
	OfflineCause       struct{}      `json:"offlineCause"`
	OfflineCauseReason string        `json:"offlineCauseReason"`
	OneOffExecutors    []interface{} `json:"oneOffExecutors"`
	TemporarilyOffline bool          `json:"temporarilyOffline"`
}

func (n *Node) Info() (*nodeResponse, error) {
	_, err := n.Poll()
	if err != nil {
		return nil, err
	}
	return n.Raw, nil
}

func (n *Node) GetName() string {
	return n.Raw.DisplayName
}

func (n *Node) Delete() (bool, error) {
	resp, err := n.Jenkins.Requester.Post(n.Base+"/doDelete", nil, nil, nil)
	if err != nil {
		return false, err
	}
	return resp.StatusCode == 200, nil
}

func (n *Node) IsOnline() (bool, error) {
	_, err := n.Poll()
	if err != nil {
		return false, err
	}
	return !n.Raw.Offline, nil
}

func (n *Node) IsTemporarilyOffline() (bool, error) {
	_, err := n.Poll()
	if err != nil {
		return false, err
	}
	return n.Raw.TemporarilyOffline, nil
}

func (n *Node) IsIdle() (bool, error) {
	_, err := n.Poll()
	if err != nil {
		return false, err
	}
	return n.Raw.Idle, nil
}

func (n *Node) IsJnlpAgent() (bool, error) {
	_, err := n.Poll()
	if err != nil {
		return false, err
	}
	return n.Raw.JnlpAgent, nil
}

func (n *Node) SetOnline() (bool, error) {
	_, err := n.Poll()

	if err != nil {
		return false, err
	}

	if n.Raw.Offline && !n.Raw.TemporarilyOffline {
		return false, errors.New("Node is Permanently offline, can't bring it up")
	}

	if n.Raw.Offline && n.Raw.TemporarilyOffline {
		return n.ToggleTemporarilyOffline()
	}

	return true, nil
}

func (n *Node) SetOffline() (bool, error) {
	if !n.Raw.Offline {
		return n.ToggleTemporarilyOffline()
	}
	return false, errors.New("Node already Offline")
}

func (n *Node) ToggleTemporarilyOffline(options ...interface{}) (bool, error) {
	state_before, err := n.IsTemporarilyOffline()
	if err != nil {
		return false, err
	}
	qr := map[string]string{"offlineMessage": "requested from gojenkins"}
	if len(options) > 0 {
		qr["offlineMessage"] = options[0].(string)
	}
	_, err = n.Jenkins.Requester.Post(n.Base+"/toggleOffline", nil, nil,  qr)
	if err != nil {
		return false, err
	}
	new_state, err := n.IsTemporarilyOffline()
	if err != nil {
		return false, err
	}
	if state_before == new_state {
		return false, errors.New("Node state not changed")
	}
	return true, nil
}

func (n *Node) Poll() (int, error) {
	_, err := n.Jenkins.Requester.GetJSON(n.Base, n.Raw, nil)
	if err != nil {
		return 0, err
	}
	return n.Jenkins.Requester.LastResponse.StatusCode, nil
}
<|endoftext|>


<commit_before>package tree

import (
	"fmt"
	"io"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"syscall"
)

// Node represent some node in the tree
// contains FileInfo, and its childs
type Node struct {
	os.FileInfo
	path   string
	depth  int
	err    error
	nodes  Nodes
	vpaths map[string]bool
}

// List of nodes
type Nodes []*Node

// To use this package programmatically, you must implement this
// interface.
// For example: PTAL on 'cmd/tree/tree.go'
type Fs interface {
	Stat(path string) (os.FileInfo, error)
	ReadDir(path string) ([]string, error)
}

// Options store the configuration for specific tree.
// Note, that 'Fs', and 'OutFile' are required (OutFile can be os.Stdout).
type Options struct {
	Fs      Fs
	OutFile io.Writer
	// List
	All        bool
	DirsOnly   bool
	FullPath   bool
	IgnoreCase bool
	FollowLink bool
	DeepLevel  int
	Pattern    string
	IPattern   string
	// File
	ByteSize bool
	UnitSize bool
	FileMode bool
	ShowUid  bool
	ShowGid  bool
	LastMod  bool
	Quotes   bool
	Inodes   bool
	Device   bool
	// Sort
	NoSort    bool
	VerSort   bool
	ModSort   bool
	DirSort   bool
	NameSort  bool
	SizeSort  bool
	CTimeSort bool
	ReverSort bool
	// Graphics
	NoIndent bool
	Colorize bool
}

// New get path and create new node(root).
func New(path string) *Node {
	return &Node{path: path, vpaths: make(map[string]bool)}
}

// Visit all files under the given node.
func (node *Node) Visit(opts *Options) (dirs, files int) {
	// visited paths
	if path, err := filepath.Abs(node.path); err == nil {
		path = filepath.Clean(path)
		node.vpaths[path] = true
	}
	// stat
	fi, err := opts.Fs.Stat(node.path)
	if err != nil {
		node.err = err
		return
	}
	node.FileInfo = fi
	if !fi.IsDir() {
		return 0, 1
	}
	// DeepLevel option
	if opts.DeepLevel > 0 && opts.DeepLevel <= node.depth {
		return 1, 0
	}
	names, err := opts.Fs.ReadDir(node.path)
	if err != nil {
		node.err = err
		return
	}
	node.nodes = make(Nodes, 0)
	for _, name := range names {
		// "all" option
		if !opts.All && strings.HasPrefix(name, ".") {
			continue
		}
		nnode := &Node{
			path:   filepath.Join(node.path, name),
			depth:  node.depth + 1,
			vpaths: node.vpaths,
		}
		d, f := nnode.Visit(opts)
		if nnode.err == nil && !nnode.IsDir() {
			// "dirs only" option
			if opts.DirsOnly {
				continue
			}
			var rePrefix string
			if opts.IgnoreCase {
				rePrefix = "(?i)"
			}
			// Pattern matching
			if opts.Pattern != "" {
				re, err := regexp.Compile(rePrefix + opts.Pattern)
				if err == nil && !re.MatchString(name) {
					continue
				}
			}
			// IPattern matching
			if opts.IPattern != "" {
				re, err := regexp.Compile(rePrefix + opts.IPattern)
				if err == nil && re.MatchString(name) {
					continue
				}
			}
		}
		node.nodes = append(node.nodes, nnode)
		dirs, files = dirs+d, files+f
	}
	// Sorting
	if !opts.NoSort {
		node.sort(opts)
	}
	return dirs + 1, files
}

func (node *Node) sort(opts *Options) {
	var fn SortFunc
	switch {
	case opts.ModSort:
		fn = ModSort
	case opts.CTimeSort:
		fn = CTimeSort
	case opts.DirSort:
		fn = DirSort
	case opts.VerSort:
		fn = VerSort
	case opts.SizeSort:
		fn = SizeSort
	case opts.NameSort:
		fn = NameSort
	}
	if fn != nil {
		if opts.ReverSort {
			sort.Sort(sort.Reverse(ByFunc{node.nodes, fn}))
		} else {
			sort.Sort(ByFunc{node.nodes, fn})
		}
	}
}

// Print nodes based on the given configuration.
func (node *Node) Print(opts *Options) { node.print("", opts) }

func (node *Node) print(indent string, opts *Options) {
	if node.err != nil {
		err := node.err.Error()
		if msgs := strings.Split(err, ": "); len(msgs) > 1 {
			err = msgs[1]
		}
		fmt.Printf("%s [%s]\n", node.path, err)
		return
	}
	if !node.IsDir() {
		var props []string
		var stat = node.Sys().(*syscall.Stat_t)
		// inodes
		if opts.Inodes {
			props = append(props, fmt.Sprintf("%d", stat.Ino))
		}
		// device
		if opts.Device {
			props = append(props, fmt.Sprintf("%3d", stat.Dev))
		}
		// Mode
		if opts.FileMode {
			props = append(props, node.Mode().String())
		}
		// Owner/Uid
		if opts.ShowUid {
			uid := strconv.Itoa(int(stat.Uid))
			if u, err := user.LookupId(uid); err != nil {
				props = append(props, fmt.Sprintf("%-8s", uid))
			} else {
				props = append(props, fmt.Sprintf("%-8s", u.Username))
			}
		}
		// Gorup/Gid
		// TODO: support groupname
		if opts.ShowGid {
			gid := strconv.Itoa(int(stat.Gid))
			props = append(props, fmt.Sprintf("%-4s", gid))
		}
		// Size
		if opts.ByteSize || opts.UnitSize {
			var size string
			if opts.UnitSize {
				size = fmt.Sprintf("%4s", formatBytes(node.Size()))
			} else {
				size = fmt.Sprintf("%11d", node.Size())
			}
			props = append(props, size)
		}
		// Last modification
		if opts.LastMod {
			props = append(props, node.ModTime().Format("Jan 02 15:04"))
		}
		// Print properties
		if len(props) > 0 {
			fmt.Fprintf(opts.OutFile, "[%s]  ", strings.Join(props, " "))
		}
	}
	// name/path
	var name string
	if node.depth == 0 || opts.FullPath {
		name = node.path
	} else {
		name = node.Name()
	}
	// Quotes
	if opts.Quotes {
		name = fmt.Sprintf("\"%s\"", name)
	}
	// Colorize
	if opts.Colorize {
		name = ANSIColor(node, name)
	}
	// IsSymlink
	if node.Mode()&os.ModeSymlink == os.ModeSymlink {
		vtarget, err := os.Readlink(node.path)
		if err != nil {
			vtarget = node.path
		}
		targetPath, err := filepath.EvalSymlinks(node.path)
		if err != nil {
			targetPath = vtarget
		}
		fi, err := opts.Fs.Stat(targetPath)
		if opts.Colorize && fi != nil {
			vtarget = ANSIColor(&Node{FileInfo: fi, path: vtarget}, vtarget)
		}
		name = fmt.Sprintf("%s -> %s", name, vtarget)
		// Follow symbolic links like directories
		if opts.FollowLink {
			path, err := filepath.Abs(targetPath)
			if err == nil && fi != nil && fi.IsDir() {
				if _, ok := node.vpaths[filepath.Clean(path)]; !ok {
					inf := &Node{FileInfo: fi, path: targetPath}
					inf.vpaths = node.vpaths
					inf.Visit(opts)
					node.nodes = inf.nodes
				} else {
					name += " [recursive, not followed]"
				}
			}
		}
	}
	// Print file details
	fmt.Fprintln(opts.OutFile, name)
	add := "│   "
	for i, nnode := range node.nodes {
		if opts.NoIndent {
			add = ""
		} else {
			if i == len(node.nodes)-1 {
				fmt.Fprintf(opts.OutFile, indent+"└── ")
				add = "    "
			} else {
				fmt.Fprintf(opts.OutFile, indent+"├── ")
			}
		}
		nnode.print(indent+add, opts)
	}
}

// Convert bytes to human readable string. Like a 2 MB, 64.2 KB, 52 B
func formatBytes(i int64) (result string) {
	var n float64
	sFmt, eFmt := "%.01f", ""
	switch {
	case i > (1024 * 1024 * 1024):
		eFmt = "G"
		n = float64(i) / 1024 / 1024 / 1024
	case i > (1024 * 1024):
		eFmt = "M"
		n = float64(i) / 1024 / 1024
	case i > 1024:
		eFmt = "K"
		n = float64(i) / 1024
	default:
		sFmt = "%.0f"
		n = float64(i)
	}
	if eFmt != "" && n >= 10 {
		sFmt = "%.0f"
	}
	result = fmt.Sprintf(sFmt+eFmt, n)
	result = strings.Trim(result, " ")
	return
}
<commit_msg>docs(node): add credit note<commit_after>package tree

import (
	"fmt"
	"io"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"syscall"
)

// Node represent some node in the tree
// contains FileInfo, and its childs
type Node struct {
	os.FileInfo
	path   string
	depth  int
	err    error
	nodes  Nodes
	vpaths map[string]bool
}

// List of nodes
type Nodes []*Node

// To use this package programmatically, you must implement this
// interface.
// For example: PTAL on 'cmd/tree/tree.go'
type Fs interface {
	Stat(path string) (os.FileInfo, error)
	ReadDir(path string) ([]string, error)
}

// Options store the configuration for specific tree.
// Note, that 'Fs', and 'OutFile' are required (OutFile can be os.Stdout).
type Options struct {
	Fs      Fs
	OutFile io.Writer
	// List
	All        bool
	DirsOnly   bool
	FullPath   bool
	IgnoreCase bool
	FollowLink bool
	DeepLevel  int
	Pattern    string
	IPattern   string
	// File
	ByteSize bool
	UnitSize bool
	FileMode bool
	ShowUid  bool
	ShowGid  bool
	LastMod  bool
	Quotes   bool
	Inodes   bool
	Device   bool
	// Sort
	NoSort    bool
	VerSort   bool
	ModSort   bool
	DirSort   bool
	NameSort  bool
	SizeSort  bool
	CTimeSort bool
	ReverSort bool
	// Graphics
	NoIndent bool
	Colorize bool
}

// New get path and create new node(root).
func New(path string) *Node {
	return &Node{path: path, vpaths: make(map[string]bool)}
}

// Visit all files under the given node.
func (node *Node) Visit(opts *Options) (dirs, files int) {
	// visited paths
	if path, err := filepath.Abs(node.path); err == nil {
		path = filepath.Clean(path)
		node.vpaths[path] = true
	}
	// stat
	fi, err := opts.Fs.Stat(node.path)
	if err != nil {
		node.err = err
		return
	}
	node.FileInfo = fi
	if !fi.IsDir() {
		return 0, 1
	}
	// DeepLevel option
	if opts.DeepLevel > 0 && opts.DeepLevel <= node.depth {
		return 1, 0
	}
	names, err := opts.Fs.ReadDir(node.path)
	if err != nil {
		node.err = err
		return
	}
	node.nodes = make(Nodes, 0)
	for _, name := range names {
		// "all" option
		if !opts.All && strings.HasPrefix(name, ".") {
			continue
		}
		nnode := &Node{
			path:   filepath.Join(node.path, name),
			depth:  node.depth + 1,
			vpaths: node.vpaths,
		}
		d, f := nnode.Visit(opts)
		if nnode.err == nil && !nnode.IsDir() {
			// "dirs only" option
			if opts.DirsOnly {
				continue
			}
			var rePrefix string
			if opts.IgnoreCase {
				rePrefix = "(?i)"
			}
			// Pattern matching
			if opts.Pattern != "" {
				re, err := regexp.Compile(rePrefix + opts.Pattern)
				if err == nil && !re.MatchString(name) {
					continue
				}
			}
			// IPattern matching
			if opts.IPattern != "" {
				re, err := regexp.Compile(rePrefix + opts.IPattern)
				if err == nil && re.MatchString(name) {
					continue
				}
			}
		}
		node.nodes = append(node.nodes, nnode)
		dirs, files = dirs+d, files+f
	}
	// Sorting
	if !opts.NoSort {
		node.sort(opts)
	}
	return dirs + 1, files
}

func (node *Node) sort(opts *Options) {
	var fn SortFunc
	switch {
	case opts.ModSort:
		fn = ModSort
	case opts.CTimeSort:
		fn = CTimeSort
	case opts.DirSort:
		fn = DirSort
	case opts.VerSort:
		fn = VerSort
	case opts.SizeSort:
		fn = SizeSort
	case opts.NameSort:
		fn = NameSort
	}
	if fn != nil {
		if opts.ReverSort {
			sort.Sort(sort.Reverse(ByFunc{node.nodes, fn}))
		} else {
			sort.Sort(ByFunc{node.nodes, fn})
		}
	}
}

// Print nodes based on the given configuration.
func (node *Node) Print(opts *Options) { node.print("", opts) }

func (node *Node) print(indent string, opts *Options) {
	if node.err != nil {
		err := node.err.Error()
		if msgs := strings.Split(err, ": "); len(msgs) > 1 {
			err = msgs[1]
		}
		fmt.Printf("%s [%s]\n", node.path, err)
		return
	}
	if !node.IsDir() {
		var props []string
		var stat = node.Sys().(*syscall.Stat_t)
		// inodes
		if opts.Inodes {
			props = append(props, fmt.Sprintf("%d", stat.Ino))
		}
		// device
		if opts.Device {
			props = append(props, fmt.Sprintf("%3d", stat.Dev))
		}
		// Mode
		if opts.FileMode {
			props = append(props, node.Mode().String())
		}
		// Owner/Uid
		if opts.ShowUid {
			uid := strconv.Itoa(int(stat.Uid))
			if u, err := user.LookupId(uid); err != nil {
				props = append(props, fmt.Sprintf("%-8s", uid))
			} else {
				props = append(props, fmt.Sprintf("%-8s", u.Username))
			}
		}
		// Gorup/Gid
		// TODO: support groupname
		if opts.ShowGid {
			gid := strconv.Itoa(int(stat.Gid))
			props = append(props, fmt.Sprintf("%-4s", gid))
		}
		// Size
		if opts.ByteSize || opts.UnitSize {
			var size string
			if opts.UnitSize {
				size = fmt.Sprintf("%4s", formatBytes(node.Size()))
			} else {
				size = fmt.Sprintf("%11d", node.Size())
			}
			props = append(props, size)
		}
		// Last modification
		if opts.LastMod {
			props = append(props, node.ModTime().Format("Jan 02 15:04"))
		}
		// Print properties
		if len(props) > 0 {
			fmt.Fprintf(opts.OutFile, "[%s]  ", strings.Join(props, " "))
		}
	}
	// name/path
	var name string
	if node.depth == 0 || opts.FullPath {
		name = node.path
	} else {
		name = node.Name()
	}
	// Quotes
	if opts.Quotes {
		name = fmt.Sprintf("\"%s\"", name)
	}
	// Colorize
	if opts.Colorize {
		name = ANSIColor(node, name)
	}
	// IsSymlink
	if node.Mode()&os.ModeSymlink == os.ModeSymlink {
		vtarget, err := os.Readlink(node.path)
		if err != nil {
			vtarget = node.path
		}
		targetPath, err := filepath.EvalSymlinks(node.path)
		if err != nil {
			targetPath = vtarget
		}
		fi, err := opts.Fs.Stat(targetPath)
		if opts.Colorize && fi != nil {
			vtarget = ANSIColor(&Node{FileInfo: fi, path: vtarget}, vtarget)
		}
		name = fmt.Sprintf("%s -> %s", name, vtarget)
		// Follow symbolic links like directories
		if opts.FollowLink {
			path, err := filepath.Abs(targetPath)
			if err == nil && fi != nil && fi.IsDir() {
				if _, ok := node.vpaths[filepath.Clean(path)]; !ok {
					inf := &Node{FileInfo: fi, path: targetPath}
					inf.vpaths = node.vpaths
					inf.Visit(opts)
					node.nodes = inf.nodes
				} else {
					name += " [recursive, not followed]"
				}
			}
		}
	}
	// Print file details
	// the main idea of the print logic came from here: github.com/campoy/tools/tree
	fmt.Fprintln(opts.OutFile, name)
	add := "│   "
	for i, nnode := range node.nodes {
		if opts.NoIndent {
			add = ""
		} else {
			if i == len(node.nodes)-1 {
				fmt.Fprintf(opts.OutFile, indent+"└── ")
				add = "    "
			} else {
				fmt.Fprintf(opts.OutFile, indent+"├── ")
			}
		}
		nnode.print(indent+add, opts)
	}
}

// Convert bytes to human readable string. Like a 2 MB, 64.2 KB, 52 B
func formatBytes(i int64) (result string) {
	var n float64
	sFmt, eFmt := "%.01f", ""
	switch {
	case i > (1024 * 1024 * 1024):
		eFmt = "G"
		n = float64(i) / 1024 / 1024 / 1024
	case i > (1024 * 1024):
		eFmt = "M"
		n = float64(i) / 1024 / 1024
	case i > 1024:
		eFmt = "K"
		n = float64(i) / 1024
	default:
		sFmt = "%.0f"
		n = float64(i)
	}
	if eFmt != "" && n >= 10 {
		sFmt = "%.0f"
	}
	result = fmt.Sprintf(sFmt+eFmt, n)
	result = strings.Trim(result, " ")
	return
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

// NodeVersion is the current node version
var NodeVersion = "?"

// RunScript runs some node code
func (p *Plugins) RunScript(script string) (cmd *exec.Cmd, done func()) {
	cacheTmp := filepath.Join(CacheHome, "tmp")
	os.MkdirAll(cacheTmp, 0755)
	f, err := ioutil.TempFile(cacheTmp, "heroku-script-")
	if err != nil {
		LogIfError(err)
	}
	if f != nil {
		defer f.Close()
		if _, err := f.WriteString(script); err != nil {
			LogIfError(err)
		}
		cmd = exec.Command(nodeBinPath(), f.Name())
	} else {
		cmd = exec.Command(nodeBinPath(), "-e", script)
	}
	cmd.Env = append([]string{"NODE_PATH=" + p.modulesPath()}, os.Environ()...)
	return cmd, func() {
		if f != nil {
			os.Remove(f.Name())
		}
	}
}

func nodeBinPath() string {
	b := os.Getenv("HEROKU_NODE_PATH")
	ext := ""
	if runtime.GOOS == WINDOWS {
		ext = ".exe"
	}
	if b == "" {
		b = filepath.Join(AppDir, "lib", "node"+ext)
	}
	if exists, _ := FileExists(b); !exists {
		var err error
		Debugf("node not found in %s. Using node from PATH\n", b)
		b, err = exec.LookPath("node" + ext)
		must(err)
	}
	return b
}

func (p *Plugins) modulesPath() string {
	return filepath.Join(p.Path, "node_modules")
}
<commit_msg>ignore logging error when creating tmp script<commit_after>package main

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

// NodeVersion is the current node version
var NodeVersion = "?"

// RunScript runs some node code
func (p *Plugins) RunScript(script string) (cmd *exec.Cmd, done func()) {
	cacheTmp := filepath.Join(CacheHome, "tmp")
	os.MkdirAll(cacheTmp, 0755)
	f, _ := ioutil.TempFile(cacheTmp, "heroku-script-")
	if f != nil {
		defer f.Close()
		if _, err := f.WriteString(script); err != nil {
			LogIfError(err)
		}
		cmd = exec.Command(nodeBinPath(), f.Name())
	} else {
		cmd = exec.Command(nodeBinPath(), "-e", script)
	}
	cmd.Env = append([]string{"NODE_PATH=" + p.modulesPath()}, os.Environ()...)
	return cmd, func() {
		if f != nil {
			os.Remove(f.Name())
		}
	}
}

func nodeBinPath() string {
	b := os.Getenv("HEROKU_NODE_PATH")
	ext := ""
	if runtime.GOOS == WINDOWS {
		ext = ".exe"
	}
	if b == "" {
		b = filepath.Join(AppDir, "lib", "node"+ext)
	}
	if exists, _ := FileExists(b); !exists {
		var err error
		Debugf("node not found in %s. Using node from PATH\n", b)
		b, err = exec.LookPath("node" + ext)
		must(err)
	}
	return b
}

func (p *Plugins) modulesPath() string {
	return filepath.Join(p.Path, "node_modules")
}
<|endoftext|>


<commit_before>/*
Copyright (C) Andres Rodriguez

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 triedb

// Persistent trie node interface
type node struct {
	key      byte
	value    Value
	next     *node
	children *node
}

func (n *node) get(key []byte, pos int) Value {
	var k = key[pos]
	// Next sibling
	if k > n.key {
		if n.next != nil {
			return n.next.get(key, pos)
		}
		return nil
	}
	// Current node
	if k == n.key {
		var last = len(key) - 1
		if pos < last {
			if n.children != nil {
				return n.children.get(key, pos+1)
			}
			return nil
		}
		if pos == last {
			return n.value
		}
		panic("Position exceeded")
	}
	// Previous sibling, should not happen
	panic("Previous sibling")
}

func (n *node) remove(key []byte, pos int) *node {
	return nil // todo
}
<commit_msg>Trie nodes<commit_after>/*
Copyright (C) Andres Rodriguez

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 triedb

// Persistent trie node interface
type node struct {
	key      byte
	depth    int16
	count    int32
	value    Value
	next     *node
	children *node
}

// Creates a new node
func createNode(key byte, value Value, next *node, children *node) *node {
	var d int16
	var c int32
	if value == nil {
		c = 0
	} else {
		c = 1
	}
	if next != nil {
		c += next.count
	}
	if children != nil {
		d = 1 + children.depth
	} else {
		d = 1
	}
	return &node{key, d, c, value, next, children}
}

// Creates a leaf node
func createLeaf(key byte, value Value) *node {
	return createNode(key, value, nil, nil)
}

// Gets the value for a key.
func (n *node) get(key []byte, pos int) Value {
	var last = len(key) - 1
	if pos >= last {
		panic("Position exceeded")
	}
	var k = key[pos]
	// Next sibling
	if k > n.key {
		if n.next != nil {
			return n.next.get(key, pos)
		}
		return nil
	}
	// Current node
	if k == n.key {
		if pos < last {
			if n.children != nil {
				return n.children.get(key, pos+1)
			}
			return nil
		}
		if pos == last {
			return n.value
		}
	}
	// Previous sibling
	return nil
}

// Changes the next pointer of a node
func (n *node) setNext(next *node) *node {
	if n.next == next {
		return n
	}
	return createNode(n.key, n.value, next, n.children)
}

// Changes the children pointer of a node
func (n *node) setChildren(children *node) *node {
	if n.children == children {
		return n
	}
	return createNode(n.key, n.value, n.next, children)
}

// Sets the value of a key.
func (n *node) set(key []byte, pos int, value Value) *node {
	var last = len(key) - 1
	if pos >= last {
		panic("Position exceeded")
	}
	var k = key[pos]
	// Previous sibling
	if k < n.key {
		return n // Not found, unmodified
	}
	var ret *node // return value
	// Next sibling
	if k > n.key {
		if n.next != nil {
			ret = n.setNext(n.next.set(key, pos, value))
		} else {
			return n // Not found, unmodified
		}
	}
	// Current node
	if k == n.key {
		if pos < last {
			if n.children != nil {
				ret = n.setChildren(n.children.set(key, pos+1, value))
			} else {
				return n // Not found, unmodified
			}
		} else { // this is the node to change
			if n.value == value {
				return n // Unmodified
			} else {
				ret = createNode(n.key, value, n.next, n.children)
			}
		}
	}
	// Check if the node has to disappear
	if ret.value == nil && ret.next == nil && ret.children == nil {
		return nil
	}
	return ret
}

// Removes a key
func (n *node) remove(key []byte, pos int) *node {
	return n.set(key, pos, nil)
}
<|endoftext|>


<commit_before>// Copyright 2014 Alea Soluciones SLL. All rights reserved.  Use of this
// source code is governed by a MIT-style license that can be found in the
// LICENSE file.

package circuitbreaker

import "time"

type Circuit struct {
	numErrors int
	commands  chan commandData
	resetTime time.Duration
}

type commandData struct {
	action int
	result chan<- interface{}
}

const (
	OK = iota
	ERROR
	GET_NUMBERS_OF_ERRORS
	RESET
	IS_RESETTING
	RESET_FINISHED
)

func NewCircuit(numErrors int, resetTime time.Duration) *Circuit {
	circuit := Circuit{
		numErrors: numErrors,
		resetTime: resetTime,
		commands:  make(chan commandData),
	}
	go circuit.run()
	return &circuit
}

func (crt Circuit) run() {
	numErrors := 0
	resetting := false
	lastError := time.Now()

	for command := range crt.commands {
		switch command.action {
		case GET_NUMBERS_OF_ERRORS:
			command.result <- numErrors
		case IS_RESETTING:
			command.result <- resetting
		case OK:
			numErrors = 0
		case ERROR:
			now := time.Now()
			if now.Sub(lastError) >= crt.resetTime {
				numErrors = 1
			} else {
				numErrors++
			}
			lastError = now

			if crt.numErrors == numErrors {
				resetting = true
				go crt.waitUntilReset(time.After(crt.resetTime))
			}
		case RESET_FINISHED:
			numErrors = 0
			resetting = false
		}
	}
}

func (crt Circuit) IsClosed() bool {
	return crt.replyTo(GET_NUMBERS_OF_ERRORS) != crt.numErrors
}

func (crt Circuit) IsOpen() bool {
	return !crt.IsClosed()
}

func (crt Circuit) replyTo(action int) interface{} {
	reply := make(chan interface{})
	crt.commands <- commandData{action: action, result: reply}
	return <-reply
}

func (crt Circuit) Ok() {
	crt.newStatus(OK)
}

func (crt Circuit) Error() {
	crt.newStatus(ERROR)
}

func (crt Circuit) newStatus(status int) {
	if !crt.isResetting() {
		crt.commands <- commandData{action: status}
	}
}

func (crt Circuit) isResetting() bool {
	return crt.replyTo(IS_RESETTING).(bool)
}

func (crt Circuit) waitUntilReset(resetTime <-chan time.Time) {
	select {
	case <-resetTime:
		crt.commands <- commandData{action: RESET_FINISHED}
	}
}
<commit_msg>clock injection at circuitbraker to facilitate the testing<commit_after>// Copyright 2014 Alea Soluciones SLL. All rights reserved.  Use of this
// source code is governed by a MIT-style license that can be found in the
// LICENSE file.

package circuitbreaker

import (
	"time"

	"github.com/aleasoluciones/goaleasoluciones/clock"
)

type Circuit struct {
	numErrors int
	commands  chan commandData
	resetTime time.Duration
	clock     clock.Clock
}

type commandData struct {
	action int
	result chan<- interface{}
}

const (
	OK = iota
	ERROR
	GET_NUMBERS_OF_ERRORS
	RESET
	IS_RESETTING
	RESET_FINISHED
)

func NewCircuitWithClock(numErrors int, resetTime time.Duration, clock clock.Clock) *Circuit {
	circuit := Circuit{
		numErrors: numErrors,
		resetTime: resetTime,
		commands:  make(chan commandData),
		clock:     clock,
	}
	go circuit.run()
	return &circuit
}

func NewCircuit(numErrors int, resetTime time.Duration) *Circuit {
	return NewCircuitWithClock(numErrors, resetTime, clock.NewClock())
}

func (crt Circuit) run() {
	numErrors := 0
	resetting := false
	lastError := time.Now()

	for command := range crt.commands {
		switch command.action {
		case GET_NUMBERS_OF_ERRORS:
			command.result <- numErrors
		case IS_RESETTING:
			command.result <- resetting
		case OK:
			numErrors = 0
		case ERROR:
			now := time.Now()
			if now.Sub(lastError) >= crt.resetTime {
				numErrors = 1
			} else {
				numErrors++
			}
			lastError = now

			if crt.numErrors == numErrors {
				resetting = true
				go crt.waitUntilReset(time.After(crt.resetTime))
			}
		case RESET_FINISHED:
			numErrors = 0
			resetting = false
		}
	}
}

func (crt Circuit) IsClosed() bool {
	return crt.replyTo(GET_NUMBERS_OF_ERRORS) != crt.numErrors
}

func (crt Circuit) IsOpen() bool {
	return !crt.IsClosed()
}

func (crt Circuit) replyTo(action int) interface{} {
	reply := make(chan interface{})
	crt.commands <- commandData{action: action, result: reply}
	return <-reply
}

func (crt Circuit) Ok() {
	crt.newStatus(OK)
}

func (crt Circuit) Error() {
	crt.newStatus(ERROR)
}

func (crt Circuit) newStatus(status int) {
	if !crt.isResetting() {
		crt.commands <- commandData{action: status}
	}
}

func (crt Circuit) isResetting() bool {
	return crt.replyTo(IS_RESETTING).(bool)
}

func (crt Circuit) waitUntilReset(resetTime <-chan time.Time) {
	select {
	case <-resetTime:
		crt.commands <- commandData{action: RESET_FINISHED}
	}
}
<|endoftext|>