<commit_before>package redis

import (
	"bufio"
	"errors"
	"fmt"
	"net"
	"net/url"
	"strconv"
	"strings"
	"sync"

	"github.com/influxdb/telegraf/plugins"
)

type Redis struct {
	Servers []string

	c   net.Conn
	buf []byte
}

var sampleConfig = `
# An array of URI to gather stats about. Specify an ip or hostname
# with optional port add password. ie redis://localhost, redis://10.10.3.33:18832,
# 10.0.0.1:10000, etc.
#
# If no servers are specified, then localhost is used as the host.
servers = ["localhost"]`

func (r *Redis) SampleConfig() string {
	return sampleConfig
}

func (r *Redis) Description() string {
	return "Read metrics from one or many redis servers"
}

var Tracking = map[string]string{
	"uptime_in_seconds":           "uptime",
	"connected_clients":           "clients",
	"used_memory":                 "used_memory",
	"used_memory_rss":             "used_memory_rss",
	"used_memory_peak":            "used_memory_peak",
	"used_memory_lua":             "used_memory_lua",
	"rdb_changes_since_last_save": "rdb_changes_since_last_save",
	"total_connections_received":  "total_connections_received",
	"total_commands_processed":    "total_commands_processed",
	"instantaneous_ops_per_sec":   "instantaneous_ops_per_sec",
	"sync_full":                   "sync_full",
	"sync_partial_ok":             "sync_partial_ok",
	"sync_partial_err":            "sync_partial_err",
	"expired_keys":                "expired_keys",
	"evicted_keys":                "evicted_keys",
	"keyspace_hits":               "keyspace_hits",
	"keyspace_misses":             "keyspace_misses",
	"pubsub_channels":             "pubsub_channels",
	"pubsub_patterns":             "pubsub_patterns",
	"latest_fork_usec":            "latest_fork_usec",
	"connected_slaves":            "connected_slaves",
	"master_repl_offset":          "master_repl_offset",
	"repl_backlog_active":         "repl_backlog_active",
	"repl_backlog_size":           "repl_backlog_size",
	"repl_backlog_histlen":        "repl_backlog_histlen",
	"mem_fragmentation_ratio":     "mem_fragmentation_ratio",
	"used_cpu_sys":                "used_cpu_sys",
	"used_cpu_user":               "used_cpu_user",
	"used_cpu_sys_children":       "used_cpu_sys_children",
	"used_cpu_user_children":      "used_cpu_user_children",
}

var ErrProtocolError = errors.New("redis protocol error")

// Reads stats from all configured servers accumulates stats.
// Returns one of the errors encountered while gather stats (if any).
func (g *Redis) Gather(acc plugins.Accumulator) error {
	if len(g.Servers) == 0 {
		url := &url.URL{
			Host: ":6379",
		}
		g.gatherServer(url, acc)
		return nil
	}

	var wg sync.WaitGroup

	var outerr error

	for _, serv := range g.Servers {
		u, err := url.Parse(serv)
		if err != nil {
			return fmt.Errorf("Unable to parse to address '%s': %s", serv, err)
		} else if u.Scheme == "" {
			// fallback to simple string based address (i.e. "10.0.0.1:10000")
			u.Host = serv
		}
		wg.Add(1)
		go func(serv string) {
			defer wg.Done()
			outerr = g.gatherServer(u, acc)
		}(serv)
	}

	wg.Wait()

	return outerr
}

const defaultPort = "6379"

func (g *Redis) gatherServer(addr *url.URL, acc plugins.Accumulator) error {
	if g.c == nil {

		_, _, err := net.SplitHostPort(addr.Host)
		if err != nil {
			addr.Host = addr.Host + ":" + defaultPort
		}

		c, err := net.Dial("tcp", addr.Host)
		if err != nil {
			return fmt.Errorf("Unable to connect to redis server '%s': %s", addr.Host, err)
		}

		if addr.User != nil {
			pwd, set := addr.User.Password()
			if set && pwd != "" {
				c.Write([]byte(fmt.Sprintf("AUTH %s\n", pwd)))

				r := bufio.NewReader(c)

				line, err := r.ReadString('\n')
				if err != nil {
					return err
				}
				if line[0] != '+' {
					return fmt.Errorf("%s", strings.TrimSpace(line)[1:])
				}
			}
		}

		g.c = c
	}

	g.c.Write([]byte("info\n"))

	r := bufio.NewReader(g.c)

	line, err := r.ReadString('\n')
	if err != nil {
		return err
	}

	if line[0] != '$' {
		return fmt.Errorf("bad line start: %s", ErrProtocolError)
	}

	line = strings.TrimSpace(line)

	szStr := line[1:]

	sz, err := strconv.Atoi(szStr)
	if err != nil {
		return fmt.Errorf("bad size string <<%s>>: %s", szStr, ErrProtocolError)
	}

	var read int

	for read < sz {
		line, err := r.ReadString('\n')
		if err != nil {
			return err
		}

		read += len(line)

		if len(line) == 1 || line[0] == '#' {
			continue
		}

		parts := strings.SplitN(line, ":", 2)

		name := string(parts[0])

		metric, ok := Tracking[name]
		if !ok {
			continue
		}

		tags := map[string]string{"host": addr}
		val := strings.TrimSpace(parts[1])

		ival, err := strconv.ParseUint(val, 10, 64)
		if err == nil {
			acc.Add(metric, ival, tags)
			continue
		}

		fval, err := strconv.ParseFloat(val, 64)
		if err != nil {
			return err
		}

		acc.Add(metric, fval, tags)
	}

	return nil
}

func init() {
	plugins.Add("redis", func() plugins.Plugin {
		return &Redis{}
	})
}
<commit_msg>Fix type error using URL as a string<commit_after>package redis

import (
	"bufio"
	"errors"
	"fmt"
	"net"
	"net/url"
	"strconv"
	"strings"
	"sync"

	"github.com/influxdb/telegraf/plugins"
)

type Redis struct {
	Servers []string

	c   net.Conn
	buf []byte
}

var sampleConfig = `
# An array of URI to gather stats about. Specify an ip or hostname
# with optional port add password. ie redis://localhost, redis://10.10.3.33:18832,
# 10.0.0.1:10000, etc.
#
# If no servers are specified, then localhost is used as the host.
servers = ["localhost"]`

func (r *Redis) SampleConfig() string {
	return sampleConfig
}

func (r *Redis) Description() string {
	return "Read metrics from one or many redis servers"
}

var Tracking = map[string]string{
	"uptime_in_seconds":           "uptime",
	"connected_clients":           "clients",
	"used_memory":                 "used_memory",
	"used_memory_rss":             "used_memory_rss",
	"used_memory_peak":            "used_memory_peak",
	"used_memory_lua":             "used_memory_lua",
	"rdb_changes_since_last_save": "rdb_changes_since_last_save",
	"total_connections_received":  "total_connections_received",
	"total_commands_processed":    "total_commands_processed",
	"instantaneous_ops_per_sec":   "instantaneous_ops_per_sec",
	"sync_full":                   "sync_full",
	"sync_partial_ok":             "sync_partial_ok",
	"sync_partial_err":            "sync_partial_err",
	"expired_keys":                "expired_keys",
	"evicted_keys":                "evicted_keys",
	"keyspace_hits":               "keyspace_hits",
	"keyspace_misses":             "keyspace_misses",
	"pubsub_channels":             "pubsub_channels",
	"pubsub_patterns":             "pubsub_patterns",
	"latest_fork_usec":            "latest_fork_usec",
	"connected_slaves":            "connected_slaves",
	"master_repl_offset":          "master_repl_offset",
	"repl_backlog_active":         "repl_backlog_active",
	"repl_backlog_size":           "repl_backlog_size",
	"repl_backlog_histlen":        "repl_backlog_histlen",
	"mem_fragmentation_ratio":     "mem_fragmentation_ratio",
	"used_cpu_sys":                "used_cpu_sys",
	"used_cpu_user":               "used_cpu_user",
	"used_cpu_sys_children":       "used_cpu_sys_children",
	"used_cpu_user_children":      "used_cpu_user_children",
}

var ErrProtocolError = errors.New("redis protocol error")

// Reads stats from all configured servers accumulates stats.
// Returns one of the errors encountered while gather stats (if any).
func (g *Redis) Gather(acc plugins.Accumulator) error {
	if len(g.Servers) == 0 {
		url := &url.URL{
			Host: ":6379",
		}
		g.gatherServer(url, acc)
		return nil
	}

	var wg sync.WaitGroup

	var outerr error

	for _, serv := range g.Servers {
		u, err := url.Parse(serv)
		if err != nil {
			return fmt.Errorf("Unable to parse to address '%s': %s", serv, err)
		} else if u.Scheme == "" {
			// fallback to simple string based address (i.e. "10.0.0.1:10000")
			u.Host = serv
		}
		wg.Add(1)
		go func(serv string) {
			defer wg.Done()
			outerr = g.gatherServer(u, acc)
		}(serv)
	}

	wg.Wait()

	return outerr
}

const defaultPort = "6379"

func (g *Redis) gatherServer(addr *url.URL, acc plugins.Accumulator) error {
	if g.c == nil {

		_, _, err := net.SplitHostPort(addr.Host)
		if err != nil {
			addr.Host = addr.Host + ":" + defaultPort
		}

		c, err := net.Dial("tcp", addr.Host)
		if err != nil {
			return fmt.Errorf("Unable to connect to redis server '%s': %s", addr.Host, err)
		}

		if addr.User != nil {
			pwd, set := addr.User.Password()
			if set && pwd != "" {
				c.Write([]byte(fmt.Sprintf("AUTH %s\n", pwd)))

				r := bufio.NewReader(c)

				line, err := r.ReadString('\n')
				if err != nil {
					return err
				}
				if line[0] != '+' {
					return fmt.Errorf("%s", strings.TrimSpace(line)[1:])
				}
			}
		}

		g.c = c
	}

	g.c.Write([]byte("info\n"))

	r := bufio.NewReader(g.c)

	line, err := r.ReadString('\n')
	if err != nil {
		return err
	}

	if line[0] != '$' {
		return fmt.Errorf("bad line start: %s", ErrProtocolError)
	}

	line = strings.TrimSpace(line)

	szStr := line[1:]

	sz, err := strconv.Atoi(szStr)
	if err != nil {
		return fmt.Errorf("bad size string <<%s>>: %s", szStr, ErrProtocolError)
	}

	var read int

	for read < sz {
		line, err := r.ReadString('\n')
		if err != nil {
			return err
		}

		read += len(line)

		if len(line) == 1 || line[0] == '#' {
			continue
		}

		parts := strings.SplitN(line, ":", 2)

		name := string(parts[0])

		metric, ok := Tracking[name]
		if !ok {
			continue
		}

		tags := map[string]string{"host": addr.String()}
		val := strings.TrimSpace(parts[1])

		ival, err := strconv.ParseUint(val, 10, 64)
		if err == nil {
			acc.Add(metric, ival, tags)
			continue
		}

		fval, err := strconv.ParseFloat(val, 64)
		if err != nil {
			return err
		}

		acc.Add(metric, fval, tags)
	}

	return nil
}

func init() {
	plugins.Add("redis", func() plugins.Plugin {
		return &Redis{}
	})
}
<|endoftext|>


<commit_before>/*
 * // Copyright (c) 2018 Cisco and/or its affiliates.
 * //
 * // 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.
 */

// Architecture
// ============
//
// Service plugin is split into multiple layers with the data moving
// in the direction from the up to the bottom. Each layer obtains service-related
// data from the layer above and outputs them processed in some way into
// the layer below. On the top there are K8s state data for endpoints and
// services as reflected into ETCD by KSR. With each layer the abstraction level
// decreases until at the very bottom the corresponding set of NAT rules
// is calculated and installed into the VPP via vpp-agent.
//
// Layers
// ------
//
//	1. Service Plugin:
//     - implements the Plugin interface for CN-Infra
//     - initializes all layers, performs dependency injection
//     - watches ETCD for changes written by KSR for endpoints and services
//     - propagates datasync events into the Service Processor without
//       any pre-processing
//     - postpones RESYNC until the Contiv plugin has finalized its RESYNC
//
//  2. Service Processor
//     - receives RESYNC and data-change events for endpoints and services
//       from the service plugin
//     - internally caches the current state of the configuration (since the last
//       RESYNC)
//     - uses the cache to match subsets of endpoints with the corresponding
//       service definition
//     - combines endpoint data with service data into a less abstract service
//       representation denoted as "ContivService":
//         * service port is matched with endpoint port by the assigned name
//         * based on the service type, collects all external IP addresses,
//           i.e. addresses on which the service should be exposed
//     - maintains the set of interfaces connecting frontends (physical
//	     interfaces and pods that do not run any service) and backends (pods
//       which act as replicas of some service)
//         * the set of physical interfaces is learned from the Contiv plugin
//         * Contiv plugin is also used to convert pod IDs to their associated
//           interfaces
//
//  3. Service Configurator
//     - until we have NAT44 supported in the vpp-agent, the configurator
//       installs the configuration directly via VPP/NAT plugin binary API
//     - translates ContivService into the corresponding NAT configuration
//     - applies out2in and in2out VPP/NAT's features on interfaces connecting
//       frontends and backends, respectivelly
//     - for each change, calculates the minimal diff, i.e. the smallest set
//       of binary API request that need to be executed to get the NAT
//       configuration in-sync with the state of K8s services
//
//
// Diagram
// -------
//
// +-----------------------------------+
// |                                   |
// |                                   |
// |              ETCD                 |
// |                                   |
// |                |                  |
// +----------------|------------------+
//                watch
// +----------------|------------------+
// |                v                  |
// |                                   |
// |       1. Service Plugin           |
// |                                   |
// |                 |                 |
// +-----------------|-----------------+
//         Data-change/RESYNC
// +-----------------|-----------------+
// |                 v                 |
// |                                   |
// |       2. Service Processor        |
// |                                   |
// |                 |                 |
// +-----------------|-----------------+
//       Configure Contiv Services
// +-----------------|-----------------+
// |                 v                 |
// |                                   |
// |       3. Service Configurator     |
// |                                   |
// |      |                     |      |
// +------|---------------------|------+
//   Install NAT configuration (currently via binary APIs, later via vpp-agent)
// +-------|--------------------|------+
// |       v                    v      |
// |                                   |
// |                VPP                |
// |                                   |
// |                                   |
// +-----------------------------------+
//

// Package service implements support for Kubernetes services for VPP using
// the VPP NAT plugin (https://wiki.fd.io/view/VPP/NAT).
package service
<commit_msg>Include KSR in the doc.go for service plugin.<commit_after>/*
 * // Copyright (c) 2018 Cisco and/or its affiliates.
 * //
 * // 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.
 */

// Architecture
// ============
//
// Service plugin is split into multiple layers with the data moving
// in the direction from the up to the bottom. Each layer obtains service-related
// data from the layer above and outputs them processed in some way into
// the layer below. On the top there are K8s state data for endpoints and
// services as reflected into ETCD by KSR. With each layer the abstraction level
// decreases until at the very bottom the corresponding set of NAT rules
// is calculated and installed into the VPP via vpp-agent.
//
// Layers
// ------
//
//	1. Service Plugin:
//     - implements the Plugin interface for CN-Infra
//     - initializes all layers, performs dependency injection
//     - watches ETCD for changes written by KSR for endpoints and services
//     - propagates datasync events into the Service Processor without
//       any pre-processing
//     - postpones RESYNC until the Contiv plugin has finalized its RESYNC
//
//  2. Service Processor
//     - receives RESYNC and data-change events for endpoints and services
//       from the service plugin
//     - internally caches the current state of the configuration (since the last
//       RESYNC)
//     - uses the cache to match subsets of endpoints with the corresponding
//       service definition
//     - combines endpoint data with service data into a less abstract service
//       representation denoted as "ContivService":
//         * service port is matched with endpoint port by the assigned name
//         * based on the service type, collects all external IP addresses,
//           i.e. addresses on which the service should be exposed
//     - maintains the set of interfaces connecting frontends (physical
//	     interfaces and pods that do not run any service) and backends (pods
//       which act as replicas of some service)
//         * the set of physical interfaces is learned from the Contiv plugin
//         * Contiv plugin is also used to convert pod IDs to their associated
//           interfaces
//
//  3. Service Configurator
//     - until we have NAT44 supported in the vpp-agent, the configurator
//       installs the configuration directly via VPP/NAT plugin binary API
//     - translates ContivService into the corresponding NAT configuration
//     - applies out2in and in2out VPP/NAT's features on interfaces connecting
//       frontends and backends, respectivelly
//     - for each change, calculates the minimal diff, i.e. the smallest set
//       of binary API request that need to be executed to get the NAT
//       configuration in-sync with the state of K8s services
//
//
// Diagram
// -------
//
// +-----------------------------------+
// |                                   |
// |                                   |
// |               K8s                 |
// |                                   |
// |                |                  |
// +----------------|------------------+
//           watch via K8s API
// +----------------|------------------+
// |                v                  |
// |                                   |
// |               KSR                 |
// |                                   |
// |                |                  |
// +----------------|------------------+
//                write
// +----------------|------------------+
// |                v                  |
// |                                   |
// |              ETCD                 |
// |                                   |
// |                |                  |
// +----------------|------------------+
//                watch
// +----------------|------------------+
// |                v                  |
// |                                   |
// |       1. Service Plugin           |
// |                                   |
// |                 |                 |
// +-----------------|-----------------+
//         Data-change/RESYNC
// +-----------------|-----------------+
// |                 v                 |
// |                                   |
// |       2. Service Processor        |
// |                                   |
// |                 |                 |
// +-----------------|-----------------+
//       Configure Contiv Services
// +-----------------|-----------------+
// |                 v                 |
// |                                   |
// |       3. Service Configurator     |
// |                                   |
// |      |                     |      |
// +------|---------------------|------+
//   Install NAT configuration (currently via binary APIs, later via vpp-agent)
// +------|---------------------|------+
// |      v                     v      |
// |                                   |
// |                VPP                |
// |                                   |
// |                                   |
// +-----------------------------------+
//

// Package service implements support for Kubernetes services for VPP using
// the VPP NAT plugin (https://wiki.fd.io/view/VPP/NAT).
package service
<|endoftext|>


<commit_before>package lora

import (
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
	"log"
	"net"
	"time"
)

const (
	PUSH_DATA = iota
	PUSH_ACK  = iota
	PULL_DATA = iota
	PULL_ACK  = iota
	PULL_RESP = iota
)

type Conn struct {
	Raw *net.UDPConn
}

type Message struct {
	SourceAddr *net.UDPAddr
	Conn       *Conn
	Header     *MessageHeader
	GatewayEui []byte
	Payload    interface{}
}

type MessageHeader struct {
	ProtocolVersion byte
	Token           uint16
	Identifier      byte
}

type PushMessagePayload struct {
	RXPK []*RXPK `json:"rxpk,omitempty"`
	Stat *Stat   `json:"stat,omitempty"`
}

type Stat struct {
	Time string  `json:"time"`
	Lati float64 `json:"lati"`
	Long float64 `json:"long"`
	Alti float64 `json:"alti"`
	Rxnb uint    `json:"rxnb"`
	Rxok uint    `json:"rxok"`
	Rxfw uint    `json:"rxfw"`
	Ackr float64 `json:"ackr"`
	Dwnb uint    `json:"dwnb"`
	Txnb uint    `json:"txnb"`
}

type RXPK struct {
	Time time.Time `json:"time"`
	Tmst uint      `json:"tmst"`
	Chan uint      `json:"chan"`
	Rfch uint      `json:"rfch"`
	Freq float64   `json:"freq"`
	Stat int       `json:"stat"`
	Modu string    `json:"modu"`
	Datr string    `json:"datr"`
	Codr string    `json:"codr"`
	Rssi int       `json:"rssi"`
	Lsnr float64   `json:"lsnr"`
	Size uint      `json:"size"`
	Data string    `json:"data"`
}

type TXPX struct {
	Imme bool    `json:"imme"`
	Freq float64 `json:"freq"`
	Rfch uint    `json:"rfch"`
	Powe uint    `json:"powe"`
	Modu string  `json:"modu"`
	Datr uint    `json:"datr"`
	Fdev uint    `json:"fdev"`
	Size uint    `json:"size"`
	Data string  `json:"data"`
}

func NewConn(r *net.UDPConn) *Conn {
	return &Conn{r}
}

func (c *Conn) ReadMessage() (*Message, error) {
	buf := make([]byte, 2048)
	n, addr, err := c.Raw.ReadFromUDP(buf)
	if err != nil {
		log.Print("Error: ", err)
		return nil, err
	}
	return c.parseMessage(addr, buf, n)
}

func (c *Conn) parseMessage(addr *net.UDPAddr, b []byte, n int) (*Message, error) {
	var header MessageHeader
	err := binary.Read(bytes.NewReader(b), binary.BigEndian, &header)
	if err != nil {
		return nil, err
	}
	msg := &Message{
		SourceAddr: addr,
		Conn:       c,
		Header:     &header,
	}
	if header.Identifier == PUSH_DATA {
		msg.GatewayEui = b[4:12]
		var payload PushMessagePayload
		err := json.Unmarshal(b[12:n], &payload)
		if err != nil {
			log.Printf("Parse message failed: %s\nMessage: %s", err.Error(), string(b[12:n]))
			return nil, err
		}
		msg.Payload = payload
	}
	return msg, nil
}

func (m *Message) Ack() error {
	ack := &MessageHeader{
		ProtocolVersion: m.Header.ProtocolVersion,
		Token:           m.Header.Token,
		Identifier:      PUSH_ACK,
	}

	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.BigEndian, ack)
	if err != nil {
		return err
	}

	_, err = m.Conn.Raw.WriteToUDP(buf.Bytes(), m.SourceAddr)
	if err != nil {
		return err
	}
	return nil
}

func (rxpk *RXPK) ParseData() (*PHYPayload, error) {
	buf, err := base64.StdEncoding.DecodeString(rxpk.Data)
	if err != nil {
		log.Printf("Failed to decode base64 data: %s", err.Error())
		return nil, err
	}

	return ParsePHYPayload(buf)
}
<commit_msg>Acknowledge appropriate identifier, closes #11<commit_after>package lora

import (
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net"
	"time"
)

const (
	PUSH_DATA = iota
	PUSH_ACK  = iota
	PULL_DATA = iota
	PULL_ACK  = iota
	PULL_RESP = iota
)

type Conn struct {
	Raw *net.UDPConn
}

type Message struct {
	SourceAddr *net.UDPAddr
	Conn       *Conn
	Header     *MessageHeader
	GatewayEui []byte
	Payload    interface{}
}

type MessageHeader struct {
	ProtocolVersion byte
	Token           uint16
	Identifier      byte
}

type PushMessagePayload struct {
	RXPK []*RXPK `json:"rxpk,omitempty"`
	Stat *Stat   `json:"stat,omitempty"`
}

type Stat struct {
	Time string  `json:"time"`
	Lati float64 `json:"lati"`
	Long float64 `json:"long"`
	Alti float64 `json:"alti"`
	Rxnb uint    `json:"rxnb"`
	Rxok uint    `json:"rxok"`
	Rxfw uint    `json:"rxfw"`
	Ackr float64 `json:"ackr"`
	Dwnb uint    `json:"dwnb"`
	Txnb uint    `json:"txnb"`
}

type RXPK struct {
	Time time.Time `json:"time"`
	Tmst uint      `json:"tmst"`
	Chan uint      `json:"chan"`
	Rfch uint      `json:"rfch"`
	Freq float64   `json:"freq"`
	Stat int       `json:"stat"`
	Modu string    `json:"modu"`
	Datr string    `json:"datr"`
	Codr string    `json:"codr"`
	Rssi int       `json:"rssi"`
	Lsnr float64   `json:"lsnr"`
	Size uint      `json:"size"`
	Data string    `json:"data"`
}

type TXPX struct {
	Imme bool    `json:"imme"`
	Freq float64 `json:"freq"`
	Rfch uint    `json:"rfch"`
	Powe uint    `json:"powe"`
	Modu string  `json:"modu"`
	Datr uint    `json:"datr"`
	Fdev uint    `json:"fdev"`
	Size uint    `json:"size"`
	Data string  `json:"data"`
}

func NewConn(r *net.UDPConn) *Conn {
	return &Conn{r}
}

func (c *Conn) ReadMessage() (*Message, error) {
	buf := make([]byte, 2048)
	n, addr, err := c.Raw.ReadFromUDP(buf)
	if err != nil {
		log.Print("Error: ", err)
		return nil, err
	}
	return c.parseMessage(addr, buf, n)
}

func (c *Conn) parseMessage(addr *net.UDPAddr, b []byte, n int) (*Message, error) {
	var header MessageHeader
	err := binary.Read(bytes.NewReader(b), binary.BigEndian, &header)
	if err != nil {
		return nil, err
	}
	msg := &Message{
		SourceAddr: addr,
		Conn:       c,
		Header:     &header,
	}
	if header.Identifier == PUSH_DATA {
		msg.GatewayEui = b[4:12]
		var payload PushMessagePayload
		err := json.Unmarshal(b[12:n], &payload)
		if err != nil {
			log.Printf("Parse message failed: %s\nMessage: %s", err.Error(), string(b[12:n]))
			return nil, err
		}
		msg.Payload = payload
	}
	return msg, nil
}

func (m *Message) Ack() error {
	var id byte
	switch m.Header.Identifier {
	case PUSH_DATA:
		id = PUSH_ACK
	case PULL_DATA:
		id = PULL_ACK
	default:
		return errors.New(fmt.Sprintf("Unknown message identifier %d to acknowledge", m.Header.Identifier))
	}

	ack := &MessageHeader{
		ProtocolVersion: m.Header.ProtocolVersion,
		Token:           m.Header.Token,
		Identifier:      id,
	}

	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.BigEndian, ack)
	if err != nil {
		return err
	}

	_, err = m.Conn.Raw.WriteToUDP(buf.Bytes(), m.SourceAddr)
	if err != nil {
		return err
	}
	return nil
}

func (rxpk *RXPK) ParseData() (*PHYPayload, error) {
	buf, err := base64.StdEncoding.DecodeString(rxpk.Data)
	if err != nil {
		log.Printf("Failed to decode base64 data: %s", err.Error())
		return nil, err
	}

	return ParsePHYPayload(buf)
}
<|endoftext|>


<commit_before>package client

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"

	"github.com/flynn/go-discover/discover"
	"github.com/flynn/lorne/types"
	"github.com/flynn/rpcplus"
)

var ErrNoServers = errors.New("lorne: no servers found")

func New(id string) (*Client, error) {
	disc, err := discover.NewClient()
	if err != nil {
		return nil, err
	}
	services, err := disc.Services("flynn-lorne." + id)
	if err != nil {
		return nil, err
	}
	addrs := services.OnlineAddrs()
	if len(addrs) == 0 {
		return nil, ErrNoServers
	}
	c, err := rpcplus.DialHTTP("tcp", addrs[0])
	return &Client{c, services}, err
}

type Client struct {
	c *rpcplus.Client

	service *discover.ServiceSet
}

func (c *Client) JobList() (map[string]lorne.Job, error) {
	var jobs map[string]lorne.Job
	err := c.c.Call("Host.JobList", struct{}{}, &jobs)
	return jobs, err
}

func (c *Client) GetJob(id string) (*lorne.Job, error) {
	var res lorne.Job
	err := c.c.Call("Host.GetJob", id, &res)
	return &res, err
}

func (c *Client) StopJob(id string) error {
	return c.c.Call("Host.StopJob", id, &struct{}{})
}

var ErrWouldWait = errors.New("lorne: attach would wait")

func (c *Client) Attach(req *lorne.AttachReq, wait bool) (ReadWriteCloser, func() error, error) {
	data, err := json.Marshal(req)
	if err != nil {
		return nil, nil, err
	}
	httpReq, err := http.NewRequest("POST", "/attach", bytes.NewBuffer(data))
	if err != nil {
		return nil, nil, err
	}
	addrs := c.service.OnlineAddrs()
	if len(addrs) == 0 {
		return nil, nil, ErrNoServers
	}
	conn, err := net.Dial("tcp", addrs[0])
	if err != nil {
		return nil, nil, err
	}
	clientconn := httputil.NewClientConn(conn, nil)
	res, err := clientconn.Do(httpReq)
	if err != nil && err != httputil.ErrPersistEOF {
		return nil, nil, err
	}
	if res.StatusCode != 200 {
		return nil, nil, fmt.Errorf("lorne: unexpected status %d", res.StatusCode)
	}
	var rwc io.ReadWriteCloser
	var buf *bufio.Reader
	rwc, buf = clientconn.Hijack()
	if buf.Buffered() > 0 {
		rwc = struct {
			io.Reader
			writeCloser
		}{
			io.MultiReader(io.LimitReader(buf, int64(buf.Buffered())), rwc),
			rwc.(writeCloser),
		}
	}

	attachState := make([]byte, 1)
	if _, err := rwc.Read(attachState); err != nil {
		rwc.Close()
		return nil, nil, err
	}

	handleState := func() error {
		switch attachState[0] {
		case lorne.AttachSuccess:
			return nil
		case lorne.AttachError:
			errBytes, err := ioutil.ReadAll(rwc)
			rwc.Close()
			if err != nil {
				return err
			}
			return errors.New(string(errBytes))
		default:
			rwc.Close()
			return fmt.Errorf("lorne: unknown attach state: %d", attachState)
		}
	}

	if attachState[0] == lorne.AttachWaiting {
		if !wait {
			rwc.Close()
			return nil, nil, ErrWouldWait
		}
		return rwc.(ReadWriteCloser), func() error {
			if _, err := rwc.Read(attachState); err != nil {
				rwc.Close()
				return err
			}
			return handleState()
		}, nil
	}

	return rwc.(ReadWriteCloser), nil, handleState()
}

type ReadWriteCloser interface {
	io.ReadWriteCloser
	CloseWrite() error
}

type writeCloser interface {
	io.WriteCloser
	CloseWrite() error
}
<commit_msg>pkg/lorne: Update discoverd references<commit_after>package client

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"

	"github.com/flynn/go-discoverd"
	"github.com/flynn/lorne/types"
	"github.com/flynn/rpcplus"
)

var ErrNoServers = errors.New("lorne: no servers found")

func New(id string) (*Client, error) {
	disc, err := discoverd.NewClient()
	if err != nil {
		return nil, err
	}
	services, err := disc.ServiceSet("flynn-lorne." + id)
	if err != nil {
		return nil, err
	}
	addrs := services.Addrs()
	if len(addrs) == 0 {
		return nil, ErrNoServers
	}
	c, err := rpcplus.DialHTTP("tcp", addrs[0])
	return &Client{c, services}, err
}

type Client struct {
	c *rpcplus.Client

	service *discoverd.ServiceSet
}

func (c *Client) JobList() (map[string]lorne.Job, error) {
	var jobs map[string]lorne.Job
	err := c.c.Call("Host.JobList", struct{}{}, &jobs)
	return jobs, err
}

func (c *Client) GetJob(id string) (*lorne.Job, error) {
	var res lorne.Job
	err := c.c.Call("Host.GetJob", id, &res)
	return &res, err
}

func (c *Client) StopJob(id string) error {
	return c.c.Call("Host.StopJob", id, &struct{}{})
}

var ErrWouldWait = errors.New("lorne: attach would wait")

func (c *Client) Attach(req *lorne.AttachReq, wait bool) (ReadWriteCloser, func() error, error) {
	data, err := json.Marshal(req)
	if err != nil {
		return nil, nil, err
	}
	httpReq, err := http.NewRequest("POST", "/attach", bytes.NewBuffer(data))
	if err != nil {
		return nil, nil, err
	}
	addrs := c.service.OnlineAddrs()
	if len(addrs) == 0 {
		return nil, nil, ErrNoServers
	}
	conn, err := net.Dial("tcp", addrs[0])
	if err != nil {
		return nil, nil, err
	}
	clientconn := httputil.NewClientConn(conn, nil)
	res, err := clientconn.Do(httpReq)
	if err != nil && err != httputil.ErrPersistEOF {
		return nil, nil, err
	}
	if res.StatusCode != 200 {
		return nil, nil, fmt.Errorf("lorne: unexpected status %d", res.StatusCode)
	}
	var rwc io.ReadWriteCloser
	var buf *bufio.Reader
	rwc, buf = clientconn.Hijack()
	if buf.Buffered() > 0 {
		rwc = struct {
			io.Reader
			writeCloser
		}{
			io.MultiReader(io.LimitReader(buf, int64(buf.Buffered())), rwc),
			rwc.(writeCloser),
		}
	}

	attachState := make([]byte, 1)
	if _, err := rwc.Read(attachState); err != nil {
		rwc.Close()
		return nil, nil, err
	}

	handleState := func() error {
		switch attachState[0] {
		case lorne.AttachSuccess:
			return nil
		case lorne.AttachError:
			errBytes, err := ioutil.ReadAll(rwc)
			rwc.Close()
			if err != nil {
				return err
			}
			return errors.New(string(errBytes))
		default:
			rwc.Close()
			return fmt.Errorf("lorne: unknown attach state: %d", attachState)
		}
	}

	if attachState[0] == lorne.AttachWaiting {
		if !wait {
			rwc.Close()
			return nil, nil, ErrWouldWait
		}
		return rwc.(ReadWriteCloser), func() error {
			if _, err := rwc.Read(attachState); err != nil {
				rwc.Close()
				return err
			}
			return handleState()
		}, nil
	}

	return rwc.(ReadWriteCloser), nil, handleState()
}

type ReadWriteCloser interface {
	io.ReadWriteCloser
	CloseWrite() error
}

type writeCloser interface {
	io.WriteCloser
	CloseWrite() error
}
<|endoftext|>


<commit_before>/* A Go package for the Firebase API #golang
 */
package firebase

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

type client interface {
	Do(req *http.Request) (resp *http.Response, err error)
}

type Reference struct {
	url          string
	postfix      string
	client       client
	token        string
	export       bool
	response     *http.Response
	responseBody []byte
}

// Retrieve a new Firebase reference for given url.
func NewReference(url string) *Reference {

	// Initialize Reference struct.
	r := &Reference{
		url:     url,
		postfix: ".json",
		export:  false,
		client:  &http.Client{},
	}

	return r
}

// Uses the Firebase secret or Auth Token to authenticate.
func (r *Reference) Auth(token string) *Reference {
	r.token = token

	return r
}

// Set to true if you want priority data to be returned.
func (r *Reference) Export(toggle bool) *Reference {
	r.export = toggle

	return r
}

// Execute a new HTTP Request.
func (r *Reference) executeRequest(method string, body io.Reader) ([]byte, error) {

	apiUrl := r.url + r.postfix

	// Build query parameters (if any).
	v := url.Values{}
	if r.token != "" {
		v.Set("auth", r.token)
	}
	if r.export == true {
		v.Set("format", "export")
	}
	q := v.Encode()

	// Attach query parameters to apiUrl.
	if len(q) > 0 {
		apiUrl = apiUrl + "?" + q
	}

	// Adding tiny sleep to prevent rate limited requests.
	time.Sleep(1 * time.Millisecond)

	// Prepare HTTP Request.
	req, err := http.NewRequest(method, apiUrl, body)
	if err != nil {
		return nil, err
	}

	// Make actual HTTP request.
	if r.response, err = r.client.Do(req); err != nil {
		return nil, err
	}
	defer r.response.Body.Close()

	// Check status code for errors.
	status := r.response.Status
	if strings.HasPrefix(status, "2") == false {
		return nil, errors.New(status)
	}

	// Read body.
	if r.responseBody, err = ioutil.ReadAll(r.response.Body); err != nil {
		return nil, err
	}

	return r.responseBody, nil
}

// Retrieve the current value for this Reference.
func (r *Reference) Value(v interface{}) error {

	// GET the data from Firebase.
	resp, err := r.executeRequest("GET", nil)
	if err != nil {
		return err
	}

	// JSON decode the data into given interface.
	err = json.Unmarshal(resp, v)
	if err != nil {
		return err
	}

	return nil
}

// Set the value for this Reference (overwrites existing value).
func (r *Reference) Write(v interface{}) error {

	// JSON encode the data.
	jsonData, err := json.Marshal(v)
	if err != nil {
		return err
	}

	// PUT the data to Firebase.
	_, err = r.executeRequest("PUT", bytes.NewReader(jsonData))
	if err != nil {
		return err
	}

	return nil
}

// Pushes a new object to this Reference (effectively creates a list).
func (r *Reference) Push(v interface{}) error {

	// JSON encode the data.
	jsonData, err := json.Marshal(v)
	if err != nil {
		return err
	}

	// POST the data to Firebase.
	_, err = r.executeRequest("POST", bytes.NewReader(jsonData))
	if err != nil {
		return err
	}

	return nil
}

// Update existing data.
func (r *Reference) Update(v interface{}) error {

	// JSON encode the data.
	jsonData, err := json.Marshal(v)
	if err != nil {
		return err
	}

	// PATCH the data on Firebase.
	_, err = r.executeRequest("PATCH", bytes.NewReader(jsonData))
	if err != nil {
		return err
	}

	return nil
}

// Delete any values for this Reference.
func (r *Reference) Delete() error {

	// DELETE the data on Firebase.
	_, err := r.executeRequest("DELETE", nil)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>increased sleeptime<commit_after>/* A Go package for the Firebase API #golang
 */
package firebase

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

type client interface {
	Do(req *http.Request) (resp *http.Response, err error)
}

type Reference struct {
	url          string
	postfix      string
	client       client
	token        string
	export       bool
	response     *http.Response
	responseBody []byte
}

// Retrieve a new Firebase reference for given url.
func NewReference(url string) *Reference {

	// Initialize Reference struct.
	r := &Reference{
		url:     url,
		postfix: ".json",
		export:  false,
		client:  &http.Client{},
	}

	return r
}

// Uses the Firebase secret or Auth Token to authenticate.
func (r *Reference) Auth(token string) *Reference {
	r.token = token

	return r
}

// Set to true if you want priority data to be returned.
func (r *Reference) Export(toggle bool) *Reference {
	r.export = toggle

	return r
}

// Execute a new HTTP Request.
func (r *Reference) executeRequest(method string, body io.Reader) ([]byte, error) {

	apiUrl := r.url + r.postfix

	// Build query parameters (if any).
	v := url.Values{}
	if r.token != "" {
		v.Set("auth", r.token)
	}
	if r.export == true {
		v.Set("format", "export")
	}
	q := v.Encode()

	// Attach query parameters to apiUrl.
	if len(q) > 0 {
		apiUrl = apiUrl + "?" + q
	}

	// Adding tiny sleep to prevent rate limited requests.
	time.Sleep(10 * time.Millisecond)

	// Prepare HTTP Request.
	req, err := http.NewRequest(method, apiUrl, body)
	if err != nil {
		return nil, err
	}

	// Make actual HTTP request.
	if r.response, err = r.client.Do(req); err != nil {
		return nil, err
	}
	defer r.response.Body.Close()

	// Check status code for errors.
	status := r.response.Status
	if strings.HasPrefix(status, "2") == false {
		return nil, errors.New(status)
	}

	// Read body.
	if r.responseBody, err = ioutil.ReadAll(r.response.Body); err != nil {
		return nil, err
	}

	return r.responseBody, nil
}

// Retrieve the current value for this Reference.
func (r *Reference) Value(v interface{}) error {

	// GET the data from Firebase.
	resp, err := r.executeRequest("GET", nil)
	if err != nil {
		return err
	}

	// JSON decode the data into given interface.
	err = json.Unmarshal(resp, v)
	if err != nil {
		return err
	}

	return nil
}

// Set the value for this Reference (overwrites existing value).
func (r *Reference) Write(v interface{}) error {

	// JSON encode the data.
	jsonData, err := json.Marshal(v)
	if err != nil {
		return err
	}

	// PUT the data to Firebase.
	_, err = r.executeRequest("PUT", bytes.NewReader(jsonData))
	if err != nil {
		return err
	}

	return nil
}

// Pushes a new object to this Reference (effectively creates a list).
func (r *Reference) Push(v interface{}) error {

	// JSON encode the data.
	jsonData, err := json.Marshal(v)
	if err != nil {
		return err
	}

	// POST the data to Firebase.
	_, err = r.executeRequest("POST", bytes.NewReader(jsonData))
	if err != nil {
		return err
	}

	return nil
}

// Update existing data.
func (r *Reference) Update(v interface{}) error {

	// JSON encode the data.
	jsonData, err := json.Marshal(v)
	if err != nil {
		return err
	}

	// PATCH the data on Firebase.
	_, err = r.executeRequest("PATCH", bytes.NewReader(jsonData))
	if err != nil {
		return err
	}

	return nil
}

// Delete any values for this Reference.
func (r *Reference) Delete() error {

	// DELETE the data on Firebase.
	_, err := r.executeRequest("DELETE", nil)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package lzma2

import (
	"bytes"
	"errors"
	"io"

	"github.com/ulikunitz/xz/lzma"
)

// Parameters describe the parameters for an LZMA2 writer.
type Parameters struct {
	LC      int
	LP      int
	PB      int
	DictCap int
	BufSize int
}

// Writer writes a sequence of LZMA2 chunks. The first chunk will always
// reset the dictionary. The Writer will not terminate the chunk
// sequence with an end-of-stream chunk. Use WriteEOS for writing the
// end of stream chunk.
type Writer struct {
	// TODO
}

// NewWriter creates an LZMA2 chunk sequence writer with the default
// parameters.
func NewWriter(lzma2 io.Writer) (w *Writer, err error) {
	panic("TODO")
}

// NewWriterParams creates an LZMA2 chunk stream writer with the given
// parameters.
func NewWriterParams(lzma2 io.Writer, params Parameters) (w *Writer,
	err error) {

	panic("TODO")
}

// Writes data to the LZMA2 chunk stream.
func (w *Writer) Write(p []byte) (n int, err error) {
	panic("TODO")
}

// Flush terminates the current chunk. If data will be provided later a
// new chunk will be created.
func (w *Writer) Flush() error {
	panic("TODO")
}

// Close terminates the chunk sequence. It doesn't write an
// end-of-stream chunk. Use WriteEOS to write such a chunk.
func (w *Writer) Close() error {
	panic("TODO")
}

// The FileWriter writes LZMA2 files with a leading dictionary capacity
// byte and an end-of-stream chunk.
type FileWriter struct {
	Writer
}

// NewFileWriter creates an LZMA2 file writer. It writes the initial
// dictionary capacity byte.
func NewFileWriter(lzma2 io.Writer) (w *FileWriter, err error) {
	panic("TODO")
}

// Close closes the file writer by terminating the active chunk and
// writing an end-of-stream chunk.
func (w *FileWriter) Close() error {
	panic("TODO")
}

// chunkWriter provides a type that takes care of writing out a single
// chunk. Since it cannot be known upfront what size the compressed
// segment will be, the compressed data has to be buffered, before it
// can be written out. At the same time there is a maximum size the
// limited byte writer has.
type chunkWriter struct {
	w     io.Writer
	ctype chunkType

	initialState *lzma.State
	encoder      *lzma.Encoder

	lbw lzma.LimitedByteWriter
	buf bytes.Buffer
}

func newChunkWriter(w io.Writer, state *lzma.State, dict *lzma.EncoderDict) (cw *chunkWriter, err error) {
	cw = &chunkWriter{
		w:            w,
		ctype:        cLRND,
		initialState: lzma.NewStateClone(state),
		lbw:          lzma.LimitedByteWriter{BW: &cw.buf, N: maxCompressed},
	}
	cw.buf.Reset()
	cw.encoder, err = lzma.NewEncoder(&cw.lbw, state, dict, 0)
	if err != nil {
		return nil, err
	}
	return cw, nil
}

func (cw *chunkWriter) Write(p []byte) (n int, err error) {
	panic("TODO")
}

func (cw *chunkWriter) writeUncompressedChunk() error {
	u := cw.encoder.Compressed()
	if u <= 0 {
		return errors.New("chunkWriter: can't write empty chunk")
	}
	switch cw.ctype {
	case cLRND:
		cw.ctype = cUD
	default:
		cw.ctype = cU
	}
	cw.encoder.State = cw.initialState

	header := chunkHeader{
		ctype:        cw.ctype,
		uncompressed: uint32(u - 1),
	}
	hdata, err := header.MarshalBinary()
	if err != nil {
		return err
	}
	if _, err = cw.w.Write(hdata); err != nil {
		return err
	}
	_, err = cw.encoder.Dict.CopyN(cw.w, int(u))
	return err
}

func (cw *chunkWriter) writeCompressedChunk() error {
	if cw.ctype == cU || cw.ctype == cUD {
		return errors.New(
			"writeCompressedChunk: uncompressed chunktype")
	}

	u := cw.encoder.Compressed()
	if u <= 0 {
		return errors.New("writeCompressedChunk: empty chunk")
	}
	c := cw.buf.Len()
	if c <= 0 {
		return errors.New("writeCompressedChunk: no compressed data")
	}
	header := chunkHeader{
		ctype:        cw.ctype,
		uncompressed: uint32(u - 1),
		compressed:   uint16(c - 1),
		props:        cw.encoder.State.Properties,
	}
	hdata, err := header.MarshalBinary()
	if err != nil {
		return err
	}
	if _, err = cw.w.Write(hdata); err != nil {
		return err
	}

	_, err = io.Copy(cw.w, &cw.buf)
	return err
}

func (cw *chunkWriter) Close() error {
	if err := cw.encoder.Close(); err != nil {
		return err
	}
	u := int(uncompressedHeaderLen + cw.encoder.Compressed())
	c := headerLen(cw.ctype) + cw.buf.Len()
	if u < c {
		return cw.writeUncompressedChunk()
	}
	return cw.writeCompressedChunk()
}
<commit_msg>lzma2: some more work in the writer<commit_after>package lzma2

import (
	"bytes"
	"errors"
	"io"

	"github.com/ulikunitz/xz/lzma"
)

// Parameters describe the parameters for an LZMA2 writer.
type Parameters struct {
	LC      int
	LP      int
	PB      int
	DictCap int
	BufSize int
}

// Writer writes a sequence of LZMA2 chunks. The first chunk will always
// reset the dictionary. The Writer will not terminate the chunk
// sequence with an end-of-stream chunk. Use WriteEOS for writing the
// end of stream chunk.
type Writer struct {
	// TODO
}

// NewWriter creates an LZMA2 chunk sequence writer with the default
// parameters.
func NewWriter(lzma2 io.Writer) (w *Writer, err error) {
	panic("TODO")
}

// NewWriterParams creates an LZMA2 chunk stream writer with the given
// parameters.
func NewWriterParams(lzma2 io.Writer, params Parameters) (w *Writer,
	err error) {

	panic("TODO")
}

// Writes data to the LZMA2 chunk stream.
func (w *Writer) Write(p []byte) (n int, err error) {
	panic("TODO")
}

// Flush terminates the current chunk. If data will be provided later a
// new chunk will be created.
func (w *Writer) Flush() error {
	panic("TODO")
}

// Close terminates the chunk sequence. It doesn't write an
// end-of-stream chunk. Use WriteEOS to write such a chunk.
func (w *Writer) Close() error {
	panic("TODO")
}

// The FileWriter writes LZMA2 files with a leading dictionary capacity
// byte and an end-of-stream chunk.
type FileWriter struct {
	Writer
}

// NewFileWriter creates an LZMA2 file writer. It writes the initial
// dictionary capacity byte.
func NewFileWriter(lzma2 io.Writer) (w *FileWriter, err error) {
	panic("TODO")
}

// Close closes the file writer by terminating the active chunk and
// writing an end-of-stream chunk.
func (w *FileWriter) Close() error {
	panic("TODO")
}

// chunkWriter provides a type that takes care of writing out a single
// chunk. Since it cannot be known upfront what size the compressed
// segment will be, the compressed data has to be buffered, before it
// can be written out.
type chunkWriter struct {
	w     io.Writer
	ctype chunkType

	initialState *lzma.State
	encoder      *lzma.Encoder

	lbw lzma.LimitedByteWriter
	buf bytes.Buffer
}

func newChunkWriter(w io.Writer, state *lzma.State, dict *lzma.EncoderDict) (cw *chunkWriter, err error) {
	cw = &chunkWriter{
		w:            w,
		ctype:        cLRND,
		initialState: lzma.NewStateClone(state),
		lbw: lzma.LimitedByteWriter{
			BW: &cw.buf, N: maxCompressed},
	}
	cw.buf.Grow(maxCompressed)

	cw.encoder, err = lzma.NewEncoder(&cw.lbw, state, dict, 0)
	if err != nil {
		return nil, err
	}

	return cw, nil
}

func (cw *chunkWriter) Reopen(ctype chunkType) error {
	cw.ctype = ctype
	cw.lbw.N = maxCompressed
	cw.buf.Reset()
	cw.initialState = lzma.NewStateClone(cw.encoder.State)
	if err := cw.encoder.Reopen(&cw.lbw); err != nil {
		return err
	}
	return nil
}

func (cw *chunkWriter) Write(p []byte) (n int, err error) {
	panic("TODO")
}

func (cw *chunkWriter) writeUncompressedChunk() error {
	u := cw.encoder.Compressed()
	if u <= 0 {
		return errors.New("chunkWriter: can't write empty chunk")
	}
	switch cw.ctype {
	case cLRND:
		cw.ctype = cUD
	default:
		cw.ctype = cU
	}
	cw.encoder.State = cw.initialState

	header := chunkHeader{
		ctype:        cw.ctype,
		uncompressed: uint32(u - 1),
	}
	hdata, err := header.MarshalBinary()
	if err != nil {
		return err
	}
	if _, err = cw.w.Write(hdata); err != nil {
		return err
	}
	_, err = cw.encoder.Dict.CopyN(cw.w, int(u))
	return err
}

func (cw *chunkWriter) writeCompressedChunk() error {
	if cw.ctype == cU || cw.ctype == cUD {
		return errors.New(
			"writeCompressedChunk: uncompressed chunktype")
	}

	u := cw.encoder.Compressed()
	if u <= 0 {
		return errors.New("writeCompressedChunk: empty chunk")
	}
	c := cw.buf.Len()
	if c <= 0 {
		return errors.New("writeCompressedChunk: no compressed data")
	}
	header := chunkHeader{
		ctype:        cw.ctype,
		uncompressed: uint32(u - 1),
		compressed:   uint16(c - 1),
		props:        cw.encoder.State.Properties,
	}
	hdata, err := header.MarshalBinary()
	if err != nil {
		return err
	}
	if _, err = cw.w.Write(hdata); err != nil {
		return err
	}

	_, err = io.Copy(cw.w, &cw.buf)
	return err
}

func (cw *chunkWriter) Close() error {
	if err := cw.encoder.Close(); err != nil {
		return err
	}
	u := int(uncompressedHeaderLen + cw.encoder.Compressed())
	c := headerLen(cw.ctype) + cw.buf.Len()
	if u < c {
		return cw.writeUncompressedChunk()
	}
	return cw.writeCompressedChunk()
}
<|endoftext|>


<commit_before>// package blockservice implements a BlockService interface that provides
// a single GetBlock/AddBlock interface that seamlessly retrieves data either
// locally or from a remote peer through the exchange.
package blockservice

import (
	"errors"
	"fmt"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	blocks "github.com/jbenet/go-ipfs/blocks"
	"github.com/jbenet/go-ipfs/blocks/blockstore"
	exchange "github.com/jbenet/go-ipfs/exchange"
	u "github.com/jbenet/go-ipfs/util"
)

var log = u.Logger("blockservice")
var ErrNotFound = errors.New("blockservice: key not found")

// BlockService is a hybrid block datastore. It stores data in a local
// datastore and may retrieve data from a remote Exchange.
// It uses an internal `datastore.Datastore` instance to store values.
type BlockService struct {
	// TODO don't expose underlying impl details
	Blockstore blockstore.Blockstore
	Exchange   exchange.Interface
}

// NewBlockService creates a BlockService with given datastore instance.
func New(bs blockstore.Blockstore, rem exchange.Interface) (*BlockService, error) {
	if bs == nil {
		return nil, fmt.Errorf("BlockService requires valid blockstore")
	}
	if rem == nil {
		log.Warning("blockservice running in local (offline) mode.")
	}
	return &BlockService{Blockstore: bs, Exchange: rem}, nil
}

// AddBlock adds a particular block to the service, Putting it into the datastore.
// TODO pass a context into this if the remote.HasBlock is going to remain here.
func (s *BlockService) AddBlock(b *blocks.Block) (u.Key, error) {
	k := b.Key()
	log.Debugf("blockservice: storing [%s] in datastore", k)
	err := s.Blockstore.Put(b)
	if err != nil {
		return k, err
	}

	// TODO this operation rate-limits blockservice operations, we should
	// consider moving this to an sync process.
	if s.Exchange != nil {
		ctx := context.TODO()
		err = s.Exchange.HasBlock(ctx, b)
	}
	return k, err
}

// GetBlock retrieves a particular block from the service,
// Getting it from the datastore using the key (hash).
func (s *BlockService) GetBlock(ctx context.Context, k u.Key) (*blocks.Block, error) {
	log.Debugf("BlockService GetBlock: '%s'", k)
	block, err := s.Blockstore.Get(k)
	if err == nil {
		return block, nil
		// TODO be careful checking ErrNotFound. If the underlying
		// implementation changes, this will break.
	} else if err == blockstore.ErrNotFound && s.Exchange != nil {
		log.Debug("Blockservice: Searching bitswap.")
		blk, err := s.Exchange.GetBlock(ctx, k)
		if err != nil {
			return nil, err
		}
		return blk, nil
	} else {
		log.Debug("Blockservice GetBlock: Not found.")
		return nil, ErrNotFound
	}
}

// GetBlocks gets a list of blocks asynchronously and returns through
// the returned channel.
// NB: No guarantees are made about order.
func (s *BlockService) GetBlocks(ctx context.Context, ks []u.Key) <-chan *blocks.Block {
	out := make(chan *blocks.Block, 0)
	go func() {
		defer close(out)
		var misses []u.Key
		for _, k := range ks {
			hit, err := s.Blockstore.Get(k)
			if err != nil {
				misses = append(misses, k)
				continue
			}
			log.Debug("Blockservice: Got data in datastore.")
			select {
			case out <- hit:
			case <-ctx.Done():
				return
			}
		}

		rblocks, err := s.Exchange.GetBlocks(ctx, misses)
		if err != nil {
			log.Errorf("Error with GetBlocks: %s", err)
			return
		}

		for b := range rblocks {
			select {
			case out <- b:
			case <-ctx.Done():
				return
			}
		}
	}()
	return out
}

// DeleteBlock deletes a block in the blockservice from the datastore
func (s *BlockService) DeleteBlock(k u.Key) error {
	return s.Blockstore.DeleteBlock(k)
}
<commit_msg>rm low SnR debug statement<commit_after>// package blockservice implements a BlockService interface that provides
// a single GetBlock/AddBlock interface that seamlessly retrieves data either
// locally or from a remote peer through the exchange.
package blockservice

import (
	"errors"
	"fmt"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	blocks "github.com/jbenet/go-ipfs/blocks"
	"github.com/jbenet/go-ipfs/blocks/blockstore"
	exchange "github.com/jbenet/go-ipfs/exchange"
	u "github.com/jbenet/go-ipfs/util"
)

var log = u.Logger("blockservice")
var ErrNotFound = errors.New("blockservice: key not found")

// BlockService is a hybrid block datastore. It stores data in a local
// datastore and may retrieve data from a remote Exchange.
// It uses an internal `datastore.Datastore` instance to store values.
type BlockService struct {
	// TODO don't expose underlying impl details
	Blockstore blockstore.Blockstore
	Exchange   exchange.Interface
}

// NewBlockService creates a BlockService with given datastore instance.
func New(bs blockstore.Blockstore, rem exchange.Interface) (*BlockService, error) {
	if bs == nil {
		return nil, fmt.Errorf("BlockService requires valid blockstore")
	}
	if rem == nil {
		log.Warning("blockservice running in local (offline) mode.")
	}
	return &BlockService{Blockstore: bs, Exchange: rem}, nil
}

// AddBlock adds a particular block to the service, Putting it into the datastore.
// TODO pass a context into this if the remote.HasBlock is going to remain here.
func (s *BlockService) AddBlock(b *blocks.Block) (u.Key, error) {
	k := b.Key()
	err := s.Blockstore.Put(b)
	if err != nil {
		return k, err
	}

	// TODO this operation rate-limits blockservice operations, we should
	// consider moving this to an sync process.
	if s.Exchange != nil {
		ctx := context.TODO()
		err = s.Exchange.HasBlock(ctx, b)
	}
	return k, err
}

// GetBlock retrieves a particular block from the service,
// Getting it from the datastore using the key (hash).
func (s *BlockService) GetBlock(ctx context.Context, k u.Key) (*blocks.Block, error) {
	log.Debugf("BlockService GetBlock: '%s'", k)
	block, err := s.Blockstore.Get(k)
	if err == nil {
		return block, nil
		// TODO be careful checking ErrNotFound. If the underlying
		// implementation changes, this will break.
	} else if err == blockstore.ErrNotFound && s.Exchange != nil {
		log.Debug("Blockservice: Searching bitswap.")
		blk, err := s.Exchange.GetBlock(ctx, k)
		if err != nil {
			return nil, err
		}
		return blk, nil
	} else {
		log.Debug("Blockservice GetBlock: Not found.")
		return nil, ErrNotFound
	}
}

// GetBlocks gets a list of blocks asynchronously and returns through
// the returned channel.
// NB: No guarantees are made about order.
func (s *BlockService) GetBlocks(ctx context.Context, ks []u.Key) <-chan *blocks.Block {
	out := make(chan *blocks.Block, 0)
	go func() {
		defer close(out)
		var misses []u.Key
		for _, k := range ks {
			hit, err := s.Blockstore.Get(k)
			if err != nil {
				misses = append(misses, k)
				continue
			}
			log.Debug("Blockservice: Got data in datastore.")
			select {
			case out <- hit:
			case <-ctx.Done():
				return
			}
		}

		rblocks, err := s.Exchange.GetBlocks(ctx, misses)
		if err != nil {
			log.Errorf("Error with GetBlocks: %s", err)
			return
		}

		for b := range rblocks {
			select {
			case out <- b:
			case <-ctx.Done():
				return
			}
		}
	}()
	return out
}

// DeleteBlock deletes a block in the blockservice from the datastore
func (s *BlockService) DeleteBlock(k u.Key) error {
	return s.Blockstore.DeleteBlock(k)
}
<|endoftext|>


<commit_before>package main

/*
// See src/os/user/lookup_unix.go for usage of "static"

#include <jni.h>

static jvalue _GoJniJValueFromJBoolean(jboolean z)
{
	jvalue v = {.z = z};
	return v;
}

static jvalue _GoJniJValueFromJByte(jbyte b)
{
	jvalue v = {.b = b};
	return v;
}

static jvalue _GoJniJValueFromJChar(jchar c)
{
	jvalue v = {.c = c};
	return v;
}

static jvalue _GoJniJValueFromJShort(jshort s)
{
	jvalue v = {.s = s};
	return v;
}

static jvalue _GoJniJValueFromJInt(jint i)
{
	jvalue v = {.i = i};
	return v;
}

static jvalue _GoJniJValueFromJLong(jlong j)
{
	jvalue v = {.j = j};
	return v;
}

static jvalue _GoJniJValueFromJFloat(jfloat f)
{
	jvalue v = {.f = f};
	return v;
}

static jvalue _GoJniJValueFromJDouble(jdouble d)
{
	jvalue v = {.d = d};
	return v;
}

static jvalue _GoJniJValueFromJObject(jobject l)
{
	jvalue v = {.l = l};
	return v;
}

static jboolean _GoJniJValueToJBoolean(jvalue v)
{
	return v.z;
}

static jbyte _GoJniJValueToJByte(jvalue v)
{
	return v.b;
}

static jchar _GoJniJValueToJChar(jvalue v)
{
	return v.c;
}

static jshort _GoJniJValueToJShort(jvalue v)
{
	return v.s;
}

static jint _GoJniJValueToJInt(jvalue v)
{
	return v.i;
}

static jlong _GoJniJValueToJLong(jvalue v)
{
	return v.j;
}

static jfloat _GoJniJValueToJFloat(jvalue v)
{
	return v.f;
}

static jdouble _GoJniJValueToJDouble(jvalue v)
{
	return v.d;
}

static jobject _GoJniJValueToJObject(jvalue v)
{
	return v.l;
}
*/
import "C"

// jvalue From Any

func JValueFromJBoolean(z C.jboolean) C.jvalue {
	return C._GoJniJValueFromJBoolean(z)
}

func JValueFromJByte(b C.jbyte) C.jvalue {
	return C._GoJniJValueFromJByte(b)
}

func JValueFromJChar(c C.jchar) C.jvalue {
	return C._GoJniJValueFromJChar(c)
}

func JValueFromJShort(s C.jshort) C.jvalue {
	return C._GoJniJValueFromJShort(s)
}

func JValueFromJInt(i C.jint) C.jvalue {
	return C._GoJniJValueFromJInt(i)
}

func JValueFromJLong(j C.jlong) C.jvalue {
	return C._GoJniJValueFromJLong(j)
}

func JValueFromJFloat(f C.jfloat) C.jvalue {
	return C._GoJniJValueFromJFloat(f)
}

func JValueFromJDouble(d C.jdouble) C.jvalue {
	return C._GoJniJValueFromJDouble(d)
}

func JValueFromJObject(l C.jobject) C.jvalue {
	return C._GoJniJValueFromJObject(l)
}

// jvalue To Any

func JValueToJBoolean(v C.jvalue) C.jboolean {
	return C._GoJniJValueToJBoolean(v)
}

func JValueToJByte(v C.jvalue) C.jbyte {
	return C._GoJniJValueToJByte(v)
}

func JValueToJChar(v C.jvalue) C.jchar {
	return C._GoJniJValueToJChar(v)
}

func JValueToJShort(v C.jvalue) C.jshort {
	return C._GoJniJValueToJShort(v)
}

func JValueToJInt(v C.jvalue) C.jint {
	return C._GoJniJValueToJInt(v)
}

func JValueToJLong(v C.jvalue) C.jlong {
	return C._GoJniJValueToJLong(v)
}

func JValueToJFloat(v C.jvalue) C.jfloat {
	return C._GoJniJValueToJFloat(v)
}

func JValueToJDouble(v C.jvalue) C.jdouble {
	return C._GoJniJValueToJDouble(v)
}

func JValueToJObject(v C.jvalue) C.jobject {
	return C._GoJniJValueToJObject(v)
}
<commit_msg>Added back comments<commit_after>package main

/*
// See src/os/user/lookup_unix.go for usage of "static"

#include <jni.h>

// jni.h:
// typedef union jvalue {
//     jboolean z;
//     jbyte    b;
//     jchar    c;
//     jshort   s;
//     jint     i;
//     jlong    j;
//     jfloat   f;
//     jdouble  d;
//     jobject  l;
// } jvalue;

// jvalue From Any

static jvalue _GoJniJValueFromJBoolean(jboolean z)
{
	jvalue v = {.z = z};
	return v;
}

static jvalue _GoJniJValueFromJByte(jbyte b)
{
	jvalue v = {.b = b};
	return v;
}

static jvalue _GoJniJValueFromJChar(jchar c)
{
	jvalue v = {.c = c};
	return v;
}

static jvalue _GoJniJValueFromJShort(jshort s)
{
	jvalue v = {.s = s};
	return v;
}

static jvalue _GoJniJValueFromJInt(jint i)
{
	jvalue v = {.i = i};
	return v;
}

static jvalue _GoJniJValueFromJLong(jlong j)
{
	jvalue v = {.j = j};
	return v;
}

static jvalue _GoJniJValueFromJFloat(jfloat f)
{
	jvalue v = {.f = f};
	return v;
}

static jvalue _GoJniJValueFromJDouble(jdouble d)
{
	jvalue v = {.d = d};
	return v;
}

static jvalue _GoJniJValueFromJObject(jobject l)
{
	jvalue v = {.l = l};
	return v;
}

// jvalue To Any

static jboolean _GoJniJValueToJBoolean(jvalue v)
{
	return v.z;
}

static jbyte _GoJniJValueToJByte(jvalue v)
{
	return v.b;
}

static jchar _GoJniJValueToJChar(jvalue v)
{
	return v.c;
}

static jshort _GoJniJValueToJShort(jvalue v)
{
	return v.s;
}

static jint _GoJniJValueToJInt(jvalue v)
{
	return v.i;
}

static jlong _GoJniJValueToJLong(jvalue v)
{
	return v.j;
}

static jfloat _GoJniJValueToJFloat(jvalue v)
{
	return v.f;
}

static jdouble _GoJniJValueToJDouble(jvalue v)
{
	return v.d;
}

static jobject _GoJniJValueToJObject(jvalue v)
{
	return v.l;
}
*/
import "C"

// jvalue From Any

func JValueFromJBoolean(z C.jboolean) C.jvalue {
	return C._GoJniJValueFromJBoolean(z)
}

func JValueFromJByte(b C.jbyte) C.jvalue {
	return C._GoJniJValueFromJByte(b)
}

func JValueFromJChar(c C.jchar) C.jvalue {
	return C._GoJniJValueFromJChar(c)
}

func JValueFromJShort(s C.jshort) C.jvalue {
	return C._GoJniJValueFromJShort(s)
}

func JValueFromJInt(i C.jint) C.jvalue {
	return C._GoJniJValueFromJInt(i)
}

func JValueFromJLong(j C.jlong) C.jvalue {
	return C._GoJniJValueFromJLong(j)
}

func JValueFromJFloat(f C.jfloat) C.jvalue {
	return C._GoJniJValueFromJFloat(f)
}

func JValueFromJDouble(d C.jdouble) C.jvalue {
	return C._GoJniJValueFromJDouble(d)
}

func JValueFromJObject(l C.jobject) C.jvalue {
	return C._GoJniJValueFromJObject(l)
}

// jvalue To Any

func JValueToJBoolean(v C.jvalue) C.jboolean {
	return C._GoJniJValueToJBoolean(v)
}

func JValueToJByte(v C.jvalue) C.jbyte {
	return C._GoJniJValueToJByte(v)
}

func JValueToJChar(v C.jvalue) C.jchar {
	return C._GoJniJValueToJChar(v)
}

func JValueToJShort(v C.jvalue) C.jshort {
	return C._GoJniJValueToJShort(v)
}

func JValueToJInt(v C.jvalue) C.jint {
	return C._GoJniJValueToJInt(v)
}

func JValueToJLong(v C.jvalue) C.jlong {
	return C._GoJniJValueToJLong(v)
}

func JValueToJFloat(v C.jvalue) C.jfloat {
	return C._GoJniJValueToJFloat(v)
}

func JValueToJDouble(v C.jvalue) C.jdouble {
	return C._GoJniJValueToJDouble(v)
}

func JValueToJObject(v C.jvalue) C.jobject {
	return C._GoJniJValueToJObject(v)
}
<|endoftext|>


<commit_before>package job

import (
	"github.com/PeopleAdmin/pdfcombiner/testmode"
	"io/ioutil"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/s3"
)

// Connect to AWS and add the handle to the Job object.
func (j *Job) connect() (err error) {
	auth, err := aws.EnvAuth()
	if err != nil {
		return
	}
	s := s3.New(auth, aws.USEast)
	j.bucket = s.Bucket(j.BucketName)
	return
}

// Get retrieves the requested document, either from S3 or by decoding the
// embedded `Data` attribute of the Document.
func (j *Job) Get(doc Document) (docContent []byte, err error) {
	if testmode.IsEnabled() {
		return
	}
	switch doc.Data {
	case "":
		return j.download(doc)
	default:
		return decodeEmbeddedData(doc.Data)
	}
}

func (j *Job) download(doc Document) (content []byte, err error) {
	remotePath := doc.s3Path()
	return j.bucket.Get(remotePath)
}

// UploadCombinedFile sends a file to the job's CombinedKey on S3.
func (j *Job) UploadCombinedFile(localPath string) (err error) {
	if testmode.IsEnabled() {
		return
	}
	content, err := ioutil.ReadFile(localPath)
	if err != nil {
		j.AddError(j.CombinedKey, err)
		return
	}
	err = j.bucket.Put(j.CombinedKey, content, "application/pdf", s3.Private)
	if err != nil {
		j.AddError(j.CombinedKey, err)
	}
	j.uploadComplete = true
	return
}
<commit_msg>Move exported functions to top of file<commit_after>package job

import (
	"github.com/PeopleAdmin/pdfcombiner/testmode"
	"io/ioutil"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/s3"
)

// Get retrieves the requested document, either from S3 or by decoding the
// embedded `Data` attribute of the Document.
func (j *Job) Get(doc Document) (docContent []byte, err error) {
	if testmode.IsEnabled() {
		return
	}
	switch doc.Data {
	case "":
		return j.download(doc)
	default:
		return decodeEmbeddedData(doc.Data)
	}
}

// UploadCombinedFile sends a file to the job's CombinedKey on S3.
func (j *Job) UploadCombinedFile(localPath string) (err error) {
	if testmode.IsEnabled() {
		return
	}
	content, err := ioutil.ReadFile(localPath)
	if err != nil {
		j.AddError(j.CombinedKey, err)
		return
	}
	err = j.bucket.Put(j.CombinedKey, content, "application/pdf", s3.Private)
	if err != nil {
		j.AddError(j.CombinedKey, err)
	}
	j.uploadComplete = true
	return
}

// Connect to AWS and add the handle to the Job object.
func (j *Job) connect() (err error) {
	auth, err := aws.EnvAuth()
	if err != nil {
		return
	}
	s := s3.New(auth, aws.USEast)
	j.bucket = s.Bucket(j.BucketName)
	return
}

func (j *Job) download(doc Document) (content []byte, err error) {
	remotePath := doc.s3Path()
	return j.bucket.Get(remotePath)
}

<|endoftext|>


<commit_before>/*Package effect provides the functionality to manipulate images to achieve various looks.*/
package effect

import (
	"image"
	"image/color"
	"math"

	"github.com/anthonynsimon/bild/adjust"
	"github.com/anthonynsimon/bild/blend"
	"github.com/anthonynsimon/bild/blur"
	"github.com/anthonynsimon/bild/clone"
	"github.com/anthonynsimon/bild/convolution"
	"github.com/anthonynsimon/bild/math/f64"
	"github.com/anthonynsimon/bild/parallel"
	"github.com/anthonynsimon/bild/util"
)

// Invert returns a negated version of the image.
func Invert(src image.Image) *image.RGBA {
	fn := func(c color.RGBA) color.RGBA {
		return color.RGBA{255 - c.R, 255 - c.G, 255 - c.B, c.A}
	}

	img := adjust.Apply(src, fn)

	return img
}

// Grayscale returns a copy of the image in Grayscale using the weights
// 0.3R + 0.6G + 0.1B as a heuristic.
func Grayscale(img image.Image) *image.RGBA {
	return GrayscaleWithWeights(img, 0.3, 0.6, 0.1)
}

// GrayscaleWithWeights returns a copy of the image in Grayscale using the given weights.
// The weights should be in the range 0.0 to 1.0 inclusive.
func GrayscaleWithWeights(img image.Image, r, g, b float64) *image.RGBA {
	src := clone.AsRGBA(img)
	bounds := src.Bounds()
	srcW, srcH := bounds.Dx(), bounds.Dy()

	if bounds.Empty() {
		return &image.RGBA{}
	}

	dst := image.NewRGBA(bounds)

	parallel.Line(srcH, func(start, end int) {
		for y := start; y < end; y++ {
			for x := 0; x < srcW; x++ {
				pos := y*src.Stride + x*4

				c := r*float64(src.Pix[pos+0]) + g*float64(src.Pix[pos+1]) + b*float64(src.Pix[pos+2])
				k := uint8(c + 0.5)
				dst.Pix[pos] = k
				dst.Pix[pos+1] = k
				dst.Pix[pos+2] = k
				dst.Pix[pos+3] = src.Pix[pos+3]
			}
		}
	})

	return dst
}

// Sepia returns a copy of the image in Sepia tone.
func Sepia(img image.Image) *image.RGBA {
	fn := func(c color.RGBA) color.RGBA {
		// Cache values as float64
		var fc [3]float64
		fc[0] = float64(c.R)
		fc[1] = float64(c.G)
		fc[2] = float64(c.B)

		// Calculate out color based on heuristic
		outRed := fc[0]*0.393 + fc[1]*0.769 + fc[2]*0.189
		outGreen := fc[0]*0.349 + fc[1]*0.686 + fc[2]*0.168
		outBlue := fc[0]*0.272 + fc[1]*0.534 + fc[2]*0.131

		// Clamp ceiled values before returning
		return color.RGBA{
			R: uint8(f64.Clamp(outRed+0.5, 0, 255)),
			G: uint8(f64.Clamp(outGreen+0.5, 0, 255)),
			B: uint8(f64.Clamp(outBlue+0.5, 0, 255)),
			A: c.A,
		}
	}

	dst := adjust.Apply(img, fn)

	return dst
}

// EdgeDetection returns a copy of the image with its edges highlighted.
func EdgeDetection(src image.Image, radius float64) *image.RGBA {
	if radius <= 0 {
		return image.NewRGBA(src.Bounds())
	}

	length := int(math.Ceil(2*radius + 1))
	k := convolution.NewKernel(length, length)

	for x := 0; x < length; x++ {
		for y := 0; y < length; y++ {
			v := -1.0
			if x == length/2 && y == length/2 {
				v = float64(length*length) - 1
			}
			k.Matrix[y*length+x] = v

		}
	}
	return convolution.Convolve(src, k, &convolution.Options{Bias: 0, Wrap: false, KeepAlpha: true})
}

// Emboss returns a copy of the image in which each pixel has been
// replaced either by a highlight or a shadow representation.
func Emboss(src image.Image) *image.RGBA {
	k := convolution.Kernel{
		Matrix: []float64{
			-1, -1, 0,
			-1, 0, 1,
			0, 1, 1,
		},
		Width:  3,
		Height: 3,
	}

	return convolution.Convolve(src, &k, &convolution.Options{Bias: 128, Wrap: false, KeepAlpha: true})
}

// Sharpen returns a sharpened copy of the image by detecting its edges and adding it to the original.
func Sharpen(src image.Image) *image.RGBA {
	k := convolution.Kernel{
		Matrix: []float64{
			0, -1, 0,
			-1, 5, -1,
			0, -1, 0,
		},
		Width:  3,
		Height: 3,
	}

	return convolution.Convolve(src, &k, &convolution.Options{Bias: 0, Wrap: false})
}

// UnsharpMask returns a copy of the image with its high-frecuency components amplified.
// Parameter radius corresponds to the radius to be samples per pixel.
// Parameter amount is the normalized strength of the effect. A value of 0.0 will leave
// the image untouched and a value of 1.0 will fully apply the unsharp mask.
func UnsharpMask(img image.Image, radius, amount float64) *image.RGBA {
	amount = f64.Clamp(amount, 0, 10)

	blurred := blur.Gaussian(img, 5*radius) // scale radius by matching factor

	bounds := img.Bounds()
	src := clone.AsRGBA(img)
	dst := image.NewRGBA(bounds)
	w, h := bounds.Dx(), bounds.Dy()

	parallel.Line(h, func(start, end int) {
		for y := start; y < end; y++ {
			for x := 0; x < w; x++ {
				pos := y*dst.Stride + x*4

				r := float64(src.Pix[pos+0])
				g := float64(src.Pix[pos+1])
				b := float64(src.Pix[pos+2])
				a := float64(src.Pix[pos+3])

				rBlur := float64(blurred.Pix[pos+0])
				gBlur := float64(blurred.Pix[pos+1])
				bBlur := float64(blurred.Pix[pos+2])
				aBlur := float64(blurred.Pix[pos+3])

				r = r + (r-rBlur)*amount
				g = g + (g-gBlur)*amount
				b = b + (b-bBlur)*amount
				a = a + (a-aBlur)*amount

				dst.Pix[pos+0] = uint8(f64.Clamp(r, 0, 255))
				dst.Pix[pos+1] = uint8(f64.Clamp(g, 0, 255))
				dst.Pix[pos+2] = uint8(f64.Clamp(b, 0, 255))
				dst.Pix[pos+3] = uint8(f64.Clamp(a, 0, 255))
			}
		}
	})

	return dst
}

// Sobel returns an image emphasising edges using an approximation to the Sobel–Feldman operator.
func Sobel(src image.Image) *image.RGBA {

	hk := convolution.Kernel{
		Matrix: []float64{
			1, 2, 1,
			0, 0, 0,
			-1, -2, -1,
		},
		Width:  3,
		Height: 3,
	}

	vk := convolution.Kernel{
		Matrix: []float64{
			-1, 0, 1,
			-2, 0, 2,
			-1, 0, 1,
		},
		Width:  3,
		Height: 3,
	}

	vSobel := convolution.Convolve(src, &vk, &convolution.Options{Bias: 0, Wrap: false, KeepAlpha: true})
	hSobel := convolution.Convolve(src, &hk, &convolution.Options{Bias: 0, Wrap: false, KeepAlpha: true})

	return blend.Add(blend.Multiply(vSobel, vSobel), blend.Multiply(hSobel, hSobel))
}

// Median returns a new image in which each pixel is the median of its neighbors.
// The parameter radius corresponds to the radius of the neighbor area to be searched,
// for example a radius of R will result in a search window length of 2R+1 for each dimension.
func Median(img image.Image, radius float64) *image.RGBA {
	fn := func(neighbors []color.RGBA) color.RGBA {
		util.SortRGBA(neighbors, 0, len(neighbors)-1)
		return neighbors[len(neighbors)/2]
	}

	result := spatialFilter(img, radius, fn)

	return result
}

// Dilate picks the local maxima from the neighbors of each pixel and returns the resulting image.
// The parameter radius corresponds to the radius of the neighbor area to be searched,
// for example a radius of R will result in a search window length of 2R+1 for each dimension.
func Dilate(img image.Image, radius float64) *image.RGBA {
	fn := func(neighbors []color.RGBA) color.RGBA {
		util.SortRGBA(neighbors, 0, len(neighbors)-1)
		return neighbors[len(neighbors)-1]
	}

	result := spatialFilter(img, radius, fn)

	return result
}

// Erode picks the local minima from the neighbors of each pixel and returns the resulting image.
// The parameter radius corresponds to the radius of the neighbor area to be searched,
// for example a radius of R will result in a search window length of 2R+1 for each dimension.
func Erode(img image.Image, radius float64) *image.RGBA {
	fn := func(neighbors []color.RGBA) color.RGBA {
		util.SortRGBA(neighbors, 0, len(neighbors)-1)
		return neighbors[0]
	}

	result := spatialFilter(img, radius, fn)

	return result
}

// spatialFilter goes through each pixel on an image collecting its neighbors and picking one
// based on the function provided. The resulting image is then returned.
// The parameter radius corresponds to the radius of the neighbor area to be searched,
// for example a radius of R will result in a search window length of 2R+1 for each dimension.
// The parameter pickerFn is the function that receives the list of neighbors and returns the selected
// neighbor to be used for the resulting image.
func spatialFilter(img image.Image, radius float64, pickerFn func(neighbors []color.RGBA) color.RGBA) *image.RGBA {
	if radius <= 0 {
		return clone.AsRGBA(img)
	}

	padding := int(radius + 0.5)
	src := clone.Pad(img, padding, padding, clone.EdgeExtend)

	kernelSize := int(2*radius + 1 + 0.5)

	bounds := img.Bounds()
	dst := image.NewRGBA(bounds)

	w, h := bounds.Dx(), bounds.Dy()
	neighborsCount := kernelSize * kernelSize

	parallel.Line(h, func(start, end int) {
		for y := start + padding; y < end+padding; y++ {
			for x := padding; x < w+padding; x++ {

				neighbors := make([]color.RGBA, neighborsCount)
				i := 0
				for ky := 0; ky < kernelSize; ky++ {
					for kx := 0; kx < kernelSize; kx++ {
						ix := x - kernelSize>>1 + kx
						iy := y - kernelSize>>1 + ky

						ipos := iy*src.Stride + ix*4
						neighbors[i] = color.RGBA{
							R: src.Pix[ipos+0],
							G: src.Pix[ipos+1],
							B: src.Pix[ipos+2],
							A: src.Pix[ipos+3],
						}
						i++
					}
				}

				c := pickerFn(neighbors)

				pos := (y-padding)*dst.Stride + (x-padding)*4
				dst.Pix[pos+0] = c.R
				dst.Pix[pos+1] = c.G
				dst.Pix[pos+2] = c.B
				dst.Pix[pos+3] = c.A
			}
		}
	})

	return dst
}
<commit_msg>Fix out of bounds bug<commit_after>/*Package effect provides the functionality to manipulate images to achieve various looks.*/
package effect

import (
	"image"
	"image/color"
	"math"

	"github.com/anthonynsimon/bild/adjust"
	"github.com/anthonynsimon/bild/blend"
	"github.com/anthonynsimon/bild/blur"
	"github.com/anthonynsimon/bild/clone"
	"github.com/anthonynsimon/bild/convolution"
	"github.com/anthonynsimon/bild/math/f64"
	"github.com/anthonynsimon/bild/parallel"
	"github.com/anthonynsimon/bild/util"
)

// Invert returns a negated version of the image.
func Invert(src image.Image) *image.RGBA {
	fn := func(c color.RGBA) color.RGBA {
		return color.RGBA{255 - c.R, 255 - c.G, 255 - c.B, c.A}
	}

	img := adjust.Apply(src, fn)

	return img
}

// Grayscale returns a copy of the image in Grayscale using the weights
// 0.3R + 0.6G + 0.1B as a heuristic.
func Grayscale(img image.Image) *image.RGBA {
	return GrayscaleWithWeights(img, 0.3, 0.6, 0.1)
}

// GrayscaleWithWeights returns a copy of the image in Grayscale using the given weights.
// The weights should be in the range 0.0 to 1.0 inclusive.
func GrayscaleWithWeights(img image.Image, r, g, b float64) *image.RGBA {
	src := clone.AsRGBA(img)
	bounds := src.Bounds()
	srcW, srcH := bounds.Dx(), bounds.Dy()

	if bounds.Empty() {
		return &image.RGBA{}
	}

	dst := image.NewRGBA(bounds)

	parallel.Line(srcH, func(start, end int) {
		for y := start; y < end; y++ {
			for x := 0; x < srcW; x++ {
				pos := y*src.Stride + x*4

				c := r*float64(src.Pix[pos+0]) + g*float64(src.Pix[pos+1]) + b*float64(src.Pix[pos+2])
				k := uint8(c + 0.5)
				dst.Pix[pos] = k
				dst.Pix[pos+1] = k
				dst.Pix[pos+2] = k
				dst.Pix[pos+3] = src.Pix[pos+3]
			}
		}
	})

	return dst
}

// Sepia returns a copy of the image in Sepia tone.
func Sepia(img image.Image) *image.RGBA {
	fn := func(c color.RGBA) color.RGBA {
		// Cache values as float64
		var fc [3]float64
		fc[0] = float64(c.R)
		fc[1] = float64(c.G)
		fc[2] = float64(c.B)

		// Calculate out color based on heuristic
		outRed := fc[0]*0.393 + fc[1]*0.769 + fc[2]*0.189
		outGreen := fc[0]*0.349 + fc[1]*0.686 + fc[2]*0.168
		outBlue := fc[0]*0.272 + fc[1]*0.534 + fc[2]*0.131

		// Clamp ceiled values before returning
		return color.RGBA{
			R: uint8(f64.Clamp(outRed+0.5, 0, 255)),
			G: uint8(f64.Clamp(outGreen+0.5, 0, 255)),
			B: uint8(f64.Clamp(outBlue+0.5, 0, 255)),
			A: c.A,
		}
	}

	dst := adjust.Apply(img, fn)

	return dst
}

// EdgeDetection returns a copy of the image with its edges highlighted.
func EdgeDetection(src image.Image, radius float64) *image.RGBA {
	if radius <= 0 {
		return image.NewRGBA(src.Bounds())
	}

	length := int(math.Ceil(2*radius + 1))
	k := convolution.NewKernel(length, length)

	for x := 0; x < length; x++ {
		for y := 0; y < length; y++ {
			v := -1.0
			if x == length/2 && y == length/2 {
				v = float64(length*length) - 1
			}
			k.Matrix[y*length+x] = v

		}
	}
	return convolution.Convolve(src, k, &convolution.Options{Bias: 0, Wrap: false, KeepAlpha: true})
}

// Emboss returns a copy of the image in which each pixel has been
// replaced either by a highlight or a shadow representation.
func Emboss(src image.Image) *image.RGBA {
	k := convolution.Kernel{
		Matrix: []float64{
			-1, -1, 0,
			-1, 0, 1,
			0, 1, 1,
		},
		Width:  3,
		Height: 3,
	}

	return convolution.Convolve(src, &k, &convolution.Options{Bias: 128, Wrap: false, KeepAlpha: true})
}

// Sharpen returns a sharpened copy of the image by detecting its edges and adding it to the original.
func Sharpen(src image.Image) *image.RGBA {
	k := convolution.Kernel{
		Matrix: []float64{
			0, -1, 0,
			-1, 5, -1,
			0, -1, 0,
		},
		Width:  3,
		Height: 3,
	}

	return convolution.Convolve(src, &k, &convolution.Options{Bias: 0, Wrap: false})
}

// UnsharpMask returns a copy of the image with its high-frecuency components amplified.
// Parameter radius corresponds to the radius to be samples per pixel.
// Parameter amount is the normalized strength of the effect. A value of 0.0 will leave
// the image untouched and a value of 1.0 will fully apply the unsharp mask.
func UnsharpMask(img image.Image, radius, amount float64) *image.RGBA {
	amount = f64.Clamp(amount, 0, 10)

	blurred := blur.Gaussian(img, 5*radius) // scale radius by matching factor

	bounds := img.Bounds()
	src := clone.AsRGBA(img)
	dst := image.NewRGBA(bounds)
	w, h := bounds.Dx(), bounds.Dy()

	parallel.Line(h, func(start, end int) {
		for y := start; y < end; y++ {
			for x := 0; x < w; x++ {
				pos := y*dst.Stride + x*4

				r := float64(src.Pix[pos+0])
				g := float64(src.Pix[pos+1])
				b := float64(src.Pix[pos+2])
				a := float64(src.Pix[pos+3])

				rBlur := float64(blurred.Pix[pos+0])
				gBlur := float64(blurred.Pix[pos+1])
				bBlur := float64(blurred.Pix[pos+2])
				aBlur := float64(blurred.Pix[pos+3])

				r = r + (r-rBlur)*amount
				g = g + (g-gBlur)*amount
				b = b + (b-bBlur)*amount
				a = a + (a-aBlur)*amount

				dst.Pix[pos+0] = uint8(f64.Clamp(r, 0, 255))
				dst.Pix[pos+1] = uint8(f64.Clamp(g, 0, 255))
				dst.Pix[pos+2] = uint8(f64.Clamp(b, 0, 255))
				dst.Pix[pos+3] = uint8(f64.Clamp(a, 0, 255))
			}
		}
	})

	return dst
}

// Sobel returns an image emphasising edges using an approximation to the Sobel–Feldman operator.
func Sobel(src image.Image) *image.RGBA {

	hk := convolution.Kernel{
		Matrix: []float64{
			1, 2, 1,
			0, 0, 0,
			-1, -2, -1,
		},
		Width:  3,
		Height: 3,
	}

	vk := convolution.Kernel{
		Matrix: []float64{
			-1, 0, 1,
			-2, 0, 2,
			-1, 0, 1,
		},
		Width:  3,
		Height: 3,
	}

	vSobel := convolution.Convolve(src, &vk, &convolution.Options{Bias: 0, Wrap: false, KeepAlpha: true})
	hSobel := convolution.Convolve(src, &hk, &convolution.Options{Bias: 0, Wrap: false, KeepAlpha: true})

	return blend.Add(blend.Multiply(vSobel, vSobel), blend.Multiply(hSobel, hSobel))
}

// Median returns a new image in which each pixel is the median of its neighbors.
// The parameter radius corresponds to the radius of the neighbor area to be searched,
// for example a radius of R will result in a search window length of 2R+1 for each dimension.
func Median(img image.Image, radius float64) *image.RGBA {
	fn := func(neighbors []color.RGBA) color.RGBA {
		util.SortRGBA(neighbors, 0, len(neighbors)-1)
		return neighbors[len(neighbors)/2]
	}

	result := spatialFilter(img, radius, fn)

	return result
}

// Dilate picks the local maxima from the neighbors of each pixel and returns the resulting image.
// The parameter radius corresponds to the radius of the neighbor area to be searched,
// for example a radius of R will result in a search window length of 2R+1 for each dimension.
func Dilate(img image.Image, radius float64) *image.RGBA {
	fn := func(neighbors []color.RGBA) color.RGBA {
		util.SortRGBA(neighbors, 0, len(neighbors)-1)
		return neighbors[len(neighbors)-1]
	}

	result := spatialFilter(img, radius, fn)

	return result
}

// Erode picks the local minima from the neighbors of each pixel and returns the resulting image.
// The parameter radius corresponds to the radius of the neighbor area to be searched,
// for example a radius of R will result in a search window length of 2R+1 for each dimension.
func Erode(img image.Image, radius float64) *image.RGBA {
	fn := func(neighbors []color.RGBA) color.RGBA {
		util.SortRGBA(neighbors, 0, len(neighbors)-1)
		return neighbors[0]
	}

	result := spatialFilter(img, radius, fn)

	return result
}

// spatialFilter goes through each pixel on an image collecting its neighbors and picking one
// based on the function provided. The resulting image is then returned.
// The parameter radius corresponds to the radius of the neighbor area to be searched,
// for example a radius of R will result in a search window length of 2R+1 for each dimension.
// The parameter pickerFn is the function that receives the list of neighbors and returns the selected
// neighbor to be used for the resulting image.
func spatialFilter(img image.Image, radius float64, pickerFn func(neighbors []color.RGBA) color.RGBA) *image.RGBA {
	if radius <= 0 {
		return clone.AsRGBA(img)
	}

	padding := int(radius + 1.5)
	src := clone.Pad(img, padding, padding, clone.EdgeExtend)

	kernelSize := int(2*radius + 1.5)

	bounds := img.Bounds()
	dst := image.NewRGBA(bounds)

	w, h := bounds.Dx(), bounds.Dy()
	neighborsCount := kernelSize * kernelSize

	parallel.Line(h, func(start, end int) {
		for y := start + padding; y < end+padding; y++ {
			for x := padding; x < w+padding; x++ {

				neighbors := make([]color.RGBA, neighborsCount)
				i := 0
				for ky := 0; ky < kernelSize; ky++ {
					for kx := 0; kx < kernelSize; kx++ {
						ix := x - kernelSize>>1 + kx
						iy := y - kernelSize>>1 + ky

						ipos := iy*src.Stride + ix*4
						neighbors[i] = color.RGBA{
							R: src.Pix[ipos+0],
							G: src.Pix[ipos+1],
							B: src.Pix[ipos+2],
							A: src.Pix[ipos+3],
						}
						i++
					}
				}

				c := pickerFn(neighbors)

				pos := (y-padding)*dst.Stride + (x-padding)*4
				dst.Pix[pos+0] = c.R
				dst.Pix[pos+1] = c.G
				dst.Pix[pos+2] = c.B
				dst.Pix[pos+3] = c.A
			}
		}
	})

	return dst
}
<|endoftext|>


<commit_before>// +build linux

package main

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"syscall"

	"github.com/Symantec/Dominator/imagebuilder/builder"
	"github.com/Symantec/Dominator/lib/fsutil"
	"github.com/Symantec/Dominator/lib/log"
)

const filePerms = syscall.S_IRUSR | syscall.S_IRGRP | syscall.S_IROTH

type logWriterType struct {
	buffer bytes.Buffer
}

func buildFromManifestSubcommand(args []string, logger log.DebugLogger) {
	srpcClient := getImageServerClient()
	logWriter := &logWriterType{}
	if *alwaysShowBuildLog {
		fmt.Fprintln(os.Stderr, "Start of build log ==========================")
	}
	name, err := builder.BuildImageFromManifest(srpcClient, args[0], args[1],
		*expiresIn, logWriter, logger)
	if err != nil {
		if !*alwaysShowBuildLog {
			os.Stderr.Write(logWriter.Bytes())
		}
		fmt.Fprintln(os.Stderr, "End of build log ============================")
		fmt.Fprintf(os.Stderr, "Error processing manifest: %s\n", err)
		os.Exit(1)
	}
	if *alwaysShowBuildLog {
		fmt.Fprintln(os.Stderr, "End of build log ============================")
	}
	fmt.Println(name)
	os.Exit(0)
}

func buildTreeFromManifestSubcommand(args []string, logger log.DebugLogger) {
	srpcClient := getImageServerClient()
	buildLog := &bytes.Buffer{}
	rootDir, err := builder.BuildTreeFromManifest(srpcClient, args[0], buildLog,
		logger)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error processing manifest: %s\n", err)
		io.Copy(os.Stderr, buildLog)
		os.Exit(1)
	}
	fmt.Println(rootDir)
	err = fsutil.CopyToFile("build.log", filePerms, buildLog,
		uint64(buildLog.Len()))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error writing build log: %s\n", err)
		os.Exit(1)
	}
	os.Exit(0)
}

func processManifestSubcommand(args []string, logger log.DebugLogger) {
	buildLog := &bytes.Buffer{}
	if err := builder.ProcessManifest(args[0], args[1], buildLog); err != nil {
		fmt.Fprintf(os.Stderr, "Error processing manifest: %s\n", err)
		io.Copy(os.Stderr, buildLog)
		os.Exit(1)
	} else {
		io.Copy(os.Stdout, buildLog)
	}
	os.Exit(0)
}

func (w *logWriterType) Bytes() []byte {
	return w.buffer.Bytes()
}

func (w *logWriterType) Write(p []byte) (int, error) {
	if *alwaysShowBuildLog {
		os.Stderr.Write(p)
	}
	return w.buffer.Write(p)
}
<commit_msg>Support -alwaysShowBuildLog option in remaining builder-tool subcommands.<commit_after>// +build linux

package main

import (
	"bytes"
	"fmt"
	"os"
	"syscall"

	"github.com/Symantec/Dominator/imagebuilder/builder"
	"github.com/Symantec/Dominator/lib/fsutil"
	"github.com/Symantec/Dominator/lib/log"
)

const filePerms = syscall.S_IRUSR | syscall.S_IRGRP | syscall.S_IROTH

type logWriterType struct {
	buffer bytes.Buffer
}

func buildFromManifestSubcommand(args []string, logger log.DebugLogger) {
	srpcClient := getImageServerClient()
	logWriter := &logWriterType{}
	if *alwaysShowBuildLog {
		fmt.Fprintln(os.Stderr, "Start of build log ==========================")
	}
	name, err := builder.BuildImageFromManifest(srpcClient, args[0], args[1],
		*expiresIn, logWriter, logger)
	if err != nil {
		if !*alwaysShowBuildLog {
			fmt.Fprintln(os.Stderr,
				"Start of build log ==========================")
			os.Stderr.Write(logWriter.Bytes())
		}
		fmt.Fprintln(os.Stderr, "End of build log ============================")
		fmt.Fprintf(os.Stderr, "Error processing manifest: %s\n", err)
		os.Exit(1)
	}
	if *alwaysShowBuildLog {
		fmt.Fprintln(os.Stderr, "End of build log ============================")
	} else {
		err := fsutil.CopyToFile("build.log", filePerms, &logWriter.buffer,
			uint64(logWriter.buffer.Len()))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error writing build log: %s\n", err)
			os.Exit(1)
		}
	}
	fmt.Println(name)
	os.Exit(0)
}

func buildTreeFromManifestSubcommand(args []string, logger log.DebugLogger) {
	srpcClient := getImageServerClient()
	logWriter := &logWriterType{}
	if *alwaysShowBuildLog {
		fmt.Fprintln(os.Stderr, "Start of build log ==========================")
	}
	rootDir, err := builder.BuildTreeFromManifest(srpcClient, args[0],
		logWriter, logger)
	if err != nil {
		if !*alwaysShowBuildLog {
			fmt.Fprintln(os.Stderr,
				"Start of build log ==========================")
			os.Stderr.Write(logWriter.Bytes())
		}
		fmt.Fprintln(os.Stderr, "End of build log ============================")
		fmt.Fprintf(os.Stderr, "Error processing manifest: %s\n", err)
		os.Exit(1)
	}
	if *alwaysShowBuildLog {
		fmt.Fprintln(os.Stderr, "End of build log ============================")
	} else {
		err := fsutil.CopyToFile("build.log", filePerms, &logWriter.buffer,
			uint64(logWriter.buffer.Len()))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error writing build log: %s\n", err)
			os.Exit(1)
		}
	}
	fmt.Println(rootDir)
	os.Exit(0)
}

func processManifestSubcommand(args []string, logger log.DebugLogger) {
	logWriter := &logWriterType{}
	if *alwaysShowBuildLog {
		fmt.Fprintln(os.Stderr, "Start of build log ==========================")
	}
	if err := builder.ProcessManifest(args[0], args[1], logWriter); err != nil {
		if !*alwaysShowBuildLog {
			fmt.Fprintln(os.Stderr,
				"Start of build log ==========================")
			os.Stderr.Write(logWriter.Bytes())
		}
		fmt.Fprintln(os.Stderr, "End of build log ============================")
		fmt.Fprintf(os.Stderr, "Error processing manifest: %s\n", err)
		os.Exit(1)
	}
	if *alwaysShowBuildLog {
		fmt.Fprintln(os.Stderr, "End of build log ============================")
	} else {
		err := fsutil.CopyToFile("build.log", filePerms, &logWriter.buffer,
			uint64(logWriter.buffer.Len()))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error writing build log: %s\n", err)
			os.Exit(1)
		}
	}
	os.Exit(0)
}

func (w *logWriterType) Bytes() []byte {
	return w.buffer.Bytes()
}

func (w *logWriterType) Write(p []byte) (int, error) {
	if *alwaysShowBuildLog {
		os.Stderr.Write(p)
	}
	return w.buffer.Write(p)
}
<|endoftext|>


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

package main

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

const gomobileHash = "bdb1ca9a1e083af5929a8214e8a056d638ebbf2d"

func runCommand(command string, args []string, env []string) error {
	if buildX || buildN {
		for _, e := range env {
			fmt.Printf("%s ", e)
		}
		fmt.Print(command)
		for _, arg := range args {
			fmt.Printf(" %s", arg)
		}
		fmt.Println()
	}

	if buildN {
		return nil
	}

	cmd := exec.Command(command, args...)
	if len(env) > 0 {
		cmd.Env = append(os.Environ(), env...)
	}
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%s %v failed: %v\n%v", command, args, string(out), err)
	}
	return nil
}

func runGo(args ...string) error {
	env := []string{
		"GO111MODULE=on",
	}
	return runCommand("go", args, env)
}

// exe adds the .exe extension to the given filename.
// Without .exe, the executable won't be found by exec.LookPath on Windows (#1096).
func exe(filename string) string {
	if runtime.GOOS == "windows" {
		return filename + ".exe"
	}
	return filename
}

func prepareGomobileCommands() error {
	tmp, err := ioutil.TempDir("", "ebitenmobile-")
	if err != nil {
		return err
	}

	newpath := filepath.Join(tmp, "bin")
	if path := os.Getenv("PATH"); path != "" {
		newpath += string(filepath.ListSeparator) + path
	}
	if buildX || buildN {
		fmt.Printf("PATH=%s\n", newpath)
	}
	if !buildN {
		os.Setenv("PATH", newpath)
	}

	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	// cd
	if buildX {
		fmt.Printf("cd %s\n", tmp)
	}
	if err := os.Chdir(tmp); err != nil {
		return err
	}
	defer func() {
		os.Chdir(pwd)
	}()

	if err := runGo("mod", "init", "ebitenmobiletemporary"); err != nil {
		return err
	}

	// To record gomobile to go.sum for Go 1.16 and later, go-get gomobile instaed of golang.org/x/mobile (#1487).
	// This also records gobind as gomobile depends on gobind indirectly.
	// Using `...` doesn't work on Windows since mobile/internal/mobileinit cannot be compiled on Windows w/o Cgo (#1493).
	// Note that `go mod tidy` doesn't work since this removes all the indirect imports.
	if err := runGo("get", "golang.org/x/mobile/cmd/gomobile@"+gomobileHash); err != nil {
		return err
	}
	if localgm := os.Getenv("EBITENMOBILE_GOMOBILE"); localgm != "" {
		if !filepath.IsAbs(localgm) {
			localgm = filepath.Join(pwd, localgm)
		}
		if err := runGo("mod", "edit", "-replace=golang.org/x/mobile="+localgm); err != nil {
			return err
		}
	}
	if err := runGo("build", "-o", exe(filepath.Join("bin", "gomobile")), "golang.org/x/mobile/cmd/gomobile"); err != nil {
		return err
	}
	if err := runGo("build", "-o", exe(filepath.Join("bin", "gobind-original")), "golang.org/x/mobile/cmd/gobind"); err != nil {
		return err
	}

	if err := os.Mkdir("src", 0755); err != nil {
		return err
	}
	if err := ioutil.WriteFile(filepath.Join("src", "gobind.go"), gobindsrc, 0644); err != nil {
		return err
	}

	if err := runGo("build", "-o", exe(filepath.Join("bin", "gobind")), "-tags", "ebitenmobilegobind", filepath.Join("src", "gobind.go")); err != nil {
		return err
	}

	if err := runCommand("gomobile", []string{"init"}, nil); err != nil {
		return err
	}

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

package main

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

const gomobileHash = "bdb1ca9a1e083af5929a8214e8a056d638ebbf2d"

func runCommand(command string, args []string, env []string) error {
	if buildX || buildN {
		for _, e := range env {
			fmt.Printf("%s ", e)
		}
		fmt.Print(command)
		for _, arg := range args {
			fmt.Printf(" %s", arg)
		}
		fmt.Println()
	}

	if buildN {
		return nil
	}

	cmd := exec.Command(command, args...)
	if len(env) > 0 {
		cmd.Env = append(os.Environ(), env...)
	}
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%s %v failed: %v\n%v", command, args, string(out), err)
	}
	return nil
}

func runGo(args ...string) error {
	env := []string{
		"GO111MODULE=on",
	}
	return runCommand("go", args, env)
}

// exe adds the .exe extension to the given filename.
// Without .exe, the executable won't be found by exec.LookPath on Windows (#1096).
func exe(filename string) string {
	if runtime.GOOS == "windows" {
		return filename + ".exe"
	}
	return filename
}

func prepareGomobileCommands() error {
	tmp, err := ioutil.TempDir("", "ebitenmobile-")
	if err != nil {
		return err
	}

	newpath := filepath.Join(tmp, "bin")
	if path := os.Getenv("PATH"); path != "" {
		newpath += string(filepath.ListSeparator) + path
	}
	if buildX || buildN {
		fmt.Printf("PATH=%s\n", newpath)
	}
	if !buildN {
		os.Setenv("PATH", newpath)
	}

	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	// cd
	if buildX {
		fmt.Printf("cd %s\n", tmp)
	}
	if err := os.Chdir(tmp); err != nil {
		return err
	}
	defer func() {
		os.Chdir(pwd)
	}()

	if err := runGo("mod", "init", "ebitenmobiletemporary"); err != nil {
		return err
	}

	// To record gomobile to go.sum for Go 1.16 and later, go-get gomobile instaed of golang.org/x/mobile (#1487).
	// This also records gobind as gomobile depends on gobind indirectly.
	// Using `...` doesn't work on Windows since mobile/internal/mobileinit cannot be compiled on Windows w/o Cgo (#1493).
	// Note that `go mod tidy` doesn't work since this removes all the indirect imports.
	if err := runGo("get", "golang.org/x/mobile/cmd/gomobile@"+gomobileHash); err != nil {
		return err
	}
	if localgm := os.Getenv("EBITENMOBILE_GOMOBILE"); localgm != "" {
		if !filepath.IsAbs(localgm) {
			localgm = filepath.Join(pwd, localgm)
		}
		if err := runGo("mod", "edit", "-replace=golang.org/x/mobile="+localgm); err != nil {
			return err
		}
	}
	if err := runGo("build", "-o", exe(filepath.Join("bin", "gomobile")), "golang.org/x/mobile/cmd/gomobile"); err != nil {
		return err
	}
	if err := runGo("build", "-o", exe(filepath.Join("bin", "gobind-original")), "golang.org/x/mobile/cmd/gobind"); err != nil {
		return err
	}

	if err := os.Mkdir("src", 0755); err != nil {
		return err
	}
	if err := ioutil.WriteFile(filepath.Join("src", "gobind.go"), gobindsrc, 0644); err != nil {
		return err
	}

	if err := runGo("build", "-o", exe(filepath.Join("bin", "gobind")), "-tags", "ebitenmobilegobind", filepath.Join("src", "gobind.go")); err != nil {
		return err
	}

	// `gomobile init` is not needed. This just ensures the existence of the latest gobind command.

	return nil
}
<|endoftext|>