<commit_before>package skydns

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"path"
	"runtime"

	"github.com/k8sp/auto-install/bootstrapper/cmd"
	"github.com/k8sp/auto-install/config"
	"github.com/topicai/candy"
)

func serviceUnit(dist string, tmpl string, c *config.Cluster) string {
	t := template.New("")

	if len(tmpl) > 0 {
		t = template.Must(t.Parse(tmpl))
	} else {
		if dist == "centos" {
			t = template.Must(t.Parse(systemdDefaultTemplate))
		} else if dist == "ubuntu" {
			t = template.Must(t.Parse(upstartDefaultTemplate))
		}
	}

	var buf bytes.Buffer
	candy.Must(t.Execute(&buf, c))
	return buf.String()
}

const (
	systemdDefaultTemplate = `
[Unit]
Description=SkyDNS
After=network.target
Requires=network.target

[Service]
Type=simple
ExecStart=/usr/bin/skydns -machines={{.GetEtcdMachines}} -addr=0.0.0.0:53 -nameservers=8.8.8.8:53,8.8.4.4:53 -domain={{.DomainName}}.

[Install]
WantedBy=multi-user.target
`
	upstartDefaultTemplate = `
description "SkyDNS service"

start on runlevel [2345]
stop on runlevel [^2345]

respawn
respawn limit 20 3

script
echo $$ > /var/run/skydns.pid
exec /usr/bin/skydns -machines={{.GetEtcdMachines}} -addr=0.0.0.0:53 -nameservers=8.8.8.8:53,8.8.4.4:53 -domain={{.DomainName}}.
end script

pre-start script
end script

pre-stop script
    rm /var/run/skydns.pid
end script
`
)

func build(c *config.Cluster) {
	installGo("")

	cmd.RunWithEnv(map[string]string{"GOPATH": "/tmp", "https_proxy": c.HTTPSProxy, "http_proxy": c.HTTPProxy},
		"go", "get", "-u", "github.com/skynetservices/skydns")

	cmd.Run("/bin/cp", "-f", "/tmp/bin/skydns", "/usr/bin/")
}

func installGo(version string) {
	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
		log.Panicf("InstallGo must work with linux/amd64, but not %s/%s", runtime.GOOS, runtime.GOARCH)
	}

	if len(version) == 0 {
		version = "1.6.3"
	}
	cmd.Run("curl", "-s", "-o", "/tmp/go.tar.gz",
		fmt.Sprintf("https://storage.googleapis.com/golang/go%s.linux-amd64.tar.gz", version))

	cmd.Run("tar", "-C", "/usr/local", "-xzf", "/tmp/go.tar.gz")
	cmd.Run("ln", "-sf", "/usr/local/go/bin/go", "/usr/local/bin/go")
}

// Download SkyDNS bianary file from github.
// requires that curl have been installed.
func getSkyDNSFile() {
	skydnsfile := path.Join("/usr/bin", "skydns")
	cmd.Run("curl", "-o", skydnsfile, "https://raw.githubusercontent.com/pineking/skydns-binary/master/skydns")
	cmd.Run("chmod", "755", skydnsfile)
}

// Install downloads and builds SkyDNS into /usr/bin/skydns.  It then
// creates a systemd service unit for CentOS.
func Install(tmpl string, c *config.Cluster) {
	build(c)

	switch dist := config.LinuxDistro(); dist {
	case "centos":
		candy.WithCreated("/etc/systemd/system/skydns.service", func(w io.Writer) {
			_, e := fmt.Fprint(w, serviceUnit(dist, tmpl, c))
			candy.Must(e)
		})

		cmd.Run("systemctl", "enable", "skydns")
		// Due to a bug of CentOS, systemctl cannot run in
		// Docker containers.  Discussions and the explanation
		// of this bug is at
		// https://github.com/docker/docker/issues/7459.  The
		// current fix
		// https://github.com/docker-library/docs/tree/master/centos#systemd-integration
		// is too complex that I don't want to implement.  So
		// I call Try here.
		cmd.Try("systemctl", "restart", "skydns")
	case "ubuntu":
		candy.WithCreated("/etc/init/skydns.conf", func(w io.Writer) {
			_, e := fmt.Fprint(w, serviceUnit(dist, tmpl, c))
			candy.Must(e)
		})

		cmd.Run("service", "skydns", "restart")
	default:
		log.Panicf("Unsupported OS: %s", dist)
	}
}
<commit_msg>Use absolute go binary path<commit_after>package skydns

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"path"
	"runtime"

	"github.com/k8sp/auto-install/bootstrapper/cmd"
	"github.com/k8sp/auto-install/config"
	"github.com/topicai/candy"
)

func serviceUnit(dist string, tmpl string, c *config.Cluster) string {
	t := template.New("")

	if len(tmpl) > 0 {
		t = template.Must(t.Parse(tmpl))
	} else {
		if dist == "centos" {
			t = template.Must(t.Parse(systemdDefaultTemplate))
		} else if dist == "ubuntu" {
			t = template.Must(t.Parse(upstartDefaultTemplate))
		}
	}

	var buf bytes.Buffer
	candy.Must(t.Execute(&buf, c))
	return buf.String()
}

const (
	systemdDefaultTemplate = `
[Unit]
Description=SkyDNS
After=network.target
Requires=network.target

[Service]
Type=simple
ExecStart=/usr/bin/skydns -machines={{.GetEtcdMachines}} -addr=0.0.0.0:53 -nameservers=8.8.8.8:53,8.8.4.4:53 -domain={{.DomainName}}.

[Install]
WantedBy=multi-user.target
`
	upstartDefaultTemplate = `
description "SkyDNS service"

start on runlevel [2345]
stop on runlevel [^2345]

respawn
respawn limit 20 3

script
echo $$ > /var/run/skydns.pid
exec /usr/bin/skydns -machines={{.GetEtcdMachines}} -addr=0.0.0.0:53 -nameservers=8.8.8.8:53,8.8.4.4:53 -domain={{.DomainName}}.
end script

pre-start script
end script

pre-stop script
    rm /var/run/skydns.pid
end script
`
)

func build(c *config.Cluster) {
	installGo("")

	cmd.RunWithEnv(map[string]string{"GOPATH": "/tmp", "https_proxy": c.HTTPSProxy, "http_proxy": c.HTTPProxy},
		"/usr/local/go/bin/go", "get", "-u", "github.com/skynetservices/skydns")

	cmd.Run("/bin/cp", "-f", "/tmp/bin/skydns", "/usr/bin/")
}

func installGo(version string) {
	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
		log.Panicf("InstallGo must work with linux/amd64, but not %s/%s", runtime.GOOS, runtime.GOARCH)
	}

	if len(version) == 0 {
		version = "1.6.3"
	}
	cmd.Run("curl", "-s", "-o", "/tmp/go.tar.gz",
		fmt.Sprintf("https://storage.googleapis.com/golang/go%s.linux-amd64.tar.gz", version))

	cmd.Run("tar", "-C", "/usr/local", "-xzf", "/tmp/go.tar.gz")
}

// Download SkyDNS bianary file from github.
// requires that curl have been installed.
func getSkyDNSFile() {
	skydnsfile := path.Join("/usr/bin", "skydns")
	cmd.Run("curl", "-o", skydnsfile, "https://raw.githubusercontent.com/pineking/skydns-binary/master/skydns")
	cmd.Run("chmod", "755", skydnsfile)
}

// Install downloads and builds SkyDNS into /usr/bin/skydns.  It then
// creates a systemd service unit for CentOS.
func Install(tmpl string, c *config.Cluster) {
	build(c)

	switch dist := config.LinuxDistro(); dist {
	case "centos":
		candy.WithCreated("/etc/systemd/system/skydns.service", func(w io.Writer) {
			_, e := fmt.Fprint(w, serviceUnit(dist, tmpl, c))
			candy.Must(e)
		})

		cmd.Run("systemctl", "enable", "skydns")
		// Due to a bug of CentOS, systemctl cannot run in
		// Docker containers.  Discussions and the explanation
		// of this bug is at
		// https://github.com/docker/docker/issues/7459.  The
		// current fix
		// https://github.com/docker-library/docs/tree/master/centos#systemd-integration
		// is too complex that I don't want to implement.  So
		// I call Try here.
		cmd.Try("systemctl", "restart", "skydns")
	case "ubuntu":
		candy.WithCreated("/etc/init/skydns.conf", func(w io.Writer) {
			_, e := fmt.Fprint(w, serviceUnit(dist, tmpl, c))
			candy.Must(e)
		})

		cmd.Run("service", "skydns", "restart")
	default:
		log.Panicf("Unsupported OS: %s", dist)
	}
}
<|endoftext|>


<commit_before>package comments

import (
	"log"
	"os"

	"github.com/google/go-github/github"
)

var (
	pendingFeedbackLabel = "pending-feedback"

	HandlerPendingFeedbackLabel = func(client *github.Client, event github.IssueCommentEvent) error {
		// if the comment is from the issue author & issue has the "pending-feedback", remove the label

		if os.Getenv("AUTO_REPLY_DEBUG") == "true" {
			log.Println("[pending_feedback_label]: received event:", event)
		}

		if senderAndCreatorEqual(event) && hasLabel(event.Issue.Labels, pendingFeedbackLabel) {
			owner, name, number := *event.Repo.Owner.Login, *event.Repo.Name, *event.Issue.Number
			_, err := client.Issues.RemoveLabelForIssue(owner, name, number, pendingFeedbackLabel)
			if err != nil {
				log.Printf("[pending_feedback_label]: error removing label (%s/%s#%d): %v", owner, name, number, err)
				return err
			}
			return nil
		}
		return nil
	}
)

func senderAndCreatorEqual(event github.IssueCommentEvent) bool {
	return event.Sender != nil && even.Issue != nil && event.Issue.User != nil && *event.Sender.ID == *event.Issue.User.ID
}

func hasLabel(labels []github.Label, desiredLabel string) bool {
	for _, label := range labels {
		if *label.Name == desiredLabel {
			return true
		}
	}
	return false
}
<commit_msg>Fix misspelling.<commit_after>package comments

import (
	"log"
	"os"

	"github.com/google/go-github/github"
)

var (
	pendingFeedbackLabel = "pending-feedback"

	HandlerPendingFeedbackLabel = func(client *github.Client, event github.IssueCommentEvent) error {
		// if the comment is from the issue author & issue has the "pending-feedback", remove the label

		if os.Getenv("AUTO_REPLY_DEBUG") == "true" {
			log.Println("[pending_feedback_label]: received event:", event)
		}

		if senderAndCreatorEqual(event) && hasLabel(event.Issue.Labels, pendingFeedbackLabel) {
			owner, name, number := *event.Repo.Owner.Login, *event.Repo.Name, *event.Issue.Number
			_, err := client.Issues.RemoveLabelForIssue(owner, name, number, pendingFeedbackLabel)
			if err != nil {
				log.Printf("[pending_feedback_label]: error removing label (%s/%s#%d): %v", owner, name, number, err)
				return err
			}
			return nil
		}
		return nil
	}
)

func senderAndCreatorEqual(event github.IssueCommentEvent) bool {
	return event.Sender != nil && event.Issue != nil && event.Issue.User != nil && *event.Sender.ID == *event.Issue.User.ID
}

func hasLabel(labels []github.Label, desiredLabel string) bool {
	for _, label := range labels {
		if *label.Name == desiredLabel {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package whisper

import (
	"encoding/binary"
	"io"
	"os"
	"time"
)

type Metadata struct {
	AggregationMethod uint32
	MaxRetention      uint32
	XFilesFactor      float32
	ArchiveCount      uint32
}

type ArchiveInfo struct {
	Offset          uint32
	SecondsPerPoint uint32
	Points          uint32
}

func (a ArchiveInfo) Retention() uint32 {
	return a.SecondsPerPoint * a.Points
}

func (a ArchiveInfo) Size() uint32 {
	return a.Points * pointSize
}

func (a ArchiveInfo) End() uint32 {
	return a.Offset + a.Size()
}

type Header struct {
	Metadata Metadata
	Archives []ArchiveInfo
}

type Archive []Point

type Point struct {
	Timestamp uint32
	Value     float64
}

type Whisper struct {
	Header Header
	file   *os.File
}

var pointSize, metadataSize, archiveSize uint32

// Aggregation type using averaging
const AGGREGATION_AVERAGE = 1

// Aggregation type using sum
const AGGREGATION_SUM = 2

// Aggregation type using the last value
const AGGREGATION_LAST = 3

// Aggregation type using the maximum value
const AGGREGATION_MAX = 4

// Aggregation type using the minimum value
const AGGREGATION_MIN = 5

func init() {
	pointSize = uint32(binary.Size(Point{}))
	metadataSize = uint32(binary.Size(Metadata{}))
	archiveSize = uint32(binary.Size(Archive{}))
}

// Read the header of a whisper database
func ReadHeader(buf io.ReadSeeker) (header Header, err error) {
	currentPos, err := buf.Seek(0, 1)
	if err != nil {
		return
	}
	defer func() {
		// Try to return to the original position when we exit
		_, e := buf.Seek(currentPos, 0)
		if e != nil {
			err = e
		}
		return
	}()

	// Start at the beginning of the file
	_, err = buf.Seek(0, 0)
	if err != nil {
		return
	}

	// Read metadata
	var metadata Metadata
	err = binary.Read(buf, binary.BigEndian, metadata)
	if err != nil {
		return
	}
	header.Metadata = metadata

	// Read archive info
	archives := make([]ArchiveInfo, metadata.ArchiveCount)
	for i := uint32(0); i < metadata.ArchiveCount; i++ {
		err = binary.Read(buf, binary.BigEndian, archives[i])
		if err != nil {
			return
		}
	}
	header.Archives = archives

	return
}

// Create a new whisper database at a given file path
func Create(path string, archives []ArchiveInfo, xFilesFactor float32, aggregationMethod uint32, sparse bool) (err error) {
	file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)

	oldest := uint32(0)
	for _, archive := range archives {
		age := archive.SecondsPerPoint * archive.Points
		if age > oldest {
			oldest = age
		}
	}

	metadata := Metadata{
		AggregationMethod: aggregationMethod,
		XFilesFactor:      xFilesFactor,
		ArchiveCount:      uint32(len(archives)),
		MaxRetention:      oldest,
	}
	err = binary.Write(file, binary.BigEndian, metadata)
	if err != nil {
		return
	}

	headerSize := metadataSize + (archiveSize * uint32(len(archives)))
	archiveOffsetPointer := headerSize

	for _, archive := range archives {
		archive.Offset = archiveOffsetPointer
		err = binary.Write(file, binary.BigEndian, archive)
		if err != nil {
			return
		}
		archiveOffsetPointer += archive.Points * pointSize
	}

	if sparse {
		file.Seek(int64(archiveOffsetPointer-headerSize-1), 0)
		file.Write([]byte{0})
	} else {
		remaining := archiveOffsetPointer - headerSize
		chunkSize := uint32(16384)
		buf := make([]byte, chunkSize)
		for remaining > chunkSize {
			file.Write(buf)
			remaining -= chunkSize
		}
		file.Write(buf[:remaining])
	}

	return
}

func Open(path string) (whisper Whisper, err error) {
	file, err := os.OpenFile(path, os.O_RDWR, 0666)
	if err != nil {
		return
	}

	header, err := ReadHeader(file)
	if err != nil {
		return
	}
	whisper = Whisper{Header: header, file: file}
	return
}

func (w Whisper) Update(point Point) (err error) {
	now := uint32(time.Now().Unix())
	diff := now - point.Timestamp
	if !((diff < w.Header.Metadata.MaxRetention) && diff >= 0) {
		// TODO: Return an error
		return
	}

	// Find the higher-precision archive that covers the timestamp
	var lowerArchives []ArchiveInfo
	var currentArchive ArchiveInfo
	for i, currentArchive := range w.Header.Archives {
		if currentArchive.Retention() < diff {
			continue
		}
		lowerArchives = w.Header.Archives[i+1:]
	}

	point.Timestamp = point.Timestamp - (point.Timestamp % currentArchive.SecondsPerPoint)
	basePoint, err := w.readPoint(currentArchive.Offset)
	if err != nil {
		return
	}

	if basePoint.Timestamp == 0 {
		// This file's first update
		err = w.writePoint(currentArchive.Offset, point)
		if err != nil {
			return
		}
	} else {
		myOffset := pointOffset(currentArchive, point.Timestamp, basePoint.Timestamp)
		err = w.writePoint(myOffset, point)
		if err != nil {
			return
		}
	}

	higherArchive := currentArchive
	var lowerArchive ArchiveInfo
	for _, lowerArchive = range lowerArchives {
		result, e := w.propagate(point.Timestamp, higherArchive, lowerArchive)
		if !result {
			break
		}
		if e != nil {
			err = e
			return
		}
		higherArchive = lowerArchive
	}

	return
}

func (w Whisper) propagate(timestamp uint32, higher ArchiveInfo, lower ArchiveInfo) (result bool, err error) {
	lowerIntervalStart := timestamp - (timestamp % lower.SecondsPerPoint)

	basePoint, err := w.readPoint(higher.Offset)
	if err != nil {
		return
	}

	var higherFirstOffset uint32
	if basePoint.Timestamp == 0 {
		higherFirstOffset = higher.Offset
	} else {
		higherFirstOffset = pointOffset(higher, lowerIntervalStart, basePoint.Timestamp)
	}

	numHigherPoints := lower.SecondsPerPoint - higher.SecondsPerPoint
	higherSize := numHigherPoints * pointSize
	relativeFirstOffset := higherFirstOffset - higher.Offset
	relativeLastOffset := (relativeFirstOffset + higherSize) % higher.Size()
	higherLastOffset := relativeLastOffset + higher.Offset

	var points []Point
	if higherFirstOffset < higherLastOffset {
		// The selection is in the middle of the archive. eg: --####---
		points = make([]Point, (higherLastOffset-higherFirstOffset)/pointSize)
		err = w.readPoints(higherFirstOffset, points)
		if err != nil {
			return
		}
	} else {
		// The selection wraps over the end of the archive. eg: ##----###
		numEndPoints := (higher.End() - higherFirstOffset) / pointSize
		numBeginPoints := (higherLastOffset - higher.Offset) / pointSize
		points = make([]Point, numBeginPoints+numEndPoints)

		err = w.readPoints(higherFirstOffset, points[:numEndPoints])
		if err != nil {
			return
		}
		err = w.readPoints(higher.Offset, points[numEndPoints:])
		if err != nil {
			return
		}
	}

	neighborPoints := make([]Point, len(points))

	currentInterval := lowerIntervalStart
	for i := 0; i < len(points); i += 2 {
		if points[i].Timestamp == currentInterval {
			neighborPoints[i/2] = points[i+1]
		}
		currentInterval += higher.SecondsPerPoint
	}

	return
}

// Read a single point from an offset in the database
func (w Whisper) readPoint(offset uint32) (point Point, err error) {
	_, err = w.file.Seek(int64(offset), 0)
	if err != nil {
		return
	}
	err = binary.Read(w.file, binary.BigEndian, point)
	return
}

// Read a slice of points from an offset in the database
func (w Whisper) readPoints(offset uint32, points []Point) (err error) {
	w.file.Seek(int64(offset), 0)
	err = binary.Read(w.file, binary.BigEndian, points)
	return
}

// Write a point to an offset in the database
func (w Whisper) writePoint(offset uint32, point Point) (err error) {
	w.file.Seek(int64(offset), 0)
	err = binary.Write(w.file, binary.BigEndian, point)
	return
}

func pointOffset(archive ArchiveInfo, timestamp uint32, baseTimestamp uint32) uint32 {
	timeDistance := timestamp - baseTimestamp
	pointDistance := timeDistance / archive.SecondsPerPoint
	byteDistance := pointDistance * pointSize
	return archive.Offset + (byteDistance % archive.Size())
}

func aggregate(aggregationMethod int, points []Point) (point Point, err error) {
	switch aggregationMethod {
	case AGGREGATION_AVERAGE:
		for _, p := range points {
			point.Value += p.Value
		}
		point.Value /= float64(len(points))
	case AGGREGATION_SUM:
		for _, p := range points {
			point.Value += p.Value
		}
	case AGGREGATION_LAST:
		point.Value = points[len(points)-1].Value
	case AGGREGATION_MAX:
		point.Value = points[0].Value
		for _, p := range points {
			if p.Value > point.Value {
				point.Value = p.Value
			}
		}
	case AGGREGATION_MIN:
		point.Value = points[0].Value
		for _, p := range points {
			if p.Value < point.Value {
				point.Value = p.Value
			}
		}
	default:
		//TODO: Set err
	}
	return
}
<commit_msg>Simplified pointOffset<commit_after>package whisper

import (
	"encoding/binary"
	"io"
	"os"
	"time"
)

type Metadata struct {
	AggregationMethod uint32
	MaxRetention      uint32
	XFilesFactor      float32
	ArchiveCount      uint32
}

type ArchiveInfo struct {
	Offset          uint32
	SecondsPerPoint uint32
	Points          uint32
}

func (a ArchiveInfo) Retention() uint32 {
	return a.SecondsPerPoint * a.Points
}

func (a ArchiveInfo) Size() uint32 {
	return a.Points * pointSize
}

func (a ArchiveInfo) End() uint32 {
	return a.Offset + a.Size()
}

type Header struct {
	Metadata Metadata
	Archives []ArchiveInfo
}

type Archive []Point

type Point struct {
	Timestamp uint32
	Value     float64
}

type Whisper struct {
	Header Header
	file   *os.File
}

var pointSize, metadataSize, archiveSize uint32

// Aggregation type using averaging
const AGGREGATION_AVERAGE = 1

// Aggregation type using sum
const AGGREGATION_SUM = 2

// Aggregation type using the last value
const AGGREGATION_LAST = 3

// Aggregation type using the maximum value
const AGGREGATION_MAX = 4

// Aggregation type using the minimum value
const AGGREGATION_MIN = 5

func init() {
	pointSize = uint32(binary.Size(Point{}))
	metadataSize = uint32(binary.Size(Metadata{}))
	archiveSize = uint32(binary.Size(Archive{}))
}

// Read the header of a whisper database
func ReadHeader(buf io.ReadSeeker) (header Header, err error) {
	currentPos, err := buf.Seek(0, 1)
	if err != nil {
		return
	}
	defer func() {
		// Try to return to the original position when we exit
		_, e := buf.Seek(currentPos, 0)
		if e != nil {
			err = e
		}
		return
	}()

	// Start at the beginning of the file
	_, err = buf.Seek(0, 0)
	if err != nil {
		return
	}

	// Read metadata
	var metadata Metadata
	err = binary.Read(buf, binary.BigEndian, metadata)
	if err != nil {
		return
	}
	header.Metadata = metadata

	// Read archive info
	archives := make([]ArchiveInfo, metadata.ArchiveCount)
	for i := uint32(0); i < metadata.ArchiveCount; i++ {
		err = binary.Read(buf, binary.BigEndian, archives[i])
		if err != nil {
			return
		}
	}
	header.Archives = archives

	return
}

// Create a new whisper database at a given file path
func Create(path string, archives []ArchiveInfo, xFilesFactor float32, aggregationMethod uint32, sparse bool) (err error) {
	file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)

	oldest := uint32(0)
	for _, archive := range archives {
		age := archive.SecondsPerPoint * archive.Points
		if age > oldest {
			oldest = age
		}
	}

	metadata := Metadata{
		AggregationMethod: aggregationMethod,
		XFilesFactor:      xFilesFactor,
		ArchiveCount:      uint32(len(archives)),
		MaxRetention:      oldest,
	}
	err = binary.Write(file, binary.BigEndian, metadata)
	if err != nil {
		return
	}

	headerSize := metadataSize + (archiveSize * uint32(len(archives)))
	archiveOffsetPointer := headerSize

	for _, archive := range archives {
		archive.Offset = archiveOffsetPointer
		err = binary.Write(file, binary.BigEndian, archive)
		if err != nil {
			return
		}
		archiveOffsetPointer += archive.Points * pointSize
	}

	if sparse {
		file.Seek(int64(archiveOffsetPointer-headerSize-1), 0)
		file.Write([]byte{0})
	} else {
		remaining := archiveOffsetPointer - headerSize
		chunkSize := uint32(16384)
		buf := make([]byte, chunkSize)
		for remaining > chunkSize {
			file.Write(buf)
			remaining -= chunkSize
		}
		file.Write(buf[:remaining])
	}

	return
}

func Open(path string) (whisper Whisper, err error) {
	file, err := os.OpenFile(path, os.O_RDWR, 0666)
	if err != nil {
		return
	}

	header, err := ReadHeader(file)
	if err != nil {
		return
	}
	whisper = Whisper{Header: header, file: file}
	return
}

func (w Whisper) Update(point Point) (err error) {
	now := uint32(time.Now().Unix())
	diff := now - point.Timestamp
	if !((diff < w.Header.Metadata.MaxRetention) && diff >= 0) {
		// TODO: Return an error
		return
	}

	// Find the higher-precision archive that covers the timestamp
	var lowerArchives []ArchiveInfo
	var currentArchive ArchiveInfo
	for i, currentArchive := range w.Header.Archives {
		if currentArchive.Retention() < diff {
			continue
		}
		lowerArchives = w.Header.Archives[i+1:]
	}

	// Normalize the point's timestamp to the current archive's precision
	point.Timestamp = point.Timestamp - (point.Timestamp % currentArchive.SecondsPerPoint)

	// Write the point
	offset, err := w.pointOffset(currentArchive, point.Timestamp)
	if err != nil {
		return
	}
	err = w.writePoint(offset, point)
	if err != nil {
		return
	}

	// Propagate data down to all the lower resolution archives
	higherArchive := currentArchive
	for _, lowerArchive := range lowerArchives {
		result, e := w.propagate(point.Timestamp, higherArchive, lowerArchive)
		if !result {
			break
		}
		if e != nil {
			err = e
			return
		}
		higherArchive = lowerArchive
	}

	return
}

func (w Whisper) propagate(timestamp uint32, higher ArchiveInfo, lower ArchiveInfo) (result bool, err error) {
	lowerIntervalStart := timestamp - (timestamp % lower.SecondsPerPoint)
	higherFirstOffset, err := w.pointOffset(higher, lowerIntervalStart)
	if err != nil {
		return
	}

	numHigherPoints := lower.SecondsPerPoint - higher.SecondsPerPoint
	higherSize := numHigherPoints * pointSize
	relativeFirstOffset := higherFirstOffset - higher.Offset
	relativeLastOffset := (relativeFirstOffset + higherSize) % higher.Size()
	higherLastOffset := relativeLastOffset + higher.Offset

	var points []Point
	if higherFirstOffset < higherLastOffset {
		// The selection is in the middle of the archive. eg: --####---
		points = make([]Point, (higherLastOffset-higherFirstOffset)/pointSize)
		err = w.readPoints(higherFirstOffset, points)
		if err != nil {
			return
		}
	} else {
		// The selection wraps over the end of the archive. eg: ##----###
		numEndPoints := (higher.End() - higherFirstOffset) / pointSize
		numBeginPoints := (higherLastOffset - higher.Offset) / pointSize
		points = make([]Point, numBeginPoints+numEndPoints)

		err = w.readPoints(higherFirstOffset, points[:numEndPoints])
		if err != nil {
			return
		}
		err = w.readPoints(higher.Offset, points[numEndPoints:])
		if err != nil {
			return
		}
	}

	neighborPoints := make([]Point, len(points))

	currentInterval := lowerIntervalStart
	for i := 0; i < len(points); i += 2 {
		if points[i].Timestamp == currentInterval {
			neighborPoints[i/2] = points[i+1]
		}
		currentInterval += higher.SecondsPerPoint
	}

	return
}

// Read a single point from an offset in the database
func (w Whisper) readPoint(offset uint32) (point Point, err error) {
	_, err = w.file.Seek(int64(offset), 0)
	if err != nil {
		return
	}
	err = binary.Read(w.file, binary.BigEndian, point)
	return
}

// Read a slice of points from an offset in the database
func (w Whisper) readPoints(offset uint32, points []Point) (err error) {
	w.file.Seek(int64(offset), 0)
	err = binary.Read(w.file, binary.BigEndian, points)
	return
}

// Write a point to an offset in the database
func (w Whisper) writePoint(offset uint32, point Point) (err error) {
	w.file.Seek(int64(offset), 0)
	err = binary.Write(w.file, binary.BigEndian, point)
	return
}

// Get the offset of a timestamp within an archive
func (w Whisper) pointOffset(archive ArchiveInfo, timestamp uint32) (offset uint32, err error) {
	basePoint, err := w.readPoint(0)
	if err != nil {
		return
	}
	if basePoint.Timestamp == 0 {
		// The archive has never been written, this will be the new base point
		offset = archive.Offset
	} else {
		timeDistance := timestamp - basePoint.Timestamp
		pointDistance := timeDistance / archive.SecondsPerPoint
		byteDistance := pointDistance * pointSize
		offset = archive.Offset + (byteDistance % archive.Size())
	}
	return
}

func aggregate(aggregationMethod int, points []Point) (point Point, err error) {
	switch aggregationMethod {
	case AGGREGATION_AVERAGE:
		for _, p := range points {
			point.Value += p.Value
		}
		point.Value /= float64(len(points))
	case AGGREGATION_SUM:
		for _, p := range points {
			point.Value += p.Value
		}
	case AGGREGATION_LAST:
		point.Value = points[len(points)-1].Value
	case AGGREGATION_MAX:
		point.Value = points[0].Value
		for _, p := range points {
			if p.Value > point.Value {
				point.Value = p.Value
			}
		}
	case AGGREGATION_MIN:
		point.Value = points[0].Value
		for _, p := range points {
			if p.Value < point.Value {
				point.Value = p.Value
			}
		}
	default:
		//TODO: Set err
	}
	return
}
<|endoftext|>


<commit_before>package upload

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/meatballhat/artifacts/path"
	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/s3"
)

type uploader struct {
	BucketName   string
	Paths        *path.PathSet
	TargetPath   string
	CacheControl string
}

// Upload does the deed!
func Upload(opts *Options) {
	newUploader(opts).Upload()
}

func newUploader(opts *Options) *uploader {
	u := &uploader{
		BucketName: opts.BucketName,
		TargetPath: opts.TargetPath,
		Paths:      path.NewPathSet(),
	}

	if opts.Private {
		opts.CacheControl = "private"
	} else if opts.CacheControl == "" {
		opts.CacheControl = "public, max-age=315360000"
	}

	u.CacheControl = opts.CacheControl

	for _, s := range strings.Split(opts.Paths, ";") {
		trimmed := strings.TrimSpace(s)
		if len(trimmed) > 0 {
			parts := strings.SplitN(trimmed, ":", 2)
			if len(parts) < 2 {
				parts = append(parts, "")
			}
			u.Paths.Add(path.NewPath(opts.WorkingDir, parts[0], parts[1]))
		}
	}

	return u
}

func (u *uploader) Upload() error {
	auth, err := aws.GetAuth("", "")
	if err != nil {
		return err
	}

	conn := s3.New(auth, aws.USEast)
	bucket := conn.Bucket(u.BucketName)

	if bucket == nil {
		return fmt.Errorf("failed to get bucket")
	}

	for artifact := range u.files() {
		u.uploadFile(bucket, artifact)
	}

	return nil
}

func (u *uploader) files() chan *artifact {
	artifacts := make(chan *artifact)

	go func() {
		for _, path := range u.Paths.All() {
			to, from, root := path.To, path.From, path.Root
			if path.IsDir() {
				root = filepath.Join(root, from)
				if strings.HasSuffix(root, "/") {
					root = root + "/"
				}
			}

			filepath.Walk(path.Fullpath(), func(f string, info os.FileInfo, err error) error {
				if info != nil && info.IsDir() {
					return nil
				}

				relPath := strings.Replace(strings.Replace(f, root, "", -1), root+"/", "", -1)
				destination := relPath
				if len(to) > 0 {
					if path.IsDir() {
						destination = filepath.Join(to, relPath)
					} else {
						destination = to
					}
				}

				artifacts <- &artifact{Source: f, Destination: destination}
				return nil
			})

		}
		close(artifacts)
	}()

	return artifacts
}

func (u *uploader) uploadFile(b *s3.Bucket, a *artifact) error {
	retries := 0

	for {
		err := u.rawUpload(b, a)
		if err != nil {
			if retries < 2 {
				retries += 1
				continue
			} else {
				return err
			}
		}
		return nil
	}
}

func (u *uploader) rawUpload(b *s3.Bucket, a *artifact) error {
	destination := strings.TrimLeft(filepath.Join(u.TargetPath, a.Destination), "/")

	reader, err := a.Reader()
	if err != nil {
		return err
	}

	return b.PutReaderHeader(destination, reader, a.Size(),
		map[string][]string{
			"Content-Type":  []string{a.ContentType()},
			"Cache-Control": []string{u.CacheControl},
		}, s3.Private)
}
<commit_msg>Showing a smidge of output during upload<commit_after>package upload

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/meatballhat/artifacts/path"
	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/s3"
)

type uploader struct {
	BucketName   string
	Paths        *path.PathSet
	TargetPath   string
	CacheControl string
}

// Upload does the deed!
func Upload(opts *Options) {
	newUploader(opts).Upload()
}

func newUploader(opts *Options) *uploader {
	u := &uploader{
		BucketName: opts.BucketName,
		TargetPath: opts.TargetPath,
		Paths:      path.NewPathSet(),
	}

	if opts.Private {
		opts.CacheControl = "private"
	} else if opts.CacheControl == "" {
		opts.CacheControl = "public, max-age=315360000"
	}

	u.CacheControl = opts.CacheControl

	for _, s := range strings.Split(opts.Paths, ";") {
		trimmed := strings.TrimSpace(s)
		if len(trimmed) > 0 {
			parts := strings.SplitN(trimmed, ":", 2)
			if len(parts) < 2 {
				parts = append(parts, "")
			}
			u.Paths.Add(path.NewPath(opts.WorkingDir, parts[0], parts[1]))
		}
	}

	return u
}

func (u *uploader) Upload() error {
	auth, err := aws.GetAuth("", "")
	if err != nil {
		return err
	}

	conn := s3.New(auth, aws.USEast)
	bucket := conn.Bucket(u.BucketName)

	if bucket == nil {
		return fmt.Errorf("failed to get bucket")
	}

	for artifact := range u.files() {
		u.uploadFile(bucket, artifact)
	}

	return nil
}

func (u *uploader) files() chan *artifact {
	artifacts := make(chan *artifact)

	go func() {
		for _, path := range u.Paths.All() {
			to, from, root := path.To, path.From, path.Root
			if path.IsDir() {
				root = filepath.Join(root, from)
				if strings.HasSuffix(root, "/") {
					root = root + "/"
				}
			}

			filepath.Walk(path.Fullpath(), func(f string, info os.FileInfo, err error) error {
				if info != nil && info.IsDir() {
					return nil
				}

				relPath := strings.Replace(strings.Replace(f, root, "", -1), root+"/", "", -1)
				destination := relPath
				if len(to) > 0 {
					if path.IsDir() {
						destination = filepath.Join(to, relPath)
					} else {
						destination = to
					}
				}

				artifacts <- &artifact{Source: f, Destination: destination}
				return nil
			})

		}
		close(artifacts)
	}()

	return artifacts
}

func (u *uploader) uploadFile(b *s3.Bucket, a *artifact) error {
	retries := 0

	for {
		fmt.Printf("uploading %q -> %q\n", a.Source, a.Destination)
		err := u.rawUpload(b, a)
		if err != nil {
			if retries < 2 {
				retries += 1
				continue
			} else {
				return err
			}
		}
		return nil
	}
}

func (u *uploader) rawUpload(b *s3.Bucket, a *artifact) error {
	destination := strings.TrimLeft(filepath.Join(u.TargetPath, a.Destination), "/")

	reader, err := a.Reader()
	if err != nil {
		return err
	}

	return b.PutReaderHeader(destination, reader, a.Size(),
		map[string][]string{
			"Content-Type":  []string{a.ContentType()},
			"Cache-Control": []string{u.CacheControl},
		}, s3.Private)
}
<|endoftext|>


<commit_before>package user

import (
	"fmt"
	"strings"

	"github.com/pivotalservices/cf-mgmt/ldap"
	"github.com/pivotalservices/cf-mgmt/uaa"
	"github.com/pkg/errors"
	"github.com/xchapter7x/lo"
)

func (m *DefaultManager) SyncLdapUsers(roleUsers *RoleUsers, uaaUsers *uaa.Users, usersInput UsersInput) error {
	origin := m.LdapConfig.Origin
	if m.LdapConfig.Enabled {
		ldapUsers, err := m.GetLDAPUsers(uaaUsers, usersInput)
		if err != nil {
			return err
		}
		lo.G.Debugf("LdapUsers: %+v", ldapUsers)
		for _, inputUser := range ldapUsers {
			userToUse := m.UpdateUserInfo(inputUser)
			userID := userToUse.UserID
			userList := uaaUsers.GetByName(userID)
			if len(userList) == 0 {
				lo.G.Debug("User", userID, "doesn't exist in cloud foundry, so creating user")
				if userGUID, err := m.UAAMgr.CreateExternalUser(userID, userToUse.Email, userToUse.UserDN, m.LdapConfig.Origin); err != nil {
					lo.G.Errorf("Unable to create user %s with error %s", userID, err.Error())
					continue
				} else {
					uaaUsers.Add(uaa.User{
						Username:   userID,
						ExternalID: userToUse.UserDN,
						Origin:     m.LdapConfig.Origin,
						Email:      userToUse.Email,
						GUID:       userGUID,
					})
				}
			}
			if !roleUsers.HasUserForOrigin(userID, origin) {
				user := uaaUsers.GetByNameAndOrigin(userID, origin)
				if user == nil {
					return fmt.Errorf("Unabled to find user %s for origin %s", userID, origin)
				}
				if err := usersInput.AddUser(usersInput, user.Username, user.GUID); err != nil {
					return errors.Wrap(err, fmt.Sprintf("User %s with origin %s", user.Username, user.Origin))
				}
			} else {
				lo.G.Debugf("User[%s] found in role", userID)
				roleUsers.RemoveUserForOrigin(userID, origin)
			}
		}
	} else {
		lo.G.Debug("Skipping LDAP sync as LDAP is disabled (enable by updating config/ldap.yml)")
	}
	return nil
}

func (m *DefaultManager) GetLDAPUsers(uaaUsers *uaa.Users, usersInput UsersInput) ([]ldap.User, error) {
	var ldapUsers []ldap.User
	for _, groupName := range usersInput.UniqueLdapGroupNames() {
		userDNList, err := m.LdapMgr.GetUserDNs(groupName)
		if err != nil {
			return nil, err
		}
		for _, userDN := range userDNList {
			lo.G.Debugf("Checking for userDN %s", userDN)
			uaaUser := uaaUsers.GetByExternalID(userDN)
			if uaaUser != nil {
				lo.G.Debugf("UserDN [%s] found in UAA as [%s], skipping ldap lookup", userDN, uaaUser.Username)
				ldapUsers = append(ldapUsers, ldap.User{
					UserID: uaaUser.Username,
					UserDN: userDN,
					Email:  uaaUser.Email,
				})
			} else {
				lo.G.Debugf("UserDN [%s] not found in UAA, executing ldap lookup", userDN)
				user, err := m.LdapMgr.GetUserByDN(userDN)
				if err != nil {
					return nil, err
				}
				if user != nil {
					ldapUsers = append(ldapUsers, *user)
				} else {
					lo.G.Infof("UserDN %s not found in ldap", userDN)
				}
			}
		}
	}
	for _, userID := range usersInput.LdapUsers {
		userList := uaaUsers.GetByName(userID)
		if len(userList) > 0 {
			lo.G.Debugf("UserID [%s] found in UAA, skipping ldap lookup", userID)
			for _, uaaUser := range userList {
				if strings.EqualFold(uaaUser.Origin, m.LdapConfig.Origin) {
					ldapUsers = append(ldapUsers, ldap.User{
						UserID: userID,
						UserDN: uaaUser.ExternalID,
						Email:  uaaUser.Email,
					})
				} else {
					lo.G.Debugf("UserID [%s] with origin [%s] and externalID [%s] does not match ldap origin", uaaUser.Username, uaaUser.Origin, uaaUser.ExternalID)
				}
			}
		} else {
			lo.G.Debugf("User [%s] not found in UAA, executing ldap lookup", userID)
			user, err := m.LdapMgr.GetUserByID(userID)
			if err != nil {
				return nil, err
			}
			if user != nil {
				ldapUsers = append(ldapUsers, *user)
			} else {
				lo.G.Infof("User %s not found in ldap", userID)
			}
		}
	}

	uniqueLDAPUsers := make(map[string]ldap.User)
	for _, ldapUser := range ldapUsers {
		uniqueLDAPUsers[strings.ToUpper(ldapUser.UserDN)] = ldapUser
	}

	ldapUsersToReturn := []ldap.User{}

	for _, uniqueLDAPUser := range uniqueLDAPUsers {
		ldapUsersToReturn = append(ldapUsersToReturn, uniqueLDAPUser)
	}
	return ldapUsersToReturn, nil
}

func (m *DefaultManager) UpdateUserInfo(user ldap.User) ldap.User {
	userID := strings.ToLower(user.UserID)
	externalID := user.UserDN
	email := user.Email
	if email == "" {
		email = fmt.Sprintf("%s@user.from.ldap.cf", userID)
	}

	return ldap.User{
		UserID: userID,
		UserDN: externalID,
		Email:  email,
	}
}
<commit_msg>add logic to no look for uniqueness if externalID is blank<commit_after>package user

import (
	"fmt"
	"strings"

	"github.com/pivotalservices/cf-mgmt/ldap"
	"github.com/pivotalservices/cf-mgmt/uaa"
	"github.com/pkg/errors"
	"github.com/xchapter7x/lo"
)

func (m *DefaultManager) SyncLdapUsers(roleUsers *RoleUsers, uaaUsers *uaa.Users, usersInput UsersInput) error {
	origin := m.LdapConfig.Origin
	if m.LdapConfig.Enabled {
		ldapUsers, err := m.GetLDAPUsers(uaaUsers, usersInput)
		if err != nil {
			return err
		}
		lo.G.Debugf("LdapUsers: %+v", ldapUsers)
		for _, inputUser := range ldapUsers {
			userToUse := m.UpdateUserInfo(inputUser)
			userID := userToUse.UserID
			userList := uaaUsers.GetByName(userID)
			if len(userList) == 0 {
				lo.G.Debug("User", userID, "doesn't exist in cloud foundry, so creating user")
				if userGUID, err := m.UAAMgr.CreateExternalUser(userID, userToUse.Email, userToUse.UserDN, m.LdapConfig.Origin); err != nil {
					lo.G.Errorf("Unable to create user %s with error %s", userID, err.Error())
					continue
				} else {
					uaaUsers.Add(uaa.User{
						Username:   userID,
						ExternalID: userToUse.UserDN,
						Origin:     m.LdapConfig.Origin,
						Email:      userToUse.Email,
						GUID:       userGUID,
					})
				}
			}
			if !roleUsers.HasUserForOrigin(userID, origin) {
				user := uaaUsers.GetByNameAndOrigin(userID, origin)
				if user == nil {
					return fmt.Errorf("Unabled to find user %s for origin %s", userID, origin)
				}
				if err := usersInput.AddUser(usersInput, user.Username, user.GUID); err != nil {
					return errors.Wrap(err, fmt.Sprintf("User %s with origin %s", user.Username, user.Origin))
				}
			} else {
				lo.G.Debugf("User[%s] found in role", userID)
				roleUsers.RemoveUserForOrigin(userID, origin)
			}
		}
	} else {
		lo.G.Debug("Skipping LDAP sync as LDAP is disabled (enable by updating config/ldap.yml)")
	}
	return nil
}

func (m *DefaultManager) GetLDAPUsers(uaaUsers *uaa.Users, usersInput UsersInput) ([]ldap.User, error) {
	var ldapUsers []ldap.User
	for _, groupName := range usersInput.UniqueLdapGroupNames() {
		userDNList, err := m.LdapMgr.GetUserDNs(groupName)
		if err != nil {
			return nil, err
		}
		for _, userDN := range userDNList {
			lo.G.Debugf("Checking for userDN %s", userDN)
			uaaUser := uaaUsers.GetByExternalID(userDN)
			if uaaUser != nil {
				lo.G.Debugf("UserDN [%s] found in UAA as [%s], skipping ldap lookup", userDN, uaaUser.Username)
				ldapUsers = append(ldapUsers, ldap.User{
					UserID: uaaUser.Username,
					UserDN: userDN,
					Email:  uaaUser.Email,
				})
			} else {
				lo.G.Debugf("UserDN [%s] not found in UAA, executing ldap lookup", userDN)
				user, err := m.LdapMgr.GetUserByDN(userDN)
				if err != nil {
					return nil, err
				}
				if user != nil {
					ldapUsers = append(ldapUsers, *user)
				} else {
					lo.G.Infof("UserDN %s not found in ldap", userDN)
				}
			}
		}
	}
	for _, userID := range usersInput.LdapUsers {
		userList := uaaUsers.GetByName(userID)
		if len(userList) > 0 {
			lo.G.Debugf("UserID [%s] found in UAA, skipping ldap lookup", userID)
			for _, uaaUser := range userList {
				lo.G.Debugf("Checking if userID [%s] with origin [%s] and externalID [%s] matches ldap origin", uaaUser.Username, uaaUser.Origin, uaaUser.ExternalID)
				if strings.EqualFold(uaaUser.Origin, m.LdapConfig.Origin) {
					ldapUsers = append(ldapUsers, ldap.User{
						UserID: userID,
						UserDN: uaaUser.ExternalID,
						Email:  uaaUser.Email,
					})
				}
			}
		} else {
			lo.G.Debugf("User [%s] not found in UAA, executing ldap lookup", userID)
			user, err := m.LdapMgr.GetUserByID(userID)
			if err != nil {
				return nil, err
			}
			if user != nil {
				ldapUsers = append(ldapUsers, *user)
			} else {
				lo.G.Infof("User %s not found in ldap", userID)
			}
		}
	}
	lo.G.Debugf("LdapUsers before unique check: %+v", ldapUsers)
	ldapUsersToReturn := []ldap.User{}
	uniqueLDAPUsers := make(map[string]ldap.User)
	for _, ldapUser := range ldapUsers {
		if len(strings.TrimSpace(ldapUser.UserDN)) == 0 {
			lo.G.Debugf("User [%s] has a blank externalID", ldapUser.UserID)
			ldapUsersToReturn = append(ldapUsersToReturn, ldapUser)
		} else {
			uniqueLDAPUsers[strings.ToUpper(ldapUser.UserDN)] = ldapUser
		}
	}
	for _, uniqueLDAPUser := range uniqueLDAPUsers {
		ldapUsersToReturn = append(ldapUsersToReturn, uniqueLDAPUser)
	}
	return ldapUsersToReturn, nil
}

func (m *DefaultManager) UpdateUserInfo(user ldap.User) ldap.User {
	userID := strings.ToLower(user.UserID)
	externalID := user.UserDN
	email := user.Email
	if email == "" {
		email = fmt.Sprintf("%s@user.from.ldap.cf", userID)
	}

	return ldap.User{
		UserID: userID,
		UserDN: externalID,
		Email:  email,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/emgee/go-xmpp/src/xmpp"
	"github.com/trasa/jabmud/commands"
	"github.com/trasa/jabmud/world"
	"log"
	"strings"
)

func HandleIq(iq *xmpp.Iq) *xmpp.Iq {
	log.Printf("iq: %T: %v", iq.Payload, iq.Payload)
	if strings.HasPrefix(iq.Payload, "<command") {
		return handleIqCommand(iq)
	} else {
		log.Printf("Not a command-iq: %s", iq.Payload)
		return iq.Response("error")
	}
}

func handleIqCommand(iq *xmpp.Iq) *xmpp.Iq {
	cmd := DeserializeIqCommand(iq.Payload)
	player := world.FindPlayerByJid(iq.From)
	log.Printf("cmd: %s - %s", player, cmd)
	// so now go do something with the command...
	payload := commands.Serialize(commands.Run(player, cmd.Name, cmd.ArgList))
	response := iq.Response("result")
	response.Payload = payload
	log.Printf("sending response: %s", response.Payload)
	return response
}
<commit_msg>Return error IQ when player is not logged in.<commit_after>package main

import (
	"github.com/emgee/go-xmpp/src/xmpp"
	"github.com/trasa/jabmud/commands"
	"github.com/trasa/jabmud/world"
	"log"
	"strings"
)

func HandleIq(iq *xmpp.Iq) *xmpp.Iq {
	log.Printf("Handle IQ: %T: %v", iq.Payload, iq.Payload)
	if strings.HasPrefix(iq.Payload, "<command") {
		return handleIqCommand(iq)
	} else {
		log.Printf("Not a command-iq: %s", iq.Payload)
		return iq.Response("error")
	}
}

func handleIqCommand(iq *xmpp.Iq) *xmpp.Iq {
	cmd := DeserializeIqCommand(iq.Payload)
	player := world.FindPlayerByJid(iq.From)
	if player == nil {
		response := iq.Response("error")
		response.Payload = "Not Logged In"
		return response
	}

	// so now go do something with the command...
	payload := commands.Serialize(commands.Run(player, cmd.Name, cmd.ArgList))
	response := iq.Response("result")
	response.Payload = payload
	return response
}
<|endoftext|>


<commit_before>// +build unit

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 utils

import (
	"testing"

	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
)

var contentReader = new(ContentReader)
var testfile = "../tests/dat/deployment_data_action_with_inputs_outputs.yaml"

func TestLocalReader_ReadLocal(t *testing.T) {
	b, _ := contentReader.ReadLocal(testfile)
	if b == nil {
		t.Error("get local centent failed")
	}
}

func TestURLReader_ReadUrl(t *testing.T) {
	var exampleUrl = "http://www.baidu.com"
	b, _ := contentReader.ReadUrl(exampleUrl)
	if b == nil {
		t.Error("get web content failed")
	}
}

// The dollar sign test cases.
func TestGetEnvVar(t *testing.T) {
	os.Setenv("NoDollar", "NO dollar")
	os.Setenv("WithDollar", "oh, dollars!")
	os.Setenv("5000", "5000")
	fmt.Println(GetEnvVar("NoDollar"))
	fmt.Println(GetEnvVar("$WithDollar"))
	fmt.Println(GetEnvVar("$5000"))
	assert.Equal(t, "NoDollar", GetEnvVar("NoDollar"), "NoDollar should be no change.")
	assert.Equal(t, "oh, dollars!", GetEnvVar("$WithDollar"), "dollar sign should be handled.")
	assert.Equal(t, "5000", GetEnvVar("5000"), "Should be no difference between integer and string.")
	assert.Equal(t, "", GetEnvVar("$WithDollarAgain"), "if not found in environemnt, return empty string.")
	assert.Equal(t, "oh, dollars!.ccc.aaa", GetEnvVar("${WithDollar}.ccc.aaa"), "String concatenation fail")
	assert.Equal(t, "ddd.NO dollar.aaa", GetEnvVar("ddd.${NoDollar}.aaa"), "String concatenation fail")
	assert.Equal(t, "oh, dollars!.NO dollar.aaa", GetEnvVar("${WithDollar}.${NoDollar}.aaa"), "String concatenation fail")
	assert.Equal(t, "ddd.ccc.oh, dollars!", GetEnvVar("ddd.ccc.${WithDollar}"), "String concatenation fail")
	assert.Equal(t, "", GetEnvVar("$WithDollarAgain.ccc.aaa"), "String concatenation fail")
	assert.Equal(t, "ddd..aaa", GetEnvVar("ddd.${WithDollarAgain}.aaa"), "String concatenation fail")
	assert.Equal(t, "oh, dollars!NO dollar.NO dollar", GetEnvVar("${WithDollar}${NoDollar}.${NoDollar}"), "String concatenation fail")
}

func TestDependencies(t *testing.T) {
	var record = NewDependencyRecord("projectPath","packageName","http://github.com/user/repo","master",nil,nil,false)
	assert.Equal(t, "projectPath", record.ProjectPath,"ProjectPath is wrong")
	assert.Equal(t, "http://github.com/user/repo", record.Location, "URL is wrong")
	assert.Equal(t, "http://github.com/user/repo", record.BaseRepo, "BaseRepo is wrong")
	assert.Equal(t, "", record.SubFolder, "SubFolder is wrong")

	record = NewDependencyRecord("projectPath","packageName","http://github.com/user/repo/subfolder1/subfolder2","master",nil,nil,false)
	assert.Equal(t, "projectPath", record.ProjectPath,"ProjectPath is wrong")
	assert.Equal(t, "http://github.com/user/repo/subfolder1/subfolder2", record.Location, "URL is wrong")
	assert.Equal(t, "http://github.com/user/repo", record.BaseRepo, "BaseRepo is wrong")
	assert.Equal(t, "/subfolder1/subfolder2", record.SubFolder, "SubFolder is wrong")
}

func TestParseOpenWhisk(t *testing.T) {
	openwhiskHost := "https://openwhisk.ng.bluemix.net"
	openwhisk, err := ParseOpenWhisk(openwhiskHost)
	assert.Equal(t, nil, err, "parse openwhisk info error happened.")
	converted := ConvertToMap(openwhisk)
	assert.Equal(t, 1, len(converted["nodejs"]), "not expected length")
	assert.Equal(t, 1, len(converted["php"]),  "not expected length")
	assert.Equal(t, 1, len(converted["java"]), "not expected length")
	assert.Equal(t, 3, len(converted["python"]), "not expected length")
	assert.Equal(t, 2, len(converted["swift"]), "not expected length")
}

func TestNewZipWritter(t *testing.T) {
	filePath := "../tests/src/integration/zipaction/actions/cat"
	zipName := filePath + ".zip"
	err := NewZipWritter(filePath, zipName).Zip()
	defer os.Remove(zipName)
	assert.Equal(t, nil, err, "zip folder error happened.")
}
<commit_msg>Fixes #290 Change util_test.go's ReadUrl test URL to a neutral address (#638)<commit_after>// +build unit

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 utils

import (
	"testing"

	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
)

var contentReader = new(ContentReader)
var testfile = "../tests/dat/deployment_data_action_with_inputs_outputs.yaml"

func TestLocalReader_ReadLocal(t *testing.T) {
	b, _ := contentReader.ReadLocal(testfile)
	if b == nil {
		t.Error("get local centent failed")
	}
}

func TestURLReader_ReadUrl(t *testing.T) {
	var exampleUrl = "https://www.apache.org/"
	b, _ := contentReader.ReadUrl(exampleUrl)
	if b == nil {
		t.Error("get web content failed")
	}
}

// The dollar sign test cases.
func TestGetEnvVar(t *testing.T) {
	os.Setenv("NoDollar", "NO dollar")
	os.Setenv("WithDollar", "oh, dollars!")
	os.Setenv("5000", "5000")
	fmt.Println(GetEnvVar("NoDollar"))
	fmt.Println(GetEnvVar("$WithDollar"))
	fmt.Println(GetEnvVar("$5000"))
	assert.Equal(t, "NoDollar", GetEnvVar("NoDollar"), "NoDollar should be no change.")
	assert.Equal(t, "oh, dollars!", GetEnvVar("$WithDollar"), "dollar sign should be handled.")
	assert.Equal(t, "5000", GetEnvVar("5000"), "Should be no difference between integer and string.")
	assert.Equal(t, "", GetEnvVar("$WithDollarAgain"), "if not found in environemnt, return empty string.")
	assert.Equal(t, "oh, dollars!.ccc.aaa", GetEnvVar("${WithDollar}.ccc.aaa"), "String concatenation fail")
	assert.Equal(t, "ddd.NO dollar.aaa", GetEnvVar("ddd.${NoDollar}.aaa"), "String concatenation fail")
	assert.Equal(t, "oh, dollars!.NO dollar.aaa", GetEnvVar("${WithDollar}.${NoDollar}.aaa"), "String concatenation fail")
	assert.Equal(t, "ddd.ccc.oh, dollars!", GetEnvVar("ddd.ccc.${WithDollar}"), "String concatenation fail")
	assert.Equal(t, "", GetEnvVar("$WithDollarAgain.ccc.aaa"), "String concatenation fail")
	assert.Equal(t, "ddd..aaa", GetEnvVar("ddd.${WithDollarAgain}.aaa"), "String concatenation fail")
	assert.Equal(t, "oh, dollars!NO dollar.NO dollar", GetEnvVar("${WithDollar}${NoDollar}.${NoDollar}"), "String concatenation fail")
}

func TestDependencies(t *testing.T) {
	var record = NewDependencyRecord("projectPath","packageName","http://github.com/user/repo","master",nil,nil,false)
	assert.Equal(t, "projectPath", record.ProjectPath,"ProjectPath is wrong")
	assert.Equal(t, "http://github.com/user/repo", record.Location, "URL is wrong")
	assert.Equal(t, "http://github.com/user/repo", record.BaseRepo, "BaseRepo is wrong")
	assert.Equal(t, "", record.SubFolder, "SubFolder is wrong")

	record = NewDependencyRecord("projectPath","packageName","http://github.com/user/repo/subfolder1/subfolder2","master",nil,nil,false)
	assert.Equal(t, "projectPath", record.ProjectPath,"ProjectPath is wrong")
	assert.Equal(t, "http://github.com/user/repo/subfolder1/subfolder2", record.Location, "URL is wrong")
	assert.Equal(t, "http://github.com/user/repo", record.BaseRepo, "BaseRepo is wrong")
	assert.Equal(t, "/subfolder1/subfolder2", record.SubFolder, "SubFolder is wrong")
}

func TestParseOpenWhisk(t *testing.T) {
	openwhiskHost := "https://openwhisk.ng.bluemix.net"
	openwhisk, err := ParseOpenWhisk(openwhiskHost)
	assert.Equal(t, nil, err, "parse openwhisk info error happened.")
	converted := ConvertToMap(openwhisk)
	assert.Equal(t, 1, len(converted["nodejs"]), "not expected length")
	assert.Equal(t, 1, len(converted["php"]),  "not expected length")
	assert.Equal(t, 1, len(converted["java"]), "not expected length")
	assert.Equal(t, 3, len(converted["python"]), "not expected length")
	assert.Equal(t, 2, len(converted["swift"]), "not expected length")
}

func TestNewZipWritter(t *testing.T) {
	filePath := "../tests/src/integration/zipaction/actions/cat"
	zipName := filePath + ".zip"
	err := NewZipWritter(filePath, zipName).Zip()
	defer os.Remove(zipName)
	assert.Equal(t, nil, err, "zip folder error happened.")
}
<|endoftext|>


<commit_before>package redis_test

import (
	"fmt"
	"strconv"

	"github.com/vmihailenco/redis/v2"
)

func ExampleTCPClient() {
	client := redis.NewTCPClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})
	defer client.Close()

	ping := client.Ping()
	fmt.Println(ping.Err(), ping.Val())
	// Output: <nil> PONG
}

func ExampleUnixClient() {
	client := redis.NewUnixClient(&redis.Options{
		Addr: "/tmp/redis.sock",
	})
	defer client.Close()

	ping := client.Ping()
	fmt.Println(ping.Err(), ping.Val())
	// Output: <nil> PONG
}

func ExampleSetGet() {
	client := redis.NewTCPClient(&redis.Options{
		Addr: ":6379",
	})
	defer client.Close()

	set := client.Set("foo", "bar")
	fmt.Println(set.Err(), set.Val())

	get := client.Get("foo")
	fmt.Println(get.Err(), get.Val())

	// Output: <nil> OK
	// <nil> bar
}

func ExamplePipeline() {
	client := redis.NewTCPClient(&redis.Options{
		Addr: ":6379",
	})
	defer client.Close()

	var set *redis.StatusCmd
	var get *redis.StringCmd
	cmds, err := client.Pipelined(func(c *redis.Pipeline) {
		set = c.Set("key1", "hello1")
		get = c.Get("key2")
	})
	fmt.Println(err, cmds)
	fmt.Println(set)
	fmt.Println(get)
	// Output: (nil) [SET key1 hello1: OK GET key2: (nil)]
	// SET key1 hello1: OK
	// GET key2: (nil)
}

func incr(tx *redis.Multi) ([]redis.Cmder, error) {
	get := tx.Get("key")
	if err := get.Err(); err != nil && err != redis.Nil {
		return nil, err
	}

	val, _ := strconv.ParseInt(get.Val(), 10, 64)

	cmds, err := tx.Exec(func() {
		tx.Set("key", strconv.FormatInt(val+1, 10))
	})
	// Transaction failed. Repeat.
	if err == redis.Nil {
		return incr(tx)
	}
	return cmds, err
}

func ExampleTransaction() {
	client := redis.NewTCPClient(&redis.Options{
		Addr: ":6379",
	})
	defer client.Close()

	client.Del("key")

	tx := client.Multi()
	defer tx.Close()

	watch := tx.Watch("key")
	_ = watch.Err()

	cmds, err := incr(tx)
	fmt.Println(err, cmds)

	// Output: <nil> [SET key 1: OK]
}

func ExamplePubSub() {
	client := redis.NewTCPClient(&redis.Options{
		Addr: ":6379",
	})
	defer client.Close()

	pubsub := client.PubSub()
	defer pubsub.Close()

	err := pubsub.Subscribe("mychannel")
	_ = err

	msg, err := pubsub.Receive()
	fmt.Println(msg, err)

	pub := client.Publish("mychannel", "hello")
	_ = pub.Err()

	msg, err = pubsub.Receive()
	fmt.Println(msg, err)

	// Output: &{subscribe mychannel 1} <nil>
	// &{mychannel hello} <nil>
}

func Get(client *redis.Client, key string) *redis.StringCmd {
	cmd := redis.NewStringCmd("GET", key)
	client.Process(cmd)
	return cmd
}

func ExampleCustomCommand() {
	client := redis.NewTCPClient(&redis.Options{
		Addr: ":6379",
	})
	defer client.Close()

	get := Get(client, "key_does_not_exist")
	fmt.Println(get.Err(), get.Val())
	// Output: (nil)
}
<commit_msg>Rename examples.<commit_after>package redis_test

import (
	"fmt"
	"strconv"

	"github.com/vmihailenco/redis/v2"
)

func ExampleNewTCPClient() {
	client := redis.NewTCPClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})
	defer client.Close()

	ping := client.Ping()
	fmt.Println(ping.Err(), ping.Val())
	// Output: <nil> PONG
}

func ExampleNewUnixClient() {
	client := redis.NewUnixClient(&redis.Options{
		Addr: "/tmp/redis.sock",
	})
	defer client.Close()

	ping := client.Ping()
	fmt.Println(ping.Err(), ping.Val())
	// Output: <nil> PONG
}

func ExampleSet() {
	client := redis.NewTCPClient(&redis.Options{
		Addr: ":6379",
	})
	defer client.Close()

	set := client.Set("foo", "bar")
	fmt.Println(set.Err(), set.Val())

	get := client.Get("foo")
	fmt.Println(get.Err(), get.Val())

	// Output: <nil> OK
	// <nil> bar
}

func ExamplePipeline() {
	client := redis.NewTCPClient(&redis.Options{
		Addr: ":6379",
	})
	defer client.Close()

	var set *redis.StatusCmd
	var get *redis.StringCmd
	cmds, err := client.Pipelined(func(c *redis.Pipeline) {
		set = c.Set("key1", "hello1")
		get = c.Get("key2")
	})
	fmt.Println(err, cmds)
	fmt.Println(set)
	fmt.Println(get)
	// Output: (nil) [SET key1 hello1: OK GET key2: (nil)]
	// SET key1 hello1: OK
	// GET key2: (nil)
}

func incr(tx *redis.Multi) ([]redis.Cmder, error) {
	get := tx.Get("key")
	if err := get.Err(); err != nil && err != redis.Nil {
		return nil, err
	}

	val, _ := strconv.ParseInt(get.Val(), 10, 64)

	cmds, err := tx.Exec(func() {
		tx.Set("key", strconv.FormatInt(val+1, 10))
	})
	// Transaction failed. Repeat.
	if err == redis.Nil {
		return incr(tx)
	}
	return cmds, err
}

func ExampleMulti() {
	client := redis.NewTCPClient(&redis.Options{
		Addr: ":6379",
	})
	defer client.Close()

	client.Del("key")

	tx := client.Multi()
	defer tx.Close()

	watch := tx.Watch("key")
	_ = watch.Err()

	cmds, err := incr(tx)
	fmt.Println(err, cmds)

	// Output: <nil> [SET key 1: OK]
}

func ExamplePubSub() {
	client := redis.NewTCPClient(&redis.Options{
		Addr: ":6379",
	})
	defer client.Close()

	pubsub := client.PubSub()
	defer pubsub.Close()

	err := pubsub.Subscribe("mychannel")
	_ = err

	msg, err := pubsub.Receive()
	fmt.Println(msg, err)

	pub := client.Publish("mychannel", "hello")
	_ = pub.Err()

	msg, err = pubsub.Receive()
	fmt.Println(msg, err)

	// Output: &{subscribe mychannel 1} <nil>
	// &{mychannel hello} <nil>
}

func Get(client *redis.Client, key string) *redis.StringCmd {
	cmd := redis.NewStringCmd("GET", key)
	client.Process(cmd)
	return cmd
}

func ExampleCustomCommand() {
	client := redis.NewTCPClient(&redis.Options{
		Addr: ":6379",
	})
	defer client.Close()

	get := Get(client, "key_does_not_exist")
	fmt.Println(get.Err(), get.Val())
	// Output: (nil)
}
<|endoftext|>


<commit_before>package pb

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/fatih/color"
)

func testState(total, value int64, maxWidth int, bools ...bool) (s *State) {
	s = &State{
		total:           total,
		current:         value,
		adaptiveElWidth: maxWidth,
		ProgressBar:     new(ProgressBar),
	}
	if len(bools) > 0 {
		s.Set(Bytes, bools[0])
	}
	if len(bools) > 1 && bools[1] {
		s.adaptive = true
	}
	return
}

func testElementBarString(t *testing.T, state *State, el Element, want string, args ...string) {
	if state.ProgressBar == nil {
		state.ProgressBar = new(ProgressBar)
	}
	res := el.ProgressElement(state, args...)
	if res != want {
		t.Errorf("Unexpected result: '%s'; want: '%s'", res, want)
	}
	if state.IsAdaptiveWidth() && state.AdaptiveElWidth() != CellCount(res) {
		t.Errorf("Unepected width: %d; want: %d", CellCount(res), state.AdaptiveElWidth())
	}
}

func TestElementPercent(t *testing.T) {
	testElementBarString(t, testState(100, 50, 0), ElementPercent, "50.00%")
	testElementBarString(t, testState(100, 50, 0), ElementPercent, "50 percent", "%v percent")
	testElementBarString(t, testState(0, 50, 0), ElementPercent, "?%")
	testElementBarString(t, testState(0, 50, 0), ElementPercent, "unkn", "%v%%", "unkn")
}

func TestElementCounters(t *testing.T) {
	testElementBarString(t, testState(100, 50, 0), ElementCounters, "50 / 100")
	testElementBarString(t, testState(100, 50, 0), ElementCounters, "50 of 100", "%s of %s")
	testElementBarString(t, testState(100, 50, 0, true), ElementCounters, "50 B of 100 B", "%s of %s")
	testElementBarString(t, testState(100, 50, 0, true), ElementCounters, "50 B / 100 B")
	testElementBarString(t, testState(0, 50, 0, true), ElementCounters, "50 B")
	testElementBarString(t, testState(0, 50, 0, true), ElementCounters, "50 B / ?", "", "%[1]s / ?")
}

func TestElementBar(t *testing.T) {
	// short
	testElementBarString(t, testState(100, 50, 1, false, true), ElementBar, "[")
	testElementBarString(t, testState(100, 50, 2, false, true), ElementBar, "[]")
	testElementBarString(t, testState(100, 50, 3, false, true), ElementBar, "[>]")
	testElementBarString(t, testState(100, 50, 4, false, true), ElementBar, "[>_]")
	testElementBarString(t, testState(100, 50, 5, false, true), ElementBar, "[->_]")
	// middle
	testElementBarString(t, testState(100, 50, 10, false, true), ElementBar, "[--->____]")
	testElementBarString(t, testState(100, 50, 10, false, true), ElementBar, "<--->____>", "<", "", "", "", ">")
	// finished
	st := testState(100, 100, 10, false, true)
	st.finished = true
	testElementBarString(t, st, ElementBar, "[--------]")
	// empty color
	st = testState(100, 50, 10, false, true)
	st.Set(Terminal, true)
	color.NoColor = false
	testElementBarString(t, st, ElementBar, " --->____]", color.RedString("%s", ""))
	// empty
	testElementBarString(t, testState(0, 50, 10, false, true), ElementBar, "[________]")
	// full
	testElementBarString(t, testState(20, 20, 10, false, true), ElementBar, "[------->]")
	// everflow
	testElementBarString(t, testState(20, 50, 10, false, true), ElementBar, "[------->]")
	// small width
	testElementBarString(t, testState(20, 50, 2, false, true), ElementBar, "[]")
	testElementBarString(t, testState(20, 50, 1, false, true), ElementBar, "[")
	// negative counters
	testElementBarString(t, testState(-50, -150, 10, false, true), ElementBar, "[------->]")
	testElementBarString(t, testState(-150, -50, 10, false, true), ElementBar, "[-->_____]")
	testElementBarString(t, testState(50, -150, 10, false, true), ElementBar, "[------->]")
	testElementBarString(t, testState(-50, 150, 10, false, true), ElementBar, "[------->]")
	// long entities / unicode
	f1 := []string{"進捗|", "многобайт", "active", "пусто", "|end"}
	testElementBarString(t, testState(100, 50, 1, false, true), ElementBar, " ", f1...)
	testElementBarString(t, testState(100, 50, 3, false, true), ElementBar, "進 ", f1...)
	testElementBarString(t, testState(100, 50, 4, false, true), ElementBar, "進捗", f1...)
	testElementBarString(t, testState(100, 50, 29, false, true), ElementBar, "進捗|многactiveпустопусто|end", f1...)
	testElementBarString(t, testState(100, 50, 11, false, true), ElementBar, "進捗|aп|end", f1...)

	// unicode
	f2 := []string{"⚑", ".", ">", "⟞", "⚐"}
	testElementBarString(t, testState(100, 50, 10, false, true), ElementBar, "⚑..>⟞⟞⟞⚐", f2...)

	// no adaptive
	testElementBarString(t, testState(0, 50, 10), ElementBar, "[____________________________]")

	var formats = [][]string{
		[]string{},
		f1, f2,
	}

	// all widths / extreme values
	// check for panic and correct width
	for _, f := range formats {
		for tt := int64(-2); tt < 12; tt++ {
			for v := int64(-2); v < 12; v++ {
				state := testState(tt, v, 0, false, true)
				for w := -2; w < 20; w++ {
					state.adaptiveElWidth = w
					res := ElementBar(state, f...)
					var we = w
					if we <= 0 {
						we = 30
					}
					if CellCount(res) != we {
						t.Errorf("Unexpected len(%d): '%s'", we, res)
					}
				}
			}
		}
	}
}

func TestElementSpeed(t *testing.T) {
	var state = testState(1000, 0, 0, false)
	state.time = time.Now()
	for i := int64(0); i < 10; i++ {
		state.id = uint64(i) + 1
		state.current += 42
		state.time = state.time.Add(time.Second)
		state.finished = i == 9
		if state.finished {
			state.current += 100
		}
		r := ElementSpeed(state)
		r2 := ElementSpeed(state)
		if r != r2 {
			t.Errorf("Must be the same: '%s' vs '%s'", r, r2)
		}
		if i < 1 {
			// do not calc first result
			if w := "? p/s"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		} else if state.finished {
			if w := "58 p/s"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
			state.time = state.time.Add(-time.Hour)
			r = ElementSpeed(state)
			if w := "? p/s"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		} else {
			if w := "42 p/s"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		}
	}
}

func TestElementRemainingTime(t *testing.T) {
	var state = testState(100, 0, 0, false)
	state.time = time.Now()
	state.startTime = state.time
	for i := int64(0); i < 10; i++ {
		state.id = uint64(i) + 1
		state.time = state.time.Add(time.Second)
		state.finished = i == 9
		r := ElementRemainingTime(state)
		if i < 1 {
			// do not calc first two results
			if w := "?"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		} else if state.finished {
			// final elapsed time
			if w := "10s"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		} else {
			w := fmt.Sprintf("%ds", 10-i)
			if r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		}
		state.current += 10
	}
}

func TestElementElapsedTime(t *testing.T) {
	var state = testState(1000, 0, 0, false)
	state.startTime = time.Now()
	state.time = state.startTime
	for i := int64(0); i < 10; i++ {
		r := ElementElapsedTime(state)
		if w := fmt.Sprintf("%ds", i); r != w {
			t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
		}
		state.time = state.time.Add(time.Second)
	}
}

func TestElementString(t *testing.T) {
	var state = testState(0, 0, 0, false)
	testElementBarString(t, state, ElementString, "", "myKey")
	state.Set("myKey", "my value")
	testElementBarString(t, state, ElementString, "my value", "myKey")
	state.Set("myKey", "my value1")
	testElementBarString(t, state, ElementString, "my value1", "myKey")
	testElementBarString(t, state, ElementString, "")
}

func TestElementCycle(t *testing.T) {
	var state = testState(0, 0, 0, false)
	testElementBarString(t, state, ElementCycle, "")
	testElementBarString(t, state, ElementCycle, "1", "1", "2", "3")
	testElementBarString(t, state, ElementCycle, "2", "1", "2", "3")
	testElementBarString(t, state, ElementCycle, "3", "1", "2", "3")
	testElementBarString(t, state, ElementCycle, "1", "1", "2", "3")
	testElementBarString(t, state, ElementCycle, "2", "1", "2")
	testElementBarString(t, state, ElementCycle, "1", "1", "2")
}

func TestAdaptiveWrap(t *testing.T) {
	var state = testState(0, 0, 0, false)
	state.id = 1
	state.Set("myKey", "my value")
	el := adaptiveWrap(ElementString)
	testElementBarString(t, state, el, adElPlaceholder, "myKey")
	if v := state.recalc[0].ProgressElement(state); v != "my value" {
		t.Errorf("Unexpected result: %s", v)
	}
	state.id = 2
	testElementBarString(t, state, el, adElPlaceholder, "myKey1")
	state.Set("myKey", "my value1")
	if v := state.recalc[0].ProgressElement(state); v != "my value1" {
		t.Errorf("Unexpected result: %s", v)
	}
}

func TestRegisterElement(t *testing.T) {
	var testEl ElementFunc = func(state *State, args ...string) string {
		return strings.Repeat("*", state.AdaptiveElWidth())
	}
	RegisterElement("testEl", testEl, true)
	result := ProgressBarTemplate(`{{testEl . }}`).New(0).SetWidth(5).String()
	if result != "*****" {
		t.Errorf("Unexpected result: '%v'", result)
	}
}

func BenchmarkBar(b *testing.B) {
	var formats = map[string][]string{
		"simple":      []string{".", ".", ".", ".", "."},
		"unicode":     []string{"⚑", "⚒", "⚟", "⟞", "⚐"},
		"color":       []string{color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", ".")},
		"long":        []string{"..", "..", "..", "..", ".."},
		"longunicode": []string{"⚑⚑", "⚒⚒", "⚟⚟", "⟞⟞", "⚐⚐"},
	}
	for name, args := range formats {
		state := testState(100, 50, 100, false, true)
		b.Run(name, func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				ElementBar(state, args...)
			}
		})
	}
}
<commit_msg>Fix test (unicode length)<commit_after>package pb

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/fatih/color"
)

func testState(total, value int64, maxWidth int, bools ...bool) (s *State) {
	s = &State{
		total:           total,
		current:         value,
		adaptiveElWidth: maxWidth,
		ProgressBar:     new(ProgressBar),
	}
	if len(bools) > 0 {
		s.Set(Bytes, bools[0])
	}
	if len(bools) > 1 && bools[1] {
		s.adaptive = true
	}
	return
}

func testElementBarString(t *testing.T, state *State, el Element, want string, args ...string) {
	if state.ProgressBar == nil {
		state.ProgressBar = new(ProgressBar)
	}
	res := el.ProgressElement(state, args...)
	if res != want {
		t.Errorf("Unexpected result: '%s'; want: '%s'", res, want)
	}
	if state.IsAdaptiveWidth() && state.AdaptiveElWidth() != CellCount(res) {
		t.Errorf("Unepected width: %d; want: %d", CellCount(res), state.AdaptiveElWidth())
	}
}

func TestElementPercent(t *testing.T) {
	testElementBarString(t, testState(100, 50, 0), ElementPercent, "50.00%")
	testElementBarString(t, testState(100, 50, 0), ElementPercent, "50 percent", "%v percent")
	testElementBarString(t, testState(0, 50, 0), ElementPercent, "?%")
	testElementBarString(t, testState(0, 50, 0), ElementPercent, "unkn", "%v%%", "unkn")
}

func TestElementCounters(t *testing.T) {
	testElementBarString(t, testState(100, 50, 0), ElementCounters, "50 / 100")
	testElementBarString(t, testState(100, 50, 0), ElementCounters, "50 of 100", "%s of %s")
	testElementBarString(t, testState(100, 50, 0, true), ElementCounters, "50 B of 100 B", "%s of %s")
	testElementBarString(t, testState(100, 50, 0, true), ElementCounters, "50 B / 100 B")
	testElementBarString(t, testState(0, 50, 0, true), ElementCounters, "50 B")
	testElementBarString(t, testState(0, 50, 0, true), ElementCounters, "50 B / ?", "", "%[1]s / ?")
}

func TestElementBar(t *testing.T) {
	// short
	testElementBarString(t, testState(100, 50, 1, false, true), ElementBar, "[")
	testElementBarString(t, testState(100, 50, 2, false, true), ElementBar, "[]")
	testElementBarString(t, testState(100, 50, 3, false, true), ElementBar, "[>]")
	testElementBarString(t, testState(100, 50, 4, false, true), ElementBar, "[>_]")
	testElementBarString(t, testState(100, 50, 5, false, true), ElementBar, "[->_]")
	// middle
	testElementBarString(t, testState(100, 50, 10, false, true), ElementBar, "[--->____]")
	testElementBarString(t, testState(100, 50, 10, false, true), ElementBar, "<--->____>", "<", "", "", "", ">")
	// finished
	st := testState(100, 100, 10, false, true)
	st.finished = true
	testElementBarString(t, st, ElementBar, "[--------]")
	// empty color
	st = testState(100, 50, 10, false, true)
	st.Set(Terminal, true)
	color.NoColor = false
	testElementBarString(t, st, ElementBar, " --->____]", color.RedString("%s", ""))
	// empty
	testElementBarString(t, testState(0, 50, 10, false, true), ElementBar, "[________]")
	// full
	testElementBarString(t, testState(20, 20, 10, false, true), ElementBar, "[------->]")
	// everflow
	testElementBarString(t, testState(20, 50, 10, false, true), ElementBar, "[------->]")
	// small width
	testElementBarString(t, testState(20, 50, 2, false, true), ElementBar, "[]")
	testElementBarString(t, testState(20, 50, 1, false, true), ElementBar, "[")
	// negative counters
	testElementBarString(t, testState(-50, -150, 10, false, true), ElementBar, "[------->]")
	testElementBarString(t, testState(-150, -50, 10, false, true), ElementBar, "[-->_____]")
	testElementBarString(t, testState(50, -150, 10, false, true), ElementBar, "[------->]")
	testElementBarString(t, testState(-50, 150, 10, false, true), ElementBar, "[------->]")
	// long entities / unicode
	f1 := []string{"進捗|", "многобайт", "active", "пусто", "|end"}
	testElementBarString(t, testState(100, 50, 1, false, true), ElementBar, " ", f1...)
	testElementBarString(t, testState(100, 50, 3, false, true), ElementBar, "進 ", f1...)
	testElementBarString(t, testState(100, 50, 4, false, true), ElementBar, "進捗", f1...)
	testElementBarString(t, testState(100, 50, 29, false, true), ElementBar, "進捗|многactiveпустопусто|end", f1...)
	testElementBarString(t, testState(100, 50, 11, false, true), ElementBar, "進捗|aп|end", f1...)

	// unicode
	f2 := []string{"⚑", ".", ">", "⟞", "⚐"}
	testElementBarString(t, testState(100, 50, 8, false, true), ElementBar, "⚑..>⟞⟞⟞⚐", f2...)

	// no adaptive
	testElementBarString(t, testState(0, 50, 10), ElementBar, "[____________________________]")

	var formats = [][]string{
		[]string{},
		f1, f2,
	}

	// all widths / extreme values
	// check for panic and correct width
	for _, f := range formats {
		for tt := int64(-2); tt < 12; tt++ {
			for v := int64(-2); v < 12; v++ {
				state := testState(tt, v, 0, false, true)
				for w := -2; w < 20; w++ {
					state.adaptiveElWidth = w
					res := ElementBar(state, f...)
					var we = w
					if we <= 0 {
						we = 30
					}
					if CellCount(res) != we {
						t.Errorf("Unexpected len(%d): '%s'", we, res)
					}
				}
			}
		}
	}
}

func TestElementSpeed(t *testing.T) {
	var state = testState(1000, 0, 0, false)
	state.time = time.Now()
	for i := int64(0); i < 10; i++ {
		state.id = uint64(i) + 1
		state.current += 42
		state.time = state.time.Add(time.Second)
		state.finished = i == 9
		if state.finished {
			state.current += 100
		}
		r := ElementSpeed(state)
		r2 := ElementSpeed(state)
		if r != r2 {
			t.Errorf("Must be the same: '%s' vs '%s'", r, r2)
		}
		if i < 1 {
			// do not calc first result
			if w := "? p/s"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		} else if state.finished {
			if w := "58 p/s"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
			state.time = state.time.Add(-time.Hour)
			r = ElementSpeed(state)
			if w := "? p/s"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		} else {
			if w := "42 p/s"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		}
	}
}

func TestElementRemainingTime(t *testing.T) {
	var state = testState(100, 0, 0, false)
	state.time = time.Now()
	state.startTime = state.time
	for i := int64(0); i < 10; i++ {
		state.id = uint64(i) + 1
		state.time = state.time.Add(time.Second)
		state.finished = i == 9
		r := ElementRemainingTime(state)
		if i < 1 {
			// do not calc first two results
			if w := "?"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		} else if state.finished {
			// final elapsed time
			if w := "10s"; r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		} else {
			w := fmt.Sprintf("%ds", 10-i)
			if r != w {
				t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
			}
		}
		state.current += 10
	}
}

func TestElementElapsedTime(t *testing.T) {
	var state = testState(1000, 0, 0, false)
	state.startTime = time.Now()
	state.time = state.startTime
	for i := int64(0); i < 10; i++ {
		r := ElementElapsedTime(state)
		if w := fmt.Sprintf("%ds", i); r != w {
			t.Errorf("Unexpected result[%d]: '%s' vs '%s'", i, r, w)
		}
		state.time = state.time.Add(time.Second)
	}
}

func TestElementString(t *testing.T) {
	var state = testState(0, 0, 0, false)
	testElementBarString(t, state, ElementString, "", "myKey")
	state.Set("myKey", "my value")
	testElementBarString(t, state, ElementString, "my value", "myKey")
	state.Set("myKey", "my value1")
	testElementBarString(t, state, ElementString, "my value1", "myKey")
	testElementBarString(t, state, ElementString, "")
}

func TestElementCycle(t *testing.T) {
	var state = testState(0, 0, 0, false)
	testElementBarString(t, state, ElementCycle, "")
	testElementBarString(t, state, ElementCycle, "1", "1", "2", "3")
	testElementBarString(t, state, ElementCycle, "2", "1", "2", "3")
	testElementBarString(t, state, ElementCycle, "3", "1", "2", "3")
	testElementBarString(t, state, ElementCycle, "1", "1", "2", "3")
	testElementBarString(t, state, ElementCycle, "2", "1", "2")
	testElementBarString(t, state, ElementCycle, "1", "1", "2")
}

func TestAdaptiveWrap(t *testing.T) {
	var state = testState(0, 0, 0, false)
	state.id = 1
	state.Set("myKey", "my value")
	el := adaptiveWrap(ElementString)
	testElementBarString(t, state, el, adElPlaceholder, "myKey")
	if v := state.recalc[0].ProgressElement(state); v != "my value" {
		t.Errorf("Unexpected result: %s", v)
	}
	state.id = 2
	testElementBarString(t, state, el, adElPlaceholder, "myKey1")
	state.Set("myKey", "my value1")
	if v := state.recalc[0].ProgressElement(state); v != "my value1" {
		t.Errorf("Unexpected result: %s", v)
	}
}

func TestRegisterElement(t *testing.T) {
	var testEl ElementFunc = func(state *State, args ...string) string {
		return strings.Repeat("*", state.AdaptiveElWidth())
	}
	RegisterElement("testEl", testEl, true)
	result := ProgressBarTemplate(`{{testEl . }}`).New(0).SetWidth(5).String()
	if result != "*****" {
		t.Errorf("Unexpected result: '%v'", result)
	}
}

func BenchmarkBar(b *testing.B) {
	var formats = map[string][]string{
		"simple":      []string{".", ".", ".", ".", "."},
		"unicode":     []string{"⚑", "⚒", "⚟", "⟞", "⚐"},
		"color":       []string{color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", "."), color.RedString("%s", ".")},
		"long":        []string{"..", "..", "..", "..", ".."},
		"longunicode": []string{"⚑⚑", "⚒⚒", "⚟⚟", "⟞⟞", "⚐⚐"},
	}
	for name, args := range formats {
		state := testState(100, 50, 100, false, true)
		b.Run(name, func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				ElementBar(state, args...)
			}
		})
	}
}
<|endoftext|>


<commit_before>package multiverse

import (
	"strings"
	"sync"
	"unicode"

	"github.com/CasualSuperman/Diorite/trie"
	"github.com/CasualSuperman/phonetics"
	"github.com/CasualSuperman/sift3"
)

func generatePhoneticsMaps(cards []*Card) trie.Trie {
	metaphoneMap := trie.Alt()

	for i, c := range cards {
		name := preventUnicode(c.Name)
		for _, word := range strings.Split(name, " ") {
			if len(word) < 4 {
				continue
			}
			mtp := phonetics.EncodeMetaphone(word)

			others, ok := metaphoneMap.Get(mtp)
			if ok {
				slice := others.([]int)
				slice = append(slice, i)
				metaphoneMap.Remove(mtp)
				metaphoneMap.Add(mtp, slice)
			} else {
				metaphoneMap.Add(mtp, []int{i})
			}
		}
	}

	return metaphoneMap
}

var phoneticsLock sync.RWMutex
var phoneticsCache = make(map[string]string)

func getMetaphone(s string) string {
	phoneticsLock.RLock()
	if cached, ok := phoneticsCache[s]; ok {
		phoneticsLock.RUnlock()
		return cached
	}
	phoneticsLock.RUnlock()

	m := phonetics.EncodeMetaphone(s)
	phoneticsLock.Lock()
	phoneticsCache[s] = m
	phoneticsLock.Unlock()
	return m
}

var unicodeLock sync.RWMutex
var unicodeCache = make(map[string]string)

func preventUnicode(name string) string {
	unicodeLock.RLock()
	if cached, ok := unicodeCache[name]; ok {
		unicodeLock.RUnlock()
		return cached
	}
	oldName := name
	name = strings.ToLower(name)
	if cached, ok := unicodeCache[name]; ok {
		unicodeLock.RUnlock()
		unicodeLock.Lock()
		unicodeCache[oldName] = cached
		unicodeLock.Unlock()
		return cached
	}

	unicodeLock.RUnlock()

	clean := ""
	for _, r := range name {
		if r > 128 {
			switch r {
			case 'á', 'à', 'â':
				clean += "a"
			case 'é':
				clean += "e"
			case 'í':
				clean += "i"
			case 'ö':
				clean += "o"
			case 'û', 'ú':
				clean += "u"

			case 'Æ', 'æ':
				clean += "ae"

			case '®':
				// We know this is an option but we're explicitly ignoring it.

			default:
			}
		} else {
			if r == ' ' || unicode.IsLetter(r) {
				clean += string(r)
			}
		}
	}

	unicodeLock.Lock()
	unicodeCache[oldName] = clean
	unicodeCache[name] = clean
	unicodeLock.Unlock()

	return clean
}

type fuzzySearchList []struct {
	index      int
	similarity float32
}

func (f *fuzzySearchList) Add(index int, similarity float32) {
	for i, item := range *f {
		if item.index == index {
			if (*f)[i].similarity < similarity {
				(*f)[i].similarity = similarity
			}
			return
		}
	}

	myLen := len(*f)

	if myLen < cap(*f) {
		(*f) = (*f)[:myLen+1]
		myLen++
	}

	for i := myLen - 1; i >= 0; i-- {
		if (*f)[i].similarity < similarity {
			if i < myLen-1 {
				(*f)[i+1] = (*f)[i]
			}
			(*f)[i].index = index
			(*f)[i].similarity = similarity
		} else {
			return
		}
	}
}

// FuzzyNameSearch searches for a card with a similar name to the searchPhrase, and returns count or less of the most likely results.
func (m Multiverse) FuzzyNameSearch(searchPhrase string, count int) []*Card {
	var aggregator = make(fuzzySearchList, 0, count)
	searchPhrase = preventUnicode(searchPhrase)
	searchGrams2 := newNGram(searchPhrase, 2)
	searchGrams3 := newNGram(searchPhrase, 3)

	for _, searchTerm := range strings.Split(searchPhrase, " ") {
		for _, candidate := range m.Pronunciations.Search(getMetaphone(searchTerm)) {
			cardIndices, _ := m.Pronunciations.Get(candidate)

			for _, cardIndex := range cardIndices.([]int) {
				name := preventUnicode(m.Cards.List[cardIndex].Name)

				bestMatch := 0
				for _, word := range strings.Split(name, " ") {
					match := phonetics.DifferenceSoundex(word, searchTerm)
					if match > bestMatch {
						bestMatch = match
					}
				}

				similarity := searchGrams2.Similarity(name)
				similarity += searchGrams3.Similarity(name)
				similarity *= float32(len(name) * bestMatch)
				similarity /= float32(sift3.Sift(searchPhrase, name))

				if strings.Contains(name, searchPhrase) {
					similarity *= 50
				}

				aggregator.Add(cardIndex, similarity)
			}
		}

		for cardIndex, card := range m.Cards.List {
			for _, word := range strings.Split(preventUnicode(card.Name), " ") {
				if sift3.Sift(word, searchTerm) <= len(searchTerm)/3 {

					name := preventUnicode(card.Name)
					similarity := searchGrams2.Similarity(name)
					similarity += searchGrams3.Similarity(name)
					similarity *= float32(len(name)*phonetics.DifferenceSoundex(word, searchTerm)) / 10.0
					similarity /= float32(sift3.Sift(searchPhrase, name))

					aggregator.Add(cardIndex, similarity)
				}
			}
		}
	}

	if len(aggregator) < count {
		count = len(aggregator)
	}

	results := make([]*Card, count)

	for i, card := range aggregator {
		results[i] = m.Cards.List[card.index]
	}

	return results
}
<commit_msg>Updated to use new Search method on Trie.<commit_after>package multiverse

import (
	"strings"
	"sync"
	"unicode"

	"github.com/CasualSuperman/Diorite/trie"
	"github.com/CasualSuperman/phonetics"
	"github.com/CasualSuperman/sift3"
)

func generatePhoneticsMaps(cards []*Card) trie.Trie {
	metaphoneMap := trie.Alt()

	for i, c := range cards {
		name := preventUnicode(c.Name)
		for _, word := range strings.Split(name, " ") {
			if len(word) < 4 {
				continue
			}
			mtp := phonetics.EncodeMetaphone(word)

			others, ok := metaphoneMap.Get(mtp)
			if ok {
				slice := others.([]int)
				slice = append(slice, i)
				metaphoneMap.Remove(mtp)
				metaphoneMap.Add(mtp, slice)
			} else {
				metaphoneMap.Add(mtp, []int{i})
			}
		}
	}

	return metaphoneMap
}

var phoneticsLock sync.RWMutex
var phoneticsCache = make(map[string]string)

func getMetaphone(s string) string {
	phoneticsLock.RLock()
	if cached, ok := phoneticsCache[s]; ok {
		phoneticsLock.RUnlock()
		return cached
	}
	phoneticsLock.RUnlock()

	m := phonetics.EncodeMetaphone(s)
	phoneticsLock.Lock()
	phoneticsCache[s] = m
	phoneticsLock.Unlock()
	return m
}

var unicodeLock sync.RWMutex
var unicodeCache = make(map[string]string)

func preventUnicode(name string) string {
	unicodeLock.RLock()
	if cached, ok := unicodeCache[name]; ok {
		unicodeLock.RUnlock()
		return cached
	}
	oldName := name
	name = strings.ToLower(name)
	if cached, ok := unicodeCache[name]; ok {
		unicodeLock.RUnlock()
		unicodeLock.Lock()
		unicodeCache[oldName] = cached
		unicodeLock.Unlock()
		return cached
	}

	unicodeLock.RUnlock()

	clean := ""
	for _, r := range name {
		if r > 128 {
			switch r {
			case 'á', 'à', 'â':
				clean += "a"
			case 'é':
				clean += "e"
			case 'í':
				clean += "i"
			case 'ö':
				clean += "o"
			case 'û', 'ú':
				clean += "u"

			case 'Æ', 'æ':
				clean += "ae"

			case '®':
				// We know this is an option but we're explicitly ignoring it.

			default:
			}
		} else {
			if r == ' ' || unicode.IsLetter(r) {
				clean += string(r)
			}
		}
	}

	unicodeLock.Lock()
	unicodeCache[oldName] = clean
	unicodeCache[name] = clean
	unicodeLock.Unlock()

	return clean
}

type fuzzySearchList []struct {
	index      int
	similarity float32
}

func (f *fuzzySearchList) Add(index int, similarity float32) {
	for i, item := range *f {
		if item.index == index {
			if (*f)[i].similarity < similarity {
				(*f)[i].similarity = similarity
			}
			return
		}
	}

	myLen := len(*f)

	if myLen < cap(*f) {
		(*f) = (*f)[:myLen+1]
		myLen++
	}

	for i := myLen - 1; i >= 0; i-- {
		if (*f)[i].similarity < similarity {
			if i < myLen-1 {
				(*f)[i+1] = (*f)[i]
			}
			(*f)[i].index = index
			(*f)[i].similarity = similarity
		} else {
			return
		}
	}
}

// FuzzyNameSearch searches for a card with a similar name to the searchPhrase, and returns count or less of the most likely results.
func (m Multiverse) FuzzyNameSearch(searchPhrase string, count int) []*Card {
	var aggregator = make(fuzzySearchList, 0, count)
	searchPhrase = preventUnicode(searchPhrase)
	searchGrams2 := newNGram(searchPhrase, 2)
	searchGrams3 := newNGram(searchPhrase, 3)

	for _, searchTerm := range strings.Split(searchPhrase, " ") {
		for _, result := range m.Pronunciations.Search(getMetaphone(searchTerm)) {
			for _, cardIndex := range result.([]int) {
				name := preventUnicode(m.Cards.List[cardIndex].Name)

				bestMatch := 0
				for _, word := range strings.Split(name, " ") {
					match := phonetics.DifferenceSoundex(word, searchTerm)
					if match > bestMatch {
						bestMatch = match
					}
				}

				similarity := searchGrams2.Similarity(name)
				similarity += searchGrams3.Similarity(name)
				similarity *= float32(len(name) * bestMatch)
				similarity /= float32(sift3.Sift(searchPhrase, name))

				if strings.Contains(name, searchPhrase) {
					similarity *= 50
				}

				aggregator.Add(cardIndex, similarity)
			}
		}

		for cardIndex, card := range m.Cards.List {
			for _, word := range strings.Split(preventUnicode(card.Name), " ") {
				if sift3.Sift(word, searchTerm) <= len(searchTerm)/3 {

					name := preventUnicode(card.Name)
					similarity := searchGrams2.Similarity(name)
					similarity += searchGrams3.Similarity(name)
					similarity *= float32(len(name)*phonetics.DifferenceSoundex(word, searchTerm)) / 10.0
					similarity /= float32(sift3.Sift(searchPhrase, name))

					aggregator.Add(cardIndex, similarity)
				}
			}
		}
	}

	if len(aggregator) < count {
		count = len(aggregator)
	}

	results := make([]*Card, count)

	for i, card := range aggregator {
		results[i] = m.Cards.List[card.index]
	}

	return results
}
<|endoftext|>


<commit_before>package http2

const (
	GzipEncoding          string = "gzip"
	AcceptEncodingHeader         = "Accept-Encoding"
	ContentTypeHeader            = "Content-Type"
	ContentEncodingHeader        = "Content-Encoding"
)
<commit_msg>Add ConnectionHeader constant<commit_after>package http2

const (
	GzipEncoding          string = "gzip"
	AcceptEncodingHeader         = "Accept-Encoding"
	ContentTypeHeader            = "Content-Type"
	ContentEncodingHeader        = "Content-Encoding"
    ConnectionHeader             = "Connection"
)
<|endoftext|>