<commit_before>package bot

import (
	"math/rand"
	"regexp"
	"strings"
	"time"

	"fmt"

	. "github.com/PoolC/slack_bot/util"
	slack "github.com/nlopes/slack"
)

var (
	remember_re   *regexp.Regexp = regexp.MustCompile("^안즈쨩? 기억해? ([^/]+)/(.+)")
	tell_re       *regexp.Regexp = regexp.MustCompile("^안즈쨩? 알려줘 (.+)")
	kawaii_re     *regexp.Regexp = regexp.MustCompile("^안즈쨩? 카와이")
	give_candy_re *regexp.Regexp = regexp.MustCompile("^안즈쨩? 사탕줄게")
)

type Anzu struct {
	*BaseBot
	rc RedisClient
}

func NewAnzu(token string, stop *chan struct{}, redisClient RedisClient) *Anzu {
	return &Anzu{NewBot(token, stop), redisClient}
}

func anzuMessageProcess(bot *Anzu, e *slack.MessageEvent) interface{} {
	force_accept := false
	switch {
	case e.Text == "사람은 일을 하고 살아야한다. 메우":
		return "이거 놔라 이 퇴근도 못하는 놈이"
	case e.Text == "안즈쨩 뭐해?":
		return "숨셔"
	default:
		if AcceptRE(e.Text, give_candy_re) {
			last := bot.rc.Get(fmt.Sprintf("%s_lastfail", e.User)).Val()
			if last == "" {
				return ""
			}
			force_accept = true
			e.Text = last
		}

		if matched, ok := MatchRE(e.Text, remember_re); ok {
			key, val := strings.TrimSpace(matched[1]), strings.TrimSpace(matched[2])
			var ret string
			switch {
			case key == "" || val == "":
				ret = "에...?"
			case AcceptRE(val, tell_re):
				ret = "에... 귀찮아..."
			case force_accept:
				ret = "응응 기억했어"
				fallthrough
			case rand.Float32() < 0.4:
				bot.rc.Set(key, val, 0)
				if len(ret) == 0 {
					ret = "에... 귀찮지만 기억했어"
				}
			default:
				ret = "귀찮아..."
				bot.rc.Set(fmt.Sprintf("%s_lastfail", e.User), e.Text, time.Duration(300*time.Second))
			}

			return ret
		} else if matched, ok := MatchRE(e.Text, tell_re); ok {
			key := strings.TrimSpace(matched[1])
			val := bot.rc.Get(key).Val()
			var ret string
			switch {
			case val == "":
				ret = "그런거 몰라"
			case force_accept:
				ret = fmt.Sprintf("%s 물어봤지?\n%s\n야", key, val)
			case rand.Float32() < 0.4:
				ret = val
			default:
				bot.rc.Set(fmt.Sprintf("%s_lastfail", e.User), e.Text, time.Duration(300*time.Second))
				ret = "Zzz..."
			}
			return ret
		} else if _, ok := MatchRE(e.Text, kawaii_re); ok {
			return "뭐... 뭐라는거야"
		}
	}
	return nil
}

func (bot *Anzu) onMessageEvent(e *slack.MessageEvent) {
	message := anzuMessageProcess(bot, e)
	switch message.(type) {
	case string:
		bot.sendSimple(e, message.(string))
	}
}
<commit_msg>Update anzu.go<commit_after>package bot

import (
	"math/rand"
	"regexp"
	"strings"
	"time"

	"fmt"

	. "github.com/PoolC/slack_bot/util"
	slack "github.com/nlopes/slack"
)

var (
	remember_re   *regexp.Regexp = regexp.MustCompile("^안즈쨩? 기억해? ([^/]+)/(.+)")
	tell_re       *regexp.Regexp = regexp.MustCompile("^안즈쨩? 알려줘 (.+)")
	kawaii_re     *regexp.Regexp = regexp.MustCompile("^안즈쨩? 카와이")
	give_candy_re *regexp.Regexp = regexp.MustCompile("^안즈쨩? 사탕줄게")
)

type Anzu struct {
	*BaseBot
	rc RedisClient
}

func NewAnzu(token string, stop *chan struct{}, redisClient RedisClient) *Anzu {
	return &Anzu{NewBot(token, stop), redisClient}
}

func anzuMessageProcess(bot *Anzu, e *slack.MessageEvent) interface{} {
	force_accept := false
	switch {
	case e.Text == "사람은 일을 하고 살아야한다. 메우":
		return "이거 놔라 이 퇴근도 못하는 놈이"
	case e.Text == "안즈쨩 뭐해?":
		return "숨셔"
	default:
		if AcceptRE(e.Text, give_candy_re) {
			last := bot.rc.Get(fmt.Sprintf("%s_lastfail", e.User)).Val()
			if last == "" {
				return ""
			}
			force_accept = true
			e.Text = last
		}

		if matched, ok := MatchRE(e.Text, remember_re); ok {
			key, val := strings.TrimSpace(matched[1]), strings.TrimSpace(matched[2])
			var ret string
			switch {
			case key == "" || val == "":
				ret = "에...?"
			case AcceptRE(val, tell_re):
				ret = "에... 귀찮아..."
			case force_accept:
				ret = "응응 기억했어"
				fallthrough
			case rand.Float32() < 0.4:
				bot.rc.Set(key, val, 0)
				if len(ret) == 0 {
					ret = "에... 귀찮지만 기억했어"
				}
			default:
				ret = "귀찮아..."
				bot.rc.Set(fmt.Sprintf("%s_lastfail", e.User), e.Text, time.Duration(300*time.Second))
			}

			return ret
		} else if matched, ok := MatchRE(e.Text, tell_re); ok {
			key := strings.TrimSpace(matched[1])
			val := bot.rc.Get(key).Val()
			var ret string
			switch {
			case val == "":
				ret = "그런거 몰라"
			case force_accept:
				ret = fmt.Sprintf("%s 물어봤지? %s 야", key, val)
			case rand.Float32() < 0.4:
				ret = val
			default:
				bot.rc.Set(fmt.Sprintf("%s_lastfail", e.User), e.Text, time.Duration(300*time.Second))
				ret = "Zzz..."
			}
			return ret
		} else if _, ok := MatchRE(e.Text, kawaii_re); ok {
			return "뭐... 뭐라는거야"
		}
	}
	return nil
}

func (bot *Anzu) onMessageEvent(e *slack.MessageEvent) {
	message := anzuMessageProcess(bot, e)
	switch message.(type) {
	case string:
		bot.sendSimple(e, message.(string))
	}
}
<|endoftext|>


<commit_before>package godirwalk

// On unix we don't need to fixup pathnames with symlinks when doing a Stat().
func evalSymlinksHelper(pathname string) (string, error) {
	return pathname, nil
}
<commit_msg>add Unix build tags<commit_after>// +build darwin freebsd linux netbsd openbsd

package godirwalk

// On unix we don't need to fixup pathnames with symlinks when doing a Stat().
func evalSymlinksHelper(pathname string) (string, error) {
	return pathname, nil
}
<|endoftext|>


<commit_before>package column

import (
	"net"

	"github.com/kshvakov/clickhouse/lib/binary"
)

type IPv4 struct {
	base
}

func (*IPv4) Read(decoder *binary.Decoder) (interface{}, error) {
	v, err := decoder.Fixed(4)
	if err != nil {
		return nil, err
	}
	return net.IPv4(v[0], v[1], v[2], v[3]), nil
}

func (ip *IPv4) Write(encoder *binary.Encoder, v interface{}) error {
	netIP, ok := v.(net.IP)
	if !ok {
		return &ErrUnexpectedType{
			T:      v,
			Column: ip,
		}
	}
	if _, err := encoder.Write([]byte(netIP.To4())); err != nil {
		return err
	}
	return nil
}
<commit_msg>Fix IPv4 endianness<commit_after>package column

import (
	"net"

	"github.com/kshvakov/clickhouse/lib/binary"
)

type IPv4 struct {
	base
}

func (*IPv4) Read(decoder *binary.Decoder) (interface{}, error) {
	v, err := decoder.Fixed(4)
	if err != nil {
		return nil, err
	}
	return net.IPv4(v[3], v[2], v[1], v[0]), nil
}

func (ip *IPv4) Write(encoder *binary.Encoder, v interface{}) error {
	netIP, ok := v.(net.IP)
	if !ok {
		return &ErrUnexpectedType{
			T:      v,
			Column: ip,
		}
	}
	ip4 := netIP.To4()
	if _, err := encoder.Write([]byte{ip4[3], ip4[2], ip4[1], ip4[0]}); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package nut

import (
	"testing"
	"time"
)

var stringTests = []struct {
	in  string
	out string
	ok  bool
}{
	// @todo: tests go here
}

var intTests = []struct {
	in  string
	out int64
	ok  bool
}{
	// decimal
	{"0", 0, true},
	{"10", 10, true},
	{"123456789", 123456789, true},

	// hexadecimal
	{"0x02", 2, true},
	{"0xff", 255, true},
	{"0xc", 12, true},

	// octal
	{"010", 8, true},
	{"01234567", 342391, true},
	{"012345678", 0, false},

	// signs
	{"+0", 0, true},
	{"-0", 0, true},
	{"+10", 10, true},
	{"-0x00", 0, true},
	{"-0x10", -16, true},
	{"+01", 1, true},
	{"-010", -8, true},

	// limits
	{"9223372036854775807", 1<<63 - 1, true},
	{"9223372036854775808", 0, false},
	{"9223372036854775809", 0, false},
	{"-9223372036854775807", -(1<<63 - 1), true},
	{"-9223372036854775808", -1 << 63, true},
	{"-9223372036854775809", 0, false},

	{"0x7FFFFFFFFFFFFFFF", 1<<63 - 1, true},
	{"0X8000000000000000", 0, false},
	{"0X8000000000000001", 0, false},
	{"-0x7FFFFFFFFFFFFFFF", -(1<<63 - 1), true},
	{"-0X8000000000000000", -1 << 63, true},
	{"-0X8000000000000001", 0, false},

	{"0777777777777777777777", 1<<63 - 1, true},
	{"01000000000000000000000", 0, false},
	{"01000000000000000000001", 0, false},
	{"-0777777777777777777777", -(1<<63 - 1), true},
	{"-01000000000000000000000", -1 << 63, true},
	{"-01000000000000000000001", 0, false},

	// invalid
	{"", 0, false},
	{"abc", 0, false},
	{"100 blue", 0, false},
	{"-0-", 0, false},
	{"++0", 0, false},
}

var boolTests = []struct {
	in  string
	out bool
	ok  bool
}{
	// truthy
	{"true", true, true},
	{"yes", true, true},
	{"on", true, true},

	// falsy
	{"false", false, true},
	{"no", false, true},
	{"off", false, true},

	// invalid
	{"", false, false},
	{"y", false, false},
	{"foo", false, false},
}

var durationTests = []struct {
	in  string
	out time.Duration
	ok  bool
}{
	// simple formats
	{"0", 0, true},
	{"0s", 0, true},
	{"5s", 5 * time.Second, true},
	{"37s", 37 * time.Second, true},
	{"010s", 10 * time.Second, true},
	{"3d", 3 * 24 * time.Hour, true},

	// all units
	{"10ns", 10 * time.Nanosecond, true},
	{"10µs", 10 * time.Microsecond, true},
	{"10μs", 10 * time.Microsecond, true},
	{"10us", 10 * time.Microsecond, true},
	{"10ms", 10 * time.Millisecond, true},
	{"10s", 10 * time.Second, true},
	{"10m", 10 * time.Minute, true},
	{"10h", 10 * time.Hour, true},
	{"10d", 10 * 24 * time.Hour, true},
	{"10w", 10 * 7 * 24 * time.Hour, true},

	// mixed units
	{"1h1m1s", time.Hour + time.Minute + time.Second, true},
	{"4h30m", 4*time.Hour + 30*time.Minute, true},
	{"1s500ms", time.Second + 500*time.Millisecond, true},
	{"1w1d24h1440m", 10 * 24 * time.Hour, true},

	// allow (ignore) spaces
	{"1h 1m1s", time.Hour + time.Minute + time.Second, true},
	{"4h 30m", 4*time.Hour + 30*time.Minute, true},
	{"1s    500ms", time.Second + 500*time.Millisecond, true},
	{"1w 1d 24h 1440m", 10 * 24 * time.Hour, true},

	// disallow signs and decimal values
	{"-3h", 0, false},
	{"+5m", 0, false},
	{"300.5h", 0, false},
	{"1h 1m 1.3s", 0, false},
	{"10w -3d", 0, false},
	{"1.2d20m", 0, false},

	// units out of order
	{"1s2m", 0, false},
	{"1200ms 3s", 0, false},
	{"4h 5d 6w 7m", 0, false},

	// other invalid formats
	{"", 0, false},
	{"1sm", 0, false},
	{"2 m 3 s", 0, false},
	{"4 d5 h", 0, false},
	{"100", 0, false},
	{"1d 200", 0, false},
	{"3 4 5ms", 0, false},
}

var timeTests = []struct {
	in  string
	out *time.Time
	ok  bool
}{
	// @todo: tests go here
}

func TestParseString(t *testing.T) {
	for _, test := range stringTests {
		fail := setup(t, "parseString", test.in)
		out, ok := parseString(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test.out)
		}
	}
}

func TestParseInt(t *testing.T) {
	for _, test := range intTests {
		fail := setup(t, "parseInt", test.in)
		out, ok := parseInt(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test.out)
		}
	}
}

func TestParseBool(t *testing.T) {
	for _, test := range boolTests {
		fail := setup(t, "parseBool", test.in)
		out, ok := parseBool(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test)
		}
	}
}

func TestParseDuration(t *testing.T) {
	for _, test := range durationTests {
		fail := setup(t, "parseDuration", test.in)
		out, ok := parseDuration(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%s != %s", out.String(), test.out.String())
		}
	}
}

func TestParseTime(t *testing.T) {
	for _, test := range timeTests {
		fail := setup(t, "parseTime", test.in)
		out, ok := parseTime(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out == nil {
			if test.out != nil {
				fail("returned nil")
			}
			continue
		}

		if !out.Equal(*test.out) {
			fail("%s != %s", out.String(), test.out.String())
		}
	}
}

// Simplify failure reporting.
type failFunc func(format string, values ...interface{})

func setup(t *testing.T, signature string, input interface{}) failFunc {
	return func(format string, values ...interface{}) {
		args := append([]interface{}{signature, input}, values...)
		t.Errorf("%s(%#v): "+format+"\n", args...)
	}
}

// Convenience function for creating a `time.Time` struct of a certain value,
// then returning a pointer to it.
func moment(value string) *time.Time {
	t, err := time.Parse("2006-01-02 15:04:05 -07:00", value)
	if err != nil {
		panic(err)
	}

	return &t
}
<commit_msg>Update `parseTime()` signature<commit_after>package nut

import (
	"testing"
	"time"
)

var stringTests = []struct {
	in  string
	out string
	ok  bool
}{
	// @todo: tests go here
}

var intTests = []struct {
	in  string
	out int64
	ok  bool
}{
	// decimal
	{"0", 0, true},
	{"10", 10, true},
	{"123456789", 123456789, true},

	// hexadecimal
	{"0x02", 2, true},
	{"0xff", 255, true},
	{"0xc", 12, true},

	// octal
	{"010", 8, true},
	{"01234567", 342391, true},
	{"012345678", 0, false},

	// signs
	{"+0", 0, true},
	{"-0", 0, true},
	{"+10", 10, true},
	{"-0x00", 0, true},
	{"-0x10", -16, true},
	{"+01", 1, true},
	{"-010", -8, true},

	// limits
	{"9223372036854775807", 1<<63 - 1, true},
	{"9223372036854775808", 0, false},
	{"9223372036854775809", 0, false},
	{"-9223372036854775807", -(1<<63 - 1), true},
	{"-9223372036854775808", -1 << 63, true},
	{"-9223372036854775809", 0, false},

	{"0x7FFFFFFFFFFFFFFF", 1<<63 - 1, true},
	{"0X8000000000000000", 0, false},
	{"0X8000000000000001", 0, false},
	{"-0x7FFFFFFFFFFFFFFF", -(1<<63 - 1), true},
	{"-0X8000000000000000", -1 << 63, true},
	{"-0X8000000000000001", 0, false},

	{"0777777777777777777777", 1<<63 - 1, true},
	{"01000000000000000000000", 0, false},
	{"01000000000000000000001", 0, false},
	{"-0777777777777777777777", -(1<<63 - 1), true},
	{"-01000000000000000000000", -1 << 63, true},
	{"-01000000000000000000001", 0, false},

	// invalid
	{"", 0, false},
	{"abc", 0, false},
	{"100 blue", 0, false},
	{"-0-", 0, false},
	{"++0", 0, false},
}

var boolTests = []struct {
	in  string
	out bool
	ok  bool
}{
	// truthy
	{"true", true, true},
	{"yes", true, true},
	{"on", true, true},

	// falsy
	{"false", false, true},
	{"no", false, true},
	{"off", false, true},

	// invalid
	{"", false, false},
	{"y", false, false},
	{"foo", false, false},
}

var durationTests = []struct {
	in  string
	out time.Duration
	ok  bool
}{
	// simple formats
	{"0", 0, true},
	{"0s", 0, true},
	{"5s", 5 * time.Second, true},
	{"37s", 37 * time.Second, true},
	{"010s", 10 * time.Second, true},
	{"3d", 3 * 24 * time.Hour, true},

	// all units
	{"10ns", 10 * time.Nanosecond, true},
	{"10µs", 10 * time.Microsecond, true},
	{"10μs", 10 * time.Microsecond, true},
	{"10us", 10 * time.Microsecond, true},
	{"10ms", 10 * time.Millisecond, true},
	{"10s", 10 * time.Second, true},
	{"10m", 10 * time.Minute, true},
	{"10h", 10 * time.Hour, true},
	{"10d", 10 * 24 * time.Hour, true},
	{"10w", 10 * 7 * 24 * time.Hour, true},

	// mixed units
	{"1h1m1s", time.Hour + time.Minute + time.Second, true},
	{"4h30m", 4*time.Hour + 30*time.Minute, true},
	{"1s500ms", time.Second + 500*time.Millisecond, true},
	{"1w1d24h1440m", 10 * 24 * time.Hour, true},

	// allow (ignore) spaces
	{"1h 1m1s", time.Hour + time.Minute + time.Second, true},
	{"4h 30m", 4*time.Hour + 30*time.Minute, true},
	{"1s    500ms", time.Second + 500*time.Millisecond, true},
	{"1w 1d 24h 1440m", 10 * 24 * time.Hour, true},

	// disallow signs and decimal values
	{"-3h", 0, false},
	{"+5m", 0, false},
	{"300.5h", 0, false},
	{"1h 1m 1.3s", 0, false},
	{"10w -3d", 0, false},
	{"1.2d20m", 0, false},

	// units out of order
	{"1s2m", 0, false},
	{"1200ms 3s", 0, false},
	{"4h 5d 6w 7m", 0, false},

	// other invalid formats
	{"", 0, false},
	{"1sm", 0, false},
	{"2 m 3 s", 0, false},
	{"4 d5 h", 0, false},
	{"100", 0, false},
	{"1d 200", 0, false},
	{"3 4 5ms", 0, false},
}

var timeTests = []struct {
	in  string
	out time.Time
	ok  bool
}{
	// @todo: tests go here
}

func TestParseString(t *testing.T) {
	for _, test := range stringTests {
		fail := setup(t, "parseString", test.in)
		out, ok := parseString(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test.out)
		}
	}
}

func TestParseInt(t *testing.T) {
	for _, test := range intTests {
		fail := setup(t, "parseInt", test.in)
		out, ok := parseInt(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test.out)
		}
	}
}

func TestParseBool(t *testing.T) {
	for _, test := range boolTests {
		fail := setup(t, "parseBool", test.in)
		out, ok := parseBool(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test)
		}
	}
}

func TestParseDuration(t *testing.T) {
	for _, test := range durationTests {
		fail := setup(t, "parseDuration", test.in)
		out, ok := parseDuration(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%s != %s", out.String(), test.out.String())
		}
	}
}

func TestParseTime(t *testing.T) {
	for _, test := range timeTests {
		fail := setup(t, "parseTime", test.in)
		out, ok := parseTime(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if !out.Equal(test.out) {
			fail("%s != %s", out.String(), test.out.String())
		}
	}
}

// Simplify failure reporting.
type failFunc func(format string, values ...interface{})

func setup(t *testing.T, signature string, input interface{}) failFunc {
	return func(format string, values ...interface{}) {
		args := append([]interface{}{signature, input}, values...)
		t.Errorf("%s(%#v): "+format+"\n", args...)
	}
}

// Reduced version of `time.Date`.
func date(y, m, d, H, M, S, ms int) time.Time {
	month := time.Month(m)
	nano := ms * int(time.Millisecond)

	return time.Date(y, month, d, H, M, S, nano, time.UTC)
}
<|endoftext|>


<commit_before>// Copyright 2014 Brian J. Downs
//
// 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 formatifier

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

// ToPhone will format the provided string as a Phone Number.  Only supports
// US numbers currently.
func ToPhone(theString, delimiter string) (string, error) {
	if len(theString) < 10 {
		return "", errors.New(lengthError)
	}

	f := New(theString)
	f.removeNonDigits()

	var buffer bytes.Buffer
	count := 0
	switch len(f.theString) {
	case 10:
		buffer.WriteString("(")
		for _, i := range f.theString {
			count++
			buffer.WriteString(string(i))
			switch count {
			case 3:
				buffer.WriteString(") ")
			case 6:
				buffer.WriteString(fmt.Sprintf("%s", delimiter))
			}
		}
	case 11:
		for _, i := range f.theString {
			count++
			buffer.WriteString(string(i))
			switch count {
			case 1:
				buffer.WriteString(" (")
			case 4:
				buffer.WriteString(") ")
			case 7:
				buffer.WriteString(fmt.Sprintf("%s", delimiter))
			}
		}
	}
	return buffer.String(), nil
}

// ToURL will format the provided string as a URL.  HTTP and HTTPS
// are the only supported protocols at this time.
func ToURL(theString, subdomain string, secure bool) (string, error) {
	// I'm assuming we have at least a 1 character domain, a dot, and a two
	// char TLD.
	if len(theString) < 4 {
		return "", errors.New(lengthError)
	}

	f := New(theString)
	f.makeLower()

	if secure {
		if len(subdomain) > 0 {
			return fmt.Sprintf("https://%s.%s", subdomain, f.theString), nil
		}
		return fmt.Sprintf("https://%s", f.theString), nil
	}

	if len(subdomain) > 0 {
		return fmt.Sprintf("http://%s.%s", subdomain, f.theString), nil
	}
	return fmt.Sprintf("http://%s", f.theString), nil
}

// ToSSN will format the provided string as a SSN.
func ToSSN(theString, delimiter string) (string, error) {
	f := New(theString)
	f.removeNonDigits()

	if len(f.theString) != 9 {
		return "", errors.New("ERROR: String needs to be 9 digits for Social Security Numbers")
	}

	var buffer bytes.Buffer
	count := 0

	for _, i := range f.theString {
		count++

		buffer.WriteString(string(i))

		if count == 3 || count == 5 {
			buffer.WriteString(delimiter)
		}
	}
	return buffer.String(), nil
}

// ToLockCombo will format the provided string as a Lock Combo.
func ToLockCombo(theString, delimiter string) (string, error) {
	f := New(theString)
	f.removeNonDigits()

	if len(f.theString) != 6 {
		return "", errors.New("ERROR: String needs to be 6 digits for Lock Combo format")
	}

	var buffer bytes.Buffer
	count := 0

	for _, i := range f.theString {
		count++

		buffer.WriteString(string(i))

		if count == 2 || count == 4 {
			buffer.WriteString(delimiter)
		}
	}
	return buffer.String(), nil
}

// ToISBN will format the provided string in International Standard Book Number
// (ISBN) format.
func ToISBN(theString, delimiter string) (string, error) {
	f := New(theString)
	f.removeNonDigits()

	if len(f.theString) != 13 {
		return "", errors.New("ERROR: string must be 13 characters")
	}

	var buffer bytes.Buffer
	count := 0

	for _, i := range f.theString {
		count++

		buffer.WriteString(string(i))

		if count == 3 || count == 4 || count == 6 || count == 12 {
			buffer.WriteString(delimiter)
		}
	}
	return buffer.String(), nil
}

// ToMorseCode will format the provided string in Morse Code.
func ToMorseCode(theString string) (string, error) {
	f := New(theString)

	if len(f.theString) < 1 {
		return "", errors.New(lengthError)
	}

	f.makeLower()

	var buffer bytes.Buffer

	for _, i := range f.theString {
		key := string(i)
		if _, ok := morse[key]; ok {
			buffer.WriteString(morse[key])
		} else if key == " " {
			buffer.WriteString(" ")
		}
	}
	return buffer.String(), nil
}

// ToPirateSpeak will format the provided string in Pirate Speak.
func ToPirateSpeak(theString string) (string, error) {
	f := New(theString)

	if len(f.theString) < 1 {
		return "", errors.New(lengthError)
	}

	f.urlEncodeSpaces()

	response, err := http.Get(fmt.Sprintf(pirateLink, f.theString))
	if err != nil {
		return "", errors.New("ERROR: Unable to convert")
	}
	defer response.Body.Close()

	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return "", err
	}
	return string(contents), nil
}

// ToIRSA will format the provided string in IRSA.
// International Radio-Telephony Spelling Alphabet
func ToIRSA(theString string) (string, error) {
	f := New(theString)

	if len(f.theString) < 1 {
		return "", errors.New(lengthError)
	}

	f.makeLower()

	var buffer bytes.Buffer

	for _, i := range f.theString {
		key := strings.ToLower(string(i))
		if _, ok := irsa[key]; ok {
			buffer.WriteString(irsa[key] + " ")
		}
	}
	return buffer.String(), nil
}

// ToLeet will format the provided string in Leet Speak.
// TODO(briandowns) Make select post match random.
func ToLeet(theString string) (string, error) {
	f := New(theString)

	if len(f.theString) < 1 {
		return "", errors.New(lengthError)
	}

	f.makeLower()

	words := strings.Fields(f.theString)
	var buffer bytes.Buffer

	for _, word := range words {
		key := string(word)
		if _, ok := leet[word]; ok {
			buffer.WriteString(leet[key][0] + " ")
		} else {
			for _, i := range word {
				letter := string(i)
				if _, ok := leet[letter]; ok {
					buffer.WriteString(leet[letter][0])
				}
			}
			buffer.WriteString(" ")
		}
	}
	return buffer.String(), nil
}
<commit_msg>added catch in ToPhone to account for non US numbers.<commit_after>// Copyright 2014 Brian J. Downs
//
// 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 formatifier

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

// ToPhone will format the provided string as a Phone Number.  Only supports
// US numbers currently.
func ToPhone(theString, delimiter string) (string, error) {
	if len(theString) < 10 {
		return "", errors.New(lengthError)
	}

	f := New(theString)
	f.removeNonDigits()

	var buffer bytes.Buffer
	count := 0
	switch len(f.theString) {
	case 10:
		buffer.WriteString("(")
		for _, i := range f.theString {
			count++
			buffer.WriteString(string(i))
			switch count {
			case 3:
				buffer.WriteString(") ")
			case 6:
				buffer.WriteString(fmt.Sprintf("%s", delimiter))
			}
		}
	case 11:
		for _, i := range f.theString {
			count++
			buffer.WriteString(string(i))
			switch count {
			case 1:
				buffer.WriteString(" (")
			case 4:
				buffer.WriteString(") ")
			case 7:
				buffer.WriteString(fmt.Sprintf("%s", delimiter))
			}
		}
	default:
		return "", errors.New("ERROR: Non US number given")
	}
	return buffer.String(), nil
}

// ToURL will format the provided string as a URL.  HTTP and HTTPS
// are the only supported protocols at this time.
func ToURL(theString, subdomain string, secure bool) (string, error) {
	// I'm assuming we have at least a 1 character domain, a dot, and a two
	// char TLD.
	if len(theString) < 4 {
		return "", errors.New(lengthError)
	}

	f := New(theString)
	f.makeLower()

	if secure {
		if len(subdomain) > 0 {
			return fmt.Sprintf("https://%s.%s", subdomain, f.theString), nil
		}
		return fmt.Sprintf("https://%s", f.theString), nil
	}

	if len(subdomain) > 0 {
		return fmt.Sprintf("http://%s.%s", subdomain, f.theString), nil
	}
	return fmt.Sprintf("http://%s", f.theString), nil
}

// ToSSN will format the provided string as a SSN.
func ToSSN(theString, delimiter string) (string, error) {
	f := New(theString)
	f.removeNonDigits()

	if len(f.theString) != 9 {
		return "", errors.New("ERROR: String needs to be 9 digits for Social Security Numbers")
	}

	var buffer bytes.Buffer
	count := 0

	for _, i := range f.theString {
		count++

		buffer.WriteString(string(i))

		if count == 3 || count == 5 {
			buffer.WriteString(delimiter)
		}
	}
	return buffer.String(), nil
}

// ToLockCombo will format the provided string as a Lock Combo.
func ToLockCombo(theString, delimiter string) (string, error) {
	f := New(theString)
	f.removeNonDigits()

	if len(f.theString) != 6 {
		return "", errors.New("ERROR: String needs to be 6 digits for Lock Combo format")
	}

	var buffer bytes.Buffer
	count := 0

	for _, i := range f.theString {
		count++

		buffer.WriteString(string(i))

		if count == 2 || count == 4 {
			buffer.WriteString(delimiter)
		}
	}
	return buffer.String(), nil
}

// ToISBN will format the provided string in International Standard Book Number
// (ISBN) format.
func ToISBN(theString, delimiter string) (string, error) {
	f := New(theString)
	f.removeNonDigits()

	if len(f.theString) != 13 {
		return "", errors.New("ERROR: string must be 13 characters")
	}

	var buffer bytes.Buffer
	count := 0

	for _, i := range f.theString {
		count++

		buffer.WriteString(string(i))

		if count == 3 || count == 4 || count == 6 || count == 12 {
			buffer.WriteString(delimiter)
		}
	}
	return buffer.String(), nil
}

// ToMorseCode will format the provided string in Morse Code.
func ToMorseCode(theString string) (string, error) {
	f := New(theString)

	if len(f.theString) < 1 {
		return "", errors.New(lengthError)
	}

	f.makeLower()

	var buffer bytes.Buffer

	for _, i := range f.theString {
		key := string(i)
		if _, ok := morse[key]; ok {
			buffer.WriteString(morse[key])
		} else if key == " " {
			buffer.WriteString(" ")
		}
	}
	return buffer.String(), nil
}

// ToPirateSpeak will format the provided string in Pirate Speak.
func ToPirateSpeak(theString string) (string, error) {
	f := New(theString)

	if len(f.theString) < 1 {
		return "", errors.New(lengthError)
	}

	f.urlEncodeSpaces()

	response, err := http.Get(fmt.Sprintf(pirateLink, f.theString))
	if err != nil {
		return "", errors.New("ERROR: Unable to convert")
	}
	defer response.Body.Close()

	contents, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return "", err
	}
	return string(contents), nil
}

// ToIRSA will format the provided string in IRSA.
// International Radio-Telephony Spelling Alphabet
func ToIRSA(theString string) (string, error) {
	f := New(theString)

	if len(f.theString) < 1 {
		return "", errors.New(lengthError)
	}

	f.makeLower()

	var buffer bytes.Buffer

	for _, i := range f.theString {
		key := strings.ToLower(string(i))
		if _, ok := irsa[key]; ok {
			buffer.WriteString(irsa[key] + " ")
		}
	}
	return buffer.String(), nil
}

// ToLeet will format the provided string in Leet Speak.
// TODO(briandowns) Make select post match random.
func ToLeet(theString string) (string, error) {
	f := New(theString)

	if len(f.theString) < 1 {
		return "", errors.New(lengthError)
	}

	f.makeLower()

	words := strings.Fields(f.theString)
	var buffer bytes.Buffer

	for _, word := range words {
		key := string(word)
		if _, ok := leet[word]; ok {
			buffer.WriteString(leet[key][0] + " ")
		} else {
			for _, i := range word {
				letter := string(i)
				if _, ok := leet[letter]; ok {
					buffer.WriteString(leet[letter][0])
				}
			}
			buffer.WriteString(" ")
		}
	}
	return buffer.String(), nil
}
<|endoftext|>


<commit_before>package tview

import (
	"fmt"
	"os"
	"sync"

	"github.com/gdamore/tcell"
)

// Application represents the top node of an application.
//
// It is not strictly required to use this class as none of the other classes
// depend on it. However, it provides useful tools to set up an application and
// plays nicely with all widgets.
type Application struct {
	sync.RWMutex

	// The application's screen.
	screen tcell.Screen

	// The primitive which currently has the keyboard focus.
	focus Primitive

	// The root primitive to be seen on the screen.
	root Primitive

	// Whether or not the application resizes the root primitive.
	rootFullscreen bool

	// An optional capture function which receives a key event and returns the
	// event to be forwarded to the default input handler (nil if nothing should
	// be forwarded).
	inputCapture func(event *tcell.EventKey) *tcell.EventKey

	// An optional callback function which is invoked just before the root
	// primitive is drawn.
	beforeDraw func(screen tcell.Screen) bool

	// An optional callback function which is invoked after the root primitive
	// was drawn.
	afterDraw func(screen tcell.Screen)

	// Used for events loop lock during Suspend()
	suspendMutex sync.Mutex
}

// NewApplication creates and returns a new application.
func NewApplication() *Application {
	return &Application{}
}

// SetInputCapture sets a function which captures all key events before they are
// forwarded to the key event handler of the primitive which currently has
// focus. This function can then choose to forward that key event (or a
// different one) by returning it or stop the key event processing by returning
// nil.
//
// Note that this also affects the default event handling of the application
// itself: Such a handler can intercept the Ctrl-C event which closes the
// applicatoon.
func (a *Application) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) *Application {
	a.inputCapture = capture
	return a
}

// GetInputCapture returns the function installed with SetInputCapture() or nil
// if no such function has been installed.
func (a *Application) GetInputCapture() func(event *tcell.EventKey) *tcell.EventKey {
	return a.inputCapture
}

// Run starts the application and thus the event loop. This function returns
// when Stop() was called.
func (a *Application) Run() error {
	var err error
	a.Lock()

	// Make a screen.
	a.screen, err = tcell.NewScreen()
	if err != nil {
		a.Unlock()
		return err
	}
	if err = a.screen.Init(); err != nil {
		a.Unlock()
		return err
	}

	// We catch panics to clean up because they mess up the terminal.
	defer func() {
		if p := recover(); p != nil {
			if a.screen != nil {
				a.screen.Fini()
			}
			panic(p)
		}
	}()

	// Draw the screen for the first time.
	a.Unlock()
	a.Draw()

	// Start event loop.
	for {
		// Do not poll events during suspend mode
		a.suspendMutex.Lock()
		a.Lock()
		screen := a.screen
		a.Unlock()
		if screen == nil {
			a.suspendMutex.Unlock()
			break
		}

		// Wait for next event.
		event := a.screen.PollEvent()
		a.suspendMutex.Unlock()
		if event == nil {
			// The screen was finalized. Exit the loop.
			break
		}

		switch event := event.(type) {
		case *tcell.EventKey:
			a.RLock()
			p := a.focus
			a.RUnlock()

			// Intercept keys.
			if a.inputCapture != nil {
				event = a.inputCapture(event)
				if event == nil {
					break // Don't forward event.
				}
			}

			// Ctrl-C closes the application.
			if event.Key() == tcell.KeyCtrlC {
				a.Stop()
			}

			// Pass other key events to the currently focused primitive.
			if p != nil {
				if handler := p.InputHandler(); handler != nil {
					handler(event, func(p Primitive) {
						a.SetFocus(p)
					})
					a.Draw()
				}
			}
		case *tcell.EventResize:
			a.Lock()
			screen := a.screen
			a.Unlock()
			screen.Clear()
			a.Draw()
		}
	}

	return nil
}

// Stop stops the application, causing Run() to return.
func (a *Application) Stop() {
	a.RLock()
	defer a.RUnlock()
	if a.screen == nil {
		return
	}
	a.screen.Fini()
	a.screen = nil
}

// Suspend temporarily suspends the application by exiting terminal UI mode and
// invoking the provided function "f". When "f" returns, terminal UI mode is
// entered again and the application resumes.
//
// A return value of true indicates that the application was suspended and "f"
// was called. If false is returned, the application was already suspended,
// terminal UI mode was not exited, and "f" was not called.
func (a *Application) Suspend(f func()) bool {
	a.Lock()

	if a.screen == nil {
		// Application is already suspended.
		a.Unlock()
		return false
	}

	// Enter suspended mode.
	a.suspendMutex.Lock()
	a.Unlock()
	a.Stop()

	// Deal with panics during suspended mode. Exit the program.
	defer func() {
		if p := recover(); p != nil {
			fmt.Println(p)
			os.Exit(1)
		}
	}()

	// Wait for "f" to return.
	f()

	// Make a new screen and redraw.
	a.Lock()
	var err error
	a.screen, err = tcell.NewScreen()
	if err != nil {
		a.suspendMutex.Unlock()
		a.Unlock()
		panic(err)
	}
	if err = a.screen.Init(); err != nil {
		a.suspendMutex.Unlock()
		a.Unlock()
		panic(err)
	}
	a.Unlock()
	a.Draw()

	// Continue application loop.
	a.suspendMutex.Unlock()
	return true
}

// Draw refreshes the screen. It calls the Draw() function of the application's
// root primitive and then syncs the screen buffer.
func (a *Application) Draw() *Application {
	a.RLock()
	screen := a.screen
	root := a.root
	fullscreen := a.rootFullscreen
	before := a.beforeDraw
	after := a.afterDraw
	a.RUnlock()

	// Maybe we're not ready yet or not anymore.
	if screen == nil || root == nil {
		return a
	}

	// Resize if requested.
	if fullscreen && root != nil {
		width, height := screen.Size()
		root.SetRect(0, 0, width, height)
	}

	// Call before handler if there is one.
	if before != nil {
		if before(screen) {
			screen.Show()
			return a
		}
	}

	// Draw all primitives.
	root.Draw(screen)

	// Call after handler if there is one.
	if after != nil {
		after(screen)
	}

	// Sync screen.
	screen.Show()

	return a
}

// SetBeforeDrawFunc installs a callback function which is invoked just before
// the root primitive is drawn during screen updates. If the function returns
// true, drawing will not continue, i.e. the root primitive will not be drawn
// (and an after-draw-handler will not be called).
//
// Note that the screen is not cleared by the application. To clear the screen,
// you may call screen.Clear().
//
// Provide nil to uninstall the callback function.
func (a *Application) SetBeforeDrawFunc(handler func(screen tcell.Screen) bool) *Application {
	a.beforeDraw = handler
	return a
}

// GetBeforeDrawFunc returns the callback function installed with
// SetBeforeDrawFunc() or nil if none has been installed.
func (a *Application) GetBeforeDrawFunc() func(screen tcell.Screen) bool {
	return a.beforeDraw
}

// SetAfterDrawFunc installs a callback function which is invoked after the root
// primitive was drawn during screen updates.
//
// Provide nil to uninstall the callback function.
func (a *Application) SetAfterDrawFunc(handler func(screen tcell.Screen)) *Application {
	a.afterDraw = handler
	return a
}

// GetAfterDrawFunc returns the callback function installed with
// SetAfterDrawFunc() or nil if none has been installed.
func (a *Application) GetAfterDrawFunc() func(screen tcell.Screen) {
	return a.afterDraw
}

// SetRoot sets the root primitive for this application. If "fullscreen" is set
// to true, the root primitive's position will be changed to fill the screen.
//
// This function must be called at least once or nothing will be displayed when
// the application starts.
//
// It also calls SetFocus() on the primitive.
func (a *Application) SetRoot(root Primitive, fullscreen bool) *Application {
	a.Lock()
	a.root = root
	a.rootFullscreen = fullscreen
	if a.screen != nil {
		a.screen.Clear()
	}
	a.Unlock()

	a.SetFocus(root)

	return a
}

// ResizeToFullScreen resizes the given primitive such that it fills the entire
// screen.
func (a *Application) ResizeToFullScreen(p Primitive) *Application {
	a.RLock()
	width, height := a.screen.Size()
	a.RUnlock()
	p.SetRect(0, 0, width, height)
	return a
}

// SetFocus sets the focus on a new primitive. All key events will be redirected
// to that primitive. Callers must ensure that the primitive will handle key
// events.
//
// Blur() will be called on the previously focused primitive. Focus() will be
// called on the new primitive.
func (a *Application) SetFocus(p Primitive) *Application {
	a.Lock()
	if a.focus != nil {
		a.focus.Blur()
	}
	a.focus = p
	if a.screen != nil {
		a.screen.HideCursor()
	}
	a.Unlock()
	if p != nil {
		p.Focus(func(p Primitive) {
			a.SetFocus(p)
		})
	}

	return a
}

// GetFocus returns the primitive which has the current focus. If none has it,
// nil is returned.
func (a *Application) GetFocus() Primitive {
	a.RLock()
	defer a.RUnlock()
	return a.focus
}
<commit_msg>Review feedback<commit_after>package tview

import (
	"fmt"
	"os"
	"sync"

	"github.com/gdamore/tcell"
)

// Application represents the top node of an application.
//
// It is not strictly required to use this class as none of the other classes
// depend on it. However, it provides useful tools to set up an application and
// plays nicely with all widgets.
type Application struct {
	sync.RWMutex

	// The application's screen.
	screen tcell.Screen

	// The primitive which currently has the keyboard focus.
	focus Primitive

	// The root primitive to be seen on the screen.
	root Primitive

	// Whether or not the application resizes the root primitive.
	rootFullscreen bool

	// An optional capture function which receives a key event and returns the
	// event to be forwarded to the default input handler (nil if nothing should
	// be forwarded).
	inputCapture func(event *tcell.EventKey) *tcell.EventKey

	// An optional callback function which is invoked just before the root
	// primitive is drawn.
	beforeDraw func(screen tcell.Screen) bool

	// An optional callback function which is invoked after the root primitive
	// was drawn.
	afterDraw func(screen tcell.Screen)

	// Halts the event loop during suspended mode
	suspendMutex sync.Mutex
}

// NewApplication creates and returns a new application.
func NewApplication() *Application {
	return &Application{}
}

// SetInputCapture sets a function which captures all key events before they are
// forwarded to the key event handler of the primitive which currently has
// focus. This function can then choose to forward that key event (or a
// different one) by returning it or stop the key event processing by returning
// nil.
//
// Note that this also affects the default event handling of the application
// itself: Such a handler can intercept the Ctrl-C event which closes the
// applicatoon.
func (a *Application) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) *Application {
	a.inputCapture = capture
	return a
}

// GetInputCapture returns the function installed with SetInputCapture() or nil
// if no such function has been installed.
func (a *Application) GetInputCapture() func(event *tcell.EventKey) *tcell.EventKey {
	return a.inputCapture
}

// Run starts the application and thus the event loop. This function returns
// when Stop() was called.
func (a *Application) Run() error {
	var err error
	a.Lock()

	// Make a screen.
	a.screen, err = tcell.NewScreen()
	if err != nil {
		a.Unlock()
		return err
	}
	if err = a.screen.Init(); err != nil {
		a.Unlock()
		return err
	}

	// We catch panics to clean up because they mess up the terminal.
	defer func() {
		if p := recover(); p != nil {
			if a.screen != nil {
				a.screen.Fini()
			}
			panic(p)
		}
	}()

	// Draw the screen for the first time.
	a.Unlock()
	a.Draw()

	// Start event loop.
	for {
		// Do not poll events during suspend mode
		a.suspendMutex.Lock()
		a.Lock()
		screen := a.screen
		a.Unlock()
		if screen == nil {
			a.suspendMutex.Unlock()
			break
		}

		// Wait for next event.
		event := a.screen.PollEvent()
		a.suspendMutex.Unlock()
		if event == nil {
			// The screen was finalized. Exit the loop.
			break
		}

		switch event := event.(type) {
		case *tcell.EventKey:
			a.RLock()
			p := a.focus
			a.RUnlock()

			// Intercept keys.
			if a.inputCapture != nil {
				event = a.inputCapture(event)
				if event == nil {
					break // Don't forward event.
				}
			}

			// Ctrl-C closes the application.
			if event.Key() == tcell.KeyCtrlC {
				a.Stop()
			}

			// Pass other key events to the currently focused primitive.
			if p != nil {
				if handler := p.InputHandler(); handler != nil {
					handler(event, func(p Primitive) {
						a.SetFocus(p)
					})
					a.Draw()
				}
			}
		case *tcell.EventResize:
			a.Lock()
			screen := a.screen
			a.Unlock()
			screen.Clear()
			a.Draw()
		}
	}

	return nil
}

// Stop stops the application, causing Run() to return.
func (a *Application) Stop() {
	a.RLock()
	defer a.RUnlock()
	if a.screen == nil {
		return
	}
	a.screen.Fini()
	a.screen = nil
}

// Suspend temporarily suspends the application by exiting terminal UI mode and
// invoking the provided function "f". When "f" returns, terminal UI mode is
// entered again and the application resumes.
//
// A return value of true indicates that the application was suspended and "f"
// was called. If false is returned, the application was already suspended,
// terminal UI mode was not exited, and "f" was not called.
func (a *Application) Suspend(f func()) bool {
	a.Lock()

	if a.screen == nil {
		// Screen has not yet been initialized
		a.Unlock()
		return false
	}

	// Enter suspended mode.
	a.suspendMutex.Lock()
	defer a.suspendMutex.Unlock()
	a.Unlock()
	a.Stop()

	// Deal with panics during suspended mode. Exit the program.
	defer func() {
		if p := recover(); p != nil {
			fmt.Println(p)
			os.Exit(1)
		}
	}()

	// Wait for "f" to return.
	f()

	// Make a new screen and redraw.
	a.Lock()
	var err error
	a.screen, err = tcell.NewScreen()
	if err != nil {
		a.Unlock()
		panic(err)
	}
	if err = a.screen.Init(); err != nil {
		a.Unlock()
		panic(err)
	}
	a.Unlock()
	a.Draw()

	// Continue application loop.
	return true
}

// Draw refreshes the screen. It calls the Draw() function of the application's
// root primitive and then syncs the screen buffer.
func (a *Application) Draw() *Application {
	a.RLock()
	screen := a.screen
	root := a.root
	fullscreen := a.rootFullscreen
	before := a.beforeDraw
	after := a.afterDraw
	a.RUnlock()

	// Maybe we're not ready yet or not anymore.
	if screen == nil || root == nil {
		return a
	}

	// Resize if requested.
	if fullscreen && root != nil {
		width, height := screen.Size()
		root.SetRect(0, 0, width, height)
	}

	// Call before handler if there is one.
	if before != nil {
		if before(screen) {
			screen.Show()
			return a
		}
	}

	// Draw all primitives.
	root.Draw(screen)

	// Call after handler if there is one.
	if after != nil {
		after(screen)
	}

	// Sync screen.
	screen.Show()

	return a
}

// SetBeforeDrawFunc installs a callback function which is invoked just before
// the root primitive is drawn during screen updates. If the function returns
// true, drawing will not continue, i.e. the root primitive will not be drawn
// (and an after-draw-handler will not be called).
//
// Note that the screen is not cleared by the application. To clear the screen,
// you may call screen.Clear().
//
// Provide nil to uninstall the callback function.
func (a *Application) SetBeforeDrawFunc(handler func(screen tcell.Screen) bool) *Application {
	a.beforeDraw = handler
	return a
}

// GetBeforeDrawFunc returns the callback function installed with
// SetBeforeDrawFunc() or nil if none has been installed.
func (a *Application) GetBeforeDrawFunc() func(screen tcell.Screen) bool {
	return a.beforeDraw
}

// SetAfterDrawFunc installs a callback function which is invoked after the root
// primitive was drawn during screen updates.
//
// Provide nil to uninstall the callback function.
func (a *Application) SetAfterDrawFunc(handler func(screen tcell.Screen)) *Application {
	a.afterDraw = handler
	return a
}

// GetAfterDrawFunc returns the callback function installed with
// SetAfterDrawFunc() or nil if none has been installed.
func (a *Application) GetAfterDrawFunc() func(screen tcell.Screen) {
	return a.afterDraw
}

// SetRoot sets the root primitive for this application. If "fullscreen" is set
// to true, the root primitive's position will be changed to fill the screen.
//
// This function must be called at least once or nothing will be displayed when
// the application starts.
//
// It also calls SetFocus() on the primitive.
func (a *Application) SetRoot(root Primitive, fullscreen bool) *Application {
	a.Lock()
	a.root = root
	a.rootFullscreen = fullscreen
	if a.screen != nil {
		a.screen.Clear()
	}
	a.Unlock()

	a.SetFocus(root)

	return a
}

// ResizeToFullScreen resizes the given primitive such that it fills the entire
// screen.
func (a *Application) ResizeToFullScreen(p Primitive) *Application {
	a.RLock()
	width, height := a.screen.Size()
	a.RUnlock()
	p.SetRect(0, 0, width, height)
	return a
}

// SetFocus sets the focus on a new primitive. All key events will be redirected
// to that primitive. Callers must ensure that the primitive will handle key
// events.
//
// Blur() will be called on the previously focused primitive. Focus() will be
// called on the new primitive.
func (a *Application) SetFocus(p Primitive) *Application {
	a.Lock()
	if a.focus != nil {
		a.focus.Blur()
	}
	a.focus = p
	if a.screen != nil {
		a.screen.HideCursor()
	}
	a.Unlock()
	if p != nil {
		p.Focus(func(p Primitive) {
			a.SetFocus(p)
		})
	}

	return a
}

// GetFocus returns the primitive which has the current focus. If none has it,
// nil is returned.
func (a *Application) GetFocus() Primitive {
	a.RLock()
	defer a.RUnlock()
	return a.focus
}
<|endoftext|>


<commit_before>/*
   Copyright 2020 Docker, Inc.

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

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

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

package main

import (
	"context"
	"fmt"
	"math/rand"
	"os"
	"os/signal"
	"path/filepath"
	"regexp"
	"syscall"
	"time"

	"github.com/docker/api/errdefs"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	// Backend registrations
	_ "github.com/docker/api/azure"
	_ "github.com/docker/api/example"
	_ "github.com/docker/api/local"
	"github.com/docker/api/metrics"

	"github.com/docker/api/cli/cmd"
	"github.com/docker/api/cli/cmd/compose"
	contextcmd "github.com/docker/api/cli/cmd/context"
	"github.com/docker/api/cli/cmd/login"
	"github.com/docker/api/cli/cmd/run"
	"github.com/docker/api/cli/mobycli"
	cliopts "github.com/docker/api/cli/options"
	"github.com/docker/api/config"
	apicontext "github.com/docker/api/context"
	"github.com/docker/api/context/store"
)

var (
	version = "dev"
)

var (
	ownCommands = map[string]struct{}{
		"context": {},
		"login":   {},
		"serve":   {},
		"version": {},
	}
	unknownCommandRegexp = regexp.MustCompile(`unknown command "([^"]*)"`)
)

func init() {
	// initial hack to get the path of the project's bin dir
	// into the env of this cli for development
	path, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		fatal(errors.Wrap(err, "unable to get absolute bin path"))
	}
	if err := os.Setenv("PATH", fmt.Sprintf("%s:%s", os.Getenv("PATH"), path)); err != nil {
		panic(err)
	}
	// Seed random
	rand.Seed(time.Now().UnixNano())
}

func isOwnCommand(cmd *cobra.Command) bool {
	if cmd == nil {
		return false
	}
	if _, ok := ownCommands[cmd.Name()]; ok {
		return true
	}
	return isOwnCommand(cmd.Parent())
}

func main() {
	var opts cliopts.GlobalOpts
	root := &cobra.Command{
		Use:           "docker",
		SilenceErrors: true,
		SilenceUsage:  true,
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			if !isOwnCommand(cmd) {
				mobycli.ExecIfDefaultCtxType(cmd.Context())
			}
			return nil
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			return cmd.Help()
		},
	}

	root.AddCommand(
		contextcmd.Command(),
		cmd.PsCommand(),
		cmd.ServeCommand(),
		run.Command(),
		cmd.ExecCommand(),
		cmd.LogsCommand(),
		cmd.RmCommand(),
		cmd.InspectCommand(),
		compose.Command(),
		login.Command(),
		cmd.VersionCommand(version),
	)

	helpFunc := root.HelpFunc()
	root.SetHelpFunc(func(cmd *cobra.Command, args []string) {
		if !isOwnCommand(cmd) {
			mobycli.ExecIfDefaultCtxType(cmd.Context())
		}
		helpFunc(cmd, args)
	})

	root.PersistentFlags().BoolVarP(&opts.Debug, "debug", "D", false, "enable debug output in the logs")
	root.PersistentFlags().StringVarP(&opts.Host, "host", "H", "", "Daemon socket(s) to connect to")
	opts.AddConfigFlags(root.PersistentFlags())
	opts.AddContextFlags(root.PersistentFlags())
	root.Flags().BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")

	// populate the opts with the global flags
	_ = root.PersistentFlags().Parse(os.Args[1:])
	if opts.Debug {
		logrus.SetLevel(logrus.DebugLevel)
	}

	ctx, cancel := newSigContext()
	defer cancel()

	// --host and --version should immediately be forwarded to the original cli
	if opts.Host != "" || opts.Version {
		mobycli.Exec(ctx)
	}

	if opts.Config == "" {
		fatal(errors.New("config path cannot be empty"))
	}
	configDir := opts.Config
	ctx = config.WithDir(ctx, configDir)

	currentContext := determineCurrentContext(opts.Context, configDir)

	s, err := store.New(store.WithRoot(configDir))
	if err != nil {
		fatal(errors.Wrap(err, "unable to create context store"))
	}

	ctype := store.DefaultContextType
	cc, _ := s.Get(currentContext)
	if cc != nil {
		ctype = cc.Type()
	}

	metrics.Track(ctype, os.Args[1:], root.PersistentFlags())

	ctx = apicontext.WithCurrentContext(ctx, currentContext)
	ctx = store.WithContextStore(ctx, s)

	if err = root.ExecuteContext(ctx); err != nil {
		// Context should always be handled by new CLI
		requiredCmd, _, _ := root.Find(os.Args[1:])
		if requiredCmd != nil && isOwnCommand(requiredCmd) {
			exit(err)
		}
		mobycli.ExecIfDefaultCtxType(ctx)

		checkIfUnknownCommandExistInDefaultContext(err, currentContext)
		exit(err)
	}
}

func exit(err error) {
	if errors.Is(err, errdefs.ErrLoginRequired) {
		fmt.Fprintln(os.Stderr, fmt.Errorf("%v", err))
		os.Exit(errdefs.ExitCodeLoginRequired)
	}
	fatal(err)
}

func checkIfUnknownCommandExistInDefaultContext(err error, currentContext string) {
	submatch := unknownCommandRegexp.FindSubmatch([]byte(err.Error()))
	if len(submatch) == 2 {
		dockerCommand := string(submatch[1])

		if mobycli.IsDefaultContextCommand(dockerCommand) {
			fmt.Fprintf(os.Stderr, "Command %q not available in current context (%s), you can use the \"default\" context to run this command\n", dockerCommand, currentContext)
			os.Exit(1)
		}
	}
}

func newSigContext() (context.Context, func()) {
	ctx, cancel := context.WithCancel(context.Background())
	s := make(chan os.Signal)
	signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
	go func() {
		<-s
		cancel()
	}()
	return ctx, cancel
}

func determineCurrentContext(flag string, configDir string) string {
	res := flag
	if res == "" {
		config, err := config.LoadFile(configDir)
		if err != nil {
			fmt.Fprintln(os.Stderr, errors.Wrap(err, "WARNING"))
			return "default"
		}
		res = config.CurrentContext
	}
	if res == "" {
		res = "default"
	}
	return res
}

func fatal(err error) {
	fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}
<commit_msg>Exit without error message if user canceled command (typical scenario : ACI `logs — follow` and ctrl-C while querying ACI)<commit_after>/*
   Copyright 2020 Docker, Inc.

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

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

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

package main

import (
	"context"
	"fmt"
	"math/rand"
	"os"
	"os/signal"
	"path/filepath"
	"regexp"
	"syscall"
	"time"

	"github.com/docker/api/errdefs"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	// Backend registrations
	_ "github.com/docker/api/azure"
	_ "github.com/docker/api/example"
	_ "github.com/docker/api/local"
	"github.com/docker/api/metrics"

	"github.com/docker/api/cli/cmd"
	"github.com/docker/api/cli/cmd/compose"
	contextcmd "github.com/docker/api/cli/cmd/context"
	"github.com/docker/api/cli/cmd/login"
	"github.com/docker/api/cli/cmd/run"
	"github.com/docker/api/cli/mobycli"
	cliopts "github.com/docker/api/cli/options"
	"github.com/docker/api/config"
	apicontext "github.com/docker/api/context"
	"github.com/docker/api/context/store"
)

var (
	version = "dev"
)

var (
	ownCommands = map[string]struct{}{
		"context": {},
		"login":   {},
		"serve":   {},
		"version": {},
	}
	unknownCommandRegexp = regexp.MustCompile(`unknown command "([^"]*)"`)
)

func init() {
	// initial hack to get the path of the project's bin dir
	// into the env of this cli for development
	path, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		fatal(errors.Wrap(err, "unable to get absolute bin path"))
	}
	if err := os.Setenv("PATH", fmt.Sprintf("%s:%s", os.Getenv("PATH"), path)); err != nil {
		panic(err)
	}
	// Seed random
	rand.Seed(time.Now().UnixNano())
}

func isOwnCommand(cmd *cobra.Command) bool {
	if cmd == nil {
		return false
	}
	if _, ok := ownCommands[cmd.Name()]; ok {
		return true
	}
	return isOwnCommand(cmd.Parent())
}

func main() {
	var opts cliopts.GlobalOpts
	root := &cobra.Command{
		Use:           "docker",
		SilenceErrors: true,
		SilenceUsage:  true,
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			if !isOwnCommand(cmd) {
				mobycli.ExecIfDefaultCtxType(cmd.Context())
			}
			return nil
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			return cmd.Help()
		},
	}

	root.AddCommand(
		contextcmd.Command(),
		cmd.PsCommand(),
		cmd.ServeCommand(),
		run.Command(),
		cmd.ExecCommand(),
		cmd.LogsCommand(),
		cmd.RmCommand(),
		cmd.InspectCommand(),
		compose.Command(),
		login.Command(),
		cmd.VersionCommand(version),
	)

	helpFunc := root.HelpFunc()
	root.SetHelpFunc(func(cmd *cobra.Command, args []string) {
		if !isOwnCommand(cmd) {
			mobycli.ExecIfDefaultCtxType(cmd.Context())
		}
		helpFunc(cmd, args)
	})

	root.PersistentFlags().BoolVarP(&opts.Debug, "debug", "D", false, "enable debug output in the logs")
	root.PersistentFlags().StringVarP(&opts.Host, "host", "H", "", "Daemon socket(s) to connect to")
	opts.AddConfigFlags(root.PersistentFlags())
	opts.AddContextFlags(root.PersistentFlags())
	root.Flags().BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")

	// populate the opts with the global flags
	_ = root.PersistentFlags().Parse(os.Args[1:])
	if opts.Debug {
		logrus.SetLevel(logrus.DebugLevel)
	}

	ctx, cancel := newSigContext()
	defer cancel()

	// --host and --version should immediately be forwarded to the original cli
	if opts.Host != "" || opts.Version {
		mobycli.Exec(ctx)
	}

	if opts.Config == "" {
		fatal(errors.New("config path cannot be empty"))
	}
	configDir := opts.Config
	ctx = config.WithDir(ctx, configDir)

	currentContext := determineCurrentContext(opts.Context, configDir)

	s, err := store.New(store.WithRoot(configDir))
	if err != nil {
		fatal(errors.Wrap(err, "unable to create context store"))
	}

	ctype := store.DefaultContextType
	cc, _ := s.Get(currentContext)
	if cc != nil {
		ctype = cc.Type()
	}

	metrics.Track(ctype, os.Args[1:], root.PersistentFlags())

	ctx = apicontext.WithCurrentContext(ctx, currentContext)
	ctx = store.WithContextStore(ctx, s)

	if err = root.ExecuteContext(ctx); err != nil {
		//if user canceled request, simply exit without any error message
		if errors.Is(ctx.Err(), context.Canceled) {
			os.Exit(130)
		}

		// Context should always be handled by new CLI
		requiredCmd, _, _ := root.Find(os.Args[1:])
		if requiredCmd != nil && isOwnCommand(requiredCmd) {
			exit(err)
		}
		mobycli.ExecIfDefaultCtxType(ctx)

		checkIfUnknownCommandExistInDefaultContext(err, currentContext)
		exit(err)
	}
}

func exit(err error) {
	if errors.Is(err, errdefs.ErrLoginRequired) {
		fmt.Fprintln(os.Stderr, fmt.Errorf("%v", err))
		os.Exit(errdefs.ExitCodeLoginRequired)
	}
	fatal(err)
}

func checkIfUnknownCommandExistInDefaultContext(err error, currentContext string) {
	submatch := unknownCommandRegexp.FindSubmatch([]byte(err.Error()))
	if len(submatch) == 2 {
		dockerCommand := string(submatch[1])

		if mobycli.IsDefaultContextCommand(dockerCommand) {
			fmt.Fprintf(os.Stderr, "Command %q not available in current context (%s), you can use the \"default\" context to run this command\n", dockerCommand, currentContext)
			os.Exit(1)
		}
	}
}

func newSigContext() (context.Context, func()) {
	ctx, cancel := context.WithCancel(context.Background())
	s := make(chan os.Signal)
	signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
	go func() {
		<-s
		cancel()
	}()
	return ctx, cancel
}

func determineCurrentContext(flag string, configDir string) string {
	res := flag
	if res == "" {
		config, err := config.LoadFile(configDir)
		if err != nil {
			fmt.Fprintln(os.Stderr, errors.Wrap(err, "WARNING"))
			return "default"
		}
		res = config.CurrentContext
	}
	if res == "" {
		res = "default"
	}
	return res
}

func fatal(err error) {
	fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package appsettings

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
)

type DataTree map[string]string

type dataStruct struct {
	Tree map[string]DataTree
}

type AppSettings struct {
	filename string
	data     dataStruct
}

func NewAppSettings(dbFilename string) (*AppSettings, error) {
	var data dataStruct
	if _, err := os.Stat(dbFilename); os.IsNotExist(err) {
		data = dataStruct{
			Tree: make(map[string]DataTree),
		}

		d1, _ := json.Marshal(data)
		err := ioutil.WriteFile(dbFilename, d1, 0644)
		if err != nil {
			return nil, err
		}
	} else {
		d1, err := ioutil.ReadFile(dbFilename)
		if err != nil {
			return nil, err
		}
		json.Unmarshal(d1, &data)

		if err != nil {
			return nil, err
		}
	}

	return &AppSettings{filename: dbFilename, data: data}, nil
}

func (a *DataTree) GetString(key string) (string, error) {
	y := *a
	if _, ok := y[key]; !ok {
		return "", fmt.Errorf("undefined key %s", key)
	}

	return y[key], nil
}

func (a *DataTree) SetString(key string, val string) {
	y := *a
	y[key] = val
}

func (a *DataTree) GetInt(key string) (int, error) {
	str, err := a.GetString(key)
	if err != nil {
		return 0, err
	}

	i, err := strconv.Atoi(str)
	if err != nil {
		return 0, err
	}
	return i, nil
}

func (a *DataTree) SetInt(key string, val int) {
	y := *a
	y[key] = strconv.Itoa(val)
}

func (a *AppSettings) GetTree(key string) DataTree {
	if _, ok := a.data.Tree[key]; !ok {
		a.data.Tree[key] = make(DataTree)
	}

	return a.data.Tree[key]
}

func (a *AppSettings) Persist() error {
	d1, _ := json.Marshal(a.data)
	err := ioutil.WriteFile(a.filename, d1, 0644)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Added initial godoc comment<commit_after>// Package appsettings provides simple key/value store functionality
package appsettings

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
)

type DataTree map[string]string

type dataStruct struct {
	Tree map[string]DataTree
}

type AppSettings struct {
	filename string
	data     dataStruct
}

func NewAppSettings(dbFilename string) (*AppSettings, error) {
	var data dataStruct
	if _, err := os.Stat(dbFilename); os.IsNotExist(err) {
		data = dataStruct{
			Tree: make(map[string]DataTree),
		}

		d1, _ := json.Marshal(data)
		err := ioutil.WriteFile(dbFilename, d1, 0644)
		if err != nil {
			return nil, err
		}
	} else {
		d1, err := ioutil.ReadFile(dbFilename)
		if err != nil {
			return nil, err
		}
		json.Unmarshal(d1, &data)

		if err != nil {
			return nil, err
		}
	}

	return &AppSettings{filename: dbFilename, data: data}, nil
}

func (a *DataTree) GetString(key string) (string, error) {
	y := *a
	if _, ok := y[key]; !ok {
		return "", fmt.Errorf("undefined key %s", key)
	}

	return y[key], nil
}

func (a *DataTree) SetString(key string, val string) {
	y := *a
	y[key] = val
}

func (a *DataTree) GetInt(key string) (int, error) {
	str, err := a.GetString(key)
	if err != nil {
		return 0, err
	}

	i, err := strconv.Atoi(str)
	if err != nil {
		return 0, err
	}
	return i, nil
}

func (a *DataTree) SetInt(key string, val int) {
	y := *a
	y[key] = strconv.Itoa(val)
}

func (a *AppSettings) GetTree(key string) DataTree {
	if _, ok := a.data.Tree[key]; !ok {
		a.data.Tree[key] = make(DataTree)
	}

	return a.data.Tree[key]
}

func (a *AppSettings) Persist() error {
	d1, _ := json.Marshal(a.data)
	err := ioutil.WriteFile(a.filename, d1, 0644)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package fusefs

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"path"
	"strings"
	"sync"
	"time"

	"github.com/asjoyner/shade"
	"github.com/asjoyner/shade/drive"
)

// Node is a very compact representation of a shade.File.  It can also be used
// to represent a sythetic directory, for tree traversal.
type Node struct {
	// Filename is the complete path to a node, with no leading or trailing
	// slash.
	Filename     string
	Filesize     int64 // in bytes
	ModifiedTime time.Time
	// Deleted indicates the file was Deleted at ModifiedTime.  NodeByPath
	// responds exactly as if the node did not exist.
	Deleted   bool
	Sha256sum []byte // the sha of the full shade.File
	// Children is a map indicating the presence of a node immediately
	// below the current node in the tree.  The key is only the name of that
	// node, a relative path, not fully qualified.
	// TODO(asjoyner): use a struct{} here for efficiency?
	// unsafe.Sizeof indicates it would save 1 byte per FS entry
	Children map[string]bool
	// TODO(asjoyner): update LastSeen each poll, timeout entries so deleted
	// files eventually disappear from Tree.
	// LastSeen time.Time
}

// Synthetic returns true for synthetically created directories.
func (n *Node) Synthetic() bool {
	if n.Sha256sum == nil {
		return true
	}
	return false
}

// Tree is a representation of all files known to the provided drive.Client.
// It initially downlods, then periodically refreshes, the set of files by
// calling ListFiles and GetChunk.  It presents methods to query for what file
// object currently describes what path, and can return a Node or shade.File
// struct representing that node in the tree.
type Tree struct {
	client drive.Client
	nodes  map[string]Node // full path to node
	nm     sync.RWMutex    // protects nodes
	debug  bool
}

// NewTree queries client to discover all the shade.File(s).  It returns a Tree
// object which is ready to answer questions about the nodes in the file tree.
// If the initial query fails, an error is returned instead.
func NewTree(client drive.Client, refresh *time.Ticker) (*Tree, error) {
	t := &Tree{
		client: client,
		nodes: map[string]Node{
			"": {
				Filename: "",
				Children: make(map[string]bool),
			}},
	}
	if err := t.Refresh(); err != nil {
		return nil, fmt.Errorf("initializing Tree: %s", err)
	}
	if refresh != nil {
		go t.periodicRefresh(refresh)
	}
	return t, nil
}

// NodeByPath returns a Node describing the given path.
func (t *Tree) NodeByPath(p string) (Node, error) {
	p = strings.TrimPrefix(p, "/")
	t.nm.RLock()
	defer t.nm.RUnlock()
	n, ok := t.nodes[p]
	if !ok || n.Deleted {
		t.log("known nodes:\n")
		for _, n := range t.nodes {
			t.log(fmt.Sprintf("%+v\n", n))
		}
		return Node{}, fmt.Errorf("no such node: %q", p)
	}
	return n, nil
}

func unmarshalChunk(fj, sha []byte) (*shade.File, error) {
	file := &shade.File{}
	if err := json.Unmarshal(fj, file); err != nil {
		return nil, fmt.Errorf("Failed to unmarshal sha256sum %x: %s", sha, err)
	}
	return file, nil
}

// FileByNode returns the full shade.File object for a given node.
func (t *Tree) FileByNode(n Node) (*shade.File, error) {
	if n.Synthetic() {
		return nil, errors.New("no shade.File defined")
	}
	fj, err := t.client.GetChunk(n.Sha256sum)
	if err != nil {
		return nil, fmt.Errorf("GetChunk(%x): %s", n.Sha256sum, err)
	}
	if fj == nil || len(fj) == 0 {
		return nil, fmt.Errorf("Could not find JSON for node: %q", n.Filename)
	}

	f := &shade.File{}
	if err := f.FromJSON(fj); err != nil {
		return nil, err
	}
	return f, nil
}

// HasChild returns true if child exists immediately below parent in the file
// tree.
func (t *Tree) HasChild(parent, child string) bool {
	t.nm.RLock()
	defer t.nm.RUnlock()
	return t.nodes[parent].Children[child]
}

// NumNodes returns the number of nodes (files + synthetic directories) in the
// system.
func (t *Tree) NumNodes() int {
	t.nm.RLock()
	defer t.nm.RUnlock()
	return len(t.nodes)
}

// Mkdir provides a way to create synthetic directories, for the Mkdir Fuse op
func (t *Tree) Mkdir(dir string) Node {
	dir = strings.TrimPrefix(dir, "/")
	t.nm.Lock()
	defer t.nm.Unlock()
	t.nodes[dir] = Node{
		Filename: dir,
		Children: make(map[string]bool),
	}
	t.addParents(dir)
	return t.nodes[dir]
}

// Create adds a new shade.File node to the tree
func (t *Tree) Create(filename string) Node {
	t.nm.Lock()
	defer t.nm.Unlock()
	node := Node{
		Filename:  filename,
		Sha256sum: []byte("f00d"),
	}
	t.nodes[node.Filename] = node
	t.addParents(node.Filename)
	return node
}

// Update accepts a replacement shade.File node
func (t *Tree) Update(n Node) {
	t.nm.Lock()
	defer t.nm.Unlock()
	on, ok := t.nodes[n.Filename]
	if !ok {
		t.log(fmt.Sprintf("Attempt to update a non-existent node: %+v", n))
		return
	}
	if on.ModifiedTime.After(n.ModifiedTime) {
		t.log(fmt.Sprintf("Update mtime (%s) older than current Node (%s)", n.ModifiedTime, on.ModifiedTime))
		return
	}
	t.nodes[n.Filename] = n
}

// Refresh updates the cached view of the Tree by calling ListFiles and
// processing the result.
func (t *Tree) Refresh() error {
	t.log("Begining cache refresh cycle.")
	// key is a string([]byte) representation of the file's SHA2
	knownNodes := make(map[string]bool)
	newFiles, err := t.client.ListFiles()
	if err != nil {
		return fmt.Errorf("%q ListFiles(): %s", t.client.GetConfig().Provider, err)
	}
	t.log(fmt.Sprintf("Found %d file(s) via %s", len(newFiles), t.client.GetConfig().Provider))
	// fetch all those files into the local disk cache
	for _, sha256sum := range newFiles {
		// check if we have already processed this Node
		if knownNodes[string(sha256sum)] {
			continue // we've already processed this file
		}

		// fetch the file Chunk
		f, err := t.client.GetChunk(sha256sum)
		if err != nil {
			// TODO(asjoyner): if !client.Local()... retry?
			log.Printf("Failed to fetch file %x: %s", sha256sum, err)
			continue
		}
		// unmarshal and populate t.nodes as the shade.files go by
		file := &shade.File{}
		if err := file.FromJSON(f); err != nil {
			log.Printf("%v", err)
			continue
		}
		node := Node{
			Filename:     file.Filename,
			Filesize:     file.Filesize,
			ModifiedTime: file.ModifiedTime,
			Deleted:      file.Deleted,
			Sha256sum:    sha256sum,
			Children:     nil,
		}
		t.nm.Lock()
		// TODO(asjoyner): handle file + directory collisions
		if existing, ok := t.nodes[node.Filename]; ok && existing.ModifiedTime.After(node.ModifiedTime) {
			t.nm.Unlock()
			continue
		}
		t.nodes[node.Filename] = node
		t.addParents(node.Filename)
		t.nm.Unlock()
		knownNodes[string(sha256sum)] = true
	}
	t.log(fmt.Sprintf("Refresh complete with %d file(s).", len(knownNodes)))
	return nil
}

// recursive function to update parent dirs
func (t *Tree) addParents(filepath string) {
	dir, f := path.Split(filepath)
	dir = strings.TrimSuffix(dir, "/")
	t.log(fmt.Sprintf("adding %q as a child of %q", f, dir))
	// TODO(asjoyner): handle file + directory collisions
	if parent, ok := t.nodes[dir]; !ok {
		// if the parent node doesn't yet exist, initialize it
		t.nodes[dir] = Node{
			Filename: dir,
			Children: map[string]bool{f: true},
		}
	} else {
		parent.Children[f] = true
		return
	}
	if dir != "" {
		t.addParents(dir)
	}
}

func (t *Tree) periodicRefresh(refresh *time.Ticker) {
	for {
		<-refresh.C
		t.Refresh()
	}
}

// Debug causes the client to print helpful message via the log library.
func (t *Tree) Debug() {
	t.debug = true
}

func (t *Tree) log(msg string) {
	if t.debug {
		log.Printf("CACHE: %s", msg)
	}
}
<commit_msg>Delete the reference to the child in the parent<commit_after>package fusefs

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"path"
	"strings"
	"sync"
	"time"

	"github.com/asjoyner/shade"
	"github.com/asjoyner/shade/drive"
)

// Node is a very compact representation of a shade.File.  It can also be used
// to represent a sythetic directory, for tree traversal.
type Node struct {
	// Filename is the complete path to a node, with no leading or trailing
	// slash.
	Filename     string
	Filesize     int64 // in bytes
	ModifiedTime time.Time
	// Deleted indicates the file was Deleted at ModifiedTime.  NodeByPath
	// responds exactly as if the node did not exist.
	Deleted   bool
	Sha256sum []byte // the sha of the full shade.File
	// Children is a map indicating the presence of a node immediately
	// below the current node in the tree.  The key is only the name of that
	// node, a relative path, not fully qualified.
	// TODO(asjoyner): use a struct{} here for efficiency?
	// unsafe.Sizeof indicates it would save 1 byte per FS entry
	Children map[string]bool
	// TODO(asjoyner): update LastSeen each poll, timeout entries so deleted
	// files eventually disappear from Tree.
	// LastSeen time.Time
}

// Synthetic returns true for synthetically created directories.
func (n *Node) Synthetic() bool {
	if n.Sha256sum == nil {
		return true
	}
	return false
}

// Tree is a representation of all files known to the provided drive.Client.
// It initially downlods, then periodically refreshes, the set of files by
// calling ListFiles and GetChunk.  It presents methods to query for what file
// object currently describes what path, and can return a Node or shade.File
// struct representing that node in the tree.
type Tree struct {
	client drive.Client
	nodes  map[string]Node // full path to node
	nm     sync.RWMutex    // protects nodes
	debug  bool
}

// NewTree queries client to discover all the shade.File(s).  It returns a Tree
// object which is ready to answer questions about the nodes in the file tree.
// If the initial query fails, an error is returned instead.
func NewTree(client drive.Client, refresh *time.Ticker) (*Tree, error) {
	t := &Tree{
		client: client,
		nodes: map[string]Node{
			"": {
				Filename: "",
				Children: make(map[string]bool),
			}},
	}
	if err := t.Refresh(); err != nil {
		return nil, fmt.Errorf("initializing Tree: %s", err)
	}
	if refresh != nil {
		go t.periodicRefresh(refresh)
	}
	return t, nil
}

// NodeByPath returns a Node describing the given path.
func (t *Tree) NodeByPath(p string) (Node, error) {
	p = strings.TrimPrefix(p, "/")
	t.nm.RLock()
	defer t.nm.RUnlock()
	n, ok := t.nodes[p]
	if !ok || n.Deleted {
		t.log("known nodes:\n")
		for _, n := range t.nodes {
			t.log(fmt.Sprintf("%+v\n", n))
		}
		return Node{}, fmt.Errorf("no such node: %q", p)
	}
	return n, nil
}

func unmarshalChunk(fj, sha []byte) (*shade.File, error) {
	file := &shade.File{}
	if err := json.Unmarshal(fj, file); err != nil {
		return nil, fmt.Errorf("Failed to unmarshal sha256sum %x: %s", sha, err)
	}
	return file, nil
}

// FileByNode returns the full shade.File object for a given node.
func (t *Tree) FileByNode(n Node) (*shade.File, error) {
	if n.Synthetic() {
		return nil, errors.New("no shade.File defined")
	}
	fj, err := t.client.GetChunk(n.Sha256sum)
	if err != nil {
		return nil, fmt.Errorf("GetChunk(%x): %s", n.Sha256sum, err)
	}
	if fj == nil || len(fj) == 0 {
		return nil, fmt.Errorf("Could not find JSON for node: %q", n.Filename)
	}

	f := &shade.File{}
	if err := f.FromJSON(fj); err != nil {
		return nil, err
	}
	return f, nil
}

// HasChild returns true if child exists immediately below parent in the file
// tree.
func (t *Tree) HasChild(parent, child string) bool {
	t.nm.RLock()
	defer t.nm.RUnlock()
	return t.nodes[parent].Children[child]
}

// NumNodes returns the number of nodes (files + synthetic directories) in the
// system.
func (t *Tree) NumNodes() int {
	t.nm.RLock()
	defer t.nm.RUnlock()
	return len(t.nodes)
}

// Mkdir provides a way to create synthetic directories, for the Mkdir Fuse op
func (t *Tree) Mkdir(dir string) Node {
	dir = strings.TrimPrefix(dir, "/")
	t.nm.Lock()
	defer t.nm.Unlock()
	t.nodes[dir] = Node{
		Filename: dir,
		Children: make(map[string]bool),
	}
	t.addParents(dir)
	return t.nodes[dir]
}

// Create adds a new shade.File node to the tree
func (t *Tree) Create(filename string) Node {
	t.nm.Lock()
	defer t.nm.Unlock()
	node := Node{
		Filename:  filename,
		Sha256sum: []byte("f00d"),
	}
	t.nodes[node.Filename] = node
	t.addParents(node.Filename)
	return node
}

// Update accepts a replacement shade.File node
func (t *Tree) Update(n Node) {
	t.nm.Lock()
	defer t.nm.Unlock()
	on, ok := t.nodes[n.Filename]
	if !ok {
		t.log(fmt.Sprintf("Attempt to update a non-existent node: %+v", n))
		return
	}
	if on.ModifiedTime.After(n.ModifiedTime) {
		t.log(fmt.Sprintf("Update mtime (%s) older than current Node (%s)", n.ModifiedTime, on.ModifiedTime))
		return
	}
	t.nodes[n.Filename] = n
	if n.Deleted {
		dir, f := path.Split(n.Filename)
		dir = strings.TrimSuffix(dir, "/")
		parent, ok := t.nodes[dir]
		if !ok {
			t.log(fmt.Sprintf("Updated node without a parent: %+v", n))
			return
		}
		delete(parent.Children, f)
	}
}

// Refresh updates the cached view of the Tree by calling ListFiles and
// processing the result.
func (t *Tree) Refresh() error {
	t.log("Begining cache refresh cycle.")
	// key is a string([]byte) representation of the file's SHA2
	knownNodes := make(map[string]bool)
	newFiles, err := t.client.ListFiles()
	if err != nil {
		return fmt.Errorf("%q ListFiles(): %s", t.client.GetConfig().Provider, err)
	}
	t.log(fmt.Sprintf("Found %d file(s) via %s", len(newFiles), t.client.GetConfig().Provider))
	// fetch all those files into the local disk cache
	for _, sha256sum := range newFiles {
		// check if we have already processed this Node
		if knownNodes[string(sha256sum)] {
			continue // we've already processed this file
		}

		// fetch the file Chunk
		f, err := t.client.GetChunk(sha256sum)
		if err != nil {
			// TODO(asjoyner): if !client.Local()... retry?
			log.Printf("Failed to fetch file %x: %s", sha256sum, err)
			continue
		}
		// unmarshal and populate t.nodes as the shade.files go by
		file := &shade.File{}
		if err := file.FromJSON(f); err != nil {
			log.Printf("%v", err)
			continue
		}
		node := Node{
			Filename:     file.Filename,
			Filesize:     file.Filesize,
			ModifiedTime: file.ModifiedTime,
			Deleted:      file.Deleted,
			Sha256sum:    sha256sum,
			Children:     nil,
		}
		t.nm.Lock()
		// TODO(asjoyner): handle file + directory collisions
		if existing, ok := t.nodes[node.Filename]; ok && existing.ModifiedTime.After(node.ModifiedTime) {
			t.nm.Unlock()
			continue
		}
		t.nodes[node.Filename] = node
		t.addParents(node.Filename)
		t.nm.Unlock()
		knownNodes[string(sha256sum)] = true
	}
	t.log(fmt.Sprintf("Refresh complete with %d file(s).", len(knownNodes)))
	return nil
}

// recursive function to update parent dirs
func (t *Tree) addParents(filepath string) {
	dir, f := path.Split(filepath)
	dir = strings.TrimSuffix(dir, "/")
	t.log(fmt.Sprintf("adding %q as a child of %q", f, dir))
	// TODO(asjoyner): handle file + directory collisions
	if parent, ok := t.nodes[dir]; !ok {
		// if the parent node doesn't yet exist, initialize it
		t.nodes[dir] = Node{
			Filename: dir,
			Children: map[string]bool{f: true},
		}
	} else {
		parent.Children[f] = true
		return
	}
	if dir != "" {
		t.addParents(dir)
	}
}

func (t *Tree) periodicRefresh(refresh *time.Ticker) {
	for {
		<-refresh.C
		t.Refresh()
	}
}

// Debug causes the client to print helpful message via the log library.
func (t *Tree) Debug() {
	t.debug = true
}

func (t *Tree) log(msg string) {
	if t.debug {
		log.Printf("CACHE: %s", msg)
	}
}
<|endoftext|>


<commit_before>package requestHandler

import (
	"bytes"
	"github.com/zwirec/TGChatScanner/requestHandler/appContext"
	file "github.com/zwirec/TGChatScanner/requestHandler/filetypes"
	"log"
	"os"
	"strconv"
	"sync"
)

type FilePreparationsPool struct {
	In            chan *file.FileBasic
	Out           chan *file.PreparedFile
	Done          chan struct{}
	WorkersNumber int
}

func (fpp *FilePreparationsPool) Run(outBufferSize int, finished *sync.WaitGroup) chan *file.PreparedFile {
	fpp.Out = make(chan *file.PreparedFile, outBufferSize)
	var wg sync.WaitGroup

	wg.Add(fpp.WorkersNumber)
	for i := 0; i < fpp.WorkersNumber; i++ {
		go func() {
			defer wg.Done()
			preparationWorker(fpp.In, fpp.Out, fpp.Done)
		}()
	}
	finished.Add(1)
	go func() {
		wg.Wait()
		close(fpp.Out)
		finished.Done()
	}()
	return fpp.Out
}

func preparationWorker(toPrepare chan *file.FileBasic, result chan *file.PreparedFile, done chan struct{}) {
	for in := range toPrepare {
		appContext.ErrLogger.Printf("comes on prep: %+v", *in)
		fileId := in.FileId
		f, err := appContext.BotAPI.PrepareFile(fileId)
		if err != nil {
			appContext.ErrLogger.Printf("error during preparation stage on %s: %s", in.FileId, err)
			continue
		}

		url, err := appContext.BotAPI.EncodeDownloadURL(f.FilePath)
		if err != nil {
			appContext.ErrLogger.Printf("incorrect url during preparation stage on %s: %s", in.FileId, err)
		}

		status := file.Undefiend
		fl := &file.FileLink{
			FileDownloadURL: url,
			LocalPath:       BuildLocalPath(in),
			Basics:          in,
			Status:          &status,
		}
		fpResult := &file.PreparedFile{Link: fl}
		appContext.ErrLogger.Printf("comes from prep: %+v", *fpResult)
		select {
		case result <- fpResult:
		case <-done:
			return
		}
	}
}

func BuildLocalPath(f *file.FileBasic) string {
	var buff bytes.Buffer
	buff.WriteString(appContext.ImagesPath)
	buff.WriteString("/")
	buff.WriteString(strconv.FormatInt(f.From, 10))
	buff.WriteString("/")
	buff.WriteString(f.Sent.Format("2006-02-01"))
	buff.WriteString("/")
	if err := os.MkdirAll(buff.String(), os.ModePerm); err != nil {
		log.Fatal(f)
	}
	buff.WriteString(f.FileId)
	return buff.String()
}
<commit_msg>Small changes<commit_after>package requestHandler

import (
	"bytes"
	"github.com/zwirec/TGChatScanner/requestHandler/appContext"
	file "github.com/zwirec/TGChatScanner/requestHandler/filetypes"
	"log"
	"os"
	"strconv"
	"sync"
)

type FilePreparationsPool struct {
	In            chan *file.FileBasic
	Out           chan *file.PreparedFile
	Done          chan struct{}
	WorkersNumber int
}

func (fpp *FilePreparationsPool) Run(outBufferSize int, finished *sync.WaitGroup) chan *file.PreparedFile {
	fpp.Out = make(chan *file.PreparedFile, outBufferSize)
	var wg sync.WaitGroup

	wg.Add(fpp.WorkersNumber)
	for i := 0; i < fpp.WorkersNumber; i++ {
		go func() {
			defer wg.Done()
			preparationWorker(fpp.In, fpp.Out, fpp.Done)
		}()
	}
	finished.Add(1)
	go func() {
		wg.Wait()
		close(fpp.Out)
		finished.Done()
	}()
	return fpp.Out
}

func preparationWorker(toPrepare chan *file.FileBasic, result chan *file.PreparedFile, done chan struct{}) {
	for in := range toPrepare {
		appContext.ErrLogger.Printf("comes on prep: %+v", *in)
		fileId := in.FileId
		f, err := appContext.BotAPI.PrepareFile(fileId)
		if err != nil {
			appContext.ErrLogger.Printf("error during preparation stage on %s: %s", in.FileId, err)
			continue
		}

		url, err := appContext.BotAPI.EncodeDownloadURL(f.FilePath)
		if err != nil {
			appContext.ErrLogger.Printf("incorrect url during preparation stage on %s: %s", in.FileId, err)
		}

		status := file.Undefiend
		fl := &file.FileLink{
			FileDownloadURL: url,
			LocalPath:       BuildLocalPath(in),
			Basics:          in,
			Status:          &status,
		}
		fpResult := &file.PreparedFile{Link: fl}
		appContext.ErrLogger.Printf("comes from prep: %+v", *fpResult)
		select {
		case result <- fpResult:
		case <-done:
			return
		}
	}
}

func BuildLocalPath(f *file.FileBasic) string {
	var buff bytes.Buffer
	buff.WriteString(appContext.ImagesPath)
	buff.WriteString("/")
	buff.WriteString(strconv.FormatInt(f.From, 10))
	buff.WriteString("/")
	buff.WriteString(f.Sent.Format("2006-02-01"))
	if err := os.MkdirAll(buff.String(), os.ModePerm); err != nil {
		log.Fatal(f)
	}
	buff.WriteString("/")
	buff.WriteString(f.FileId)
	return buff.String()
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"google.golang.org/api/compute/v1"
)

func TestAccComputeHealthCheck_tcp(t *testing.T) {
	var healthCheck compute.HealthCheck

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeHealthCheckDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccComputeHealthCheck_tcp,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeHealthCheckExists(
						"google_compute_health_check.foobar", &healthCheck),
					testAccCheckComputeHealthCheckThresholds(
						3, 3, &healthCheck),
					testAccCheckComputeHealthCheckTcpPort(80, &healthCheck),
				),
			},
		},
	})
}

func TestAccComputeHealthCheck_ssl(t *testing.T) {
	var healthCheck compute.HealthCheck

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeHealthCheckDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccComputeHealthCheck_ssl,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeHealthCheckExists(
						"google_compute_health_check.foobar", &healthCheck),
					testAccCheckComputeHealthCheckThresholds(
						3, 3, &healthCheck),
				),
			},
		},
	})
}

func TestAccComputeHealthCheck_http(t *testing.T) {
	var healthCheck compute.HealthCheck

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeHealthCheckDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccComputeHealthCheck_http,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeHealthCheckExists(
						"google_compute_health_check.foobar", &healthCheck),
					testAccCheckComputeHealthCheckThresholds(
						3, 3, &healthCheck),
				),
			},
		},
	})
}

func TestAccComputeHealthCheck_https(t *testing.T) {
	var healthCheck compute.HealthCheck

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeHealthCheckDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccComputeHealthCheck_https,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeHealthCheckExists(
						"google_compute_health_check.foobar", &healthCheck),
					testAccCheckComputeHealthCheckThresholds(
						3, 3, &healthCheck),
				),
			},
		},
	})
}

// add in update test?

func testAccCheckComputeHealthCheckDestroy(s *terraform.State) error {
	config := testAccProvider.Meta().(*Config)

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "google_compute_health_check" {
			continue
		}

		_, err := config.clientCompute.HealthChecks.Get(
			config.Project, rs.Primary.ID).Do()
		if err == nil {
			return fmt.Errorf("HealthCheck still exists")
		}
	}

	return nil
}

func testAccCheckComputeHealthCheckExists(n string, healthCheck *compute.HealthCheck) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		config := testAccProvider.Meta().(*Config)

		found, err := config.clientCompute.HealthChecks.Get(
			config.Project, rs.Primary.ID).Do()
		if err != nil {
			return err
		}

		if found.Name != rs.Primary.ID {
			return fmt.Errorf("HealthCheck not found")
		}

		*healthCheck = *found

		return nil
	}
}

func testAccCheckComputeHealthCheckThresholds(healthy, unhealthy int64, healthCheck *compute.HealthCheck) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if healthCheck.HealthyThreshold != healthy {
			return fmt.Errorf("HealthyThreshold doesn't match: expected %d, got %d", healthy, healthCheck.HealthyThreshold)
		}

		if healthCheck.UnhealthyThreshold != unhealthy {
			return fmt.Errorf("UnhealthyThreshold doesn't match: expected %d, got %d", unhealthy, healthCheck.UnhealthyThreshold)
		}

		return nil
	}
}

func testAccCheckComputeHealthCheckTcpPort(port int64, healthCheck *compute.HealthCheck) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if healthCheck.TcpHealthCheck.Port != port {
			return fmt.Errorf("Port doesn't match: expected %v, got %v", port, healthCheck.TcpHealthCheck.Port)
		}
		return nil
	}
}

var testAccComputeHealthCheck_tcp = fmt.Sprintf(`
resource "google_compute_health_check" "foobar" {
	check_interval_sec = 3
	description = "Resource created for Terraform acceptance testing"
	healthy_threshold = 3
	name = "health-test-%s"
	timeout_sec = 2
	unhealthy_threshold = 3
	tcp_health_check {
	}
}
`, acctest.RandString(10))

var testAccComputeHealthCheck_ssl = fmt.Sprintf(`
resource "google_compute_health_check" "foobar" {
	check_interval_sec = 3
	description = "Resource created for Terraform acceptance testing"
	healthy_threshold = 3
	name = "health-test-%s"
	timeout_sec = 2
	unhealthy_threshold = 3
	type = "SSL"
	ssl_health_check {
		port = "443"
	}
}
`, acctest.RandString(10))

var testAccComputeHealthCheck_http = fmt.Sprintf(`
resource "google_compute_health_check" "foobar" {
	check_interval_sec = 3
	description = "Resource created for Terraform acceptance testing"
	healthy_threshold = 3
	name = "health-test-%s"
	timeout_sec = 2
	unhealthy_threshold = 3
	type = "HTTP"
	http_health_check {
		port = "80"
	}
}
`, acctest.RandString(10))

var testAccComputeHealthCheck_https = fmt.Sprintf(`
resource "google_compute_health_check" "foobar" {
	check_interval_sec = 3
	description = "Resource created for Terraform acceptance testing"
	healthy_threshold = 3
	name = "health-test-%s"
	timeout_sec = 2
	unhealthy_threshold = 3
	type = "HTTPS"
	https_health_check {
		port = "443"
	}
}
`, acctest.RandString(10))
<commit_msg>add one more test for updating a health check<commit_after>package google

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"google.golang.org/api/compute/v1"
)

func TestAccComputeHealthCheck_tcp(t *testing.T) {
	var healthCheck compute.HealthCheck

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeHealthCheckDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccComputeHealthCheck_tcp,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeHealthCheckExists(
						"google_compute_health_check.foobar", &healthCheck),
					testAccCheckComputeHealthCheckThresholds(
						3, 3, &healthCheck),
					testAccCheckComputeHealthCheckTcpPort(80, &healthCheck),
				),
			},
		},
	})
}

func TestAccComputeHealthCheck_tcp_update(t *testing.T) {
	var healthCheck compute.HealthCheck

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeHealthCheckDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccComputeHealthCheck_tcp,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeHealthCheckExists(
						"google_compute_health_check.foobar", &healthCheck),
					testAccCheckComputeHealthCheckThresholds(
						3, 3, &healthCheck),
					testAccCheckComputeHealthCheckTcpPort(80, &healthCheck),
				),
			},
			resource.TestStep{
				Config: testAccComputeHealthCheck_tcp_update,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeHealthCheckExists(
						"google_compute_health_check.foobar", &healthCheck),
					testAccCheckComputeHealthCheckThresholds(
						10, 10, &healthCheck),
					testAccCheckComputeHealthCheckTcpPort(8080, &healthCheck),
				),
			},
		},
	})
}

func TestAccComputeHealthCheck_ssl(t *testing.T) {
	var healthCheck compute.HealthCheck

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeHealthCheckDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccComputeHealthCheck_ssl,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeHealthCheckExists(
						"google_compute_health_check.foobar", &healthCheck),
					testAccCheckComputeHealthCheckThresholds(
						3, 3, &healthCheck),
				),
			},
		},
	})
}

func TestAccComputeHealthCheck_http(t *testing.T) {
	var healthCheck compute.HealthCheck

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeHealthCheckDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccComputeHealthCheck_http,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeHealthCheckExists(
						"google_compute_health_check.foobar", &healthCheck),
					testAccCheckComputeHealthCheckThresholds(
						3, 3, &healthCheck),
				),
			},
		},
	})
}

func TestAccComputeHealthCheck_https(t *testing.T) {
	var healthCheck compute.HealthCheck

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeHealthCheckDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccComputeHealthCheck_https,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeHealthCheckExists(
						"google_compute_health_check.foobar", &healthCheck),
					testAccCheckComputeHealthCheckThresholds(
						3, 3, &healthCheck),
				),
			},
		},
	})
}

func testAccCheckComputeHealthCheckDestroy(s *terraform.State) error {
	config := testAccProvider.Meta().(*Config)

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "google_compute_health_check" {
			continue
		}

		_, err := config.clientCompute.HealthChecks.Get(
			config.Project, rs.Primary.ID).Do()
		if err == nil {
			return fmt.Errorf("HealthCheck still exists")
		}
	}

	return nil
}

func testAccCheckComputeHealthCheckExists(n string, healthCheck *compute.HealthCheck) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		config := testAccProvider.Meta().(*Config)

		found, err := config.clientCompute.HealthChecks.Get(
			config.Project, rs.Primary.ID).Do()
		if err != nil {
			return err
		}

		if found.Name != rs.Primary.ID {
			return fmt.Errorf("HealthCheck not found")
		}

		*healthCheck = *found

		return nil
	}
}

func testAccCheckComputeHealthCheckThresholds(healthy, unhealthy int64, healthCheck *compute.HealthCheck) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if healthCheck.HealthyThreshold != healthy {
			return fmt.Errorf("HealthyThreshold doesn't match: expected %d, got %d", healthy, healthCheck.HealthyThreshold)
		}

		if healthCheck.UnhealthyThreshold != unhealthy {
			return fmt.Errorf("UnhealthyThreshold doesn't match: expected %d, got %d", unhealthy, healthCheck.UnhealthyThreshold)
		}

		return nil
	}
}

func testAccCheckComputeHealthCheckTcpPort(port int64, healthCheck *compute.HealthCheck) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if healthCheck.TcpHealthCheck.Port != port {
			return fmt.Errorf("Port doesn't match: expected %v, got %v", port, healthCheck.TcpHealthCheck.Port)
		}
		return nil
	}
}

var testAccComputeHealthCheck_tcp = fmt.Sprintf(`
resource "google_compute_health_check" "foobar" {
	check_interval_sec = 3
	description = "Resource created for Terraform acceptance testing"
	healthy_threshold = 3
	name = "health-test-%s"
	timeout_sec = 2
	unhealthy_threshold = 3
	tcp_health_check {
	}
}
`, acctest.RandString(10))

var testAccComputeHealthCheck_tcp_update = fmt.Sprintf(`
resource "google_compute_health_check" "foobar" {
	check_interval_sec = 3
	description = "Resource updated for Terraform acceptance testing"
	healthy_threshold = 10
	name = "health-test-%s"
	timeout_sec = 2
	unhealthy_threshold = 10
	tcp_health_check {
		port = "8080"
	}
}
`, acctest.RandString(10))

var testAccComputeHealthCheck_ssl = fmt.Sprintf(`
resource "google_compute_health_check" "foobar" {
	check_interval_sec = 3
	description = "Resource created for Terraform acceptance testing"
	healthy_threshold = 3
	name = "health-test-%s"
	timeout_sec = 2
	unhealthy_threshold = 3
	type = "SSL"
	ssl_health_check {
		port = "443"
	}
}
`, acctest.RandString(10))

var testAccComputeHealthCheck_http = fmt.Sprintf(`
resource "google_compute_health_check" "foobar" {
	check_interval_sec = 3
	description = "Resource created for Terraform acceptance testing"
	healthy_threshold = 3
	name = "health-test-%s"
	timeout_sec = 2
	unhealthy_threshold = 3
	type = "HTTP"
	http_health_check {
		port = "80"
	}
}
`, acctest.RandString(10))

var testAccComputeHealthCheck_https = fmt.Sprintf(`
resource "google_compute_health_check" "foobar" {
	check_interval_sec = 3
	description = "Resource created for Terraform acceptance testing"
	healthy_threshold = 3
	name = "health-test-%s"
	timeout_sec = 2
	unhealthy_threshold = 3
	type = "HTTPS"
	https_health_check {
		port = "443"
	}
}
`, acctest.RandString(10))
<|endoftext|>