<commit_before>package appui

import (
	"bytes"
	"fmt"
	"strings"
	"sync"
	"text/tabwriter"
	"text/template"

	"github.com/docker/engine-api/types"
	"github.com/moncho/dry/docker"
	"github.com/moncho/dry/ui"
)

type column struct {
	name  string // The name of the field in the struct.
	title string // Title to display in the tableHeader.
	mode  docker.SortMode
}

//DockerPsRenderData holds information that might be
//used during ps rendering
type DockerPsRenderData struct {
	containers        []types.Container
	selectedContainer int
	sortMode          docker.SortMode
}

//NewDockerPsRenderData creates render data structs
func NewDockerPsRenderData(containers []types.Container, selectedContainer int, sortMode docker.SortMode) *DockerPsRenderData {
	return &DockerPsRenderData{
		containers:        containers,
		selectedContainer: selectedContainer,
		sortMode:          sortMode,
	}
}

//DockerPs knows how render a container list
type DockerPs struct {
	appHeadear             *ui.Renderer
	columns                []column // List of columns.
	containerTableTemplate *template.Template
	containerTemplate      *template.Template
	dockerInfo             string // Docker environment information
	height                 int
	layout                 *ui.Layout
	data                   *DockerPsRenderData
	renderLock             sync.Mutex
}

//NewDockerPsRenderer creates a renderer for a container list
func NewDockerPsRenderer(daemon docker.ContainerDaemon, screenHeight int) *DockerPs {
	r := &DockerPs{}

	r.columns = []column{
		{`ID`, `CONTAINER ID`, docker.SortByContainerID},
		{`Image`, `IMAGE`, docker.SortByImage},
		{`Command`, `COMMAND`, docker.NoSort},
		{`Created`, `CREATED`, docker.NoSort},
		{`Status`, `STATUS`, docker.SortByStatus},
		{`Ports`, `PORTS`, docker.NoSort},
		{`Names`, `NAMES`, docker.SortByName},
	}
	di := dockerInfo(daemon)
	r.layout = ui.NewLayout()
	//r.layout.Header = appHeader
	r.containerTableTemplate = buildContainerTableTemplate(di)
	r.containerTemplate = buildContainerTemplate()
	r.height = screenHeight

	return r
}

//PrepareToRender passes information to this renderer before render time
//selected is the position, on the container list, of the selected one
func (r *DockerPs) PrepareToRender(data *DockerPsRenderData) {
	r.renderLock.Lock()
	r.data = data
	r.renderLock.Unlock()
}

//Render docker ps
func (r *DockerPs) Render() string {
	r.renderLock.Lock()
	defer r.renderLock.Unlock()

	vars := struct {
		ContainerTable string
	}{
		r.containerTable(),
	}

	buffer := new(bytes.Buffer)
	r.containerTableTemplate.Execute(buffer, vars)

	return buffer.String()
}
func (r *DockerPs) containerTable() string {
	buffer := new(bytes.Buffer)
	t := tabwriter.NewWriter(buffer, 22, 0, 1, ' ', 0)
	replacer := strings.NewReplacer(`\t`, "\t", `\n`, "\n")
	fmt.Fprintln(t, replacer.Replace(r.tableHeader()))
	fmt.Fprint(t, replacer.Replace(r.containerInformation()))
	t.Flush()
	return buffer.String()
}
func (r *DockerPs) tableHeader() string {
	columns := make([]string, len(r.columns))
	for i, col := range r.columns {
		if r.data.sortMode != col.mode {
			columns[i] = col.title
		} else {
			columns[i] = DownArrow + col.title
		}
	}
	return "<green>" + strings.Join(columns, "\t") + "</>"
}

func (r *DockerPs) containerInformation() string {
	buf := bytes.NewBufferString("")
	containers := r.containersToShow()

	//From the containers-to-show list
	//decide which one is selected
	selected := len(containers) - 1
	if r.data.selectedContainer < selected {
		selected = r.data.selectedContainer
	}
	context := docker.FormattingContext{
		Output:   buf,
		Template: r.containerTemplate,
		Trunc:    true,
		Selected: selected,
	}
	docker.Format(
		context,
		containers)

	return buf.String()
}

func (r *DockerPs) containersToShow() []types.Container {
	containers := r.data.containers
	cursorPos := r.data.selectedContainer
	availableLines := r.height - containerTableStartPos - 1

	if len(containers) < availableLines {
		return containers
	}

	start := 0
	end := len(containers)

	if cursorPos > availableLines {
		start = cursorPos + 1 - availableLines
		end = cursorPos + 1
	} else if cursorPos == availableLines {
		start = 1
		end = availableLines + 1
	} else {
		start = 0
		end = availableLines
	}

	return containers[start:end]
}

func buildContainerTableTemplate(dockerInfo string) *template.Template {
	markup := dockerInfo +
		`

{{.ContainerTable}}
`
	return template.Must(template.New(`containers`).Parse(markup))
}

func buildContainerTemplate() *template.Template {

	return template.Must(template.New(`container`).Parse(docker.DefaultTableFormat))
}
<commit_msg>Remove created column from container list<commit_after>package appui

import (
	"bytes"
	"fmt"
	"strings"
	"sync"
	"text/tabwriter"
	"text/template"

	"github.com/docker/engine-api/types"
	"github.com/moncho/dry/docker"
	"github.com/moncho/dry/ui"
)

type column struct {
	name  string // The name of the field in the struct.
	title string // Title to display in the tableHeader.
	mode  docker.SortMode
}

//DockerPsRenderData holds information that might be
//used during ps rendering
type DockerPsRenderData struct {
	containers        []types.Container
	selectedContainer int
	sortMode          docker.SortMode
}

//NewDockerPsRenderData creates render data structs
func NewDockerPsRenderData(containers []types.Container, selectedContainer int, sortMode docker.SortMode) *DockerPsRenderData {
	return &DockerPsRenderData{
		containers:        containers,
		selectedContainer: selectedContainer,
		sortMode:          sortMode,
	}
}

//DockerPs knows how render a container list
type DockerPs struct {
	columns                []column // List of columns.
	containerTableTemplate *template.Template
	containerTemplate      *template.Template
	dockerInfo             string // Docker environment information
	height                 int
	layout                 *ui.Layout
	data                   *DockerPsRenderData
	renderLock             sync.Mutex
}

//NewDockerPsRenderer creates a renderer for a container list
func NewDockerPsRenderer(daemon docker.ContainerDaemon, screenHeight int) *DockerPs {
	r := &DockerPs{}

	r.columns = []column{
		{`ID`, `CONTAINER`, docker.SortByContainerID},
		{`Image`, `IMAGE`, docker.SortByImage},
		{`Command`, `COMMAND`, docker.NoSort},
		{`Status`, `STATUS`, docker.SortByStatus},
		{`Ports`, `PORTS`, docker.NoSort},
		{`Names`, `NAMES`, docker.SortByName},
	}
	di := dockerInfo(daemon)
	r.layout = ui.NewLayout()
	//r.layout.Header = appHeader
	r.containerTableTemplate = buildContainerTableTemplate(di)
	r.containerTemplate = buildContainerTemplate()
	r.height = screenHeight

	return r
}

//PrepareToRender passes information to this renderer before render time
//selected is the position, on the container list, of the selected one
func (r *DockerPs) PrepareToRender(data *DockerPsRenderData) {
	r.renderLock.Lock()
	r.data = data
	r.renderLock.Unlock()
}

//Render docker ps
func (r *DockerPs) Render() string {
	r.renderLock.Lock()
	defer r.renderLock.Unlock()

	vars := struct {
		ContainerTable string
	}{
		r.containerTable(),
	}

	buffer := new(bytes.Buffer)
	r.containerTableTemplate.Execute(buffer, vars)

	return buffer.String()
}
func (r *DockerPs) containerTable() string {
	buffer := new(bytes.Buffer)
	t := tabwriter.NewWriter(buffer, 22, 0, 1, ' ', 0)
	replacer := strings.NewReplacer(`\t`, "\t", `\n`, "\n")
	fmt.Fprintln(t, replacer.Replace(r.tableHeader()))
	fmt.Fprint(t, replacer.Replace(r.containerInformation()))
	t.Flush()
	return buffer.String()
}
func (r *DockerPs) tableHeader() string {
	columns := make([]string, len(r.columns))
	for i, col := range r.columns {
		if r.data.sortMode != col.mode {
			columns[i] = col.title
		} else {
			columns[i] = DownArrow + col.title
		}
	}
	return "<green>" + strings.Join(columns, "\t") + "</>"
}

func (r *DockerPs) containerInformation() string {
	buf := bytes.NewBufferString("")
	containers := r.containersToShow()

	//From the containers-to-show list
	//decide which one is selected
	selected := len(containers) - 1
	if r.data.selectedContainer < selected {
		selected = r.data.selectedContainer
	}
	context := docker.FormattingContext{
		Output:   buf,
		Template: r.containerTemplate,
		Trunc:    true,
		Selected: selected,
	}
	docker.Format(
		context,
		containers)

	return buf.String()
}

func (r *DockerPs) containersToShow() []types.Container {
	containers := r.data.containers
	cursorPos := r.data.selectedContainer
	availableLines := r.height - containerTableStartPos - 1

	if len(containers) < availableLines {
		return containers
	}

	start := 0
	end := len(containers)

	if cursorPos > availableLines {
		start = cursorPos + 1 - availableLines
		end = cursorPos + 1
	} else if cursorPos == availableLines {
		start = 1
		end = availableLines + 1
	} else {
		start = 0
		end = availableLines
	}

	return containers[start:end]
}

func buildContainerTableTemplate(dockerInfo string) *template.Template {
	markup := dockerInfo +
		`

{{.ContainerTable}}
`
	return template.Must(template.New(`containers`).Parse(markup))
}

func buildContainerTemplate() *template.Template {

	return template.Must(template.New(`container`).Parse(docker.DefaultTableFormat))
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path/filepath"

	tor "git.torproject.org/user/phw/zoossh.git"
)

// collectFiles returns a closure of type WalkFunc which is used to collect all
// file names in a given directory.
func collectFiles(fileNames *[]string) func(path string, info os.FileInfo, err error) error {

	return func(path string, info os.FileInfo, err error) error {

		if !info.IsDir() {
			*fileNames = append(*fileNames, path)
		}

		return nil
	}
}

// logConsensus writes the given consensus to a file which is put in the output
// directory.
func logConsensus(fileName string, consensus *tor.Consensus) {

	// Convert the given (partial) consensus to a string blurb.
	var buffer bytes.Buffer
	for _, status := range consensus.RouterStatuses {
		buffer.WriteString(fmt.Sprint(status))
	}

	err := writeStringToFile(filepath.Base(fileName), buffer.String())
	if err != nil {
		log.Panicln(err)
	}
}

// getArchiveParser returns a closure which takes a file name of a network
// consensus, parses it, and determines the amount of previously unobserved
// relay fingerprints in it compared to all previously observed file names.
// Depending on if the file names are sorted in lexical or reverse lexical
// order, this tells us how many relays join or leave the network,
// respectively.
func getArchiveParser(threshold int) func(fileName string) error {

	var allCons = tor.NewConsensus()
	var currCons = tor.NewConsensus()
	var err error

	return func(fileName string) error {

		currCons, err = tor.ParseConsensusFile(fileName)
		if err != nil {
			return err
		}

		// Determine and print the amount of previously unknown relay
		// fingerprints.
		if allCons.Length() != 0 {
			fmt.Printf("%s, ", filepath.Base(fileName))

			unobserved := currCons.Subtract(allCons)
			fmt.Printf("%d\n", unobserved.Length())

			// Dump previously unobserved statuses to file for manual analysis.
			if unobserved.Length() > threshold {
				log.Printf("Observed change in \"%s\" exceeds threshold by %d.\n",
					filepath.Base(fileName), unobserved.Length()-threshold)
				logConsensus(filepath.Base(fileName), unobserved)
			}
		}

		// Only keep track of fingerprints and discard the router statuses
		// because we don't need them.
		for fingerprint, _ := range currCons.RouterStatuses {
			allCons.Set(fingerprint, nil)
		}

		return nil
	}
}
<commit_msg>Add package documentation.<commit_after>// archives analyses consensuses as archived by CollecTor.
package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path/filepath"

	tor "git.torproject.org/user/phw/zoossh.git"
)

// collectFiles returns a closure of type WalkFunc which is used to collect all
// file names in a given directory.
func collectFiles(fileNames *[]string) func(path string, info os.FileInfo, err error) error {

	return func(path string, info os.FileInfo, err error) error {

		if !info.IsDir() {
			*fileNames = append(*fileNames, path)
		}

		return nil
	}
}

// logConsensus writes the given consensus to a file which is put in the output
// directory.
func logConsensus(fileName string, consensus *tor.Consensus) {

	// Convert the given (partial) consensus to a string blurb.
	var buffer bytes.Buffer
	for _, status := range consensus.RouterStatuses {
		buffer.WriteString(fmt.Sprint(status))
	}

	err := writeStringToFile(filepath.Base(fileName), buffer.String())
	if err != nil {
		log.Panicln(err)
	}
}

// getArchiveParser returns a closure which takes a file name of a network
// consensus, parses it, and determines the amount of previously unobserved
// relay fingerprints in it compared to all previously observed file names.
// Depending on if the file names are sorted in lexical or reverse lexical
// order, this tells us how many relays join or leave the network,
// respectively.
func getArchiveParser(threshold int) func(fileName string) error {

	var allCons = tor.NewConsensus()
	var currCons = tor.NewConsensus()
	var err error

	return func(fileName string) error {

		currCons, err = tor.ParseConsensusFile(fileName)
		if err != nil {
			return err
		}

		// Determine and print the amount of previously unknown relay
		// fingerprints.
		if allCons.Length() != 0 {
			fmt.Printf("%s, ", filepath.Base(fileName))

			unobserved := currCons.Subtract(allCons)
			fmt.Printf("%d\n", unobserved.Length())

			// Dump previously unobserved statuses to file for manual analysis.
			if unobserved.Length() > threshold {
				log.Printf("Observed change in \"%s\" exceeds threshold by %d.\n",
					filepath.Base(fileName), unobserved.Length()-threshold)
				logConsensus(filepath.Base(fileName), unobserved)
			}
		}

		// Only keep track of fingerprints and discard the router statuses
		// because we don't need them.
		for fingerprint, _ := range currCons.RouterStatuses {
			allCons.Set(fingerprint, nil)
		}

		return nil
	}
}
<|endoftext|>


<commit_before>package app

import (
	"strings"
	"time"

	"github.com/albertoleal/backstage/db"
	"github.com/albertoleal/backstage/errors"
)

type Service struct {
	Subdomain       string `bson:"_id"`
	CreatedAt       time.Time
	UpdatedAt       time.Time
	AllowKeylessUse bool
	Description     string
	Disabled        bool
	Documentation   string
	Endpoint        map[string]interface{}
	Owner           string
	Timeout         int
	Name            string
}

func CreateService(service *Service, user *User) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()

	if service.Subdomain == "" {
		message := "Subdomain cannot be empty."
		return &errors.ValidationError{Message: message}
	}
	if len(service.Endpoint) == 0 {
		message := "Endpoint cannot be empty."
		return &errors.ValidationError{Message: message}
	}

	// FIXME: improve this.
	service.Subdomain = strings.ToLower(service.Subdomain)
	service.CreatedAt = time.Now().In(time.UTC)
	service.UpdatedAt = time.Now().In(time.UTC)
	service.Owner = user.Username
	err = conn.Services().Insert(service)
	if err != nil && strings.Contains(err.Error(), "duplicate key") {
		message := "There is another service with this subdomain."
		return &errors.ValidationError{Message: message}
	}
	return err
}

func DeleteService(service *Service) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()

	err = conn.Services().Remove(service)
	if err != nil && strings.Contains(err.Error(), "not found") {
		message := "Document not found."
		return &errors.ValidationError{Message: message}
	}
	return err
}

func CountService() (int, error) {
	conn, err := db.Conn()
	if err != nil {
		return 0, err
	}
	defer conn.Close()

	return conn.Services().Count()
}
<commit_msg>Add space.<commit_after>package app

import (
	"strings"
	"time"

	"github.com/albertoleal/backstage/db"
	"github.com/albertoleal/backstage/errors"
)

type Service struct {
	Subdomain       string `bson:"_id"`
	CreatedAt       time.Time
	UpdatedAt       time.Time
	AllowKeylessUse bool
	Description     string
	Disabled        bool
	Documentation   string
	Endpoint        map[string]interface{}
	Owner           string
	Timeout         int
	Name            string
}

func CreateService(service *Service, user *User) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()

	if service.Subdomain == "" {
		message := "Subdomain cannot be empty."
		return &errors.ValidationError{Message: message}
	}
	if len(service.Endpoint) == 0 {
		message := "Endpoint cannot be empty."
		return &errors.ValidationError{Message: message}
	}

	// FIXME: improve this.
	service.Subdomain = strings.ToLower(service.Subdomain)
	service.CreatedAt = time.Now().In(time.UTC)
	service.UpdatedAt = time.Now().In(time.UTC)
	service.Owner = user.Username

	err = conn.Services().Insert(service)
	if err != nil && strings.Contains(err.Error(), "duplicate key") {
		message := "There is another service with this subdomain."
		return &errors.ValidationError{Message: message}
	}
	return err
}

func DeleteService(service *Service) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()

	err = conn.Services().Remove(service)
	if err != nil && strings.Contains(err.Error(), "not found") {
		message := "Document not found."
		return &errors.ValidationError{Message: message}
	}
	return err
}

func CountService() (int, error) {
	conn, err := db.Conn()
	if err != nil {
		return 0, err
	}
	defer conn.Close()

	return conn.Services().Count()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	disc "github.com/jeffjen/agent/discovery"
	d2k "github.com/jeffjen/go-dockerevents"
	"path"
	"time"
)

func publish(dflag string, addr string, ttl time.Duration) (event chan *d2k.Event) {
	event = make(chan *d2k.Event, 100)
	go func() {
		// init docker client for container inspection
		client, err := d2k.NewClient()
		if err != nil {
			log.Fatal("unable to establish docker client: %v", err)
		}
		for ev := range event {
			container, err := client.InspectContainer(ev.ID)
			if err != nil {
				log.Error(err)
				continue
			}
			portmap := container.NetworkSettings.PortMappingAPI()
			for idx, _ := range portmap {
				if portmap[idx].PrivatePort != 0 {
					portmap[idx].IP = addr
				}
			}
			payload, _ := json.Marshal(portmap)
			for {
				dkv, err := disc.New(dflag, "")
				if err != nil {
					log.Fatal("unable to establish connection to discovery -- %v", err)
				}
				err = dkv.Set(path.Join(INSTANCE_ROOT, ev.ID), string(payload), ttl)
				if err != nil {
					log.Warning(err)
					time.Sleep(1 * time.Second)
					continue
				}
				log.WithFields(log.Fields{"discovery": dflag, "addr": addr, "ttl": ttl}).Infof("Registering instance: %s", ev.ID)
				break
			}
		}
	}()
	return
}

func monitor(c *cli.Context) {
	dflag := getDiscovery(c)
	if dflag == "" {
		log.Fatalf("discovery required publish instance info. See '%s monitor --help'.", c.App.Name)
	}

	addr := c.String("addr")
	if addr == "" {
		log.Fatal("missing mandatory --addr flag")
	}

	ttl, err := time.ParseDuration(c.String("ttl"))
	if err != nil {
		log.Fatal("invlaid --ttl: %v", err)
	}

	filter := d2k.ParseEventFilter(c.String("filter"))

	// init docker event loop
	eventSink := d2k.EventLoop(filter, 100)

	// init docker event publisher
	etcdpub := publish(dflag, addr, ttl)

	log.Println("begin monitor process...")
	for event := range eventSink {
		switch event.Status {
		case "start":
			log.Infof("Obtained instance: %s", event.ID)
			etcdpub <- event
			break
		}
	}
}
<commit_msg>UPDATE: invalidate stopped instance from discovery<commit_after>package main

import (
	"encoding/json"
	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	disc "github.com/jeffjen/agent/discovery"
	d2k "github.com/jeffjen/go-dockerevents"
	"path"
	"time"
)

const (
	INVALIDATE_SERVICE_TTL = 1 * time.Second
)

func publish(dflag string, addr string, ttl time.Duration) (event chan *d2k.Event) {
	event = make(chan *d2k.Event, 100)
	go func() {
		// init docker client for container inspection
		client, err := d2k.NewClient()
		if err != nil {
			log.Fatal("unable to establish docker client: %v", err)
		}
		for ev := range event {
			container, err := client.InspectContainer(ev.ID)
			if err != nil {
				log.Error(err)
				continue
			}
			portmap := container.NetworkSettings.PortMappingAPI()
			for idx, _ := range portmap {
				if portmap[idx].PrivatePort != 0 {
					portmap[idx].IP = addr
				}
			}
			payload, _ := json.Marshal(portmap)
			for {
				dkv, err := disc.New(dflag, "")
				if err != nil {
					log.Fatal("unable to establish connection to discovery -- %v", err)
				}
				switch ev.Status {
				case "start":
					log.WithFields(log.Fields{"discovery": dflag, "addr": addr, "ttl": ttl}).Infof("Registering instance: %s", ev.ID)
					err = dkv.Set(path.Join(INSTANCE_ROOT, ev.ID), string(payload), ttl)
					break
				case "stop":
					log.WithFields(log.Fields{"discovery": dflag, "addr": addr, "ttl": ttl}).Infof("Invalidate instance: %s", ev.ID)
					err = dkv.Set(path.Join(INSTANCE_ROOT, ev.ID), "", INVALIDATE_SERVICE_TTL)
					break
				}
				if err != nil {
					log.Warning(err)
					time.Sleep(1 * time.Second)
					continue
				}
				break
			}
		}
	}()
	return
}

func monitor(c *cli.Context) {
	dflag := getDiscovery(c)
	if dflag == "" {
		log.Fatalf("discovery required publish instance info. See '%s monitor --help'.", c.App.Name)
	}

	addr := c.String("addr")
	if addr == "" {
		log.Fatal("missing mandatory --addr flag")
	}

	ttl, err := time.ParseDuration(c.String("ttl"))
	if err != nil {
		log.Fatal("invlaid --ttl: %v", err)
	}

	filter := d2k.ParseEventFilter(c.String("filter"))

	// init docker event loop
	eventSink := d2k.EventLoop(filter, 100)

	// init docker event publisher
	etcdpub := publish(dflag, addr, ttl)

	log.Println("begin monitor process...")
	for event := range eventSink {
		switch event.Status {
		case "start":
			log.Infof("Obtained instance: %s", event.ID)
			etcdpub <- event
			break
		case "stop":
			log.Infof("Spot invalid instance: %s", event.ID)
			etcdpub <- event
			break
		}
	}
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"strings"

	"github.com/fatih/color"
	"github.com/r3labs/sse"
	"github.com/urfave/cli"
)

// Message represents an incomming websocket message
type Message struct {
	Body  string `json:"body"`
	Level string `json:"level"`
}

// NullWriter to disable logging
type NullWriter int

// Write sends to nowhere the log messages
func (NullWriter) Write([]byte) (int, error) { return 0, nil }

// PrettyPrint unmarshals received messages and print it
func PrettyPrint(body []byte) {
	m := Message{}

	// clean msg body of any null characters
	cleanedInput := bytes.Trim(body, "\x00")

	err := json.Unmarshal(cleanedInput, &m)
	if err != nil {
		fmt.Println(err)
	}

	if m.Body == "error" || m.Body == "success" {
		os.Exit(0)
	}
	PrintLine(m)
}

// PrintLine prints each received message on a line with its color
func PrintLine(m Message) {
	if m.Level == "ERROR" {
		color.Red(m.Body)
	} else if m.Level == "SUCCESS" {
		color.Green(m.Body)
	} else if m.Level == "INFO" {
		color.Yellow(m.Body)
	} else {
		fmt.Println(m.Body)
	}
}

// Monitorize opens a websocket connection to get input messages
func Monitorize(host, token, stream string) {
	url := host + "/events"
	client := sse.NewClient(url)
	client.Connection.Transport = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	client.Headers["Authorization"] = fmt.Sprintf("Bearer %s", token)

	err := client.Subscribe(stream, func(msg *sse.Event) {
		if msg.Data != nil {
			PrettyPrint(msg.Data)
		}
	})
	if err != nil {
		log.Println("Failed with: " + err.Error())
		os.Exit(1)
	}
}

// MonitorService command
// Monitorizes an service and shows the actions being performed on it
var MonitorService = cli.Command{
	Name:      "monitor",
	Aliases:   []string{"m"},
	Usage:     "Monitor a service.",
	ArgsUsage: "<service_name>",
	Description: `Monitors a service while it is being built by its service name.

   Example:
    $ ernest monitor my_service
	`,
	Action: func(c *cli.Context) error {
		m, cfg := setup(c)
		if cfg.Token == "" {
			color.Red("You're not allowed to perform this action, please log in")
			return nil
		}

		if len(c.Args()) == 0 {
			color.Red("You should specify an existing service name")
			return nil
		}

		name := c.Args()[0]
		service, err := m.ServiceStatus(cfg.Token, name)
		if err != nil {
			color.Red(err.Error())
			return nil
		}
		parts := strings.Split(service.ID, "-")
		if len(parts) == 0 {
			color.Red("Invalid service specified")
			return nil
		}
		if service.Status == "done" {
			color.Yellow("Service has been successfully built")
			color.Yellow("You can check its information running `ernest-cli service info " + name + "`")
			return nil
		}

		Monitorize(cfg.URL, cfg.Token, parts[len(parts)-1])
		runtime.Goexit()
		return nil
	},
}
<commit_msg>re-enabling encoding<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"strings"

	"github.com/fatih/color"
	"github.com/r3labs/sse"
	"github.com/urfave/cli"
)

// Message represents an incomming websocket message
type Message struct {
	Body  string `json:"body"`
	Level string `json:"level"`
}

// NullWriter to disable logging
type NullWriter int

// Write sends to nowhere the log messages
func (NullWriter) Write([]byte) (int, error) { return 0, nil }

// PrettyPrint unmarshals received messages and print it
func PrettyPrint(body []byte) {
	m := Message{}

	// clean msg body of any null characters
	cleanedInput := bytes.Trim(body, "\x00")

	err := json.Unmarshal(cleanedInput, &m)
	if err != nil {
		fmt.Println(err)
	}

	if m.Body == "error" || m.Body == "success" {
		os.Exit(0)
	}
	PrintLine(m)
}

// PrintLine prints each received message on a line with its color
func PrintLine(m Message) {
	if m.Level == "ERROR" {
		color.Red(m.Body)
	} else if m.Level == "SUCCESS" {
		color.Green(m.Body)
	} else if m.Level == "INFO" {
		color.Yellow(m.Body)
	} else {
		fmt.Println(m.Body)
	}
}

// Monitorize opens a websocket connection to get input messages
func Monitorize(host, token, stream string) {
	url := host + "/events"
	client := sse.NewClient(url)
	client.EncodingBase64 = true
	client.Connection.Transport = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	client.Headers["Authorization"] = fmt.Sprintf("Bearer %s", token)

	err := client.Subscribe(stream, func(msg *sse.Event) {
		if msg.Data != nil {
			PrettyPrint(msg.Data)
		}
	})
	if err != nil {
		log.Println("Failed with: " + err.Error())
		os.Exit(1)
	}
}

// MonitorService command
// Monitorizes an service and shows the actions being performed on it
var MonitorService = cli.Command{
	Name:      "monitor",
	Aliases:   []string{"m"},
	Usage:     "Monitor a service.",
	ArgsUsage: "<service_name>",
	Description: `Monitors a service while it is being built by its service name.

   Example:
    $ ernest monitor my_service
	`,
	Action: func(c *cli.Context) error {
		m, cfg := setup(c)
		if cfg.Token == "" {
			color.Red("You're not allowed to perform this action, please log in")
			return nil
		}

		if len(c.Args()) == 0 {
			color.Red("You should specify an existing service name")
			return nil
		}

		name := c.Args()[0]
		service, err := m.ServiceStatus(cfg.Token, name)
		if err != nil {
			color.Red(err.Error())
			return nil
		}
		parts := strings.Split(service.ID, "-")
		if len(parts) == 0 {
			color.Red("Invalid service specified")
			return nil
		}
		if service.Status == "done" {
			color.Yellow("Service has been successfully built")
			color.Yellow("You can check its information running `ernest-cli service info " + name + "`")
			return nil
		}

		Monitorize(cfg.URL, cfg.Token, parts[len(parts)-1])
		runtime.Goexit()
		return nil
	},
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go.net/websocket"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"queue"
	"runtime"
	"strings"
	"time"
)

const debug = true
const maxSizeHealthStatusQueue = 600 // Magnificent Server Log Store Size, displays the last 600 seconds in the plot

type Msg struct {
	MessageId string
	Content   string
	TimeStamp int64
}

// Client connection consists of the websocket and the client ip
type Client struct {
	websocket *websocket.Conn
	clientIP  string
}

type ServiceMonitor struct {
	errChan           chan error // unbuffered channel
	errChanWebsock    chan error // unbuffered channel
	activeClients     map[string]Client
	healthStatusChan  chan bool
	alertChan         chan string
	newClientChan     chan Client
	alertQueue        *queue.Queue
	healthStatusQueue *queue.Queue
}

func NewServiceMonitor() *ServiceMonitor {
	m := ServiceMonitor{}
	m.activeClients = make(map[string]Client)
	m.errChan = make(chan error)
	m.healthStatusChan = make(chan bool, 10)
	m.alertChan = make(chan string, 10)
	m.newClientChan = make(chan Client, 10)
	m.alertQueue = queue.NewQueue()
	m.healthStatusQueue = queue.NewQueue()
	return &m
}

func BoolToString(value bool) string {
	if value {
		return "1"
	}
	return "0"
}

func (m *ServiceMonitor) sendClientMsg(msg *Msg, ip string) {
	var err error
	var Message = websocket.JSON

	if err = Message.Send(m.activeClients[ip].websocket, msg); err != nil {
		// we could not send the message to a peer
		log.Println("Could not send message to:", ip, err.Error())
		log.Println("Client disconnected:", ip)
		delete(m.activeClients, ip)
	}
}

func (m *ServiceMonitor) sendBroadcastMsg(msg *Msg) {
	var err error
	var Message = websocket.JSON

	for ip, _ := range m.activeClients {
		if err = Message.Send(m.activeClients[ip].websocket, msg); err != nil {
			// we could not send the message to a peer
			log.Println("Could not send message to:", ip, err.Error())
			log.Println("Client disconnected:", ip)
			delete(m.activeClients, ip)
		}
	}
}

func (m *ServiceMonitor) sendQueueData(ip string) {
	for i := 0; i < m.healthStatusQueue.Len(); i++ {
		e, found := m.healthStatusQueue.Get(i)

		if found {
			if msg, ok := e.(*Msg); ok {
				m.sendClientMsg(msg, ip)
			}
		}
	}

	for i := 0; i < m.alertQueue.Len(); i++ {
		e, found := m.alertQueue.Get(i)

		if found {
			if msg, ok := e.(*Msg); ok {
				m.sendClientMsg(msg, ip)
			}
		}
	}
}

// this routine handles all outgoing websocket messages
func (m *ServiceMonitor) pushDataToClients() {
	for {
		select {
		// a new Client is connecting
		case newClient := <-m.newClientChan:
			// send current Queue data to the new connecting client
			m.activeClients[newClient.clientIP] = newClient
			m.sendQueueData(newClient.clientIP)

		// broadcast a new health status message to all clients
		// newHealthStatus == 1 ... deamon failure
		// newHealthStatus == 0 ... deamon ok
		case newHealthStatus := <-m.healthStatusChan:
			msg := Msg{"Plot", BoolToString(newHealthStatus), time.Now().UnixNano() / int64(time.Millisecond)}
			m.sendBroadcastMsg(&msg)
			// add msg to HealthStatusQueue
			if m.healthStatusQueue.Len() < maxSizeHealthStatusQueue {
				m.healthStatusQueue.Push(&msg)
			} else {
				m.healthStatusQueue.Pop()
				m.healthStatusQueue.Push(&msg)
			}

		// broadcast an alert message to all clients
		case newAlert := <-m.alertChan:
			msg := Msg{"Alert", newAlert, time.Now().UnixNano() / int64(time.Millisecond)}
			m.sendBroadcastMsg(&msg)
			// add msg to alertQueue
      if m.alertQueue.Len() < maxSizeHealthStatusQueue {
        m.alertQueue.Push(&msg)
      } else {
        m.alertQueue.Pop()
        m.alertQueue.Push(&msg)
      }
		}
	}
}

// reference: https://github.com/Niessy/websocket-golang-chat
// WebSocket server to handle clients
func (m *ServiceMonitor) WebSocketServer(ws *websocket.Conn) {
	var err error

	// cleanup on server side
	defer func() {
		if err = ws.Close(); err != nil {
			log.Println("Websocket could not be closed", err.Error())
		}
	}()

	client := ws.Request().RemoteAddr
	if debug {
		log.Println("New client connected:", client)
	}

	m.newClientChan <- Client{ws, client}

	// wait for errChan, so the websocket stays open otherwise it'll close
	err = <-m.errChanWebsock
}

// handler for the main page
func HomeHandler(response http.ResponseWriter, request *http.Request) {
	response.Header().Set("Content-type", "text/html")
	webpage, err := ioutil.ReadFile("home.html")

	if err != nil {
		http.Error(response, fmt.Sprintf("home.html file error %v", err), 500)
	}

	fmt.Fprint(response, string(webpage))
}

func (m *ServiceMonitor) parseResponse(resp string) {
  if !strings.Contains(resp, "Magnificent!") {
		m.healthStatusChan <- false
	} else {
		m.healthStatusChan <- true
		m.alertChan <- "Server has failed"
	}
}

func (m *ServiceMonitor) requestDaemonStatus(url string) {
	response, err := http.Get(url)
	if err != nil {
		if debug {
			log.Println("requestDeamonStatus failed:", err.Error())
			return
		}
	}

	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		if debug {
			log.Println("requestDeamonStatus failed:", err.Error())
			return
		}
	}

	resp := string(contents)
	m.parseResponse(resp)
}

func (m *ServiceMonitor) monitorDaemon(url string, time_interval time.Duration) {
	for {
		m.requestDaemonStatus(url)
		time.Sleep(time_interval * time.Second)
	}
}

func (m *ServiceMonitor) startHTTPServer() {
	http.Handle("/", http.HandlerFunc(HomeHandler))
	http.Handle("/sock", websocket.Handler(m.WebSocketServer))

	err := http.ListenAndServe(":8080", nil)
	m.errChanWebsock <- err
	m.errChan <- err
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	m := NewServiceMonitor()

	go m.startHTTPServer()
	go m.pushDataToClients()
	go m.monitorDaemon("http://localhost:12345/", 1)

	err := <-m.errChan
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}
}
<commit_msg>formatted code<commit_after>package main

import (
	"code.google.com/p/go.net/websocket"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"queue"
	"runtime"
	"strings"
	"time"
)

const debug = true
const maxSizeHealthStatusQueue = 600 // Magnificent Server Log Store Size, displays the last 600 seconds in the plot

type Msg struct {
	MessageId string
	Content   string
	TimeStamp int64
}

// Client connection consists of the websocket and the client ip
type Client struct {
	websocket *websocket.Conn
	clientIP  string
}

type ServiceMonitor struct {
	errChan           chan error // unbuffered channel
	errChanWebsock    chan error // unbuffered channel
	activeClients     map[string]Client
	healthStatusChan  chan bool
	alertChan         chan string
	newClientChan     chan Client
	alertQueue        *queue.Queue
	healthStatusQueue *queue.Queue
}

func NewServiceMonitor() *ServiceMonitor {
	m := ServiceMonitor{}
	m.activeClients = make(map[string]Client)
	m.errChan = make(chan error)
	m.healthStatusChan = make(chan bool, 10)
	m.alertChan = make(chan string, 10)
	m.newClientChan = make(chan Client, 10)
	m.alertQueue = queue.NewQueue()
	m.healthStatusQueue = queue.NewQueue()
	return &m
}

func BoolToString(value bool) string {
	if value {
		return "1"
	}
	return "0"
}

func (m *ServiceMonitor) sendClientMsg(msg *Msg, ip string) {
	var err error
	var Message = websocket.JSON

	if err = Message.Send(m.activeClients[ip].websocket, msg); err != nil {
		// we could not send the message to a peer
		log.Println("Could not send message to:", ip, err.Error())
		log.Println("Client disconnected:", ip)
		delete(m.activeClients, ip)
	}
}

func (m *ServiceMonitor) sendBroadcastMsg(msg *Msg) {
	var err error
	var Message = websocket.JSON

	for ip, _ := range m.activeClients {
		if err = Message.Send(m.activeClients[ip].websocket, msg); err != nil {
			// we could not send the message to a peer
			log.Println("Could not send message to:", ip, err.Error())
			log.Println("Client disconnected:", ip)
			delete(m.activeClients, ip)
		}
	}
}

func (m *ServiceMonitor) sendQueueData(ip string) {
	for i := 0; i < m.healthStatusQueue.Len(); i++ {
		e, found := m.healthStatusQueue.Get(i)

		if found {
			if msg, ok := e.(*Msg); ok {
				m.sendClientMsg(msg, ip)
			}
		}
	}

	for i := 0; i < m.alertQueue.Len(); i++ {
		e, found := m.alertQueue.Get(i)

		if found {
			if msg, ok := e.(*Msg); ok {
				m.sendClientMsg(msg, ip)
			}
		}
	}
}

// this routine handles all outgoing websocket messages
func (m *ServiceMonitor) pushDataToClients() {
	for {
		select {
		// a new Client is connecting
		case newClient := <-m.newClientChan:
			// send current Queue data to the new connecting client
			m.activeClients[newClient.clientIP] = newClient
			m.sendQueueData(newClient.clientIP)

		// broadcast a new health status message to all clients
		// newHealthStatus == 1 ... deamon failure
		// newHealthStatus == 0 ... deamon ok
		case newHealthStatus := <-m.healthStatusChan:
			msg := Msg{"Plot", BoolToString(newHealthStatus), time.Now().UnixNano() / int64(time.Millisecond)}
			m.sendBroadcastMsg(&msg)
			// add msg to HealthStatusQueue
			if m.healthStatusQueue.Len() < maxSizeHealthStatusQueue {
				m.healthStatusQueue.Push(&msg)
			} else {
				m.healthStatusQueue.Pop()
				m.healthStatusQueue.Push(&msg)
			}

		// broadcast an alert message to all clients
		case newAlert := <-m.alertChan:
			msg := Msg{"Alert", newAlert, time.Now().UnixNano() / int64(time.Millisecond)}
			m.sendBroadcastMsg(&msg)
			// add msg to alertQueue
			if m.alertQueue.Len() < maxSizeHealthStatusQueue {
				m.alertQueue.Push(&msg)
			} else {
				m.alertQueue.Pop()
				m.alertQueue.Push(&msg)
			}
		}
	}
}

// reference: https://github.com/Niessy/websocket-golang-chat
// WebSocket server to handle clients
func (m *ServiceMonitor) WebSocketServer(ws *websocket.Conn) {
	var err error

	// cleanup on server side
	defer func() {
		if err = ws.Close(); err != nil {
			log.Println("Websocket could not be closed", err.Error())
		}
	}()

	client := ws.Request().RemoteAddr
	if debug {
		log.Println("New client connected:", client)
	}

	m.newClientChan <- Client{ws, client}

	// wait for errChan, so the websocket stays open otherwise it'll close
	err = <-m.errChanWebsock
}

// handler for the main page
func HomeHandler(response http.ResponseWriter, request *http.Request) {
	response.Header().Set("Content-type", "text/html")
	webpage, err := ioutil.ReadFile("home.html")

	if err != nil {
		http.Error(response, fmt.Sprintf("home.html file error %v", err), 500)
	}

	fmt.Fprint(response, string(webpage))
}

func (m *ServiceMonitor) parseResponse(resp string) {
	if !strings.Contains(resp, "Magnificent!") {
		m.healthStatusChan <- false
	} else {
		m.healthStatusChan <- true
		m.alertChan <- "Server has failed"
	}
}

func (m *ServiceMonitor) requestDaemonStatus(url string) {
	response, err := http.Get(url)
	if err != nil {
		if debug {
			log.Println("requestDeamonStatus failed:", err.Error())
			return
		}
	}

	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		if debug {
			log.Println("requestDeamonStatus failed:", err.Error())
			return
		}
	}

	resp := string(contents)
	m.parseResponse(resp)
}

func (m *ServiceMonitor) monitorDaemon(url string, time_interval time.Duration) {
	for {
		m.requestDaemonStatus(url)
		time.Sleep(time_interval * time.Second)
	}
}

func (m *ServiceMonitor) startHTTPServer() {
	http.Handle("/", http.HandlerFunc(HomeHandler))
	http.Handle("/sock", websocket.Handler(m.WebSocketServer))

	err := http.ListenAndServe(":8080", nil)
	m.errChanWebsock <- err
	m.errChan <- err
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	m := NewServiceMonitor()

	go m.startHTTPServer()
	go m.pushDataToClients()
	go m.monitorDaemon("http://localhost:12345/", 1)

	err := <-m.errChan
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package monocle

import (
	"github.com/spf13/cobra"
)

var DefaultMonocle = &Monocle{}

// Enable enables monocle on a cobra command using the default monocle
func Enable(c *cobra.Command) {
	DefaultMonocle.Enable(c)
}

// Primary sets the commands a primary help topic
func Primary(cmds ...*cobra.Command) {
	DefaultMonocle.Primary(cmds...)
}

// Monocle represents the component that enables custom help on a cobra command
type Monocle struct {
	*cobra.Command

	primaries []*cobra.Command
}

// New returns a a new Monocle
func New() *Monocle {
	return &Monocle{}
}

// Enable enables monocle on a cobra command
func (m *Monocle) Enable(c *cobra.Command) {
	m.Command = c
	c.SetUsageFunc(m.UsageFunc())
}

// UsageFunc returns the usage function that'll be used for the command
func (m *Monocle) UsageFunc() (f func(*cobra.Command) error) {
	// if m.Command.HasParent() {
	// 	return m.Command.Parent().UsageFunc()
	// }
	return func(c *cobra.Command) error {
		if c == m.Command {
			return tmpl(c.Out(), topicTemplate, m)
		}
		return tmpl(c.Out(), usageTemplate, c)
	}
}

// Primary sets a command a primary help topic
func (m *Monocle) Primary(cmds ...*cobra.Command) {
	m.primaries = append(m.primaries, cmds...)
}

// PrimaryCommands returns a list primary commands enabled using the Primary function
func (m *Monocle) PrimaryCommands() []*cobra.Command {
	return m.primaries
}

// AdditionalCommands returns the a list addtional commands when a primary command is specified. Returns nil otherwise
func (m *Monocle) AdditionalCommands() []*cobra.Command {
	hasPrimary := len(m.primaries) > 0
	if hasPrimary {
		res := make([]*cobra.Command, 0)
		for _, cmd := range m.Command.Commands() {
			include := true
			for _, primaryCmd := range m.primaries {
				if cmd == primaryCmd {
					include = false
					break
				}
			}
			if include {
				res = append(res, cmd)
			}
		}
		return res
	}
	return make([]*cobra.Command, 0)
}
<commit_msg>update cobra<commit_after>package monocle

import (
	"github.com/spf13/cobra"
)

var DefaultMonocle = &Monocle{}

// Enable enables monocle on a cobra command using the default monocle
func Enable(c *cobra.Command) {
	DefaultMonocle.Enable(c)
}

// Primary sets the commands a primary help topic
func Primary(cmds ...*cobra.Command) {
	DefaultMonocle.Primary(cmds...)
}

// Monocle represents the component that enables custom help on a cobra command
type Monocle struct {
	*cobra.Command

	primaries []*cobra.Command
}

// New returns a a new Monocle
func New() *Monocle {
	return &Monocle{}
}

// Enable enables monocle on a cobra command
func (m *Monocle) Enable(c *cobra.Command) {
	m.Command = c
	c.SetUsageFunc(m.UsageFunc())
}

// UsageFunc returns the usage function that'll be used for the command
func (m *Monocle) UsageFunc() (f func(*cobra.Command) error) {
	// if m.Command.HasParent() {
	// 	return m.Command.Parent().UsageFunc()
	// }
	return func(c *cobra.Command) error {
		if c == m.Command {
			return tmpl(c.OutOrStderr(), topicTemplate, m)
		}
		return tmpl(c.OutOrStderr(), usageTemplate, c)
	}
}

// Primary sets a command a primary help topic
func (m *Monocle) Primary(cmds ...*cobra.Command) {
	m.primaries = append(m.primaries, cmds...)
}

// PrimaryCommands returns a list primary commands enabled using the Primary function
func (m *Monocle) PrimaryCommands() []*cobra.Command {
	return m.primaries
}

// AdditionalCommands returns the a list addtional commands when a primary command is specified. Returns nil otherwise
func (m *Monocle) AdditionalCommands() []*cobra.Command {
	hasPrimary := len(m.primaries) > 0
	if hasPrimary {
		res := make([]*cobra.Command, 0)
		for _, cmd := range m.Command.Commands() {
			include := true
			for _, primaryCmd := range m.primaries {
				if cmd == primaryCmd {
					include = false
					break
				}
			}
			if include {
				res = append(res, cmd)
			}
		}
		return res
	}
	return make([]*cobra.Command, 0)
}
<|endoftext|>


<commit_before>/* For license and copyright information please see LEGAL file in repository */

package assets

import (
	"bytes"
	"compress/gzip"
	"regexp"

	"../log"

	"github.com/tdewolff/minify"
	"github.com/tdewolff/minify/css"
	"github.com/tdewolff/minify/html"
	"github.com/tdewolff/minify/js"
	"github.com/tdewolff/minify/json"
	"github.com/tdewolff/minify/svg"
	"github.com/tdewolff/minify/xml"
)

// File :
type File struct {
	FullName     string
	Name         string
	Extension    string
	MimeType     string
	Dep          *Folder
	State        uint8
	Data         []byte
	CompressData []byte
	CompressType string
}

// File||Folder State
const (
	StateUnChanged uint8 = iota
	StateChanged
)

// Copy returns a copy of the file.
func (f *File) Copy() *File {
	var file = File{
		FullName:  f.FullName,
		Name:      f.Name,
		Extension: f.Extension,
		MimeType:  f.MimeType,
		Dep:       f.Dep,
		State:     f.State,
		Data:      f.Data,
	}
	return &file
}

// DeepCopy returns a deep copy of the file.
func (f *File) DeepCopy() *File {
	var file = File{
		FullName:  f.FullName,
		Name:      f.Name,
		Extension: f.Extension,
		MimeType:  f.MimeType,
		Dep:       f.Dep,
		State:     f.State,
	}
	copy(file.Data, f.Data)
	return &file
}

var m = minify.New()
var htmlMinify = regexp.MustCompile(`\r?\n|(<!--.*?-->)|(<!--[\w\W\n\s]+?-->)`)

func init() {
	m.AddFunc("text/css", css.Minify)
	m.AddFunc("text/html", html.Minify)
	m.AddFunc("image/svg+xml", svg.Minify)
	m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify)
	m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify)
	m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify)
}

// Minify replace file data with minify of them.
func (f *File) Minify() {
	// TODO::: have problem minify HTML >> https://github.com/tdewolff/minify/issues/318
	if f.Extension == "html" {
		f.Data = htmlMinify.ReplaceAll(f.Data, []byte{})
		return
	}
	var err error
	f.Data, err = m.Bytes(f.MimeType, f.Data)
	if err != nil {
		log.Warn("Minify", f.FullName, "occur this error:", err)
	}
}

// Supported compress types
const (
	CompressTypeGZIP = "gzip"
)

// Compress use to compress file data to mostly to use in serving file by servers.
func (f *File) Compress(compressType string) {
	// Check file type and compress just if it worth.
	switch f.Extension {
	case "png", "jpg", "gif", "jpeg", "mkv", "avi", "mp3", "mp4":
		f.CompressData = f.Data
		return
	}

	f.CompressType = compressType
	switch compressType {
	case "gzip":
		var b bytes.Buffer
		var gz = gzip.NewWriter(&b)
		gz.Write(f.Data)
		gz.Close()
		f.CompressData = b.Bytes()
	}
}
<commit_msg>Add two new method to assets file ... to help serve files on network with cache ability<commit_after>/* For license and copyright information please see LEGAL file in repository */

package assets

import (
	"bytes"
	"compress/gzip"
	"hash/crc32"
	"regexp"
	"strconv"

	"../log"

	"github.com/tdewolff/minify"
	"github.com/tdewolff/minify/css"
	"github.com/tdewolff/minify/html"
	"github.com/tdewolff/minify/js"
	"github.com/tdewolff/minify/json"
	"github.com/tdewolff/minify/svg"
	"github.com/tdewolff/minify/xml"
)

// File store some data about a file!
type File struct {
	FullName     string
	Name         string
	Extension    string
	MimeType     string
	Dep          *Folder
	State        uint8
	Data         []byte
	CompressData []byte
	CompressType string
}

// File||Folder State
const (
	StateUnChanged uint8 = iota
	StateChanged
)

// var md5Hasher = md5.New()

// GetHashOfData return hash of f.Data
func (f *File) GetHashOfData() (hash string) {
	// Just want to differ two same file, So crc32 is more enough!
	// md5Hasher.Write(f.Data)
	// hash = hex.EncodeToString(md5Hasher.Sum(nil))
	// md5Hasher.Reset()
	return strconv.FormatUint(uint64(crc32.ChecksumIEEE(f.Data)), 10)
}

// AddHashToName add f.Data hash to its name and full name.
func (f *File) AddHashToName() {
	f.Name += "-" + f.GetHashOfData()
	f.FullName = f.Name + "." + f.Extension
}

// Copy returns a copy of the file.
func (f *File) Copy() *File {
	var file = File{
		FullName:  f.FullName,
		Name:      f.Name,
		Extension: f.Extension,
		MimeType:  f.MimeType,
		Dep:       f.Dep,
		State:     f.State,
		Data:      f.Data,
	}
	return &file
}

// DeepCopy returns a deep copy of the file.
func (f *File) DeepCopy() *File {
	var file = File{
		FullName:  f.FullName,
		Name:      f.Name,
		Extension: f.Extension,
		MimeType:  f.MimeType,
		Dep:       f.Dep,
		State:     f.State,
	}
	copy(file.Data, f.Data)
	return &file
}

var m = minify.New()
var htmlMinify = regexp.MustCompile(`\r?\n|(<!--.*?-->)|(<!--[\w\W\n\s]+?-->)`)

func init() {
	m.AddFunc("text/css", css.Minify)
	m.AddFunc("text/html", html.Minify)
	m.AddFunc("image/svg+xml", svg.Minify)
	m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify)
	m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify)
	m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify)
}

// Minify replace file data with minify of them.
func (f *File) Minify() {
	// TODO::: have problem minify HTML >> https://github.com/tdewolff/minify/issues/318
	if f.Extension == "html" {
		f.Data = htmlMinify.ReplaceAll(f.Data, []byte{})
		return
	}
	var err error
	f.Data, err = m.Bytes(f.MimeType, f.Data)
	if err != nil {
		log.Warn("Minify", f.FullName, "occur this error:", err)
	}
}

// Supported compress types
const (
	CompressTypeGZIP = "gzip"
)

// Compress use to compress file data to mostly to use in serving file by servers.
func (f *File) Compress(compressType string) {
	// Check file type and compress just if it worth.
	switch f.Extension {
	case "png", "jpg", "gif", "jpeg", "mkv", "avi", "mp3", "mp4":
		f.CompressData = f.Data
		return
	}

	f.CompressType = compressType
	switch compressType {
	case "gzip":
		var b bytes.Buffer
		var gz = gzip.NewWriter(&b)
		gz.Write(f.Data)
		gz.Close()
		f.CompressData = b.Bytes()
	}
}
<|endoftext|>


<commit_before>package ast

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/Zac-Garby/pluto/token"
)

const treeIndent = 2

func in(indent int) string {
	return strings.Repeat(" ", treeIndent*indent)
}

func prefix(indent int, name string) string {
	str := in(indent)

	if name != "" {
		str += name + " ‣ "
	}

	return str
}

func Tree(node Node, indent int, name string) string {
	val := reflect.ValueOf(node)

	typeName := fmt.Sprintf("%T", node)[5:]

	if name != "" {
		name = fmt.Sprintf("%s (%s)", name, typeName)
	} else {
		name = fmt.Sprintf("(%s)", typeName)
	}

	str := prefix(indent, name) + val.Type().Name()

	for val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	for i := 0; i < val.Type().NumField(); i++ {
		field := val.Field(i).Interface()
		label := val.Type().Field(i).Name

		if label == "Value" {
			label = ""
		}

		if _, ok := field.(*Null); ok {
			str += "\n" + prefix(indent+1, label) + "<null>"
			continue
		}

		switch n := field.(type) {
		case token.Token:
		case Node:
			str += "\n" + Tree(n, indent+1, label)
		case map[Statement]Statement:
			nodes := make(map[Node]Node)

			for key, value := range n {
				nodes[key] = value
			}

			str += "\n" + makeDictTree(indent+1, nodes, label)
		case map[Expression]Expression:
			nodes := make(map[Node]Node)

			for key, value := range n {
				nodes[key] = value
			}

			str += "\n" + makeDictTree(indent+1, nodes, label)
		case []Statement:
			var nodes []Node

			for _, item := range n {
				nodes = append(nodes, item.(Node))
			}

			str += "\n" + makeListTree(indent+1, nodes, label)
		case []Expression:
			var nodes []Node

			for _, item := range n {
				nodes = append(nodes, item.(Node))
			}

			str += "\n" + makeListTree(indent+1, nodes, label)
		case []Arm:
			str += "\n" + prefix(indent+1, label) + "arms ["

			if len(n) == 0 {
				str += "]"
				break
			}

			for _, arm := range n {
				var nodes []Node

				for _, item := range arm.Exprs {
					nodes = append(nodes, item.(Node))
				}

				str += fmt.Sprintf(
					"\n%sarm (\n%s\n%s\n%s)",
					in(indent+2),
					makeListTree(indent+3, nodes, "expressions"),
					Tree(arm.Body, indent+3, "body"),
					in(indent+2),
				)
			}

			str += "\n" + in(indent+1) + "]"
		default:
			str += "\n" + fmt.Sprintf("%s%s", prefix(indent+1, label), fmt.Sprintf("%v", n))
		}
	}

	return str
}

func makeListTree(indent int, nodes []Node, name string) string {
	str := prefix(indent, name) + "["

	if len(nodes) == 0 {
		return str + "]"
	}

	for _, node := range nodes {
		str += "\n" + Tree(node, indent+1, "")
	}

	return str + "\n" + in(indent) + "]"
}

func makeDictTree(indent int, pairs map[Node]Node, name string) string {
	str := prefix(indent, name) + "["

	if len(pairs) == 0 {
		return str + ":]"
	}

	for key, value := range pairs {
		str += fmt.Sprintf("%s\n%s\n%s\n",
			in(indent),
			Tree(key, indent+1, "key"),
			Tree(value, indent+1, "value"),
		)
	}

	return str + in(indent) + "]"
}
<commit_msg>Comment Tree()<commit_after>package ast

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/Zac-Garby/pluto/token"
)

const treeIndent = 2

func in(indent int) string {
	return strings.Repeat(" ", treeIndent*indent)
}

func prefix(indent int, name string) string {
	str := in(indent)

	if name != "" {
		str += name + " ‣ "
	}

	return str
}

// Tree returns a tree representation of a node
func Tree(node Node, indent int, name string) string {
	val := reflect.ValueOf(node)

	typeName := fmt.Sprintf("%T", node)[5:]

	if name != "" {
		name = fmt.Sprintf("%s (%s)", name, typeName)
	} else {
		name = fmt.Sprintf("(%s)", typeName)
	}

	str := prefix(indent, name) + val.Type().Name()

	for val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	for i := 0; i < val.Type().NumField(); i++ {
		field := val.Field(i).Interface()
		label := val.Type().Field(i).Name

		if label == "Value" {
			label = ""
		}

		if _, ok := field.(*Null); ok {
			str += "\n" + prefix(indent+1, label) + "<null>"
			continue
		}

		switch n := field.(type) {
		case token.Token:
		case Node:
			str += "\n" + Tree(n, indent+1, label)
		case map[Statement]Statement:
			nodes := make(map[Node]Node)

			for key, value := range n {
				nodes[key] = value
			}

			str += "\n" + makeDictTree(indent+1, nodes, label)
		case map[Expression]Expression:
			nodes := make(map[Node]Node)

			for key, value := range n {
				nodes[key] = value
			}

			str += "\n" + makeDictTree(indent+1, nodes, label)
		case []Statement:
			var nodes []Node

			for _, item := range n {
				nodes = append(nodes, item.(Node))
			}

			str += "\n" + makeListTree(indent+1, nodes, label)
		case []Expression:
			var nodes []Node

			for _, item := range n {
				nodes = append(nodes, item.(Node))
			}

			str += "\n" + makeListTree(indent+1, nodes, label)
		case []Arm:
			str += "\n" + prefix(indent+1, label) + "arms ["

			if len(n) == 0 {
				str += "]"
				break
			}

			for _, arm := range n {
				var nodes []Node

				for _, item := range arm.Exprs {
					nodes = append(nodes, item.(Node))
				}

				str += fmt.Sprintf(
					"\n%sarm (\n%s\n%s\n%s)",
					in(indent+2),
					makeListTree(indent+3, nodes, "expressions"),
					Tree(arm.Body, indent+3, "body"),
					in(indent+2),
				)
			}

			str += "\n" + in(indent+1) + "]"
		default:
			str += "\n" + fmt.Sprintf("%s%s", prefix(indent+1, label), fmt.Sprintf("%v", n))
		}
	}

	return str
}

func makeListTree(indent int, nodes []Node, name string) string {
	str := prefix(indent, name) + "["

	if len(nodes) == 0 {
		return str + "]"
	}

	for _, node := range nodes {
		str += "\n" + Tree(node, indent+1, "")
	}

	return str + "\n" + in(indent) + "]"
}

func makeDictTree(indent int, pairs map[Node]Node, name string) string {
	str := prefix(indent, name) + "["

	if len(pairs) == 0 {
		return str + ":]"
	}

	for key, value := range pairs {
		str += fmt.Sprintf("%s\n%s\n%s\n",
			in(indent),
			Tree(key, indent+1, "key"),
			Tree(value, indent+1, "value"),
		)
	}

	return str + in(indent) + "]"
}
<|endoftext|>


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

// Package audio provides audio players. This can be used with or without ebiten package.
//
// The stream format must be 16-bit little endian and 2 channels.
//
// An audio context has a sample rate you can set and all streams you want to play must have the same
// sample rate.
//
// An audio context can generate 'players' (instances of audio.Player),
// and you can play sound by calling Play function of players.
// When multiple players play, mixing is automatically done.
// Note that too many players may cause distortion.
package audio

import (
	"io"
	"runtime"
	"sync"
	"time"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/audio/internal/driver"
)

type players struct {
	players map[*Player]struct{}
	sync.RWMutex
}

const (
	channelNum     = 2
	bytesPerSample = 2

	// TODO: This assumes that channelNum is a power of 2.
	mask = ^(channelNum*bytesPerSample - 1)
)

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func (p *players) Read(b []byte) (int, error) {
	p.Lock()
	defer p.Unlock()

	if len(p.players) == 0 {
		l := len(b)
		l &= mask
		copy(b, make([]byte, l))
		return l, nil
	}
	closed := []*Player{}
	l := len(b)
	for p := range p.players {
		err := p.readToBuffer(l)
		if err == io.EOF {
			closed = append(closed, p)
		} else if err != nil {
			return 0, err
		}
		l = min(p.bufferLength(), l)
	}
	l &= mask
	b16s := [][]int16{}
	for p := range p.players {
		b16s = append(b16s, p.bufferToInt16(l))
	}
	for i := 0; i < l/2; i++ {
		x := 0
		for _, b16 := range b16s {
			x += int(b16[i])
		}
		if x > (1<<15)-1 {
			x = (1 << 15) - 1
		}
		if x < -(1 << 15) {
			x = -(1 << 15)
		}
		b[2*i] = byte(x)
		b[2*i+1] = byte(x >> 8)
	}
	for p := range p.players {
		p.proceed(l)
	}
	for _, pl := range closed {
		delete(p.players, pl)
	}
	return l, nil
}

func (p *players) addPlayer(player *Player) {
	p.Lock()
	defer p.Unlock()
	p.players[player] = struct{}{}
}

func (p *players) removePlayer(player *Player) {
	p.Lock()
	defer p.Unlock()
	delete(p.players, player)
}

func (p *players) hasPlayer(player *Player) bool {
	p.RLock()
	defer p.RUnlock()
	_, ok := p.players[player]
	return ok
}

func (p *players) seekPlayer(player *Player, offset int64) error {
	p.Lock()
	defer p.Unlock()
	return player.seek(offset)
}

func (p *players) playerCurrent(player *Player, sampleRate int) time.Duration {
	p.RLock()
	defer p.RUnlock()
	sample := player.pos / bytesPerSample / channelNum
	return time.Duration(sample) * time.Second / time.Duration(sampleRate)
}

// TODO: Enable to specify the format like Mono8?

// A Context is a current state of audio.
//
// The typical usage with ebiten package is:
//
//    var audioContext *audio.Context
//
//    func update(screen *ebiten.Image) error {
//        // Update updates the audio stream by 1/60 [sec].
//        if err := audioContext.Update(); err != nil {
//            return err
//        }
//        // ...
//    }
//
//    func main() {
//        audioContext, err = audio.NewContext(sampleRate)
//        if err != nil {
//            panic(err)
//        }
//        ebiten.Run(run, update, 320, 240, 2, "Audio test")
//    }
//
// This is 'sync mode' in that game's (logical) time and audio time are synchronized.
// You can also call Update independently from the game loop as 'async mode'.
// In this case, audio goes on even when the game stops e.g. by diactivating the screen.
type Context struct {
	players      *players
	driver       *driver.Player
	sampleRate   int
	frames       int
	writtenBytes int
}

// NewContext creates a new audio context with the given sample rate (e.g. 44100).
func NewContext(sampleRate int) (*Context, error) {
	// TODO: Panic if one context exists.
	c := &Context{
		sampleRate: sampleRate,
	}
	c.players = &players{
		players: map[*Player]struct{}{},
	}
	return c, nil

}

// Update proceeds the inner (logical) time of the context by 1/60 second.
//
// This is expected to be called in the game's updating function (sync mode)
// or an independent goroutine with timers (async mode).
// In sync mode, the game logical time syncs the audio logical time and
// you will find audio stops when the game stops e.g. when the window is deactivated.
// In async mode, the audio never stops even when the game stops.
func (c *Context) Update() error {
	// Initialize c.driver lazily to enable calling NewContext in an 'init' function.
	// Accessing driver functions requires that the environment is already initialized,
	// but if Ebiten is used for a shared library, how init functions are called is unexpectable.
	// e.g. a variable for JVM on Android might not be set.
	if c.driver == nil {
		// TODO: Rename this other than player
		p, err := driver.NewPlayer(c.sampleRate, channelNum, bytesPerSample)
		c.driver = p
		if err != nil {
			return err
		}
	}
	c.frames++
	bytesPerFrame := c.sampleRate * bytesPerSample * channelNum / ebiten.FPS
	l := (c.frames * bytesPerFrame) - c.writtenBytes
	l &= mask
	c.writtenBytes += l
	buf := make([]byte, l)
	n, err := io.ReadFull(c.players, buf)
	if err != nil {
		return err
	}
	if n != len(buf) {
		return c.driver.Close()
	}
	// TODO: Rename this to Enqueue
	err = c.driver.Proceed(buf)
	if err == io.EOF {
		return c.driver.Close()
	}
	if err != nil {
		return err
	}
	return nil
}

// SampleRate returns the sample rate.
// All audio source must have the same sample rate.
//
// This function is concurrent-safe.
func (c *Context) SampleRate() int {
	return c.sampleRate
}

// ReadSeekCloser is an io.ReadSeeker and io.Closer.
type ReadSeekCloser interface {
	io.ReadSeeker
	io.Closer
}

// Player is an audio player which has one stream.
type Player struct {
	players    *players
	src        ReadSeekCloser
	buf        []byte
	sampleRate int
	pos        int64
	volume     float64
}

// NewPlayer creates a new player with the given stream.
//
// src's format must be linear PCM (16bits little endian, 2 channel stereo)
// without a header (e.g. RIFF header).
// The sample rate must be same as that of the audio context.
//
// This function is concurrent-safe.
func NewPlayer(context *Context, src ReadSeekCloser) (*Player, error) {
	p := &Player{
		players:    context.players,
		src:        src,
		sampleRate: context.sampleRate,
		buf:        []byte{},
		volume:     1,
	}
	// Get the current position of the source.
	pos, err := p.src.Seek(0, 1)
	if err != nil {
		return nil, err
	}
	p.pos = pos
	runtime.SetFinalizer(p, (*Player).Close)
	return p, nil
}

// Close closes the stream. Ths source stream passed by NewPlayer will also be closed.
//
// This function is concurrent-safe.
func (p *Player) Close() error {
	p.players.removePlayer(p)
	runtime.SetFinalizer(p, nil)
	return p.src.Close()
}

func (p *Player) readToBuffer(length int) error {
	bb := make([]byte, length)
	n, err := p.src.Read(bb)
	if 0 < n {
		p.buf = append(p.buf, bb[:n]...)
	}
	return err
}

func (p *Player) bufferToInt16(lengthInBytes int) []int16 {
	r := make([]int16, lengthInBytes/2)
	for i := 0; i < lengthInBytes/2; i++ {
		r[i] = int16(p.buf[2*i]) | (int16(p.buf[2*i+1]) << 8)
		r[i] = int16(float64(r[i]) * p.volume)
	}
	return r
}

func (p *Player) proceed(length int) {
	p.buf = p.buf[length:]
	p.pos += int64(length)
}

func (p *Player) bufferLength() int {
	return len(p.buf)
}

// Play plays the stream.
//
// This function is concurrent-safe.
func (p *Player) Play() error {
	p.players.addPlayer(p)
	return nil
}

// IsPlaying returns boolean indicating whether the player is playing.
//
// This function is concurrent-safe.
func (p *Player) IsPlaying() bool {
	return p.players.hasPlayer(p)
}

// Rewind rewinds the current position to the start.
//
// This function is concurrent-safe.
func (p *Player) Rewind() error {
	return p.Seek(0)
}

// Seek seeks the position with the given offset.
//
// This function is concurrent-safe.
func (p *Player) Seek(offset time.Duration) error {
	o := int64(offset) * bytesPerSample * channelNum * int64(p.sampleRate) / int64(time.Second)
	o &= mask
	return p.players.seekPlayer(p, o)
}

func (p *Player) seek(offset int64) error {
	p.buf = []byte{}
	pos, err := p.src.Seek(offset, 0)
	if err != nil {
		return err
	}
	p.pos = pos
	return nil
}

// Pause pauses the playing.
//
// This function is concurrent-safe.
func (p *Player) Pause() error {
	p.players.removePlayer(p)
	return nil
}

// Current returns the current position.
//
// This function is concurrent-safe.
func (p *Player) Current() time.Duration {
	return p.players.playerCurrent(p, p.sampleRate)
}

// Volume returns the current volume of this player [0-1].
func (p *Player) Volume() float64 {
	return p.volume
}

// SetVolume sets the volume of this player.
// volume must be in between 0 and 1. This function panics otherwise.
func (p *Player) SetVolume(volume float64) {
	// The condition must be true when volume is NaN.
	if !(0 <= volume && volume <= 1) {
		panic("audio: volume must be in between 0 and 1")
	}
	p.volume = volume
}
<commit_msg>audio: Fix a comment<commit_after>// Copyright 2015 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package audio provides audio players. This can be used with or without ebiten package.
//
// The stream format must be 16-bit little endian and 2 channels.
//
// An audio context has a sample rate you can set and all streams you want to play must have the same
// sample rate.
//
// An audio context can generate 'players' (instances of audio.Player),
// and you can play sound by calling Play function of players.
// When multiple players play, mixing is automatically done.
// Note that too many players may cause distortion.
package audio

import (
	"io"
	"runtime"
	"sync"
	"time"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/audio/internal/driver"
)

type players struct {
	players map[*Player]struct{}
	sync.RWMutex
}

const (
	channelNum     = 2
	bytesPerSample = 2

	// TODO: This assumes that channelNum is a power of 2.
	mask = ^(channelNum*bytesPerSample - 1)
)

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func (p *players) Read(b []byte) (int, error) {
	p.Lock()
	defer p.Unlock()

	if len(p.players) == 0 {
		l := len(b)
		l &= mask
		copy(b, make([]byte, l))
		return l, nil
	}
	closed := []*Player{}
	l := len(b)
	for p := range p.players {
		err := p.readToBuffer(l)
		if err == io.EOF {
			closed = append(closed, p)
		} else if err != nil {
			return 0, err
		}
		l = min(p.bufferLength(), l)
	}
	l &= mask
	b16s := [][]int16{}
	for p := range p.players {
		b16s = append(b16s, p.bufferToInt16(l))
	}
	for i := 0; i < l/2; i++ {
		x := 0
		for _, b16 := range b16s {
			x += int(b16[i])
		}
		if x > (1<<15)-1 {
			x = (1 << 15) - 1
		}
		if x < -(1 << 15) {
			x = -(1 << 15)
		}
		b[2*i] = byte(x)
		b[2*i+1] = byte(x >> 8)
	}
	for p := range p.players {
		p.proceed(l)
	}
	for _, pl := range closed {
		delete(p.players, pl)
	}
	return l, nil
}

func (p *players) addPlayer(player *Player) {
	p.Lock()
	defer p.Unlock()
	p.players[player] = struct{}{}
}

func (p *players) removePlayer(player *Player) {
	p.Lock()
	defer p.Unlock()
	delete(p.players, player)
}

func (p *players) hasPlayer(player *Player) bool {
	p.RLock()
	defer p.RUnlock()
	_, ok := p.players[player]
	return ok
}

func (p *players) seekPlayer(player *Player, offset int64) error {
	p.Lock()
	defer p.Unlock()
	return player.seek(offset)
}

func (p *players) playerCurrent(player *Player, sampleRate int) time.Duration {
	p.RLock()
	defer p.RUnlock()
	sample := player.pos / bytesPerSample / channelNum
	return time.Duration(sample) * time.Second / time.Duration(sampleRate)
}

// TODO: Enable to specify the format like Mono8?

// A Context is a current state of audio.
//
// The typical usage with ebiten package is:
//
//    var audioContext *audio.Context
//
//    func update(screen *ebiten.Image) error {
//        // Update updates the audio stream by 1/60 [sec].
//        if err := audioContext.Update(); err != nil {
//            return err
//        }
//        // ...
//    }
//
//    func main() {
//        audioContext, err = audio.NewContext(sampleRate)
//        if err != nil {
//            panic(err)
//        }
//        ebiten.Run(run, update, 320, 240, 2, "Audio test")
//    }
//
// This is 'sync mode' in that game's (logical) time and audio time are synchronized.
// You can also call Update independently from the game loop as 'async mode'.
// In this case, audio goes on even when the game stops e.g. by diactivating the screen.
type Context struct {
	players      *players
	driver       *driver.Player
	sampleRate   int
	frames       int
	writtenBytes int
}

// NewContext creates a new audio context with the given sample rate (e.g. 44100).
func NewContext(sampleRate int) (*Context, error) {
	// TODO: Panic if one context exists.
	c := &Context{
		sampleRate: sampleRate,
	}
	c.players = &players{
		players: map[*Player]struct{}{},
	}
	return c, nil

}

// Update proceeds the inner (logical) time of the context by 1/60 second.
//
// This is expected to be called in the game's updating function (sync mode)
// or an independent goroutine with timers (async mode).
// In sync mode, the game logical time syncs the audio logical time and
// you will find audio stops when the game stops e.g. when the window is deactivated.
// In async mode, the audio never stops even when the game stops.
func (c *Context) Update() error {
	// Initialize c.driver lazily to enable calling NewContext in an 'init' function.
	// Accessing driver functions requires the environment to be already initialized,
	// but if Ebiten is used for a shared library, the timing when init functions are called
	// is unexpectable.
	// e.g. a variable for JVM on Android might not be set.
	if c.driver == nil {
		// TODO: Rename this other than player
		p, err := driver.NewPlayer(c.sampleRate, channelNum, bytesPerSample)
		c.driver = p
		if err != nil {
			return err
		}
	}
	c.frames++
	bytesPerFrame := c.sampleRate * bytesPerSample * channelNum / ebiten.FPS
	l := (c.frames * bytesPerFrame) - c.writtenBytes
	l &= mask
	c.writtenBytes += l
	buf := make([]byte, l)
	n, err := io.ReadFull(c.players, buf)
	if err != nil {
		return err
	}
	if n != len(buf) {
		return c.driver.Close()
	}
	// TODO: Rename this to Enqueue
	err = c.driver.Proceed(buf)
	if err == io.EOF {
		return c.driver.Close()
	}
	if err != nil {
		return err
	}
	return nil
}

// SampleRate returns the sample rate.
// All audio source must have the same sample rate.
//
// This function is concurrent-safe.
func (c *Context) SampleRate() int {
	return c.sampleRate
}

// ReadSeekCloser is an io.ReadSeeker and io.Closer.
type ReadSeekCloser interface {
	io.ReadSeeker
	io.Closer
}

// Player is an audio player which has one stream.
type Player struct {
	players    *players
	src        ReadSeekCloser
	buf        []byte
	sampleRate int
	pos        int64
	volume     float64
}

// NewPlayer creates a new player with the given stream.
//
// src's format must be linear PCM (16bits little endian, 2 channel stereo)
// without a header (e.g. RIFF header).
// The sample rate must be same as that of the audio context.
//
// This function is concurrent-safe.
func NewPlayer(context *Context, src ReadSeekCloser) (*Player, error) {
	p := &Player{
		players:    context.players,
		src:        src,
		sampleRate: context.sampleRate,
		buf:        []byte{},
		volume:     1,
	}
	// Get the current position of the source.
	pos, err := p.src.Seek(0, 1)
	if err != nil {
		return nil, err
	}
	p.pos = pos
	runtime.SetFinalizer(p, (*Player).Close)
	return p, nil
}

// Close closes the stream. Ths source stream passed by NewPlayer will also be closed.
//
// This function is concurrent-safe.
func (p *Player) Close() error {
	p.players.removePlayer(p)
	runtime.SetFinalizer(p, nil)
	return p.src.Close()
}

func (p *Player) readToBuffer(length int) error {
	bb := make([]byte, length)
	n, err := p.src.Read(bb)
	if 0 < n {
		p.buf = append(p.buf, bb[:n]...)
	}
	return err
}

func (p *Player) bufferToInt16(lengthInBytes int) []int16 {
	r := make([]int16, lengthInBytes/2)
	for i := 0; i < lengthInBytes/2; i++ {
		r[i] = int16(p.buf[2*i]) | (int16(p.buf[2*i+1]) << 8)
		r[i] = int16(float64(r[i]) * p.volume)
	}
	return r
}

func (p *Player) proceed(length int) {
	p.buf = p.buf[length:]
	p.pos += int64(length)
}

func (p *Player) bufferLength() int {
	return len(p.buf)
}

// Play plays the stream.
//
// This function is concurrent-safe.
func (p *Player) Play() error {
	p.players.addPlayer(p)
	return nil
}

// IsPlaying returns boolean indicating whether the player is playing.
//
// This function is concurrent-safe.
func (p *Player) IsPlaying() bool {
	return p.players.hasPlayer(p)
}

// Rewind rewinds the current position to the start.
//
// This function is concurrent-safe.
func (p *Player) Rewind() error {
	return p.Seek(0)
}

// Seek seeks the position with the given offset.
//
// This function is concurrent-safe.
func (p *Player) Seek(offset time.Duration) error {
	o := int64(offset) * bytesPerSample * channelNum * int64(p.sampleRate) / int64(time.Second)
	o &= mask
	return p.players.seekPlayer(p, o)
}

func (p *Player) seek(offset int64) error {
	p.buf = []byte{}
	pos, err := p.src.Seek(offset, 0)
	if err != nil {
		return err
	}
	p.pos = pos
	return nil
}

// Pause pauses the playing.
//
// This function is concurrent-safe.
func (p *Player) Pause() error {
	p.players.removePlayer(p)
	return nil
}

// Current returns the current position.
//
// This function is concurrent-safe.
func (p *Player) Current() time.Duration {
	return p.players.playerCurrent(p, p.sampleRate)
}

// Volume returns the current volume of this player [0-1].
func (p *Player) Volume() float64 {
	return p.volume
}

// SetVolume sets the volume of this player.
// volume must be in between 0 and 1. This function panics otherwise.
func (p *Player) SetVolume(volume float64) {
	// The condition must be true when volume is NaN.
	if !(0 <= volume && volume <= 1) {
		panic("audio: volume must be in between 0 and 1")
	}
	p.volume = volume
}
<|endoftext|>


<commit_before>package container

import (
	"os"
	"os/exec"

	"github.com/subutai-io/base/agent/config"
	"github.com/subutai-io/base/agent/log"
)

var (
	contsStatus map[string]int
)

func init() {
	contsStatus = make(map[string]int)
}

func ContainersRestoreState() {
	for _, cont := range GetActiveContainers(false) {
		var start, stop bool

		switch contsStatus[cont.Name] {
		case 100:
		case 5:
			{
				log.Debug("Failed to START sontainer " + cont.Name + " after 5 attempts")
				contsStatus[cont.Name] = 100
			}
		case -5:
			{
				log.Debug("Failed to STOP sontainer " + cont.Name + " after 5 attempts")
				contsStatus[cont.Name] = 100
			}
		case 10:
			{
				log.Debug(".start and .stop files exist on " + cont.Name + " cont ")
				contsStatus[cont.Name] = 100
			}
		default:
			{
				if _, err := os.Stat(config.Agent.LxcPrefix + cont.Name + "/.start"); err == nil {
					start = true
				}
				if _, err := os.Stat(config.Agent.LxcPrefix + cont.Name + "/.stop"); err == nil {
					stop = true
				}
				if start && stop {
					contsStatus[cont.Name] = 10
					break
				}
				switch {
				case start && cont.Status != "RUNNING":
					{
						log.Debug("Trying start " + cont.Name)
						exec.Command("subutai", "start", cont.Name).Run()
						contsStatus[cont.Name]++
					}
				case stop && cont.Status != "STOPPED":
					{
						log.Debug("Trying stop " + cont.Name)
						exec.Command("subutai", "stop", cont.Name).Run()
						contsStatus[cont.Name]--

					}
				default:
					contsStatus[cont.Name] = 0
				}
			}
		}
	}
}
<commit_msg>Typo fix.<commit_after>package container

import (
	"os"
	"os/exec"

	"github.com/subutai-io/base/agent/config"
	"github.com/subutai-io/base/agent/log"
)

var (
	contsStatus map[string]int
)

func init() {
	contsStatus = make(map[string]int)
}

func ContainersRestoreState() {
	for _, cont := range GetActiveContainers(false) {
		var start, stop bool

		switch contsStatus[cont.Name] {
		case 100:
		case 5:
			{
				log.Debug("Failed to START container " + cont.Name + " after 5 attempts")
				contsStatus[cont.Name] = 100
			}
		case -5:
			{
				log.Debug("Failed to STOP container " + cont.Name + " after 5 attempts")
				contsStatus[cont.Name] = 100
			}
		case 10:
			{
				log.Debug(".start and .stop files exist on " + cont.Name + " cont ")
				contsStatus[cont.Name] = 100
			}
		default:
			{
				if _, err := os.Stat(config.Agent.LxcPrefix + cont.Name + "/.start"); err == nil {
					start = true
				}
				if _, err := os.Stat(config.Agent.LxcPrefix + cont.Name + "/.stop"); err == nil {
					stop = true
				}
				if start && stop {
					contsStatus[cont.Name] = 10
					break
				}
				switch {
				case start && cont.Status != "RUNNING":
					{
						log.Debug("Trying start " + cont.Name)
						exec.Command("subutai", "start", cont.Name).Run()
						contsStatus[cont.Name]++
					}
				case stop && cont.Status != "STOPPED":
					{
						log.Debug("Trying stop " + cont.Name)
						exec.Command("subutai", "stop", cont.Name).Run()
						contsStatus[cont.Name]--

					}
				default:
					contsStatus[cont.Name] = 0
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package loginsight

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/cloudfoundry-community/firehose-to-syslog/logging"
)

type Forwarder struct {
	LogInsightReservedFields []string
	url                      *string
	hasJSONLogMsg            bool
	debug                    bool
	channel                  chan *ChannelMessage
	client                   *http.Client
}

//NewForwarder - Creates new instance of LogInsight that implments logging.Logging interface
func NewForwarder(logInsightServer string, logInsightPort int, logInsightReservedFields,
	logInsightAgentID string, logInsightHasJsonLogMsg, debugging bool, concurrentWorkers int,
	maxIdleConns, maxIdleConnsPerHost int, idleConnTimeout int32) logging.Logging {

	url := fmt.Sprintf("https://%s:%d/api/v1/messages/ingest/%s", logInsightServer, logInsightPort, logInsightAgentID)
	logging.LogStd(fmt.Sprintf("Using %s for log insight", url), true)
	theForwarder := &Forwarder{
		LogInsightReservedFields: strings.Split(logInsightReservedFields, ","),
		url:                      &url,
		hasJSONLogMsg:            logInsightHasJsonLogMsg,
		debug:                    debugging,
		channel:                  make(chan *ChannelMessage, 1024),
		client: &http.Client{
			Transport: &http.Transport{
				DisableCompression:  true,
				TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
				MaxIdleConns:        maxIdleConns,
				MaxIdleConnsPerHost: maxIdleConnsPerHost,
				IdleConnTimeout:     time.Duration(idleConnTimeout) * time.Second,
			},
		},
	}
	for i := 0; i < concurrentWorkers; i++ {
		go theForwarder.ConsumeMessages()
	}

	return theForwarder
}

func (f *Forwarder) Connect() bool {
	return true
}

func (f *Forwarder) CreateKey(k string) string {
	if contains(f.LogInsightReservedFields, k) {
		return "cf_" + k
	} else {
		return k
	}
}

func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

func (f *Forwarder) ShipEvents(eventFields map[string]interface{}, msg string) {
	channelMessage := &ChannelMessage{
		eventFields: eventFields,
		msg:         msg,
	}
	f.channel <- channelMessage
}

func (f *Forwarder) ConsumeMessages() {
	for channelMessage := range f.channel {
		messages := Messages{}
		message := Message{
			Text: channelMessage.msg,
		}

		for k, v := range channelMessage.eventFields {
			if k == "timestamp" {
				message.Timestamp = v.(int64)
			} else {
				message.Fields = append(message.Fields, Field{Name: f.CreateKey(k), Content: fmt.Sprint(v)})
			}
		}

		if f.hasJSONLogMsg {

			var obj map[string]interface{}
			msgbytes := []byte(channelMessage.msg)
			err := json.Unmarshal(msgbytes, &obj)
			if err == nil {
				for k, v := range obj {
					message.Fields = append(message.Fields, Field{Name: f.CreateKey(k), Content: fmt.Sprint(v)})
				}
			} else {
				logging.LogError("Error unmarshalling", err)
				return
			}
		}

		messages.Messages = append(messages.Messages, message)
		payload, err := json.Marshal(messages)
		if err == nil {
			f.Post(*f.url, payload)
		} else {
			logging.LogError("Error marshalling", err)
		}
	}
}

func (f *Forwarder) Post(url string, payload []byte) {
	if f.debug {
		logging.LogStd("Post being sent", true)
	}
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	if err != nil {
		logging.LogError("Error building request", err)
		return
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := f.client.Do(req)
	if err != nil {
		logging.LogError("Error Posting data", err)
		return
	}
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	if f.debug {
		logging.LogStd(fmt.Sprintf("Post response code %s with body %s", resp.Status, body), true)
	}
}

type Messages struct {
	Messages []Message `json:"messages"`
}

type Message struct {
	Fields    []Field `json:"fields"`
	Text      string  `json:"text"`
	Timestamp int64   `json:"timestamp"`
}

type Field struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

type ChannelMessage struct {
	eventFields map[string]interface{}
	msg         string
}
<commit_msg>create new http client per request<commit_after>package loginsight

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/cloudfoundry-community/firehose-to-syslog/logging"
)

type Forwarder struct {
	LogInsightReservedFields []string
	url                      *string
	hasJSONLogMsg            bool
	debug                    bool
	channel                  chan *ChannelMessage
	maxIdleConns             int
	maxIdleConnsPerHost      int
	idleConnTimeout          int32
}

//NewForwarder - Creates new instance of LogInsight that implments logging.Logging interface
func NewForwarder(logInsightServer string, logInsightPort int, logInsightReservedFields,
	logInsightAgentID string, logInsightHasJsonLogMsg, debugging bool, concurrentWorkers int,
	maxIdleConns, maxIdleConnsPerHost int, idleConnTimeout int32) logging.Logging {

	url := fmt.Sprintf("https://%s:%d/api/v1/messages/ingest/%s", logInsightServer, logInsightPort, logInsightAgentID)
	logging.LogStd(fmt.Sprintf("Using %s for log insight", url), true)
	theForwarder := &Forwarder{
		LogInsightReservedFields: strings.Split(logInsightReservedFields, ","),
		url:                      &url,
		hasJSONLogMsg:            logInsightHasJsonLogMsg,
		debug:                    debugging,
		channel:                  make(chan *ChannelMessage, 1024),
		maxIdleConns:             maxIdleConns,
		maxIdleConnsPerHost:      maxIdleConnsPerHost,
		idleConnTimeout:          idleConnTimeout,
	}
	for i := 0; i < concurrentWorkers; i++ {
		go theForwarder.ConsumeMessages()
	}

	return theForwarder
}

func (f *Forwarder) Connect() bool {
	return true
}

func (f *Forwarder) CreateKey(k string) string {
	if contains(f.LogInsightReservedFields, k) {
		return "cf_" + k
	} else {
		return k
	}
}

func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

func (f *Forwarder) ShipEvents(eventFields map[string]interface{}, msg string) {
	channelMessage := &ChannelMessage{
		eventFields: eventFields,
		msg:         msg,
	}
	f.channel <- channelMessage
}

func (f *Forwarder) ConsumeMessages() {
	for channelMessage := range f.channel {
		messages := Messages{}
		message := Message{
			Text: channelMessage.msg,
		}

		for k, v := range channelMessage.eventFields {
			if k == "timestamp" {
				message.Timestamp = v.(int64)
			} else {
				message.Fields = append(message.Fields, Field{Name: f.CreateKey(k), Content: fmt.Sprint(v)})
			}
		}

		if f.hasJSONLogMsg {

			var obj map[string]interface{}
			msgbytes := []byte(channelMessage.msg)
			err := json.Unmarshal(msgbytes, &obj)
			if err == nil {
				for k, v := range obj {
					message.Fields = append(message.Fields, Field{Name: f.CreateKey(k), Content: fmt.Sprint(v)})
				}
			} else {
				logging.LogError("Error unmarshalling", err)
				return
			}
		}

		messages.Messages = append(messages.Messages, message)
		payload, err := json.Marshal(messages)
		if err == nil {
			f.Post(*f.url, payload)
		} else {
			logging.LogError("Error marshalling", err)
		}
	}
}

func (f *Forwarder) Post(url string, payload []byte) {
	if f.debug {
		logging.LogStd("Post being sent", true)
	}
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	if err != nil {
		logging.LogError("Error building request", err)
		return
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{
		Transport: &http.Transport{
			DisableCompression:  true,
			TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
			MaxIdleConns:        f.maxIdleConns,
			MaxIdleConnsPerHost: f.maxIdleConnsPerHost,
			IdleConnTimeout:     time.Duration(f.idleConnTimeout) * time.Second,
		},
	}
	resp, err := client.Do(req)
	if err != nil {
		logging.LogError("Error Posting data", err)
		return
	}
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	if f.debug {
		logging.LogStd(fmt.Sprintf("Post response code %s with body %s", resp.Status, body), true)
	}
}

type Messages struct {
	Messages []Message `json:"messages"`
}

type Message struct {
	Fields    []Field `json:"fields"`
	Text      string  `json:"text"`
	Timestamp int64   `json:"timestamp"`
}

type Field struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

type ChannelMessage struct {
	eventFields map[string]interface{}
	msg         string
}
<|endoftext|>


<commit_before>package kafka

import (
	"testing"
	"time"

	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/golib/pool"
	log "github.com/funkygao/log4go"
)

func init() {
	ctx.LoadConfig("/etc/kateway.cf")
	log.AddFilter("stdout", log.INFO, log.NewConsoleLogWriter())
}

func BenchmarkPubPool(b *testing.B) {
	s := NewPubStore(nil, false)
	p := newPubPool(s, []string{"localhost:9092"}, 100)
	for i := 0; i < b.N; i++ {
		c, err := p.Get()
		if err != nil {
			b.Fatal(err)
		}

		c.Recycle()
	}
	s.Stop()
}

type TestResource struct {
	num    int64
	closed bool
}

func (tr *TestResource) Close() {
}

func (this *TestResource) Id() uint64 {
	return 1
}

func PoolFactory() (pool.Resource, error) {
	return &TestResource{1, false}, nil
}

func BenchmarkDumbPool(b *testing.B) {
	p := pool.NewResourcePool("dumbpool", PoolFactory, 100,
		100, 0, time.Hour, 0)
	for i := 0; i < b.N; i++ {
		r, e := p.Get()
		if e != nil {
			b.Fatal(e)
		}

		p.Put(r)
	}

}
<commit_msg>benchmark of the lock primitive<commit_after>package kafka

import (
	"sync"
	"testing"
	"time"

	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/golib/pool"
	log "github.com/funkygao/log4go"
)

func init() {
	ctx.LoadConfig("/etc/kateway.cf")
	log.AddFilter("stdout", log.INFO, log.NewConsoleLogWriter())
}

func BenchmarkPubPool(b *testing.B) {
	s := NewPubStore(nil, false)
	p := newPubPool(s, []string{"localhost:9092"}, 100)
	for i := 0; i < b.N; i++ {
		c, err := p.Get()
		if err != nil {
			b.Fatal(err)
		}

		c.Recycle()
	}
	s.Stop()
}

type TestResource struct {
	num    int64
	closed bool
}

func (tr *TestResource) Close() {
}

func (this *TestResource) Id() uint64 {
	return 1
}

func PoolFactory() (pool.Resource, error) {
	return &TestResource{1, false}, nil
}

func BenchmarkDumbPool(b *testing.B) {
	p := pool.NewResourcePool("dumbpool", PoolFactory, 100,
		100, 0, time.Hour, 0)
	for i := 0; i < b.N; i++ {
		r, e := p.Get()
		if e != nil {
			b.Fatal(e)
		}

		p.Put(r)
	}

}

func BenchmarkRWMutexRLock(b *testing.B) {
	var l sync.RWMutex
	for i := 0; i < b.N; i++ {
		l.RLock()
		l.RUnlock()
	}
}

func BenchmarkRWMutexLock(b *testing.B) {
	var l sync.RWMutex
	for i := 0; i < b.N; i++ {
		l.Lock()
		l.Unlock()
	}
}

func BenchmarkMutex(b *testing.B) {
	var l sync.Mutex
	for i := 0; i < b.N; i++ {
		l.Lock()
		l.Unlock()
	}
}
<|endoftext|>


<commit_before>// Package metalarchives is a library to search for bands on metal archives.
package metalarchives

import (
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"
	"strings"

	"github.com/StalkR/goircbot/lib/metal"
	"github.com/StalkR/goircbot/lib/transport"
)

const baseURL = "http://www.metal-archives.com/search/ajax-band-search/"

// Search finds bands by name.
func Search(name string) ([]metal.Band, error) {
	client, err := transport.Client(baseURL)
	if err != nil {
		return nil, err
	}
	u := url.Values{"query": {name}, "field": {"name"}}
	resp, err := client.Get(fmt.Sprintf("%s?%s", baseURL, u.Encode()))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var result struct {
		Bands [][]string `json:"aaData"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, err
	}
	var results []metal.Band
	for _, r := range result.Bands {
		if len(r) < 3 {
			continue
		}
		results = append(results, metal.Band{
			Name:    strings.TrimSpace(stripTags(r[0])),
			Genre:   r[1],
			Country: r[2],
		})
	}
	return results, nil
}

var htmlTagsRE = regexp.MustCompile(`<[^>]*>`)

func stripTags(s string) string {
	return htmlTagsRE.ReplaceAllString(s, "")
}
<commit_msg>lib/metal/metalarchives: default Go user-agent is 403, change<commit_after>// Package metalarchives is a library to search for bands on metal archives.
package metalarchives

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"regexp"
	"strings"

	"github.com/StalkR/goircbot/lib/metal"
	"github.com/StalkR/goircbot/lib/transport"
)

const baseURL = "https://www.metal-archives.com/search/ajax-band-search/"

// Search finds bands by name.
func Search(name string) ([]metal.Band, error) {
	client, err := transport.Client(baseURL)
	if err != nil {
		return nil, err
	}
	u := url.Values{"query": {name}, "field": {"name"}}
	uri := fmt.Sprintf("%s?%s", baseURL, u.Encode())
	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("User-Agent", "Go IRC Bot (github.com/StalkR/goircbot)")
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var result struct {
		Bands [][]string `json:"aaData"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, err
	}
	var results []metal.Band
	for _, r := range result.Bands {
		if len(r) < 3 {
			continue
		}
		results = append(results, metal.Band{
			Name:    strings.TrimSpace(stripTags(r[0])),
			Genre:   r[1],
			Country: r[2],
		})
	}
	return results, nil
}

var htmlTagsRE = regexp.MustCompile(`<[^>]*>`)

func stripTags(s string) string {
	return htmlTagsRE.ReplaceAllString(s, "")
}
<|endoftext|>