<commit_before>package nyb

import (
	"encoding/json"
	"fmt"
	"log"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/ugjka/go-tz"

	"github.com/hako/durafmt"
	irc "github.com/ugjka/dumbirc"
	c "github.com/ugjka/newyearsbot/common"
)

const logChanLen = 100

//LogChan is a channel that sends log messages
type LogChan chan string

func (l LogChan) Write(p []byte) (n int, err error) {
	if len(l) < logChanLen {
		l <- string(p)
	}
	return len(p), nil
}

//NewLogChan make new log channel
func NewLogChan() LogChan {
	return make(chan string, logChanLen)
}

//Settings for bot
type Settings struct {
	IrcNick    string
	IrcChans   []string
	IrcServer  string
	IrcTrigger string
	UseTLS     bool
	LogCh      LogChan
	Stopper    chan bool
	IrcObj     *irc.Connection
	Email      string
	Nominatim  string
}

//Stop stops the bot
func (s *Settings) Stop() {
	select {
	case <-s.Stopper:
		return
	default:
		close(s.Stopper)
	}
}

//NewIrcObj return empty irc connection
func NewIrcObj() *irc.Connection {
	return &irc.Connection{}
}

//New creates new bot
func New(nick string, chans []string, trigger string, server string, tls bool, email string, nominatim string) *Settings {
	return &Settings{
		nick,
		chans,
		server,
		trigger,
		tls,
		NewLogChan(),
		make(chan bool),
		&irc.Connection{},
		email,
		nominatim,
	}
}

//Set target year
var target = func() time.Time {
	tmp := time.Now().UTC()
	if tmp.Month() == time.January && tmp.Day() < 2 {
		return time.Date(tmp.Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
	}
	//return time.Date(tmp.Year(), time.February, 13, 0, 0, 0, 0, time.UTC)
	return time.Date(tmp.Year()+1, time.January, 1, 0, 0, 0, 0, time.UTC)
}()

//Start starts the bot
func (s *Settings) Start() {
	log.SetOutput(s.LogCh)
	log.Println("Starting the bot...")
	var start = make(chan bool)
	var once sync.Once
	var next c.TZ
	var last c.TZ

	//This is used to prevent sending ping before we
	//have response from previous ping (any activity on irc)
	//pingpong(pp) sends a signal to ping timer
	pp := make(chan bool, 1)

	//To exit gracefully we need to wait
	var wait sync.WaitGroup
	defer wait.Wait()

	//
	//Set up irc and its callbacks
	//
	s.IrcObj = irc.New(s.IrcNick, "nyebot", s.IrcServer, s.UseTLS)

	//On any message send a signal to ping timer to be ready
	s.IrcObj.AddCallback(irc.ANYMESSAGE, func(msg irc.Message) {
		pingpong(pp)
	})

	//Join channels on WELCOME
	s.IrcObj.AddCallback(irc.WELCOME, func(msg irc.Message) {
		s.IrcObj.Join(s.IrcChans)
		//Prevent early start
		once.Do(func() {
			close(start)
		})
	})
	//Reply ping messages with pong
	s.IrcObj.AddCallback(irc.PING, func(msg irc.Message) {
		log.Println("PING recieved, sending PONG")
		s.IrcObj.Pong()
	})
	//Log pongs
	s.IrcObj.AddCallback(irc.PONG, func(msg irc.Message) {
		log.Println("Got PONG...")
	})
	//Change nick if taken
	s.IrcObj.AddCallback(irc.NICKTAKEN, func(msg irc.Message) {
		log.Println("Nick taken, changing...")
		if strings.HasSuffix(s.IrcObj.Nick, "_") {
			s.IrcObj.Nick = s.IrcObj.Nick[:len(s.IrcObj.Nick)-1]
		} else {
			s.IrcObj.Nick += "_"
		}
		s.IrcObj.NewNick(s.IrcObj.Nick)
	})
	//Callback for queries
	s.IrcObj.AddCallback(irc.PRIVMSG, func(msg irc.Message) {
		//Help
		if strings.HasPrefix(msg.Trailing, fmt.Sprintf("%s !help", s.IrcTrigger)) ||
			(strings.HasPrefix(msg.Trailing, fmt.Sprintf("%s", s.IrcObj.Nick)) &&
				strings.HasSuffix(msg.Trailing, fmt.Sprintf("help"))) {
			s.IrcObj.Reply(msg, fmt.Sprintf("%s: Query location: '%s <location>', Next zone: '%s !next', Last zone: '%s !last', Source code: https://github.com/ugjka/newyearsbot",
				msg.Name, s.IrcTrigger, s.IrcTrigger, s.IrcTrigger))
			return
		}
		//Next
		if strings.HasPrefix(msg.Trailing, fmt.Sprintf("%s !next", s.IrcTrigger)) {
			log.Println("Querying !next...")
			dur, err := time.ParseDuration(next.Offset + "h")
			if err != nil {
				return
			}
			if time.Now().UTC().Add(dur).After(target) {
				s.IrcObj.Reply(msg, fmt.Sprintf("No more next, %d is here AoE", target.Year()))
				return
			}
			humandur, err := durafmt.ParseString(target.Sub(time.Now().UTC().Add(dur)).String())
			if err != nil {
				return
			}
			s.IrcObj.Reply(msg, fmt.Sprintf("Next New Year in %s in %s",
				removeMilliseconds(humandur.String()), next.String()))
			return
		}
		//Last
		if strings.HasPrefix(msg.Trailing, fmt.Sprintf("%s !last", s.IrcTrigger)) {
			log.Println("Querying !last...")
			dur, err := time.ParseDuration(last.Offset + "h")
			if err != nil {
				return
			}
			humandur, err := durafmt.ParseString(time.Now().UTC().Add(dur).Sub(target).String())
			if err != nil {
				return
			}
			if last.Offset == "-12" {
				humandur, err = durafmt.ParseString(time.Now().UTC().Add(dur).Sub(target.AddDate(-1, 0, 0)).String())
				if err != nil {
					return
				}
			}
			s.IrcObj.Reply(msg, fmt.Sprintf("Last NewYear %s ago in %s",
				removeMilliseconds(humandur.String()), last.String()))
			return
		}
		//hny Location Query
		if strings.HasPrefix(msg.Trailing, fmt.Sprintf("%s ", s.IrcTrigger)) {
			tz, err := getNewYear(msg.Trailing[len(s.IrcTrigger)+1:], s.Email, s.Nominatim)
			if err != nil {
				log.Println("Query error:", err)
				s.IrcObj.Reply(msg, "Some error occurred!")
				return
			}
			s.IrcObj.Reply(msg, fmt.Sprintf("%s: %s", msg.Name, tz))
			return
		}

	})
	//Reconnect logic and Irc Pinger
	wait.Add(1)
	go func() {
		var err error
		defer wait.Done()
		for {
			timer := time.NewTimer(time.Minute * 1)
			select {
			case err = <-s.IrcObj.Errchan:
				log.Println("Error:", err)
				log.Println("Restarting the bot...")
				time.AfterFunc(time.Second*30, func() {
					select {
					case <-s.Stopper:
						return
					default:
						s.IrcObj.Start()
					}
				})
			case <-s.Stopper:
				timer.Stop()
				log.Println("Stopping the bot...")
				log.Println("Disconnecting...")
				s.IrcObj.Disconnect()
				return
			//ping timer
			case <-timer.C:
				timer.Stop()
				//pingpong stuff
				select {
				case <-pp:
					log.Println("Sending PING...")
					s.IrcObj.Ping()
				default:
					log.Println("Got no Response...")
				}
			}

		}
	}()
	s.IrcObj.Start()
	//Starts when joined, see once.Do
	select {
	case <-start:
		log.Println("Got start...")
	case <-s.Stopper:
		return
	}
	var zones c.TZS
	if err := json.Unmarshal([]byte(TZ), &zones); err != nil {
		log.Fatal(err)
	}
	sort.Sort(sort.Reverse(zones))
wrap:
	for i := 0; i < len(zones); i++ {
		dur, err := time.ParseDuration(zones[i].Offset + "h")
		if err != nil {
			log.Fatal(err)
		}
		//Check if zone is past target
		next = zones[i]
		if i == 0 {
			last = zones[len(zones)-1]
		} else {
			last = zones[i-1]
		}
		if time.Now().UTC().Add(dur).Before(target) {
			time.Sleep(time.Second * 2)
			log.Println("Zone pending:", zones[i].Offset)
			humandur, err := durafmt.ParseString(target.Sub(time.Now().UTC().Add(dur)).String())
			if err != nil {
				log.Fatal(err)
			}
			msg := fmt.Sprintf("Next New Year in %s in %s", removeMilliseconds(humandur.String()), zones[i])
			s.IrcObj.PrivMsgBulk(s.IrcChans, msg)
			//Wait till Target in Timezone
			timer := c.NewTimer(target.Sub(time.Now().UTC().Add(dur)))

			select {
			case <-timer.C:
				timer.Stop()
				msg = fmt.Sprintf("Happy New Year in %s", zones[i])
				s.IrcObj.PrivMsgBulk(s.IrcChans, msg)
				log.Println("Announcing zone:", zones[i].Offset)
			case <-s.Stopper:
				timer.Stop()
				return
			}
		}
	}
	s.IrcObj.PrivMsgBulk(s.IrcChans, fmt.Sprintf("That's it, Year %d is here AoE", target.Year()))
	log.Println("All zones finished...")
	target = target.AddDate(1, 0, 0)
	log.Printf("Wrapping target date around to %d\n", target.Year())
	goto wrap
}

func pingpong(c chan bool) {
	select {
	case c <- true:
	default:
		return
	}
}

//Func for querying newyears in specified location
func getNewYear(loc string, email string, server string) (string, error) {
	var adress string
	log.Println("Querying location:", loc)
	maps := url.Values{}
	maps.Add("q", loc)
	maps.Add("format", "json")
	maps.Add("accept-language", "en")
	maps.Add("limit", "1")
	maps.Add("email", email)
	data, err := c.NominatimGetter(server + c.NominatimGeoCode + maps.Encode())
	if err != nil {
		log.Println(err)
		return "", err
	}
	var mapj c.NominatimResults
	if err = json.Unmarshal(data, &mapj); err != nil {
		log.Println(err)
		return "", err
	}
	if len(mapj) == 0 {
		return "Couldn't find that place.", nil
	}
	adress = mapj[0].DisplayName
	lat, err := strconv.ParseFloat(mapj[0].Lat, 64)
	if err != nil {
		return "", err
	}
	lon, err := strconv.ParseFloat(mapj[0].Lon, 64)
	if err != nil {
		return "", err
	}
	p := gotz.Point{
		Lat: lat,
		Lng: lon,
	}
	zone, err := gotz.GetZone(p)
	if err != nil {
		return "Couldn't get the timezone for that location.", nil
	}
	//RawOffset
	offset, err := time.ParseDuration(fmt.Sprintf("%ds", getOffset(target, zone)))
	if err != nil {
		log.Println(err)
		return "", err
	}
	//Check if past target
	if time.Now().UTC().Add(offset).Before(target) {
		humandur, err := durafmt.ParseString(target.Sub(time.Now().UTC().Add(offset)).String())
		if err != nil {
			log.Println(err)
			return "", err
		}
		return fmt.Sprintf("New Year in %s will happen in %s", adress, removeMilliseconds(humandur.String())), nil
	}
	return fmt.Sprintf("New Year in %s already happened.", adress), nil
}

func removeMilliseconds(dur string) string {
	arr := strings.Split(dur, " ")
	if len(arr) < 3 {
		return dur
	}
	return strings.Join(arr[:len(arr)-2], " ")
}

func getOffset(target time.Time, zone *time.Location) int {
	_, offset := time.Date(target.Year(), target.Month(), target.Day(),
		target.Hour(), target.Minute(), target.Second(),
		target.Nanosecond(), zone).Zone()
	return offset
}
<commit_msg>print what time ago new year happened<commit_after>package nyb

import (
	"encoding/json"
	"fmt"
	"log"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/ugjka/go-tz"

	"github.com/hako/durafmt"
	irc "github.com/ugjka/dumbirc"
	c "github.com/ugjka/newyearsbot/common"
)

const logChanLen = 100

//LogChan is a channel that sends log messages
type LogChan chan string

func (l LogChan) Write(p []byte) (n int, err error) {
	if len(l) < logChanLen {
		l <- string(p)
	}
	return len(p), nil
}

//NewLogChan make new log channel
func NewLogChan() LogChan {
	return make(chan string, logChanLen)
}

//Settings for bot
type Settings struct {
	IrcNick    string
	IrcChans   []string
	IrcServer  string
	IrcTrigger string
	UseTLS     bool
	LogCh      LogChan
	Stopper    chan bool
	IrcObj     *irc.Connection
	Email      string
	Nominatim  string
}

//Stop stops the bot
func (s *Settings) Stop() {
	select {
	case <-s.Stopper:
		return
	default:
		close(s.Stopper)
	}
}

//NewIrcObj return empty irc connection
func NewIrcObj() *irc.Connection {
	return &irc.Connection{}
}

//New creates new bot
func New(nick string, chans []string, trigger string, server string, tls bool, email string, nominatim string) *Settings {
	return &Settings{
		nick,
		chans,
		server,
		trigger,
		tls,
		NewLogChan(),
		make(chan bool),
		&irc.Connection{},
		email,
		nominatim,
	}
}

//Set target year
var target = func() time.Time {
	tmp := time.Now().UTC()
	if tmp.Month() == time.January && tmp.Day() < 2 {
		return time.Date(tmp.Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
	}
	//return time.Date(tmp.Year(), time.February, 14, 0, 0, 0, 0, time.UTC)
	return time.Date(tmp.Year()+1, time.January, 1, 0, 0, 0, 0, time.UTC)
}()

//Start starts the bot
func (s *Settings) Start() {
	log.SetOutput(s.LogCh)
	log.Println("Starting the bot...")
	var start = make(chan bool)
	var once sync.Once
	var next c.TZ
	var last c.TZ

	//This is used to prevent sending ping before we
	//have response from previous ping (any activity on irc)
	//pingpong(pp) sends a signal to ping timer
	pp := make(chan bool, 1)

	//To exit gracefully we need to wait
	var wait sync.WaitGroup
	defer wait.Wait()

	//
	//Set up irc and its callbacks
	//
	s.IrcObj = irc.New(s.IrcNick, "nyebot", s.IrcServer, s.UseTLS)

	//On any message send a signal to ping timer to be ready
	s.IrcObj.AddCallback(irc.ANYMESSAGE, func(msg irc.Message) {
		pingpong(pp)
	})

	//Join channels on WELCOME
	s.IrcObj.AddCallback(irc.WELCOME, func(msg irc.Message) {
		s.IrcObj.Join(s.IrcChans)
		//Prevent early start
		once.Do(func() {
			close(start)
		})
	})
	//Reply ping messages with pong
	s.IrcObj.AddCallback(irc.PING, func(msg irc.Message) {
		log.Println("PING recieved, sending PONG")
		s.IrcObj.Pong()
	})
	//Log pongs
	s.IrcObj.AddCallback(irc.PONG, func(msg irc.Message) {
		log.Println("Got PONG...")
	})
	//Change nick if taken
	s.IrcObj.AddCallback(irc.NICKTAKEN, func(msg irc.Message) {
		log.Println("Nick taken, changing...")
		if strings.HasSuffix(s.IrcObj.Nick, "_") {
			s.IrcObj.Nick = s.IrcObj.Nick[:len(s.IrcObj.Nick)-1]
		} else {
			s.IrcObj.Nick += "_"
		}
		s.IrcObj.NewNick(s.IrcObj.Nick)
	})
	//Callback for queries
	s.IrcObj.AddCallback(irc.PRIVMSG, func(msg irc.Message) {
		//Help
		if strings.HasPrefix(msg.Trailing, fmt.Sprintf("%s !help", s.IrcTrigger)) ||
			(strings.HasPrefix(msg.Trailing, fmt.Sprintf("%s", s.IrcObj.Nick)) &&
				strings.HasSuffix(msg.Trailing, fmt.Sprintf("help"))) {
			s.IrcObj.Reply(msg, fmt.Sprintf("%s: Query location: '%s <location>', Next zone: '%s !next', Last zone: '%s !last', Source code: https://github.com/ugjka/newyearsbot",
				msg.Name, s.IrcTrigger, s.IrcTrigger, s.IrcTrigger))
			return
		}
		//Next
		if strings.HasPrefix(msg.Trailing, fmt.Sprintf("%s !next", s.IrcTrigger)) {
			log.Println("Querying !next...")
			dur, err := time.ParseDuration(next.Offset + "h")
			if err != nil {
				return
			}
			if time.Now().UTC().Add(dur).After(target) {
				s.IrcObj.Reply(msg, fmt.Sprintf("No more next, %d is here AoE", target.Year()))
				return
			}
			humandur, err := durafmt.ParseString(target.Sub(time.Now().UTC().Add(dur)).String())
			if err != nil {
				return
			}
			s.IrcObj.Reply(msg, fmt.Sprintf("Next New Year in %s in %s",
				removeMilliseconds(humandur.String()), next.String()))
			return
		}
		//Last
		if strings.HasPrefix(msg.Trailing, fmt.Sprintf("%s !last", s.IrcTrigger)) {
			log.Println("Querying !last...")
			dur, err := time.ParseDuration(last.Offset + "h")
			if err != nil {
				return
			}
			humandur, err := durafmt.ParseString(time.Now().UTC().Add(dur).Sub(target).String())
			if err != nil {
				return
			}
			if last.Offset == "-12" {
				humandur, err = durafmt.ParseString(time.Now().UTC().Add(dur).Sub(target.AddDate(-1, 0, 0)).String())
				if err != nil {
					return
				}
			}
			s.IrcObj.Reply(msg, fmt.Sprintf("Last NewYear %s ago in %s",
				removeMilliseconds(humandur.String()), last.String()))
			return
		}
		//hny Location Query
		if strings.HasPrefix(msg.Trailing, fmt.Sprintf("%s ", s.IrcTrigger)) {
			tz, err := getNewYear(msg.Trailing[len(s.IrcTrigger)+1:], s.Email, s.Nominatim)
			if err != nil {
				log.Println("Query error:", err)
				s.IrcObj.Reply(msg, "Some error occurred!")
				return
			}
			s.IrcObj.Reply(msg, fmt.Sprintf("%s: %s", msg.Name, tz))
			return
		}

	})
	//Reconnect logic and Irc Pinger
	wait.Add(1)
	go func() {
		var err error
		defer wait.Done()
		for {
			timer := time.NewTimer(time.Minute * 1)
			select {
			case err = <-s.IrcObj.Errchan:
				log.Println("Error:", err)
				log.Println("Restarting the bot...")
				time.AfterFunc(time.Second*30, func() {
					select {
					case <-s.Stopper:
						return
					default:
						s.IrcObj.Start()
					}
				})
			case <-s.Stopper:
				timer.Stop()
				log.Println("Stopping the bot...")
				log.Println("Disconnecting...")
				s.IrcObj.Disconnect()
				return
			//ping timer
			case <-timer.C:
				timer.Stop()
				//pingpong stuff
				select {
				case <-pp:
					log.Println("Sending PING...")
					s.IrcObj.Ping()
				default:
					log.Println("Got no Response...")
				}
			}

		}
	}()
	s.IrcObj.Start()
	//Starts when joined, see once.Do
	select {
	case <-start:
		log.Println("Got start...")
	case <-s.Stopper:
		return
	}
	var zones c.TZS
	if err := json.Unmarshal([]byte(TZ), &zones); err != nil {
		log.Fatal(err)
	}
	sort.Sort(sort.Reverse(zones))
wrap:
	for i := 0; i < len(zones); i++ {
		dur, err := time.ParseDuration(zones[i].Offset + "h")
		if err != nil {
			log.Fatal(err)
		}
		//Check if zone is past target
		next = zones[i]
		if i == 0 {
			last = zones[len(zones)-1]
		} else {
			last = zones[i-1]
		}
		if time.Now().UTC().Add(dur).Before(target) {
			time.Sleep(time.Second * 2)
			log.Println("Zone pending:", zones[i].Offset)
			humandur, err := durafmt.ParseString(target.Sub(time.Now().UTC().Add(dur)).String())
			if err != nil {
				log.Fatal(err)
			}
			msg := fmt.Sprintf("Next New Year in %s in %s", removeMilliseconds(humandur.String()), zones[i])
			s.IrcObj.PrivMsgBulk(s.IrcChans, msg)
			//Wait till Target in Timezone
			timer := c.NewTimer(target.Sub(time.Now().UTC().Add(dur)))

			select {
			case <-timer.C:
				timer.Stop()
				msg = fmt.Sprintf("Happy New Year in %s", zones[i])
				s.IrcObj.PrivMsgBulk(s.IrcChans, msg)
				log.Println("Announcing zone:", zones[i].Offset)
			case <-s.Stopper:
				timer.Stop()
				return
			}
		}
	}
	s.IrcObj.PrivMsgBulk(s.IrcChans, fmt.Sprintf("That's it, Year %d is here AoE", target.Year()))
	log.Println("All zones finished...")
	target = target.AddDate(1, 0, 0)
	log.Printf("Wrapping target date around to %d\n", target.Year())
	goto wrap
}

func pingpong(c chan bool) {
	select {
	case c <- true:
	default:
		return
	}
}

//Func for querying newyears in specified location
func getNewYear(loc string, email string, server string) (string, error) {
	var adress string
	log.Println("Querying location:", loc)
	maps := url.Values{}
	maps.Add("q", loc)
	maps.Add("format", "json")
	maps.Add("accept-language", "en")
	maps.Add("limit", "1")
	maps.Add("email", email)
	data, err := c.NominatimGetter(server + c.NominatimGeoCode + maps.Encode())
	if err != nil {
		log.Println(err)
		return "", err
	}
	var mapj c.NominatimResults
	if err = json.Unmarshal(data, &mapj); err != nil {
		log.Println(err)
		return "", err
	}
	if len(mapj) == 0 {
		return "Couldn't find that place.", nil
	}
	adress = mapj[0].DisplayName
	lat, err := strconv.ParseFloat(mapj[0].Lat, 64)
	if err != nil {
		return "", err
	}
	lon, err := strconv.ParseFloat(mapj[0].Lon, 64)
	if err != nil {
		return "", err
	}
	p := gotz.Point{
		Lat: lat,
		Lng: lon,
	}
	zone, err := gotz.GetZone(p)
	if err != nil {
		return "Couldn't get the timezone for that location.", nil
	}
	//RawOffset
	offset, err := time.ParseDuration(fmt.Sprintf("%ds", getOffset(target, zone)))
	if err != nil {
		log.Println(err)
		return "", err
	}
	//Check if past target
	if time.Now().UTC().Add(offset).Before(target) {
		humandur, err := durafmt.ParseString(target.Sub(time.Now().UTC().Add(offset)).String())
		if err != nil {
			log.Println(err)
			return "", err
		}
		return fmt.Sprintf("New Year in %s will happen in %s", adress, removeMilliseconds(humandur.String())), nil
	}
	humandur, err := durafmt.ParseString(time.Now().UTC().Add(offset).Sub(target).String())
	if err != nil {
		log.Println(err)
		return "", err
	}
	return fmt.Sprintf("New Year in %s happened %s ago", adress, removeMilliseconds(humandur.String())), nil
}

func removeMilliseconds(dur string) string {
	arr := strings.Split(dur, " ")
	if len(arr) < 3 {
		return dur
	}
	return strings.Join(arr[:len(arr)-2], " ")
}

func getOffset(target time.Time, zone *time.Location) int {
	_, offset := time.Date(target.Year(), target.Month(), target.Day(),
		target.Hour(), target.Minute(), target.Second(),
		target.Nanosecond(), zone).Zone()
	return offset
}
<|endoftext|>


<commit_before>package oci

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

	"github.com/mrunalp/ocid/utils"
)

// New creates a new Runtime with options provided
func New(runtimePath string, containerDir string) (*Runtime, error) {
	r := &Runtime{
		name:         filepath.Base(runtimePath),
		path:         runtimePath,
		containerDir: containerDir,
	}
	return r, nil
}

// Runtime stores the information about a oci runtime
type Runtime struct {
	name         string
	path         string
	sandboxDir   string
	containerDir string
}

// Name returns the name of the OCI Runtime
func (r *Runtime) Name() string {
	return r.name
}

// Path returns the full path the OCI Runtime executable
func (r *Runtime) Path() string {
	return r.path
}

// ContainerDir returns the path to the base directory for storing container configurations
func (r *Runtime) ContainerDir() string {
	return r.containerDir
}

// Version returns the version of the OCI Runtime
func (r *Runtime) Version() (string, error) {
	runtimeVersion, err := getOCIVersion(r.path, "-v")
	if err != nil {
		return "", err
	}
	return runtimeVersion, nil
}

func getOCIVersion(name string, args ...string) (string, error) {
	out, err := utils.ExecCmd(name, args...)
	if err != nil {
		return "", err
	}

	firstLine := out[:strings.Index(out, "\n")]
	v := firstLine[strings.LastIndex(firstLine, " ")+1:]
	return v, nil
}

// CreateContainer creates a container.
func (r *Runtime) CreateContainer(c *Container) error {
	return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "--systemd-cgroup", "create", "--bundle", c.bundlePath, c.name)
}

// StartContainer starts a container.
func (r *Runtime) StartContainer(c *Container) error {
	return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "start", c.name)
}

// StopContainer stops a container.
func (r *Runtime) StopContainer(c *Container) error {
	// TODO: Check if it is still running after some time and send SIGKILL
	return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "kill", c.name)
}

// Container respresents a runtime container.
type Container struct {
	name       string
	bundlePath string
	logPath    string
	labels     map[string]string
	sandbox    string
}

// NewContainer creates a container object.
func NewContainer(name string, bundlePath string, logPath string, labels map[string]string, sandbox string) (*Container, error) {
	c := &Container{
		name:       name,
		bundlePath: bundlePath,
		logPath:    logPath,
		labels:     labels,
		sandbox:    sandbox,
	}
	return c, nil
}

// Name returns the name of the container.
func (c *Container) Name() string {
	return c.name
}

// BundlePath returns the bundlePath of the container.
func (c *Container) BundlePath() string {
	return c.bundlePath
}

// LogPath returns the log path of the container.
func (c *Container) LogPath() string {
	return c.logPath
}

// Labels returns the labels of the container.
func (c *Container) Labels() map[string]string {
	return c.labels
}

// Sandbox returns the sandbox name of the container.
func (c *Container) Sandbox() string {
	return c.sandbox
}
<commit_msg>Add helper for deleting a container<commit_after>package oci

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

	"github.com/mrunalp/ocid/utils"
)

// New creates a new Runtime with options provided
func New(runtimePath string, containerDir string) (*Runtime, error) {
	r := &Runtime{
		name:         filepath.Base(runtimePath),
		path:         runtimePath,
		containerDir: containerDir,
	}
	return r, nil
}

// Runtime stores the information about a oci runtime
type Runtime struct {
	name         string
	path         string
	sandboxDir   string
	containerDir string
}

// Name returns the name of the OCI Runtime
func (r *Runtime) Name() string {
	return r.name
}

// Path returns the full path the OCI Runtime executable
func (r *Runtime) Path() string {
	return r.path
}

// ContainerDir returns the path to the base directory for storing container configurations
func (r *Runtime) ContainerDir() string {
	return r.containerDir
}

// Version returns the version of the OCI Runtime
func (r *Runtime) Version() (string, error) {
	runtimeVersion, err := getOCIVersion(r.path, "-v")
	if err != nil {
		return "", err
	}
	return runtimeVersion, nil
}

func getOCIVersion(name string, args ...string) (string, error) {
	out, err := utils.ExecCmd(name, args...)
	if err != nil {
		return "", err
	}

	firstLine := out[:strings.Index(out, "\n")]
	v := firstLine[strings.LastIndex(firstLine, " ")+1:]
	return v, nil
}

// CreateContainer creates a container.
func (r *Runtime) CreateContainer(c *Container) error {
	return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "--systemd-cgroup", "create", "--bundle", c.bundlePath, c.name)
}

// StartContainer starts a container.
func (r *Runtime) StartContainer(c *Container) error {
	return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "start", c.name)
}

// StopContainer stops a container.
func (r *Runtime) StopContainer(c *Container) error {
	// TODO: Check if it is still running after some time and send SIGKILL
	return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "kill", c.name)
}

// DeleteContainer deletes a container.
func (r *Runtime) DeleteContainer(c *Container) error {
	return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.path, "delete", c.name)
}

// Container respresents a runtime container.
type Container struct {
	name       string
	bundlePath string
	logPath    string
	labels     map[string]string
	sandbox    string
}

// NewContainer creates a container object.
func NewContainer(name string, bundlePath string, logPath string, labels map[string]string, sandbox string) (*Container, error) {
	c := &Container{
		name:       name,
		bundlePath: bundlePath,
		logPath:    logPath,
		labels:     labels,
		sandbox:    sandbox,
	}
	return c, nil
}

// Name returns the name of the container.
func (c *Container) Name() string {
	return c.name
}

// BundlePath returns the bundlePath of the container.
func (c *Container) BundlePath() string {
	return c.bundlePath
}

// LogPath returns the log path of the container.
func (c *Container) LogPath() string {
	return c.logPath
}

// Labels returns the labels of the container.
func (c *Container) Labels() map[string]string {
	return c.labels
}

// Sandbox returns the sandbox name of the container.
func (c *Container) Sandbox() string {
	return c.sandbox
}
<|endoftext|>


<commit_before>// Copyright 2016 The Gosl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package pde

import (
	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/fun"
	"github.com/cpmech/gosl/fun/dbf"
	"github.com/cpmech/gosl/gm"
	"github.com/cpmech/gosl/la"
)

// FdmLaplacian implements the Finite Difference (FDM) Laplacian operator (2D or 3D)
//
//              ∂²u        ∂²u        ∂²u
//    L{u} = kx ———  +  ky ———  +  kz ———
//              ∂x²        ∂y²        ∂z²
//
type FdmLaplacian struct {
	Kx       float64        // isotropic coefficient x
	Ky       float64        // isotropic coefficient y
	Kz       float64        // isotropic coefficient z
	Grid     *gm.Grid       // grid
	Source   fun.Svs        // source term function s({x},t)
	EssenBcs *BoundaryConds // essential boundary conditions
	Eqs      *la.Equations  // equations
	bcsReady bool           // boundary conditions are set
}

// NewFdmLaplacian creates a new FDM Laplacian operator with given parameters
func NewFdmLaplacian(params dbf.Params, grid *gm.Grid, source fun.Svs) (o *FdmLaplacian) {
	o = new(FdmLaplacian)
	err := params.ConnectSetOpt(
		[]*float64{&o.Kx, &o.Ky, &o.Kz},
		[]string{"kx", "ky", "kz"},
		[]bool{false, false, true},
		"FdmLaplacian",
	)
	if err != "" {
		chk.Panic(err)
	}
	o.Grid = grid
	o.Source = source
	o.EssenBcs = NewBoundaryCondsGrid(grid, 1) // 1:maxNdof
	o.bcsReady = false
	return
}

// AddEbc adds essential boundary condition given tag of edge or face
//   tag    -- edge or face tag in grid
//   cvalue -- constant value [optional]; or
//   fvalue -- function value [optional]
func (o *FdmLaplacian) AddEbc(tag int, cvalue float64, fvalue fun.Svs) {
	o.bcsReady = false
	o.EssenBcs.AddUsingTag(tag, 0, cvalue, fvalue)
}

// SetHbc sets homogeneous boundary conditions; i.e. all boundaries with zero EBC
func (o *FdmLaplacian) SetHbc() {
	if o.Grid.Ndim() == 2 {
		o.AddEbc(10, 0.0, nil)
		o.AddEbc(11, 0.0, nil)
		o.AddEbc(20, 0.0, nil)
		o.AddEbc(21, 0.0, nil)
		return
	}
	o.AddEbc(100, 0.0, nil)
	o.AddEbc(101, 0.0, nil)
	o.AddEbc(200, 0.0, nil)
	o.AddEbc(201, 0.0, nil)
	o.AddEbc(300, 0.0, nil)
	o.AddEbc(301, 0.0, nil)
}

// Assemble assembles operator into A matrix from [A] ⋅ {u} = {b}
//  reactions -- prepare for computation of RHS
func (o *FdmLaplacian) Assemble(reactions bool) {
	if !o.bcsReady {
		o.Eqs = la.NewEquations(o.Grid.Size(), o.EssenBcs.Nodes())
		o.Eqs.Alloc([]int{5 * o.Eqs.Nu, 5 * o.Eqs.Nu, 5 * o.Eqs.Nk, 5 * o.Eqs.Nk}, reactions, true)
		o.bcsReady = true
	}
	o.Eqs.Start()
	if o.Grid.Ndim() == 2 {
		nx := o.Grid.Npts(0)
		ny := o.Grid.Npts(1)
		dx := o.Grid.Xlen(0) / float64(nx-1)
		dy := o.Grid.Xlen(1) / float64(ny-1)
		dx2 := dx * dx
		dy2 := dy * dy
		α := -2.0 * (o.Kx/dx2 + o.Ky/dy2)
		β := o.Kx / dx2
		γ := o.Ky / dy2
		mol := []float64{α, β, β, γ, γ}
		jays := make([]int, 5)
		for I := 0; I < o.Eqs.N; I++ { // loop over all Nx*Ny equations
			col := I % nx    // grid column number
			row := I / nx    // grid row number
			jays[0] = I      // current node
			jays[1] = I - 1  // left node
			jays[2] = I + 1  // right node
			jays[3] = I - nx // bottom node
			jays[4] = I + nx // top node
			if col == 0 {
				jays[1] = jays[2]
			}
			if col == nx-1 {
				jays[2] = jays[1]
			}
			if row == 0 {
				jays[3] = jays[4]
			}
			if row == ny-1 {
				jays[4] = jays[3]
			}
			for k, J := range jays { // loop over non-zero columns
				o.Eqs.Put(I, J, mol[k])
			}
		}
		return
	}
	chk.Panic("TODO: Implement Assemble() in 3D\n")
}

// SolveSteady solves steady problem
//   Solves: [K]⋅{u} = {f} represented by [A]⋅{x} = {b}
func (o *FdmLaplacian) SolveSteady(reactions bool) (u, f []float64) {
	o.Eqs.SolveOnce(o.calcXk, o.calcBu)
	u = make([]float64, o.Grid.Size())
	o.Eqs.JoinVector(u, o.Eqs.Xu, o.Eqs.Xk)
	if reactions {
		f = make([]float64, o.Grid.Size())
		if o.Eqs.Nk > 0 { // need to calc Bu again because it was modified
			for i, I := range o.Eqs.UtoF {
				o.Eqs.Bu[i] = o.calcBu(I, 0)
			}
		}
		o.Eqs.JoinVector(f, o.Eqs.Bu, o.Eqs.Bk)
	}
	return
}

// auxiliary //////////////////////////////////////////////////////////////////////////////////////

// calcXk calculates known {u} values (CalcXk in la.Equations)
//  I -- node number
//  t -- time
func (o *FdmLaplacian) calcXk(I int, t float64) float64 {
	_, val, available := o.EssenBcs.Value(I, 0, t)
	if available {
		return val
	}
	return 0
}

// calcBu calculates RHS vector (e.g. source) corresponding to known values of {u} (CalcBu in la.Equations)
//  I -- node number
//  t -- time
func (o *FdmLaplacian) calcBu(I int, t float64) float64 {
	if o.Source != nil {
		return o.Source(o.Grid.Node(I), t)
	}
	return 0
}
<commit_msg>Add package description<commit_after>// Copyright 2016 The Gosl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package pde implements numerical methods for the solution of Partial Differential Equations.
// For example, this package includes the Finite Difference and the Spectral Collocation methods.
package pde

import (
	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/fun"
	"github.com/cpmech/gosl/fun/dbf"
	"github.com/cpmech/gosl/gm"
	"github.com/cpmech/gosl/la"
)

// FdmLaplacian implements the Finite Difference (FDM) Laplacian operator (2D or 3D)
//
//              ∂²u        ∂²u        ∂²u
//    L{u} = kx ———  +  ky ———  +  kz ———
//              ∂x²        ∂y²        ∂z²
//
type FdmLaplacian struct {
	Kx       float64        // isotropic coefficient x
	Ky       float64        // isotropic coefficient y
	Kz       float64        // isotropic coefficient z
	Grid     *gm.Grid       // grid
	Source   fun.Svs        // source term function s({x},t)
	EssenBcs *BoundaryConds // essential boundary conditions
	Eqs      *la.Equations  // equations
	bcsReady bool           // boundary conditions are set
}

// NewFdmLaplacian creates a new FDM Laplacian operator with given parameters
func NewFdmLaplacian(params dbf.Params, grid *gm.Grid, source fun.Svs) (o *FdmLaplacian) {
	o = new(FdmLaplacian)
	err := params.ConnectSetOpt(
		[]*float64{&o.Kx, &o.Ky, &o.Kz},
		[]string{"kx", "ky", "kz"},
		[]bool{false, false, true},
		"FdmLaplacian",
	)
	if err != "" {
		chk.Panic(err)
	}
	o.Grid = grid
	o.Source = source
	o.EssenBcs = NewBoundaryCondsGrid(grid, 1) // 1:maxNdof
	o.bcsReady = false
	return
}

// AddEbc adds essential boundary condition given tag of edge or face
//   tag    -- edge or face tag in grid
//   cvalue -- constant value [optional]; or
//   fvalue -- function value [optional]
func (o *FdmLaplacian) AddEbc(tag int, cvalue float64, fvalue fun.Svs) {
	o.bcsReady = false
	o.EssenBcs.AddUsingTag(tag, 0, cvalue, fvalue)
}

// SetHbc sets homogeneous boundary conditions; i.e. all boundaries with zero EBC
func (o *FdmLaplacian) SetHbc() {
	if o.Grid.Ndim() == 2 {
		o.AddEbc(10, 0.0, nil)
		o.AddEbc(11, 0.0, nil)
		o.AddEbc(20, 0.0, nil)
		o.AddEbc(21, 0.0, nil)
		return
	}
	o.AddEbc(100, 0.0, nil)
	o.AddEbc(101, 0.0, nil)
	o.AddEbc(200, 0.0, nil)
	o.AddEbc(201, 0.0, nil)
	o.AddEbc(300, 0.0, nil)
	o.AddEbc(301, 0.0, nil)
}

// Assemble assembles operator into A matrix from [A] ⋅ {u} = {b}
//  reactions -- prepare for computation of RHS
func (o *FdmLaplacian) Assemble(reactions bool) {
	if !o.bcsReady {
		o.Eqs = la.NewEquations(o.Grid.Size(), o.EssenBcs.Nodes())
		o.Eqs.Alloc([]int{5 * o.Eqs.Nu, 5 * o.Eqs.Nu, 5 * o.Eqs.Nk, 5 * o.Eqs.Nk}, reactions, true)
		o.bcsReady = true
	}
	o.Eqs.Start()
	if o.Grid.Ndim() == 2 {
		nx := o.Grid.Npts(0)
		ny := o.Grid.Npts(1)
		dx := o.Grid.Xlen(0) / float64(nx-1)
		dy := o.Grid.Xlen(1) / float64(ny-1)
		dx2 := dx * dx
		dy2 := dy * dy
		α := -2.0 * (o.Kx/dx2 + o.Ky/dy2)
		β := o.Kx / dx2
		γ := o.Ky / dy2
		mol := []float64{α, β, β, γ, γ}
		jays := make([]int, 5)
		for I := 0; I < o.Eqs.N; I++ { // loop over all Nx*Ny equations
			col := I % nx    // grid column number
			row := I / nx    // grid row number
			jays[0] = I      // current node
			jays[1] = I - 1  // left node
			jays[2] = I + 1  // right node
			jays[3] = I - nx // bottom node
			jays[4] = I + nx // top node
			if col == 0 {
				jays[1] = jays[2]
			}
			if col == nx-1 {
				jays[2] = jays[1]
			}
			if row == 0 {
				jays[3] = jays[4]
			}
			if row == ny-1 {
				jays[4] = jays[3]
			}
			for k, J := range jays { // loop over non-zero columns
				o.Eqs.Put(I, J, mol[k])
			}
		}
		return
	}
	chk.Panic("TODO: Implement Assemble() in 3D\n")
}

// SolveSteady solves steady problem
//   Solves: [K]⋅{u} = {f} represented by [A]⋅{x} = {b}
func (o *FdmLaplacian) SolveSteady(reactions bool) (u, f []float64) {
	o.Eqs.SolveOnce(o.calcXk, o.calcBu)
	u = make([]float64, o.Grid.Size())
	o.Eqs.JoinVector(u, o.Eqs.Xu, o.Eqs.Xk)
	if reactions {
		f = make([]float64, o.Grid.Size())
		if o.Eqs.Nk > 0 { // need to calc Bu again because it was modified
			for i, I := range o.Eqs.UtoF {
				o.Eqs.Bu[i] = o.calcBu(I, 0)
			}
		}
		o.Eqs.JoinVector(f, o.Eqs.Bu, o.Eqs.Bk)
	}
	return
}

// auxiliary //////////////////////////////////////////////////////////////////////////////////////

// calcXk calculates known {u} values (CalcXk in la.Equations)
//  I -- node number
//  t -- time
func (o *FdmLaplacian) calcXk(I int, t float64) float64 {
	_, val, available := o.EssenBcs.Value(I, 0, t)
	if available {
		return val
	}
	return 0
}

// calcBu calculates RHS vector (e.g. source) corresponding to known values of {u} (CalcBu in la.Equations)
//  I -- node number
//  t -- time
func (o *FdmLaplacian) calcBu(I int, t float64) float64 {
	if o.Source != nil {
		return o.Source(o.Grid.Node(I), t)
	}
	return 0
}
<|endoftext|>


<commit_before>package penname

import (
	"fmt"
	"net/http"
)

type PenName struct {
	Closed         bool
	Written        []byte
	WrittenHeaders []byte
	returnError    error
}

func New() *PenName {
	return &PenName{}
}

func (p *PenName) Close() error {
	if p.returnError != nil {
		return p.returnError
	}

	p.Closed = true
	return nil
}

// Implements the ResponseWriter interface, returning an empty set of headers
// to meet the interface requirements
func (p *PenName) Header() http.Header {
	return http.Header{}
}

// Convencinece method for reseting state.
func (p *PenName) Reset() {
	p.Closed = false
	p.Written = []byte{}
}

// Sets the error that will be returned when actions are attempted.
func (p *PenName) ReturnError(err error) {
	p.returnError = err
}

// Implements the Writer interface, returning an error if returnError is set.
// The contents of what is written is stored in Written for inspection later.
func (p *PenName) Write(b []byte) (n int, err error) {
	if p.returnError != nil {
		return 0, p.returnError
	}

	p.Written = b
	return len(p.Written), nil
}

// Implements the ResponseWriter interface, capturing headers to the same written buffer
func (p *PenName) WriteHeader(i int) {
	b := []byte(fmt.Sprintf("Header: %v", i))
	p.WrittenHeaders = b
	p.Write(b)
}
<commit_msg>updating method docs<commit_after>package penname

import (
	"fmt"
	"net/http"
)

// PenName contains the state of the mock for performing its designated actions
// and capturing details for assertions
type PenName struct {
	Closed         bool
	Written        []byte
	WrittenHeaders []byte
	returnError    error
}

// New returns an initialized PenName for use in tests
func New() *PenName {
	return &PenName{}
}

// Close implements the closer interface, returning an error if returnError is
// set.  Whether or not Close is called is stored in Closed for inspection
// later.
func (p *PenName) Close() error {
	if p.returnError != nil {
		return p.returnError
	}

	p.Closed = true
	return nil
}

// Header implements the ResponseWriter interface, returning an empty set of
// headers to meet the interface requirements
func (p *PenName) Header() http.Header {
	return http.Header{}
}

// Reset is a convencinece method for reseting the state of the mock
func (p *PenName) Reset() {
	p.Closed = false
	p.Written = []byte{}
}

// ReturnError sets the error that will be returned when actions are attempted
func (p *PenName) ReturnError(err error) {
	p.returnError = err
}

// Write implements the Writer interface, returning an error if returnError is
// set.  The contents of what is written is stored in Written for inspection
// later.
func (p *PenName) Write(b []byte) (n int, err error) {
	if p.returnError != nil {
		return 0, p.returnError
	}

	p.Written = b
	return len(p.Written), nil
}

// WriteHeader implements the ResponseWriter interface, capturing headers to the
// same written buffer
func (p *PenName) WriteHeader(i int) {
	b := []byte(fmt.Sprintf("Header: %v", i))
	p.WrittenHeaders = b
	p.Write(b)
}
<|endoftext|>


<commit_before>package msgqueue

import (
	"runtime"
	"time"

	"github.com/go-redis/redis"
	"github.com/go-redis/redis_rate"
	"golang.org/x/time/rate"
)

type Redis interface {
	Del(keys ...string) *redis.IntCmd
	SetNX(key string, value interface{}, expiration time.Duration) *redis.BoolCmd
	SAdd(key string, members ...interface{}) *redis.IntCmd
	SMembers(key string) *redis.StringSliceCmd
	Pipelined(func(pipe redis.Pipeliner) error) ([]redis.Cmder, error)
	Eval(script string, keys []string, args ...interface{}) *redis.Cmd
	Publish(channel, message string) *redis.IntCmd
}

type Storage interface {
	Exists(key string) bool
}

type redisStorage struct {
	Redis
}

var _ Storage = (*redisStorage)(nil)

func (s redisStorage) Exists(key string) bool {
	val, err := s.SetNX(key, "", 24*time.Hour).Result()
	if err != nil {
		return true
	}
	return !val
}

type RateLimiter interface {
	AllowRate(name string, limit rate.Limit) (delay time.Duration, allow bool)
}

type Options struct {
	// Queue name.
	Name string
	// Queue group name.
	GroupName string

	// Function called to process a message.
	Handler interface{}
	// Function called to process failed message.
	FallbackHandler interface{}

	// Number of worker goroutines processing messages.
	// Default is 4 * number of CPUs.
	WorkerNumber int
	// Global limit of concurrently running workers. Overrides WorkerNumber.
	WorkerLimit int

	// Size of the buffer where reserved messages are stored.
	// Default is the same as WorkerNumber.
	BufferSize int

	// Number of messages reserved in the queue in 1 request.
	// Default is 10.
	ReservationSize int
	// Time after which the reserved message is returned to the queue.
	ReservationTimeout time.Duration
	// Time that a long polling receive call waits for a message to become
	// available before returning an empty response.
	// Default is 10 seconds.
	WaitTimeout time.Duration

	// Number of tries/releases after which the message fails permanently
	// and is deleted.
	RetryLimit int
	// Minimum backoff time between retries.
	MinBackoff time.Duration
	// Maximum backoff time between retries.
	MaxBackoff time.Duration

	// Number of consecutive failures after which queue processing is paused.
	// Default is 100 failures.
	PauseErrorsThreshold int

	// Processing rate limit.
	RateLimit rate.Limit

	// Redis client that is used for storing metadata.
	Redis Redis

	// Optional storage interface. The default is to use Redis.
	Storage Storage

	// Optional rate limiter interface. The default is to use Redis.
	RateLimiter RateLimiter

	inited bool
}

func (opt *Options) Init() {
	if opt.inited {
		return
	}
	opt.inited = true

	if opt.GroupName == "" {
		opt.GroupName = opt.Name
	}

	if opt.WorkerLimit > 0 {
		opt.WorkerNumber = opt.WorkerLimit
	}
	if opt.WorkerNumber == 0 {
		opt.WorkerNumber = 4 * runtime.NumCPU()
	}

	if opt.BufferSize == 0 {
		opt.BufferSize = opt.WorkerNumber
	}

	switch opt.PauseErrorsThreshold {
	case -1:
		opt.PauseErrorsThreshold = 0
	case 0:
		opt.PauseErrorsThreshold = 100
	}

	if opt.RateLimit == 0 {
		opt.RateLimit = rate.Inf
	}

	if opt.ReservationSize == 0 {
		opt.ReservationSize = 10
	}
	if opt.ReservationTimeout == 0 {
		opt.ReservationTimeout = 300 * time.Second
	}
	if opt.WaitTimeout == 0 {
		opt.WaitTimeout = 10 * time.Second
	}

	if opt.RetryLimit == 0 {
		opt.RetryLimit = 10
	}
	if opt.MinBackoff == 0 {
		opt.MinBackoff = 30 * time.Second
	}
	if opt.MaxBackoff == 0 {
		opt.MaxBackoff = 12 * time.Hour
	}

	if opt.Storage == nil {
		opt.Storage = redisStorage{opt.Redis}
	}

	if opt.RateLimit != rate.Inf && opt.RateLimiter == nil && opt.Redis != nil {
		limiter := redis_rate.NewLimiter(opt.Redis)
		limiter.Fallback = rate.NewLimiter(opt.RateLimit, 1)
		opt.RateLimiter = limiter
	}
}
<commit_msg>Update go-redis<commit_after>package msgqueue

import (
	"runtime"
	"time"

	"github.com/go-redis/redis"
	"github.com/go-redis/redis_rate"
	"golang.org/x/time/rate"
)

type Redis interface {
	Del(keys ...string) *redis.IntCmd
	SetNX(key string, value interface{}, expiration time.Duration) *redis.BoolCmd
	SAdd(key string, members ...interface{}) *redis.IntCmd
	SMembers(key string) *redis.StringSliceCmd
	Pipelined(func(pipe redis.Pipeliner) error) ([]redis.Cmder, error)
	Eval(script string, keys []string, args ...interface{}) *redis.Cmd
	Publish(channel string, message interface{}) *redis.IntCmd
}

type Storage interface {
	Exists(key string) bool
}

type redisStorage struct {
	Redis
}

var _ Storage = (*redisStorage)(nil)

func (s redisStorage) Exists(key string) bool {
	val, err := s.SetNX(key, "", 24*time.Hour).Result()
	if err != nil {
		return true
	}
	return !val
}

type RateLimiter interface {
	AllowRate(name string, limit rate.Limit) (delay time.Duration, allow bool)
}

type Options struct {
	// Queue name.
	Name string
	// Queue group name.
	GroupName string

	// Function called to process a message.
	Handler interface{}
	// Function called to process failed message.
	FallbackHandler interface{}

	// Number of worker goroutines processing messages.
	// Default is 4 * number of CPUs.
	WorkerNumber int
	// Global limit of concurrently running workers. Overrides WorkerNumber.
	WorkerLimit int

	// Size of the buffer where reserved messages are stored.
	// Default is the same as WorkerNumber.
	BufferSize int

	// Number of messages reserved in the queue in 1 request.
	// Default is 10.
	ReservationSize int
	// Time after which the reserved message is returned to the queue.
	ReservationTimeout time.Duration
	// Time that a long polling receive call waits for a message to become
	// available before returning an empty response.
	// Default is 10 seconds.
	WaitTimeout time.Duration

	// Number of tries/releases after which the message fails permanently
	// and is deleted.
	RetryLimit int
	// Minimum backoff time between retries.
	MinBackoff time.Duration
	// Maximum backoff time between retries.
	MaxBackoff time.Duration

	// Number of consecutive failures after which queue processing is paused.
	// Default is 100 failures.
	PauseErrorsThreshold int

	// Processing rate limit.
	RateLimit rate.Limit

	// Redis client that is used for storing metadata.
	Redis Redis

	// Optional storage interface. The default is to use Redis.
	Storage Storage

	// Optional rate limiter interface. The default is to use Redis.
	RateLimiter RateLimiter

	inited bool
}

func (opt *Options) Init() {
	if opt.inited {
		return
	}
	opt.inited = true

	if opt.GroupName == "" {
		opt.GroupName = opt.Name
	}

	if opt.WorkerLimit > 0 {
		opt.WorkerNumber = opt.WorkerLimit
	}
	if opt.WorkerNumber == 0 {
		opt.WorkerNumber = 4 * runtime.NumCPU()
	}

	if opt.BufferSize == 0 {
		opt.BufferSize = opt.WorkerNumber
	}

	switch opt.PauseErrorsThreshold {
	case -1:
		opt.PauseErrorsThreshold = 0
	case 0:
		opt.PauseErrorsThreshold = 100
	}

	if opt.RateLimit == 0 {
		opt.RateLimit = rate.Inf
	}

	if opt.ReservationSize == 0 {
		opt.ReservationSize = 10
	}
	if opt.ReservationTimeout == 0 {
		opt.ReservationTimeout = 300 * time.Second
	}
	if opt.WaitTimeout == 0 {
		opt.WaitTimeout = 10 * time.Second
	}

	if opt.RetryLimit == 0 {
		opt.RetryLimit = 10
	}
	if opt.MinBackoff == 0 {
		opt.MinBackoff = 30 * time.Second
	}
	if opt.MaxBackoff == 0 {
		opt.MaxBackoff = 12 * time.Hour
	}

	if opt.Storage == nil {
		opt.Storage = redisStorage{opt.Redis}
	}

	if opt.RateLimit != rate.Inf && opt.RateLimiter == nil && opt.Redis != nil {
		limiter := redis_rate.NewLimiter(opt.Redis)
		limiter.Fallback = rate.NewLimiter(opt.RateLimit, 1)
		opt.RateLimiter = limiter
	}
}
<|endoftext|>


<commit_before>package msgqueue

import (
	"runtime"
	"time"

	"github.com/go-redis/rate"
	"github.com/go-redis/redis"
	timerate "golang.org/x/time/rate"
)

type Redis interface {
	Del(keys ...string) *redis.IntCmd
	SetNX(key string, value interface{}, expiration time.Duration) *redis.BoolCmd
	SAdd(key string, members ...interface{}) *redis.IntCmd
	SMembers(key string) *redis.StringSliceCmd
	Pipelined(func(pipe *redis.Pipeline) error) ([]redis.Cmder, error)
	Eval(script string, keys []string, args ...interface{}) *redis.Cmd
	Publish(channel, message string) *redis.IntCmd
}

type Storage interface {
	Exists(key string) bool
}

type redisStorage struct {
	Redis
}

var _ Storage = (*redisStorage)(nil)

func (s redisStorage) Exists(key string) bool {
	return !s.SetNX(key, "", 24*time.Hour).Val()
}

type RateLimiter interface {
	AllowRate(name string, limit timerate.Limit) (delay time.Duration, allow bool)
}

type Options struct {
	// Queue name.
	Name string
	// Queue group name.
	GroupName string

	// Function called to process a message.
	Handler interface{}
	// Function called to process failed message.
	FallbackHandler interface{}

	// Number of goroutines processing messages.
	WorkerNumber int
	// Global limit of concurrently running workers. Overrides WorkerNumber.
	WorkerLimit int

	// Size of the buffer where reserved messages are stored.
	BufferSize int

	// Time after which the reserved message is returned to the queue.
	ReservationTimeout time.Duration

	// Number of tries/releases after which the message fails permanently
	// and is deleted.
	RetryLimit int

	// Minimum time between retries.
	MinBackoff time.Duration

	// Processing rate limit.
	RateLimit timerate.Limit

	// Redis client that is used for storing metadata.
	Redis Redis

	// Optional storage interface. The default is to use Redis.
	Storage Storage

	// Optional rate limiter interface. The default is to use Redis.
	RateLimiter RateLimiter

	inited bool
}

func (opt *Options) Init() {
	if opt.inited {
		return
	}
	opt.inited = true

	if opt.GroupName == "" {
		opt.GroupName = opt.Name
	}
	if opt.WorkerLimit > 0 {
		opt.WorkerNumber = opt.WorkerLimit
	}
	if opt.WorkerNumber == 0 {
		opt.WorkerNumber = 10 * runtime.NumCPU()
	}
	if opt.BufferSize == 0 {
		opt.BufferSize = opt.WorkerNumber
		if opt.BufferSize > 10 {
			opt.BufferSize = 10
		}
	}
	if opt.RateLimit == 0 {
		opt.RateLimit = timerate.Inf
	}
	if opt.ReservationTimeout == 0 {
		opt.ReservationTimeout = 300 * time.Second
	}
	if opt.RetryLimit == 0 {
		opt.RetryLimit = 10
	}
	if opt.MinBackoff == 0 {
		opt.MinBackoff = 3 * time.Second
	}

	if opt.Storage == nil {
		opt.Storage = redisStorage{opt.Redis}
	}

	if opt.RateLimit != timerate.Inf && opt.RateLimiter == nil && opt.Redis != nil {
		fallbackLimiter := timerate.NewLimiter(opt.RateLimit, 1)
		opt.RateLimiter = rate.NewLimiter(opt.Redis, fallbackLimiter)
	}
}
<commit_msg>Update to latest Redis client<commit_after>package msgqueue

import (
	"runtime"
	"time"

	"github.com/go-redis/rate"
	"github.com/go-redis/redis"
	timerate "golang.org/x/time/rate"
)

type Redis interface {
	Del(keys ...string) *redis.IntCmd
	SetNX(key string, value interface{}, expiration time.Duration) *redis.BoolCmd
	SAdd(key string, members ...interface{}) *redis.IntCmd
	SMembers(key string) *redis.StringSliceCmd
	Pipelined(func(pipe redis.Pipeliner) error) ([]redis.Cmder, error)
	Eval(script string, keys []string, args ...interface{}) *redis.Cmd
	Publish(channel, message string) *redis.IntCmd
}

type Storage interface {
	Exists(key string) bool
}

type redisStorage struct {
	Redis
}

var _ Storage = (*redisStorage)(nil)

func (s redisStorage) Exists(key string) bool {
	return !s.SetNX(key, "", 24*time.Hour).Val()
}

type RateLimiter interface {
	AllowRate(name string, limit timerate.Limit) (delay time.Duration, allow bool)
}

type Options struct {
	// Queue name.
	Name string
	// Queue group name.
	GroupName string

	// Function called to process a message.
	Handler interface{}
	// Function called to process failed message.
	FallbackHandler interface{}

	// Number of goroutines processing messages.
	WorkerNumber int
	// Global limit of concurrently running workers. Overrides WorkerNumber.
	WorkerLimit int

	// Size of the buffer where reserved messages are stored.
	BufferSize int

	// Time after which the reserved message is returned to the queue.
	ReservationTimeout time.Duration

	// Number of tries/releases after which the message fails permanently
	// and is deleted.
	RetryLimit int

	// Minimum time between retries.
	MinBackoff time.Duration

	// Processing rate limit.
	RateLimit timerate.Limit

	// Redis client that is used for storing metadata.
	Redis Redis

	// Optional storage interface. The default is to use Redis.
	Storage Storage

	// Optional rate limiter interface. The default is to use Redis.
	RateLimiter RateLimiter

	inited bool
}

func (opt *Options) Init() {
	if opt.inited {
		return
	}
	opt.inited = true

	if opt.GroupName == "" {
		opt.GroupName = opt.Name
	}
	if opt.WorkerLimit > 0 {
		opt.WorkerNumber = opt.WorkerLimit
	}
	if opt.WorkerNumber == 0 {
		opt.WorkerNumber = 10 * runtime.NumCPU()
	}
	if opt.BufferSize == 0 {
		opt.BufferSize = opt.WorkerNumber
		if opt.BufferSize > 10 {
			opt.BufferSize = 10
		}
	}
	if opt.RateLimit == 0 {
		opt.RateLimit = timerate.Inf
	}
	if opt.ReservationTimeout == 0 {
		opt.ReservationTimeout = 300 * time.Second
	}
	if opt.RetryLimit == 0 {
		opt.RetryLimit = 10
	}
	if opt.MinBackoff == 0 {
		opt.MinBackoff = 3 * time.Second
	}

	if opt.Storage == nil {
		opt.Storage = redisStorage{opt.Redis}
	}

	if opt.RateLimit != timerate.Inf && opt.RateLimiter == nil && opt.Redis != nil {
		fallbackLimiter := timerate.NewLimiter(opt.RateLimit, 1)
		opt.RateLimiter = rate.NewLimiter(opt.Redis, fallbackLimiter)
	}
}
<|endoftext|>


<commit_before>// +build linux darwin dragonfly openbsd_amd64 freebsd

package action

import (
	shellquote "github.com/kballard/go-shellquote"
	"github.com/zyedidia/micro/v2/internal/shell"
)

// TermEmuSupported is a constant that marks if the terminal emulator is supported
const TermEmuSupported = true

// RunTermEmulator starts a terminal emulator from a bufpane with the given input (command)
// if wait is true it will wait for the user to exit by pressing enter once the executable has terminated
// if getOutput is true it will redirect the stdout of the process to a pipe which will be passed to the
// callback which is a function that takes a string and a list of optional user arguments
func RunTermEmulator(h *BufPane, input string, wait bool, getOutput bool, callback func(out string, userargs []interface{}), userargs []interface{}) error {
	args, err := shellquote.Split(input)
	if err != nil {
		return err
	}
	if len(args) == 0 {
		return nil
	}

	t := new(shell.Terminal)
	t.Start(args, getOutput, wait, callback, userargs)

	h.AddTab()
	id := MainTab().Panes[0].ID()

	v := h.GetView()

	tp, err := NewTermPane(v.X, v.Y, v.Width, v.Height, t, id, MainTab())
	if err != nil {
		return err
	}
	MainTab().Panes[0] = tp
	MainTab().SetActive(0)

	return nil
}
<commit_msg>Check error in terminal emulator<commit_after>// +build linux darwin dragonfly openbsd_amd64 freebsd

package action

import (
	shellquote "github.com/kballard/go-shellquote"
	"github.com/zyedidia/micro/v2/internal/shell"
)

// TermEmuSupported is a constant that marks if the terminal emulator is supported
const TermEmuSupported = true

// RunTermEmulator starts a terminal emulator from a bufpane with the given input (command)
// if wait is true it will wait for the user to exit by pressing enter once the executable has terminated
// if getOutput is true it will redirect the stdout of the process to a pipe which will be passed to the
// callback which is a function that takes a string and a list of optional user arguments
func RunTermEmulator(h *BufPane, input string, wait bool, getOutput bool, callback func(out string, userargs []interface{}), userargs []interface{}) error {
	args, err := shellquote.Split(input)
	if err != nil {
		return err
	}
	if len(args) == 0 {
		return nil
	}

	t := new(shell.Terminal)
	err = t.Start(args, getOutput, wait, callback, userargs)
	if err != nil {
		return err
	}

	h.AddTab()
	id := MainTab().Panes[0].ID()

	v := h.GetView()

	tp, err := NewTermPane(v.X, v.Y, v.Width, v.Height, t, id, MainTab())
	if err != nil {
		return err
	}
	MainTab().Panes[0] = tp
	MainTab().SetActive(0)

	return nil
}
<|endoftext|>


<commit_before>package features

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/route53"
	"github.com/barnybug/cli53"

	. "github.com/lsegal/gucumber"
)

func getService() *route53.Route53 {
	client := aws.Config{}
	return route53.New(&client)
}

func fatalIfErr(err error) {
	if err != nil {
		log.Fatalf("Unexpected error: %s", err)
	}
}

var cleanupIds = []string{}
var runOutput string

func domainExists(name string) bool {
	return domainId(name) != ""
}

func domainId(name string) string {
	r53 := getService()
	zones, err := r53.ListHostedZones(nil)
	fatalIfErr(err)
	for _, zone := range zones.HostedZones {
		if *zone.Name == name+"." {
			return *zone.Id
		}
	}
	return ""
}

var seeded sync.Once

func uniqueReference() string {
	seeded.Do(func() {
		rand.Seed(time.Now().UnixNano())
	})
	return fmt.Sprint(rand.Int())
}

func cleanupDomain(r53 *route53.Route53, id string) {
	// delete all non-default SOA/NS records
	rrsets, err := cli53.ListAllRecordSets(r53, id)
	fatalIfErr(err)
	changes := []*route53.Change{}
	for _, rrset := range rrsets {
		if *rrset.Type != "NS" && *rrset.Type != "SOA" {
			change := &route53.Change{
				Action:            aws.String("DELETE"),
				ResourceRecordSet: rrset,
			}
			changes = append(changes, change)
		}
	}

	if len(changes) > 0 {
		req2 := route53.ChangeResourceRecordSetsInput{
			HostedZoneId: &id,
			ChangeBatch: &route53.ChangeBatch{
				Changes: changes,
			},
		}
		_, err = r53.ChangeResourceRecordSets(&req2)
		if err != nil {
			fmt.Printf("Warning: cleanup failed - %s\n", err)
		}
	}

	req3 := route53.DeleteHostedZoneInput{Id: &id}
	_, err = r53.DeleteHostedZone(&req3)
	if err != nil {
		fmt.Printf("Warning: cleanup failed - %s\n", err)
	}
}

// Split on whitespace, but leave quoted strings in tact
func safeSplit(s string) []string {
	split := strings.Split(s, " ")

	var result []string
	var inquote string
	var block string
	for _, i := range split {
		if inquote == "" {
			if strings.HasPrefix(i, "'") || strings.HasPrefix(i, "\"") {
				inquote = string(i[0])
				block = strings.TrimPrefix(i, inquote) + " "
			} else {
				result = append(result, i)
			}
		} else {
			if !strings.HasSuffix(i, inquote) {
				block += i + " "
			} else {
				block += strings.TrimSuffix(i, inquote)
				inquote = ""
				result = append(result, block)
				block = ""
			}
		}
	}

	return result
}

func init() {
	After("", func() {
		if len(cleanupIds) > 0 {
			// cleanup
			r53 := getService()
			for _, id := range cleanupIds {
				cleanupDomain(r53, id)
			}
			cleanupIds = []string{}
		}
	})

	Given(`^I have a domain "(.+?)"$`, func(name string) {
		// create a test domain
		r53 := getService()
		callerReference := uniqueReference()
		req := route53.CreateHostedZoneInput{
			CallerReference: &callerReference,
			Name:            &name,
		}
		resp, err := r53.CreateHostedZone(&req)
		fatalIfErr(err)
		cleanupIds = append(cleanupIds, *resp.HostedZone.Id)
	})

	When(`^I run "(.+?)"$`, func(cmd string) {
		args := safeSplit(cmd)
		ps := exec.Command("./"+args[0], args[1:]...)
		out, err := ps.CombinedOutput()
		if err != nil {
			T.Errorf("Error: %s Output: %s", err, out)
		} else {
			runOutput = string(out)
		}
	})

	Then(`^the domain "(.+?)" is created$`, func(name string) {
		id := domainId(name)
		if id == "" {
			T.Errorf("Domain %s was not created", name)
		} else {
			cleanupIds = append(cleanupIds, id)
		}
	})

	Then(`^the domain "(.+?)" is deleted$`, func(name string) {
		id := domainId(name)
		if id == "" {
			cleanupIds = []string{} // drop from cleanupIds
		} else {
			T.Errorf("Domain %s was not deleted", name)
			cleanupIds = append(cleanupIds, id)
		}
	})

	Then(`^the domain "(.+?)" has (\d+) records$`, func(name string, expected int) {
		r53 := getService()
		id := domainId(name)
		rrsets, err := cli53.ListAllRecordSets(r53, id)
		fatalIfErr(err)
		actual := len(rrsets)
		if expected != actual {
			T.Errorf("Domain %s: Expected %d records, actually %d records ", name, expected, actual)
		}
	})

	Then(`^the domain "(.+?)" has record "(.+)"$`, func(name, record string) {
		if !hasRecord(name, record) {
			T.Errorf("Domain %s: missing record %s", name, record)
		}
	})

	Then(`^the domain "(.+?)" doesn't have record "(.+)"$`, func(name, record string) {
		if hasRecord(name, record) {
			T.Errorf("Domain %s: present record %s", name, record)
		}
	})

	Then(`^the domain "(.+?)" export matches file "(.+?)"( including auth)?$`, func(name, filename, auth string) {
		ps := exec.Command("./cli53", "export", name)
		actual, err := ps.CombinedOutput()
		if err != nil {
			T.Errorf("Error: %s Output: %s", err, actual)
		} else {
			rfile, err := os.Open(filename)
			fatalIfErr(err)
			defer rfile.Close()
			expected, err := ioutil.ReadAll(rfile)
			fatalIfErr(err)

			errors := compareDomains(expected, actual, auth != "")
			if len(errors) > 0 {
				T.Errorf(errors)
			}
		}
	})

	Then(`^the output contains "(.+?)"$`, func(s string) {
		if !strings.Contains(runOutput, s) {
			T.Errorf("Output did not contain \"%s\"", s)
		}
	})
}

func hasRecord(name, record string) bool {
	r53 := getService()
	id := domainId(name)
	rrsets, err := cli53.ListAllRecordSets(r53, id)
	fatalIfErr(err)

	for _, rrset := range rrsets {
		rrs := cli53.ConvertRRSetToBind(rrset)
		for _, rr := range rrs {
			line := rr.String()
			line = strings.Replace(line, "\t", " ", -1)
			if record == line {
				return true
			}
		}
	}
	return false
}

func prepareZoneFile(b []byte, includeAuth bool) map[string]bool {
	s := string(b)
	s = strings.Replace(s, "\t", " ", -1)
	lines := strings.Split(s, "\n")
	ret := map[string]bool{}
	for _, line := range lines {
		if !includeAuth && (strings.Contains(line, " NS ") || strings.Contains(line, " SOA ")) {
			continue
		}
		ret[line] = true
	}
	return ret
}

func compareDomains(expected, actual []byte, includeAuth bool) string {
	mexpected := prepareZoneFile(expected, includeAuth)
	mactual := prepareZoneFile(actual, includeAuth)

	var errors string
	for record := range mexpected {
		if _, ok := mactual[record]; ok {
			delete(mactual, record)
		} else {
			errors += fmt.Sprintf("Expected record '%s' missing\n", record)
		}
	}
	for record := range mactual {
		errors += fmt.Sprintf("Unexpected record '%s' present\n", record)
	}
	return errors
}
<commit_msg>Ensure throttled requests in tests are retried.<commit_after>package features

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/route53"
	"github.com/barnybug/cli53"

	. "github.com/lsegal/gucumber"
)

func getService() *route53.Route53 {
	config := aws.Config{}
	// ensures throttled requests are retried
	config.MaxRetries = aws.Int(100)
	return route53.New(&config)
}

func fatalIfErr(err error) {
	if err != nil {
		log.Fatalf("Unexpected error: %s", err)
	}
}

var cleanupIds = []string{}
var runOutput string

func domainExists(name string) bool {
	return domainId(name) != ""
}

func domainId(name string) string {
	r53 := getService()
	zones, err := r53.ListHostedZones(nil)
	fatalIfErr(err)
	for _, zone := range zones.HostedZones {
		if *zone.Name == name+"." {
			return *zone.Id
		}
	}
	return ""
}

var seeded sync.Once

func uniqueReference() string {
	seeded.Do(func() {
		rand.Seed(time.Now().UnixNano())
	})
	return fmt.Sprint(rand.Int())
}

func cleanupDomain(r53 *route53.Route53, id string) {
	// delete all non-default SOA/NS records
	rrsets, err := cli53.ListAllRecordSets(r53, id)
	fatalIfErr(err)
	changes := []*route53.Change{}
	for _, rrset := range rrsets {
		if *rrset.Type != "NS" && *rrset.Type != "SOA" {
			change := &route53.Change{
				Action:            aws.String("DELETE"),
				ResourceRecordSet: rrset,
			}
			changes = append(changes, change)
		}
	}

	if len(changes) > 0 {
		req2 := route53.ChangeResourceRecordSetsInput{
			HostedZoneId: &id,
			ChangeBatch: &route53.ChangeBatch{
				Changes: changes,
			},
		}
		_, err = r53.ChangeResourceRecordSets(&req2)
		if err != nil {
			fmt.Printf("Warning: cleanup failed - %s\n", err)
		}
	}

	req3 := route53.DeleteHostedZoneInput{Id: &id}
	_, err = r53.DeleteHostedZone(&req3)
	if err != nil {
		fmt.Printf("Warning: cleanup failed - %s\n", err)
	}
}

// Split on whitespace, but leave quoted strings in tact
func safeSplit(s string) []string {
	split := strings.Split(s, " ")

	var result []string
	var inquote string
	var block string
	for _, i := range split {
		if inquote == "" {
			if strings.HasPrefix(i, "'") || strings.HasPrefix(i, "\"") {
				inquote = string(i[0])
				block = strings.TrimPrefix(i, inquote) + " "
			} else {
				result = append(result, i)
			}
		} else {
			if !strings.HasSuffix(i, inquote) {
				block += i + " "
			} else {
				block += strings.TrimSuffix(i, inquote)
				inquote = ""
				result = append(result, block)
				block = ""
			}
		}
	}

	return result
}

func init() {
	After("", func() {
		if len(cleanupIds) > 0 {
			// cleanup
			r53 := getService()
			for _, id := range cleanupIds {
				cleanupDomain(r53, id)
			}
			cleanupIds = []string{}
		}
	})

	Given(`^I have a domain "(.+?)"$`, func(name string) {
		// create a test domain
		r53 := getService()
		callerReference := uniqueReference()
		req := route53.CreateHostedZoneInput{
			CallerReference: &callerReference,
			Name:            &name,
		}
		resp, err := r53.CreateHostedZone(&req)
		fatalIfErr(err)
		cleanupIds = append(cleanupIds, *resp.HostedZone.Id)
	})

	When(`^I run "(.+?)"$`, func(cmd string) {
		args := safeSplit(cmd)
		ps := exec.Command("./"+args[0], args[1:]...)
		out, err := ps.CombinedOutput()
		if err != nil {
			T.Errorf("Error: %s Output: %s", err, out)
		} else {
			runOutput = string(out)
		}
	})

	Then(`^the domain "(.+?)" is created$`, func(name string) {
		id := domainId(name)
		if id == "" {
			T.Errorf("Domain %s was not created", name)
		} else {
			cleanupIds = append(cleanupIds, id)
		}
	})

	Then(`^the domain "(.+?)" is deleted$`, func(name string) {
		id := domainId(name)
		if id == "" {
			cleanupIds = []string{} // drop from cleanupIds
		} else {
			T.Errorf("Domain %s was not deleted", name)
			cleanupIds = append(cleanupIds, id)
		}
	})

	Then(`^the domain "(.+?)" has (\d+) records$`, func(name string, expected int) {
		r53 := getService()
		id := domainId(name)
		rrsets, err := cli53.ListAllRecordSets(r53, id)
		fatalIfErr(err)
		actual := len(rrsets)
		if expected != actual {
			T.Errorf("Domain %s: Expected %d records, actually %d records ", name, expected, actual)
		}
	})

	Then(`^the domain "(.+?)" has record "(.+)"$`, func(name, record string) {
		if !hasRecord(name, record) {
			T.Errorf("Domain %s: missing record %s", name, record)
		}
	})

	Then(`^the domain "(.+?)" doesn't have record "(.+)"$`, func(name, record string) {
		if hasRecord(name, record) {
			T.Errorf("Domain %s: present record %s", name, record)
		}
	})

	Then(`^the domain "(.+?)" export matches file "(.+?)"( including auth)?$`, func(name, filename, auth string) {
		ps := exec.Command("./cli53", "export", name)
		actual, err := ps.CombinedOutput()
		if err != nil {
			T.Errorf("Error: %s Output: %s", err, actual)
		} else {
			rfile, err := os.Open(filename)
			fatalIfErr(err)
			defer rfile.Close()
			expected, err := ioutil.ReadAll(rfile)
			fatalIfErr(err)

			errors := compareDomains(expected, actual, auth != "")
			if len(errors) > 0 {
				T.Errorf(errors)
			}
		}
	})

	Then(`^the output contains "(.+?)"$`, func(s string) {
		if !strings.Contains(runOutput, s) {
			T.Errorf("Output did not contain \"%s\"", s)
		}
	})
}

func hasRecord(name, record string) bool {
	r53 := getService()
	id := domainId(name)
	rrsets, err := cli53.ListAllRecordSets(r53, id)
	fatalIfErr(err)

	for _, rrset := range rrsets {
		rrs := cli53.ConvertRRSetToBind(rrset)
		for _, rr := range rrs {
			line := rr.String()
			line = strings.Replace(line, "\t", " ", -1)
			if record == line {
				return true
			}
		}
	}
	return false
}

func prepareZoneFile(b []byte, includeAuth bool) map[string]bool {
	s := string(b)
	s = strings.Replace(s, "\t", " ", -1)
	lines := strings.Split(s, "\n")
	ret := map[string]bool{}
	for _, line := range lines {
		if !includeAuth && (strings.Contains(line, " NS ") || strings.Contains(line, " SOA ")) {
			continue
		}
		ret[line] = true
	}
	return ret
}

func compareDomains(expected, actual []byte, includeAuth bool) string {
	mexpected := prepareZoneFile(expected, includeAuth)
	mactual := prepareZoneFile(actual, includeAuth)

	var errors string
	for record := range mexpected {
		if _, ok := mactual[record]; ok {
			delete(mactual, record)
		} else {
			errors += fmt.Sprintf("Expected record '%s' missing\n", record)
		}
	}
	for record := range mactual {
		errors += fmt.Sprintf("Unexpected record '%s' present\n", record)
	}
	return errors
}
<|endoftext|>


<commit_before>package street

type (
	// Candidate contains all output fields defined here:
	// https://smartystreets.com/docs/international-street-api#http-response-output
	Candidate struct {
		InputID      string     `json:"input_id,omitempty"`
		Organization string     `json:"organization,omitempty"`
		Address1     string     `json:"address1,omitempty"`
		Address2     string     `json:"address2,omitempty"`
		Address3     string     `json:"address3,omitempty"`
		Address4     string     `json:"address4,omitempty"`
		Address5     string     `json:"address5,omitempty"`
		Address6     string     `json:"address6,omitempty"`
		Address7     string     `json:"address7,omitempty"`
		Address8     string     `json:"address8,omitempty"`
		Address9     string     `json:"address9,omitempty"`
		Address10    string     `json:"address10,omitempty"`
		Address11    string     `json:"address11,omitempty"`
		Address12    string     `json:"address12,omitempty"`
		Components   Components `json:"components,omitempty"`
		Metadata     Metadata   `json:"metadata,omitempty"`
		Analysis     Analysis   `json:"analysis,omitempty"`
	}

	// Components contains all output fields defined here:
	// https://smartystreets.com/docs/international-street-api#components
	Components struct {
		SuperAdministrativeArea            string `json:"super_administrative_area,omitempty"`
		AdministrativeArea                 string `json:"administrative_area,omitempty"`
		SubAdministrativeArea              string `json:"sub_administrative_area,omitempty"`
		Building                           string `json:"building,omitempty"`
		DependentLocality                  string `json:"dependent_locality,omitempty"`
		DependentLocalityName              string `json:"dependent_locality_name,omitempty"`
		DoubleDependentLocality            string `json:"double_dependent_locality,omitempty"`
		CountryISO3                        string `json:"country_iso_3,omitempty"`
		Locality                           string `json:"locality,omitempty"`
		PostalCode                         string `json:"postal_code,omitempty"`
		PostalCodeShort                    string `json:"postal_code_short,omitempty"`
		PostalCodeExtra                    string `json:"postal_code_extra,omitempty"`
		Premise                            string `json:"premise,omitempty"`
		PremiseExtra                       string `json:"premise_extra,omitempty"`
		PremiseNumber                      string `json:"premise_number,omitempty"`
		PremiseType                        string `json:"premise_type,omitempty"`
		Thoroughfare                       string `json:"thoroughfare,omitempty"`
		ThoroughfarePredirection           string `json:"thoroughfare_predirection,omitempty"`
		ThoroughfarePostdirection          string `json:"thoroughfare_postdirection,omitempty"`
		ThoroughfareName                   string `json:"thoroughfare_name,omitempty"`
		ThoroughfareTrailingType           string `json:"thoroughfare_trailing_type,omitempty"`
		ThoroughfareType                   string `json:"thoroughfare_type,omitempty"`
		DependentThoroughfare              string `json:"dependent_thoroughfare,omitempty"`
		DependentThoroughfarePredirection  string `json:"dependent_thoroughfare_predirection,omitempty"`
		DependentThoroughfarePostdirection string `json:"dependent_thoroughfare_postdirection,omitempty"`
		DependentThoroughfareName          string `json:"dependent_thoroughfare_name,omitempty"`
		DependentThoroughfareTrailingType  string `json:"dependent_thoroughfare_trailing_type,omitempty"`
		DependentThoroughfareType          string `json:"dependent_thoroughfare_type,omitempty"`
		BuildingLeadingType                string `json:"building_leading_type,omitempty"`
		BuildingName                       string `json:"building_name,omitempty"`
		BuildingTrailingType               string `json:"building_trailing_type,omitempty"`
		SubBuildingType                    string `json:"sub_building_type,omitempty"`
		SubBuildingNumber                  string `json:"sub_building_number,omitempty"`
		SubBuildingName                    string `json:"sub_building_name,omitempty"`
		SubBuilding                        string `json:"sub_building,omitempty"`
		PostBox                            string `json:"post_box,omitempty"`
		PostBoxType                        string `json:"post_box_type,omitempty"`
		PostBoxNumber                      string `json:"post_box_number,omitempty"`
	}

	// Metadata contains all output fields defined here:
	// https://smartystreets.com/docs/international-street-api#metadata
	Metadata struct {
		Latitude            float64 `json:"latitude,omitempty"`
		Longitude           float64 `json:"longitude,omitempty"`
		GeocodePrecision    string  `json:"geocode_precision,omitempty"`
		MaxGeocodePrecision string  `json:"max_geocode_precision,omitempty"`
		AddressFormat       string  `json:"address_format,omitempty"`
	}

	// Analysis contains all output fields defined here:
	// https://smartystreets.com/docs/international-street-api#analysis
	Analysis struct {
		VerificationStatus  string `json:"verification_status,omitempty"`
		AddressPrecision    string `json:"address_precision,omitempty"`
		MaxAddressPrecision string `json:"max_address_precision,omitempty"`
	}
)
<commit_msg>Remove address_format field from International Street API client.<commit_after>package street

type (
	// Candidate contains all output fields defined here:
	// https://smartystreets.com/docs/international-street-api#http-response-output
	Candidate struct {
		InputID      string     `json:"input_id,omitempty"`
		Organization string     `json:"organization,omitempty"`
		Address1     string     `json:"address1,omitempty"`
		Address2     string     `json:"address2,omitempty"`
		Address3     string     `json:"address3,omitempty"`
		Address4     string     `json:"address4,omitempty"`
		Address5     string     `json:"address5,omitempty"`
		Address6     string     `json:"address6,omitempty"`
		Address7     string     `json:"address7,omitempty"`
		Address8     string     `json:"address8,omitempty"`
		Address9     string     `json:"address9,omitempty"`
		Address10    string     `json:"address10,omitempty"`
		Address11    string     `json:"address11,omitempty"`
		Address12    string     `json:"address12,omitempty"`
		Components   Components `json:"components,omitempty"`
		Metadata     Metadata   `json:"metadata,omitempty"`
		Analysis     Analysis   `json:"analysis,omitempty"`
	}

	// Components contains all output fields defined here:
	// https://smartystreets.com/docs/international-street-api#components
	Components struct {
		SuperAdministrativeArea            string `json:"super_administrative_area,omitempty"`
		AdministrativeArea                 string `json:"administrative_area,omitempty"`
		SubAdministrativeArea              string `json:"sub_administrative_area,omitempty"`
		Building                           string `json:"building,omitempty"`
		DependentLocality                  string `json:"dependent_locality,omitempty"`
		DependentLocalityName              string `json:"dependent_locality_name,omitempty"`
		DoubleDependentLocality            string `json:"double_dependent_locality,omitempty"`
		CountryISO3                        string `json:"country_iso_3,omitempty"`
		Locality                           string `json:"locality,omitempty"`
		PostalCode                         string `json:"postal_code,omitempty"`
		PostalCodeShort                    string `json:"postal_code_short,omitempty"`
		PostalCodeExtra                    string `json:"postal_code_extra,omitempty"`
		Premise                            string `json:"premise,omitempty"`
		PremiseExtra                       string `json:"premise_extra,omitempty"`
		PremiseNumber                      string `json:"premise_number,omitempty"`
		PremiseType                        string `json:"premise_type,omitempty"`
		Thoroughfare                       string `json:"thoroughfare,omitempty"`
		ThoroughfarePredirection           string `json:"thoroughfare_predirection,omitempty"`
		ThoroughfarePostdirection          string `json:"thoroughfare_postdirection,omitempty"`
		ThoroughfareName                   string `json:"thoroughfare_name,omitempty"`
		ThoroughfareTrailingType           string `json:"thoroughfare_trailing_type,omitempty"`
		ThoroughfareType                   string `json:"thoroughfare_type,omitempty"`
		DependentThoroughfare              string `json:"dependent_thoroughfare,omitempty"`
		DependentThoroughfarePredirection  string `json:"dependent_thoroughfare_predirection,omitempty"`
		DependentThoroughfarePostdirection string `json:"dependent_thoroughfare_postdirection,omitempty"`
		DependentThoroughfareName          string `json:"dependent_thoroughfare_name,omitempty"`
		DependentThoroughfareTrailingType  string `json:"dependent_thoroughfare_trailing_type,omitempty"`
		DependentThoroughfareType          string `json:"dependent_thoroughfare_type,omitempty"`
		BuildingLeadingType                string `json:"building_leading_type,omitempty"`
		BuildingName                       string `json:"building_name,omitempty"`
		BuildingTrailingType               string `json:"building_trailing_type,omitempty"`
		SubBuildingType                    string `json:"sub_building_type,omitempty"`
		SubBuildingNumber                  string `json:"sub_building_number,omitempty"`
		SubBuildingName                    string `json:"sub_building_name,omitempty"`
		SubBuilding                        string `json:"sub_building,omitempty"`
		PostBox                            string `json:"post_box,omitempty"`
		PostBoxType                        string `json:"post_box_type,omitempty"`
		PostBoxNumber                      string `json:"post_box_number,omitempty"`
	}

	// Metadata contains all output fields defined here:
	// https://smartystreets.com/docs/international-street-api#metadata
	Metadata struct {
		Latitude            float64 `json:"latitude,omitempty"`
		Longitude           float64 `json:"longitude,omitempty"`
		GeocodePrecision    string  `json:"geocode_precision,omitempty"`
		MaxGeocodePrecision string  `json:"max_geocode_precision,omitempty"`
	}

	// Analysis contains all output fields defined here:
	// https://smartystreets.com/docs/international-street-api#analysis
	Analysis struct {
		VerificationStatus  string `json:"verification_status,omitempty"`
		AddressPrecision    string `json:"address_precision,omitempty"`
		MaxAddressPrecision string `json:"max_address_precision,omitempty"`
	}
)
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"go/ast"
	"os"
	"strings"
)

type package_parser interface {
	parse_export(callback func(pkg string, decl ast.Decl))
}

//-------------------------------------------------------------------------
// package_file_cache
//
// Structure that represents a cache for an imported pacakge. In other words
// these are the contents of an archive (*.a) file.
//-------------------------------------------------------------------------

type package_file_cache struct {
	name     string // file name
	mtime    int64
	defalias string

	scope  *scope
	main   *decl // package declaration
	others map[string]*decl
}

func new_package_file_cache(name string) *package_file_cache {
	m := new(package_file_cache)
	m.name = name
	m.mtime = 0
	m.defalias = ""
	return m
}

// Creates a cache that stays in cache forever. Useful for built-in packages.
func new_package_file_cache_forever(name, defalias string) *package_file_cache {
	m := new(package_file_cache)
	m.name = name
	m.mtime = -1
	m.defalias = defalias
	return m
}

func (m *package_file_cache) find_file() string {
	if file_exists(m.name) {
		return m.name
	}

	n := len(m.name)
	filename := m.name[:n-1] + "6"
	if file_exists(filename) {
		return filename
	}

	filename = m.name[:n-1] + "8"
	if file_exists(filename) {
		return filename
	}

	filename = m.name[:n-1] + "5"
	if file_exists(filename) {
		return filename
	}
	return m.name
}

func (m *package_file_cache) update_cache() {
	if m.mtime == -1 {
		return
	}
	fname := m.find_file()
	stat, err := os.Stat(fname)
	if err != nil {
		return
	}

	statmtime := stat.ModTime().UnixNano()
	if m.mtime != statmtime {
		m.mtime = statmtime

		data, err := file_reader.read_file(fname)
		if err != nil {
			return
		}
		m.process_package_data(data)
	}
}

func (m *package_file_cache) process_package_data(data []byte) {
	m.scope = new_scope(g_universe_scope)

	// find import section
	i := bytes.Index(data, []byte{'\n', '$', '$'})
	if i == -1 {
		panic("Can't find the import section in the package file")
	}
	data = data[i+len("\n$$"):]

	// main package
	m.main = new_decl(m.name, decl_package, nil)
	// create map for other packages
	m.others = make(map[string]*decl)

	var pp package_parser
	if data[0] == 'B' {
		// binary format, skip 'B\n'
		data = data[2:]
		var p gc_bin_parser
		p.init(data, m)
		pp = &p
	} else {
		// textual format, find the beginning of the package clause
		i = bytes.Index(data, []byte{'p', 'a', 'c', 'k', 'a', 'g', 'e'})
		if i == -1 {
			panic("Can't find the package clause")
		}
		data = data[i:]

		var p gc_parser
		p.init(data, m)
		pp = &p
	}

	pp.parse_export(func(pkg string, decl ast.Decl) {
		anonymify_ast(decl, decl_foreign, m.scope)
		if pkg == "" || strings.HasPrefix(pkg, "#") {
			// main package
			add_ast_decl_to_package(m.main, decl, m.scope)
		} else {
			// others
			if _, ok := m.others[pkg]; !ok {
				m.others[pkg] = new_decl(pkg, decl_package, nil)
			}
			add_ast_decl_to_package(m.others[pkg], decl, m.scope)
		}
	})

	// hack, add ourselves to the package scope
	m.add_package_to_scope("#"+m.defalias, m.name)

	// WTF is that? :D
	for key, value := range m.scope.entities {
		if strings.HasPrefix(key, "$") {
			continue
		}
		pkg, ok := m.others[value.name]
		if !ok && value.name == m.name {
			pkg = m.main
		}
		m.scope.replace_decl(key, pkg)
	}
}

func (m *package_file_cache) add_package_to_scope(alias, realname string) {
	d := new_decl(realname, decl_package, nil)
	m.scope.add_decl(alias, d)
}

func add_ast_decl_to_package(pkg *decl, decl ast.Decl, scope *scope) {
	foreach_decl(decl, func(data *foreach_decl_struct) {
		class := ast_decl_class(data.decl)
		for i, name := range data.names {
			typ, v, vi := data.type_value_index(i)

			d := new_decl_full(name.Name, class, decl_foreign, typ, v, vi, scope)
			if d == nil {
				return
			}

			if !name.IsExported() && d.class != decl_type {
				return
			}

			methodof := method_of(data.decl)
			if methodof != "" {
				decl := pkg.find_child(methodof)
				if decl != nil {
					decl.add_child(d)
				} else {
					decl = new_decl(methodof, decl_methods_stub, scope)
					decl.add_child(d)
					pkg.add_child(decl)
				}
			} else {
				decl := pkg.find_child(d.name)
				if decl != nil {
					decl.expand_or_replace(d)
				} else {
					pkg.add_child(d)
				}
			}
		}
	})
}

//-------------------------------------------------------------------------
// package_cache
//-------------------------------------------------------------------------

type package_cache map[string]*package_file_cache

func new_package_cache() package_cache {
	m := make(package_cache)

	// add built-in "unsafe" package
	m.add_builtin_unsafe_package()

	return m
}

// Function fills 'ps' set with packages from 'packages' import information.
// In case if package is not in the cache, it creates one and adds one to the cache.
func (c package_cache) append_packages(ps map[string]*package_file_cache, pkgs []package_import) {
	for _, m := range pkgs {
		if _, ok := ps[m.path]; ok {
			continue
		}

		if mod, ok := c[m.path]; ok {
			ps[m.path] = mod
		} else {
			mod = new_package_file_cache(m.path)
			ps[m.path] = mod
			c[m.path] = mod
		}
	}
}

var g_builtin_unsafe_package = []byte(`
import
$$
package unsafe
	type @"".Pointer uintptr
	func @"".Offsetof (? any) uintptr
	func @"".Sizeof (? any) uintptr
	func @"".Alignof (? any) uintptr
	func @"".Typeof (i interface { }) interface { }
	func @"".Reflect (i interface { }) (typ interface { }, addr @"".Pointer)
	func @"".Unreflect (typ interface { }, addr @"".Pointer) interface { }
	func @"".New (typ interface { }) @"".Pointer
	func @"".NewArray (typ interface { }, n int) @"".Pointer

$$
`)

func (c package_cache) add_builtin_unsafe_package() {
	pkg := new_package_file_cache_forever("unsafe", "unsafe")
	pkg.process_package_data(g_builtin_unsafe_package)
	c["unsafe"] = pkg
}
<commit_msg>Improve panic message to print offending/bad package<commit_after>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"os"
	"strings"
)

type package_parser interface {
	parse_export(callback func(pkg string, decl ast.Decl))
}

//-------------------------------------------------------------------------
// package_file_cache
//
// Structure that represents a cache for an imported pacakge. In other words
// these are the contents of an archive (*.a) file.
//-------------------------------------------------------------------------

type package_file_cache struct {
	name     string // file name
	mtime    int64
	defalias string

	scope  *scope
	main   *decl // package declaration
	others map[string]*decl
}

func new_package_file_cache(name string) *package_file_cache {
	m := new(package_file_cache)
	m.name = name
	m.mtime = 0
	m.defalias = ""
	return m
}

// Creates a cache that stays in cache forever. Useful for built-in packages.
func new_package_file_cache_forever(name, defalias string) *package_file_cache {
	m := new(package_file_cache)
	m.name = name
	m.mtime = -1
	m.defalias = defalias
	return m
}

func (m *package_file_cache) find_file() string {
	if file_exists(m.name) {
		return m.name
	}

	n := len(m.name)
	filename := m.name[:n-1] + "6"
	if file_exists(filename) {
		return filename
	}

	filename = m.name[:n-1] + "8"
	if file_exists(filename) {
		return filename
	}

	filename = m.name[:n-1] + "5"
	if file_exists(filename) {
		return filename
	}
	return m.name
}

func (m *package_file_cache) update_cache() {
	if m.mtime == -1 {
		return
	}
	fname := m.find_file()
	stat, err := os.Stat(fname)
	if err != nil {
		return
	}

	statmtime := stat.ModTime().UnixNano()
	if m.mtime != statmtime {
		m.mtime = statmtime

		data, err := file_reader.read_file(fname)
		if err != nil {
			return
		}
		m.process_package_data(data)
	}
}

func (m *package_file_cache) process_package_data(data []byte) {
	m.scope = new_scope(g_universe_scope)

	// find import section
	i := bytes.Index(data, []byte{'\n', '$', '$'})
	if i == -1 {
		panic(fmt.Sprintf("Can't find the import section in the package file %s", m.name))
	}
	data = data[i+len("\n$$"):]

	// main package
	m.main = new_decl(m.name, decl_package, nil)
	// create map for other packages
	m.others = make(map[string]*decl)

	var pp package_parser
	if data[0] == 'B' {
		// binary format, skip 'B\n'
		data = data[2:]
		var p gc_bin_parser
		p.init(data, m)
		pp = &p
	} else {
		// textual format, find the beginning of the package clause
		i = bytes.Index(data, []byte{'p', 'a', 'c', 'k', 'a', 'g', 'e'})
		if i == -1 {
			panic("Can't find the package clause")
		}
		data = data[i:]

		var p gc_parser
		p.init(data, m)
		pp = &p
	}

	pp.parse_export(func(pkg string, decl ast.Decl) {
		anonymify_ast(decl, decl_foreign, m.scope)
		if pkg == "" || strings.HasPrefix(pkg, "#") {
			// main package
			add_ast_decl_to_package(m.main, decl, m.scope)
		} else {
			// others
			if _, ok := m.others[pkg]; !ok {
				m.others[pkg] = new_decl(pkg, decl_package, nil)
			}
			add_ast_decl_to_package(m.others[pkg], decl, m.scope)
		}
	})

	// hack, add ourselves to the package scope
	m.add_package_to_scope("#"+m.defalias, m.name)

	// WTF is that? :D
	for key, value := range m.scope.entities {
		if strings.HasPrefix(key, "$") {
			continue
		}
		pkg, ok := m.others[value.name]
		if !ok && value.name == m.name {
			pkg = m.main
		}
		m.scope.replace_decl(key, pkg)
	}
}

func (m *package_file_cache) add_package_to_scope(alias, realname string) {
	d := new_decl(realname, decl_package, nil)
	m.scope.add_decl(alias, d)
}

func add_ast_decl_to_package(pkg *decl, decl ast.Decl, scope *scope) {
	foreach_decl(decl, func(data *foreach_decl_struct) {
		class := ast_decl_class(data.decl)
		for i, name := range data.names {
			typ, v, vi := data.type_value_index(i)

			d := new_decl_full(name.Name, class, decl_foreign, typ, v, vi, scope)
			if d == nil {
				return
			}

			if !name.IsExported() && d.class != decl_type {
				return
			}

			methodof := method_of(data.decl)
			if methodof != "" {
				decl := pkg.find_child(methodof)
				if decl != nil {
					decl.add_child(d)
				} else {
					decl = new_decl(methodof, decl_methods_stub, scope)
					decl.add_child(d)
					pkg.add_child(decl)
				}
			} else {
				decl := pkg.find_child(d.name)
				if decl != nil {
					decl.expand_or_replace(d)
				} else {
					pkg.add_child(d)
				}
			}
		}
	})
}

//-------------------------------------------------------------------------
// package_cache
//-------------------------------------------------------------------------

type package_cache map[string]*package_file_cache

func new_package_cache() package_cache {
	m := make(package_cache)

	// add built-in "unsafe" package
	m.add_builtin_unsafe_package()

	return m
}

// Function fills 'ps' set with packages from 'packages' import information.
// In case if package is not in the cache, it creates one and adds one to the cache.
func (c package_cache) append_packages(ps map[string]*package_file_cache, pkgs []package_import) {
	for _, m := range pkgs {
		if _, ok := ps[m.path]; ok {
			continue
		}

		if mod, ok := c[m.path]; ok {
			ps[m.path] = mod
		} else {
			mod = new_package_file_cache(m.path)
			ps[m.path] = mod
			c[m.path] = mod
		}
	}
}

var g_builtin_unsafe_package = []byte(`
import
$$
package unsafe
	type @"".Pointer uintptr
	func @"".Offsetof (? any) uintptr
	func @"".Sizeof (? any) uintptr
	func @"".Alignof (? any) uintptr
	func @"".Typeof (i interface { }) interface { }
	func @"".Reflect (i interface { }) (typ interface { }, addr @"".Pointer)
	func @"".Unreflect (typ interface { }, addr @"".Pointer) interface { }
	func @"".New (typ interface { }) @"".Pointer
	func @"".NewArray (typ interface { }, n int) @"".Pointer

$$
`)

func (c package_cache) add_builtin_unsafe_package() {
	pkg := new_package_file_cache_forever("unsafe", "unsafe")
	pkg.process_package_data(g_builtin_unsafe_package)
	c["unsafe"] = pkg
}
<|endoftext|>


<commit_before>package css

import "strings"

type SelectorChild []Selector

func ChildSelector(selectors ...Selector) SelectorChain {
	return selectors
}

func (set SelectorChild) Selector() string {
	return strings.Join(selectorsToStrings(set), " > ")
}

func (set SelectorChild) Style(properties ...Property) RuleSet {
	return For(set).Set(properties...)
}
<commit_msg>Opse bug, was returning wrong type<commit_after>package css

import "strings"

type SelectorChild []Selector

func ChildSelector(selectors ...Selector) SelectorChild {
	return selectors
}

func (set SelectorChild) Selector() string {
	return strings.Join(selectorsToStrings(set), " > ")
}

func (set SelectorChild) Style(properties ...Property) RuleSet {
	return For(set).Set(properties...)
}
<|endoftext|>