<commit_before>package raw

import (
	"bytes"
	"errors"
	"log"
	"net"
	"os"
	"reflect"
	"text/template"

	"github.com/gliderlabs/logspout/router"
	"github.com/gliderlabs/logspout/utils"
	"strings"
	"time"
)

func init() {
	router.AdapterFactories.Register(NewRawAdapter, "raw")
}

var address string
var connection net.Conn
var netType string

func NewRawAdapter(route *router.Route) (router.LogAdapter, error) {
	transport, found := router.AdapterTransports.Lookup(route.AdapterTransport("udp"))
	if !found {
		return nil, errors.New("bad transport: " + route.Adapter)
	}
	address = route.Address
	netType = strings.Replace(route.Adapter, "raw+", "", -1)
	conn, err := transport.Dial(route.Address, route.Options)
	connection = conn
	if err != nil {
		return nil, err
	}
	tmplStr := "{{.Data}}\n"
	if os.Getenv("RAW_FORMAT") != "" {
		tmplStr = os.Getenv("RAW_FORMAT")
	}
	tmpl, err := template.New("raw").Parse(tmplStr)
	if err != nil {
		return nil, err
	}
	return &RawAdapter{
		route: route,
		conn:  conn,
		tmpl:  tmpl,
	}, nil
}

type RawAdapter struct {
	conn  net.Conn
	route *router.Route
	tmpl  *template.Template
}

func (a *RawAdapter) Stream(logstream chan *router.Message) {
	go connPing()
	for message := range logstream {
		buf := new(bytes.Buffer)
		err := a.tmpl.Execute(buf, message)
		if err != nil {
			log.Println("raw:", err)
			return
		}

		if cn := utils.M1[message.Container.Name]; cn != "" {
			t := time.Unix(time.Now().Unix(), 0)
			timestr := t.Format("2006-01-02T15:04:05")
			//logmsg := strings.Replace(string(timestr), "\"", "", -1) + " " + utils.UUID + " " + utils.IP + " " + utils.Hostname + " " + cn + " " + buf.String()
			logmsg := strings.Replace(string(timestr), "\"", "", -1) + " " +
				utils.UserId + " " +
				utils.ClusterId + " " +
				utils.UUID + " " +
				utils.IP + " " +
				utils.Hostname + " " +
				cn + " " +
				buf.String()
			_, err = connection.Write([]byte(logmsg))
			if err != nil {
				log.Println("raw:", err, reflect.TypeOf(a.conn).String())
				/*if reflect.TypeOf(a.conn).String() != "*net.TCPConn"{
					return
				}*/
			}
		}
	}

}

func connPing() {
	timer := time.NewTicker(2 * time.Second)
	for {
		select {
		case <-timer.C:
			_, err := connection.Write([]byte(""))
			if err != nil {
				if netType == "tcp" {
					conn, err := utils.ConnTCP(address)
					log.Println("can connection tcp ", err)
					if err == nil {
						connection = conn
					}
				} else if netType == "tls" {
					conn, err := utils.ConnTLS(address)
					log.Println("can connection tls ", err)
					if err == nil {
						connection = conn
					}
				}
			}
		}
	}
}
<commit_msg>update<commit_after>package raw

import (
	"bytes"
	"errors"
	"log"
	"net"
	"os"
	"reflect"
	"text/template"

	"github.com/gliderlabs/logspout/router"
	"github.com/gliderlabs/logspout/utils"
	"strings"
	"time"
)

func init() {
	router.AdapterFactories.Register(NewRawAdapter, "raw")
}

var address string
var connection net.Conn
var netType string

func NewRawAdapter(route *router.Route) (router.LogAdapter, error) {
	transport, found := router.AdapterTransports.Lookup(route.AdapterTransport("udp"))
	if !found {
		return nil, errors.New("bad transport: " + route.Adapter)
	}
	address = route.Address
	netType = strings.Replace(route.Adapter, "raw+", "", -1)
	conn, err := transport.Dial(route.Address, route.Options)
	connection = conn
	if err != nil {
		return nil, err
	}
	tmplStr := "{{.Data}}\n"
	if os.Getenv("RAW_FORMAT") != "" {
		tmplStr = os.Getenv("RAW_FORMAT")
	}
	tmpl, err := template.New("raw").Parse(tmplStr)
	if err != nil {
		return nil, err
	}
	go connPing()
	return &RawAdapter{
		route: route,
		conn:  conn,
		tmpl:  tmpl,
	}, nil
}

type RawAdapter struct {
	conn  net.Conn
	route *router.Route
	tmpl  *template.Template
}

func (a *RawAdapter) Stream(logstream chan *router.Message) {
	for message := range logstream {
		buf := new(bytes.Buffer)
		err := a.tmpl.Execute(buf, message)
		if err != nil {
			log.Println("raw:", err)
			return
		}

		if cn := utils.M1[message.Container.Name]; cn != "" {
			t := time.Unix(time.Now().Unix(), 0)
			timestr := t.Format("2006-01-02T15:04:05")
			//logmsg := strings.Replace(string(timestr), "\"", "", -1) + " " + utils.UUID + " " + utils.IP + " " + utils.Hostname + " " + cn + " " + buf.String()
			logmsg := strings.Replace(string(timestr), "\"", "", -1) + " " +
				utils.UserId + " " +
				utils.ClusterId + " " +
				utils.UUID + " " +
				utils.IP + " " +
				utils.Hostname + " " +
				cn + " " +
				buf.String()
			_, err = connection.Write([]byte(logmsg))
			if err != nil {
				log.Println("raw:", err, reflect.TypeOf(a.conn).String())
				/*if reflect.TypeOf(a.conn).String() != "*net.TCPConn"{
					return
				}*/
			}
		}
	}

}

func connPing() {
	timer := time.NewTicker(2 * time.Second)
	log.Println("ping tcp ......")
	for {
		select {
		case <-timer.C:
			_, err := connection.Write([]byte(""))
			if err != nil {
				if netType == "tcp" {
					conn, err := utils.ConnTCP(address)
					log.Println("can connection tcp ", err)
					if err == nil {
						connection = conn
					}
				} else if netType == "tls" {
					conn, err := utils.ConnTLS(address)
					log.Println("can connection tls ", err)
					if err == nil {
						connection = conn
					}
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package dns

import (
	"context"
	"sync"
	"sync/atomic"
	"time"

	"github.com/miekg/dns"
	"v2ray.com/core"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/common/task"
	"v2ray.com/core/transport/internet/udp"
)

var (
	multiQuestionDNS = map[net.Address]bool{
		net.IPAddress([]byte{8, 8, 8, 8}): true,
		net.IPAddress([]byte{8, 8, 4, 4}): true,
		net.IPAddress([]byte{9, 9, 9, 9}): true,
	}
)

type IPRecord struct {
	IP     net.IP
	Expire time.Time
}

type ClassicNameServer struct {
	sync.RWMutex
	address   net.Destination
	ips       map[string][]IPRecord
	updated   signal.Notifier
	udpServer *udp.Dispatcher
	cleanup   *task.Periodic
	reqID     uint32
	clientIP  net.IP
}

func NewClassicNameServer(address net.Destination, dispatcher core.Dispatcher, clientIP net.IP) *ClassicNameServer {
	s := &ClassicNameServer{
		address:   address,
		ips:       make(map[string][]IPRecord),
		udpServer: udp.NewDispatcher(dispatcher),
		clientIP:  clientIP,
	}
	s.cleanup = &task.Periodic{
		Interval: time.Minute,
		Execute:  s.Cleanup,
	}
	common.Must(s.cleanup.Start())
	return s
}

func (s *ClassicNameServer) Cleanup() error {
	now := time.Now()
	s.Lock()
	for domain, ips := range s.ips {
		newIPs := make([]IPRecord, 0, len(ips))
		for _, ip := range ips {
			if ip.Expire.After(now) {
				newIPs = append(newIPs, ip)
			}
		}
		if len(newIPs) == 0 {
			delete(s.ips, domain)
		} else if len(newIPs) < len(ips) {
			s.ips[domain] = newIPs
		}
	}

	if len(s.ips) == 0 {
		s.ips = make(map[string][]IPRecord)
	}

	s.Unlock()
	return nil
}

func (s *ClassicNameServer) HandleResponse(payload *buf.Buffer) {
	msg := new(dns.Msg)
	err := msg.Unpack(payload.Bytes())
	if err == dns.ErrTruncated {
		newError("truncated message received. DNS server should still work. If you see anything abnormal, please submit an issue to v2ray-core.").AtWarning().WriteToLog()
	} else if err != nil {
		newError("failed to parse DNS response").Base(err).AtWarning().WriteToLog()
		return
	}

	var domain string
	ips := make([]IPRecord, 0, 16)

	now := time.Now()
	for _, rr := range msg.Answer {
		var ip net.IP
		domain = rr.Header().Name
		ttl := rr.Header().Ttl
		switch rr := rr.(type) {
		case *dns.A:
			ip = rr.A
		case *dns.AAAA:
			ip = rr.AAAA
		}
		if ttl == 0 {
			ttl = 300
		}
		if len(ip) > 0 {
			ips = append(ips, IPRecord{
				IP:     ip,
				Expire: now.Add(time.Second * time.Duration(ttl)),
			})
		}
	}

	if len(domain) > 0 && len(ips) > 0 {
		s.updateIP(domain, ips)
	}
}

func (s *ClassicNameServer) updateIP(domain string, ips []IPRecord) {
	s.Lock()
	defer s.Unlock()

	newError("updating IP records for domain:", domain).AtDebug().WriteToLog()
	now := time.Now()
	eips := s.ips[domain]
	for _, ip := range eips {
		if ip.Expire.After(now) {
			ips = append(ips, ip)
		}
	}
	s.ips[domain] = ips
	s.updated.Signal()
}

func (s *ClassicNameServer) getMsgOptions() *dns.OPT {
	if len(s.clientIP) == 0 {
		return nil
	}

	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.SetUDPSize(1280)

	e := new(dns.EDNS0_SUBNET)
	e.Code = dns.EDNS0SUBNET
	if len(s.clientIP) == 4 {
		e.Family = 1 // 1 for IPv4 source address, 2 for IPv6
	} else {
		e.Family = 2
	}

	e.SourceNetmask = 24 // 32 for IPV4, 128 for IPv6
	e.SourceScope = 0
	e.Address = s.clientIP
	o.Option = append(o.Option, e)

	return o

}

func (s *ClassicNameServer) buildMsgs(domain string) []*dns.Msg {
	allowMulti := multiQuestionDNS[s.address.Address]

	qA := dns.Question{
		Name:   domain,
		Qtype:  dns.TypeA,
		Qclass: dns.ClassINET,
	}

	qAAAA := dns.Question{
		Name:   domain,
		Qtype:  dns.TypeAAAA,
		Qclass: dns.ClassINET,
	}

	var msgs []*dns.Msg

	{
		msg := new(dns.Msg)
		msg.Id = uint16(atomic.AddUint32(&s.reqID, 1))
		msg.RecursionDesired = true
		msg.Question = []dns.Question{qA}
		if allowMulti {
			msg.Question = append(msg.Question, qAAAA)
		}
		if opt := s.getMsgOptions(); opt != nil {
			msg.Extra = append(msg.Extra, opt)
		}
		msgs = append(msgs, msg)
	}

	if !allowMulti {
		msg := new(dns.Msg)
		msg.Id = uint16(atomic.AddUint32(&s.reqID, 1))
		msg.RecursionDesired = true
		msg.Question = []dns.Question{qAAAA}
		if opt := s.getMsgOptions(); opt != nil {
			msg.Extra = append(msg.Extra, opt)
		}
		msgs = append(msgs, msg)
	}

	return msgs
}

func msgToBuffer(msg *dns.Msg) (*buf.Buffer, error) {
	buffer := buf.New()
	if err := buffer.Reset(func(b []byte) (int, error) {
		writtenBuffer, err := msg.PackBuffer(b)
		return len(writtenBuffer), err
	}); err != nil {
		return nil, err
	}
	return buffer, nil
}

func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string) {
	msgs := s.buildMsgs(domain)

	for _, msg := range msgs {
		b, err := msgToBuffer(msg)
		common.Must(err)
		s.udpServer.Dispatch(ctx, s.address, b, s.HandleResponse)
	}
}

func (s *ClassicNameServer) findIPsForDomain(domain string) []net.IP {
	records, found := s.ips[domain]
	if found && len(records) > 0 {
		var ips []net.IP
		now := time.Now()
		for _, rec := range records {
			if rec.Expire.After(now) {
				ips = append(ips, rec.IP)
			}
		}
		return ips
	}
	return nil
}

func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string) ([]net.IP, error) {
	fqdn := dns.Fqdn(domain)

	ips := s.findIPsForDomain(fqdn)
	if len(ips) > 0 {
		return ips, nil
	}

	s.sendQuery(ctx, fqdn)

	for {
		ips := s.findIPsForDomain(fqdn)
		if len(ips) > 0 {
			return ips, nil
		}

		select {
		case <-ctx.Done():
			return nil, ctx.Err()
		case <-s.updated.Wait():
		}
	}
}
<commit_msg>fix #1165<commit_after>package dns

import (
	"context"
	"sync"
	"sync/atomic"
	"time"

	"github.com/miekg/dns"
	"v2ray.com/core"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/common/task"
	"v2ray.com/core/transport/internet/udp"
)

var (
	multiQuestionDNS = map[net.Address]bool{
		net.IPAddress([]byte{8, 8, 8, 8}): true,
		net.IPAddress([]byte{8, 8, 4, 4}): true,
		net.IPAddress([]byte{9, 9, 9, 9}): true,
	}
)

type IPRecord struct {
	IP     net.IP
	Expire time.Time
}

type ClassicNameServer struct {
	sync.RWMutex
	address   net.Destination
	ips       map[string][]IPRecord
	updated   signal.Notifier
	udpServer *udp.Dispatcher
	cleanup   *task.Periodic
	reqID     uint32
	clientIP  net.IP
}

func NewClassicNameServer(address net.Destination, dispatcher core.Dispatcher, clientIP net.IP) *ClassicNameServer {
	s := &ClassicNameServer{
		address:   address,
		ips:       make(map[string][]IPRecord),
		udpServer: udp.NewDispatcher(dispatcher),
		clientIP:  clientIP,
	}
	s.cleanup = &task.Periodic{
		Interval: time.Minute,
		Execute:  s.Cleanup,
	}
	common.Must(s.cleanup.Start())
	return s
}

func (s *ClassicNameServer) Cleanup() error {
	now := time.Now()
	s.Lock()
	for domain, ips := range s.ips {
		newIPs := make([]IPRecord, 0, len(ips))
		for _, ip := range ips {
			if ip.Expire.After(now) {
				newIPs = append(newIPs, ip)
			}
		}
		if len(newIPs) == 0 {
			delete(s.ips, domain)
		} else if len(newIPs) < len(ips) {
			s.ips[domain] = newIPs
		}
	}

	if len(s.ips) == 0 {
		s.ips = make(map[string][]IPRecord)
	}

	s.Unlock()
	return nil
}

func (s *ClassicNameServer) HandleResponse(payload *buf.Buffer) {
	msg := new(dns.Msg)
	err := msg.Unpack(payload.Bytes())
	if err == dns.ErrTruncated {
		newError("truncated message received. DNS server should still work. If you see anything abnormal, please submit an issue to v2ray-core.").AtWarning().WriteToLog()
	} else if err != nil {
		newError("failed to parse DNS response").Base(err).AtWarning().WriteToLog()
		return
	}

	var domain string
	ips := make([]IPRecord, 0, 16)

	now := time.Now()
	for _, rr := range msg.Answer {
		var ip net.IP
		domain = rr.Header().Name
		ttl := rr.Header().Ttl
		switch rr := rr.(type) {
		case *dns.A:
			ip = rr.A
		case *dns.AAAA:
			ip = rr.AAAA
		}
		if ttl == 0 {
			ttl = 300
		}
		if len(ip) > 0 {
			ips = append(ips, IPRecord{
				IP:     ip,
				Expire: now.Add(time.Second * time.Duration(ttl)),
			})
		}
	}

	if len(domain) > 0 && len(ips) > 0 {
		s.updateIP(domain, ips)
	}
}

func (s *ClassicNameServer) updateIP(domain string, ips []IPRecord) {
	s.Lock()
	defer s.Unlock()

	newError("updating IP records for domain:", domain).AtDebug().WriteToLog()
	now := time.Now()
	eips := s.ips[domain]
	for _, ip := range eips {
		if ip.Expire.After(now) {
			ips = append(ips, ip)
		}
	}
	s.ips[domain] = ips
	s.updated.Signal()
}

func (s *ClassicNameServer) getMsgOptions() *dns.OPT {
	if len(s.clientIP) == 0 {
		return nil
	}

	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.SetUDPSize(1280)

	e := new(dns.EDNS0_SUBNET)
	e.Code = dns.EDNS0SUBNET
	if len(s.clientIP) == 4 {
		e.Family = 1 // 1 for IPv4 source address, 2 for IPv6
	} else {
		e.Family = 2
	}

	e.SourceNetmask = 24 // 32 for IPV4, 128 for IPv6
	e.SourceScope = 0
	e.Address = s.clientIP
	o.Option = append(o.Option, e)

	return o

}

func (s *ClassicNameServer) buildMsgs(domain string) []*dns.Msg {
	allowMulti := multiQuestionDNS[s.address.Address]

	qA := dns.Question{
		Name:   domain,
		Qtype:  dns.TypeA,
		Qclass: dns.ClassINET,
	}

	qAAAA := dns.Question{
		Name:   domain,
		Qtype:  dns.TypeAAAA,
		Qclass: dns.ClassINET,
	}

	var msgs []*dns.Msg

	{
		msg := new(dns.Msg)
		msg.Id = uint16(atomic.AddUint32(&s.reqID, 1))
		msg.RecursionDesired = true
		msg.Question = []dns.Question{qA}
		if allowMulti {
			msg.Question = append(msg.Question, qAAAA)
		}
		if opt := s.getMsgOptions(); opt != nil {
			msg.Extra = append(msg.Extra, opt)
		}
		msgs = append(msgs, msg)
	}

	if !allowMulti {
		msg := new(dns.Msg)
		msg.Id = uint16(atomic.AddUint32(&s.reqID, 1))
		msg.RecursionDesired = true
		msg.Question = []dns.Question{qAAAA}
		if opt := s.getMsgOptions(); opt != nil {
			msg.Extra = append(msg.Extra, opt)
		}
		msgs = append(msgs, msg)
	}

	return msgs
}

func msgToBuffer(msg *dns.Msg) (*buf.Buffer, error) {
	buffer := buf.New()
	if err := buffer.Reset(func(b []byte) (int, error) {
		writtenBuffer, err := msg.PackBuffer(b)
		return len(writtenBuffer), err
	}); err != nil {
		return nil, err
	}
	return buffer, nil
}

func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string) {
	msgs := s.buildMsgs(domain)

	for _, msg := range msgs {
		b, err := msgToBuffer(msg)
		common.Must(err)
		s.udpServer.Dispatch(ctx, s.address, b, s.HandleResponse)
	}
}

func (s *ClassicNameServer) findIPsForDomain(domain string) []net.IP {
	s.RLock()
	records, found := s.ips[domain]
	s.RUnlock()

	if found && len(records) > 0 {
		var ips []net.IP
		now := time.Now()
		for _, rec := range records {
			if rec.Expire.After(now) {
				ips = append(ips, rec.IP)
			}
		}
		return ips
	}
	return nil
}

func (s *ClassicNameServer) QueryIP(ctx context.Context, domain string) ([]net.IP, error) {
	fqdn := dns.Fqdn(domain)

	ips := s.findIPsForDomain(fqdn)
	if len(ips) > 0 {
		return ips, nil
	}

	s.sendQuery(ctx, fqdn)

	for {
		ips := s.findIPsForDomain(fqdn)
		if len(ips) > 0 {
			return ips, nil
		}

		select {
		case <-ctx.Done():
			return nil, ctx.Err()
		case <-s.updated.Wait():
		}
	}
}
<|endoftext|>


<commit_before>package admin

import (
	"encoding/json"
	"fmt"
	"net/http"
	"path"
	"strings"

	"github.com/qor/qor/responder"
)

type controller struct {
	*Admin
}

func renderError(context *Context, err error) {
	responder.With("html", func() {
		context.Writer.WriteHeader(http.StatusNotAcceptable)
		if _, er := context.Writer.Write([]byte(err.Error())); er != nil {
			println("failed to write response", er.Error())
		}
	}).With("json", func() {
		data, er := json.Marshal(map[string]string{"error": err.Error()})
		if er != nil {
			println("failed to marshal error json")
		}
		context.Writer.WriteHeader(http.StatusNotAcceptable)
		if _, er := context.Writer.Write(data); er != nil {
			println("failed to write reponse", er.Error())
		}
	}).Respond(context.Writer, context.Request)
}

func (ac *controller) Dashboard(context *Context) {
	context.Execute("dashboard", nil)
}

func (ac *controller) Index(context *Context) {
	if result, err := context.FindMany(); err == nil {
		responder.With("html", func() {
			context.Execute("index", result)
		}).With("json", func() {
			res := context.Resource
			js, _ := json.Marshal(res.ConvertObjectToMap(context, result, res.IndexMetas()))
			context.Writer.Write(js)
		}).Respond(context.Writer, context.Request)
	} else {
		http.NotFound(context.Writer, context.Request)
	}
}

func (ac *controller) Show(context *Context) {
	result, _ := context.FindOne()

	responder.With("html", func() {
		context.Execute("show", result)
	}).With("json", func() {
		res := context.Resource
		js, _ := json.Marshal(res.ConvertObjectToMap(context, result, res.ShowMetas()))
		context.Writer.Write(js)
	}).Respond(context.Writer, context.Request)
}

func (ac *controller) New(context *Context) {
	context.Execute("new", nil)
}

func (ac *controller) Create(context *Context) {
	res := ac.GetResource(context.ResourcePath())
	result := res.NewStruct()
	if errs := res.Decode(context, result); len(errs) == 0 {
		res.CallSaver(result, context.Context)
		responder.With("html", func() {
			primaryKey := fmt.Sprintf("%v", context.GetDB().NewScope(result).PrimaryKeyValue())
			http.Redirect(context.Writer, context.Request, path.Join(context.Request.RequestURI, primaryKey), http.StatusFound)
		}).With("json", func() {
			res := context.Resource
			js, _ := json.Marshal(res.ConvertObjectToMap(context, result, res.ShowMetas()))
			context.Writer.Write(js)
		}).Respond(context.Writer, context.Request)
	}
}

func (ac *controller) Update(context *Context) {
	if result, err := context.FindOne(); err == nil {
		if errs := context.Resource.Decode(context, result); len(errs) == 0 {
			if err := context.Resource.CallSaver(result, context.Context); err != nil {
				renderError(context, err)
				return
			}
			responder.With("html", func() {
				http.Redirect(context.Writer, context.Request, context.Request.RequestURI, http.StatusFound)
			}).With("json", func() {
				res := context.Resource
				js, _ := json.Marshal(res.ConvertObjectToMap(context, result, res.ShowMetas()))
				context.Writer.Write(js)
			}).Respond(context.Writer, context.Request)
		}
	} else {
		renderError(context, err)
	}
}

func (ac *controller) Delete(context *Context) {
	res := ac.GetResource(context.ResourcePath())

	responder.With("html", func() {
		if res.CallDeleter(res.NewStruct(), context.Context) == nil {
			http.Redirect(context.Writer, context.Request, path.Join(ac.GetRouter().Prefix, res.ToParam()), http.StatusFound)
		} else {
			http.Redirect(context.Writer, context.Request, path.Join(ac.GetRouter().Prefix, res.ToParam()), http.StatusNotFound)
		}
	}).With("json", func() {
		if res.CallDeleter(res.NewStruct(), context.Context) == nil {
			context.Writer.WriteHeader(http.StatusOK)
		} else {
			context.Writer.WriteHeader(http.StatusNotFound)
		}
	}).Respond(context.Writer, context.Request)
}

func (ac *controller) Action(context *Context) {
	var err error
	name := strings.Split(context.Request.URL.Path, "/")[4]

	for _, action := range context.Resource.actions {
		if action.Name == name {
			ids := context.Request.Form.Get("ids")
			scope := context.GetDB().Where(fmt.Sprintf("%v IN (?)", context.Resource.PrimaryField().DBName), ids)
			err = action.Handle(scope, context.Context)
		}
	}

	responder.With("html", func() {
		http.Redirect(context.Writer, context.Request, context.Request.Referer(), http.StatusFound)
	}).With("json", func() {
		if err == nil {
			context.Writer.Write([]byte("OK"))
		} else {
			context.Writer.Write([]byte(err.Error()))
		}
	}).Respond(context.Writer, context.Request)
}

func (ac *controller) Asset(context *Context) {
	file := strings.TrimPrefix(context.Request.URL.Path, ac.GetRouter().Prefix)
	if filename, err := context.findFile(file); err == nil {
		http.ServeFile(context.Writer, context.Request, filename)
	} else {
		http.NotFound(context.Writer, context.Request)
	}
}
<commit_msg>Add permission check for resource<commit_after>package admin

import (
	"encoding/json"
	"fmt"
	"net/http"
	"path"
	"strings"

	"github.com/qor/qor/responder"
	"github.com/qor/qor/roles"
)

type controller struct {
	*Admin
}

func renderError(context *Context, err error) {
	responder.With("html", func() {
		context.Writer.WriteHeader(http.StatusNotAcceptable)
		if _, er := context.Writer.Write([]byte(err.Error())); er != nil {
			println("failed to write response", er.Error())
		}
	}).With("json", func() {
		data, er := json.Marshal(map[string]string{"error": err.Error()})
		if er != nil {
			println("failed to marshal error json")
		}
		context.Writer.WriteHeader(http.StatusNotAcceptable)
		if _, er := context.Writer.Write(data); er != nil {
			println("failed to write reponse", er.Error())
		}
	}).Respond(context.Writer, context.Request)
}

func (context *Context) CheckResourcePermission(permission roles.PermissionMode) bool {
	if context.Resource.HasPermission(permission, context.Context) {
		return true
	}
	context.Writer.Write([]byte("Permission denied"))
	return false
}

func (ac *controller) Dashboard(context *Context) {
	context.Execute("dashboard", nil)
}

func (ac *controller) Index(context *Context) {
	if context.CheckResourcePermission(roles.Read) {
		if result, err := context.FindMany(); err == nil {
			responder.With("html", func() {
				context.Execute("index", result)
			}).With("json", func() {
				res := context.Resource
				js, _ := json.Marshal(res.ConvertObjectToMap(context, result, res.IndexMetas()))
				context.Writer.Write(js)
			}).Respond(context.Writer, context.Request)
		} else {
			http.NotFound(context.Writer, context.Request)
		}
	}
}

func (ac *controller) Show(context *Context) {
	if context.CheckResourcePermission(roles.Read) {
		result, _ := context.FindOne()

		responder.With("html", func() {
			context.Execute("show", result)
		}).With("json", func() {
			res := context.Resource
			js, _ := json.Marshal(res.ConvertObjectToMap(context, result, res.ShowMetas()))
			context.Writer.Write(js)
		}).Respond(context.Writer, context.Request)
	}
}

func (ac *controller) New(context *Context) {
	if context.CheckResourcePermission(roles.Create) {
		context.Execute("new", nil)
	}
}

func (ac *controller) Create(context *Context) {
	if context.CheckResourcePermission(roles.Create) {
		res := context.Resource

		result := res.NewStruct()
		if errs := res.Decode(context, result); len(errs) == 0 {
			res.CallSaver(result, context.Context)
			responder.With("html", func() {
				primaryKey := fmt.Sprintf("%v", context.GetDB().NewScope(result).PrimaryKeyValue())
				http.Redirect(context.Writer, context.Request, path.Join(context.Request.RequestURI, primaryKey), http.StatusFound)
			}).With("json", func() {
				res := context.Resource
				js, _ := json.Marshal(res.ConvertObjectToMap(context, result, res.ShowMetas()))
				context.Writer.Write(js)
			}).Respond(context.Writer, context.Request)
		}
	}
}

func (ac *controller) Update(context *Context) {
	if context.CheckResourcePermission(roles.Update) {
		if result, err := context.FindOne(); err == nil {
			if errs := context.Resource.Decode(context, result); len(errs) == 0 {
				if err := context.Resource.CallSaver(result, context.Context); err != nil {
					renderError(context, err)
					return
				}
				responder.With("html", func() {
					http.Redirect(context.Writer, context.Request, context.Request.RequestURI, http.StatusFound)
				}).With("json", func() {
					res := context.Resource
					js, _ := json.Marshal(res.ConvertObjectToMap(context, result, res.ShowMetas()))
					context.Writer.Write(js)
				}).Respond(context.Writer, context.Request)
			}
		} else {
			renderError(context, err)
		}
	}
}

func (ac *controller) Delete(context *Context) {
	if context.CheckResourcePermission(roles.Delete) {
		res := context.Resource

		responder.With("html", func() {
			if res.CallDeleter(res.NewStruct(), context.Context) == nil {
				http.Redirect(context.Writer, context.Request, path.Join(ac.GetRouter().Prefix, res.ToParam()), http.StatusFound)
			} else {
				http.Redirect(context.Writer, context.Request, path.Join(ac.GetRouter().Prefix, res.ToParam()), http.StatusNotFound)
			}
		}).With("json", func() {
			if res.CallDeleter(res.NewStruct(), context.Context) == nil {
				context.Writer.WriteHeader(http.StatusOK)
			} else {
				context.Writer.WriteHeader(http.StatusNotFound)
			}
		}).Respond(context.Writer, context.Request)
	}
}

func (ac *controller) Action(context *Context) {
	var err error
	name := strings.Split(context.Request.URL.Path, "/")[4]

	for _, action := range context.Resource.actions {
		if action.Name == name {
			ids := context.Request.Form.Get("ids")
			scope := context.GetDB().Where(fmt.Sprintf("%v IN (?)", context.Resource.PrimaryField().DBName), ids)
			err = action.Handle(scope, context.Context)
		}
	}

	responder.With("html", func() {
		http.Redirect(context.Writer, context.Request, context.Request.Referer(), http.StatusFound)
	}).With("json", func() {
		if err == nil {
			context.Writer.Write([]byte("OK"))
		} else {
			context.Writer.Write([]byte(err.Error()))
		}
	}).Respond(context.Writer, context.Request)
}

func (ac *controller) Asset(context *Context) {
	file := strings.TrimPrefix(context.Request.URL.Path, ac.GetRouter().Prefix)
	if filename, err := context.findFile(file); err == nil {
		http.ServeFile(context.Writer, context.Request, filename)
	} else {
		http.NotFound(context.Writer, context.Request)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package aggregator

import (
	"container/list"
	"errors"
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/m3db/m3metrics/metric"
	"github.com/m3db/m3metrics/metric/unaggregated"
	"github.com/m3db/m3metrics/policy"
)

var (
	errEntryClosed = errors.New("entry is closed")
)

// Entry stores metadata about current policies and aggregations
// for a metric. Note since the metric namespace is part of the
// metric ID, we only need to keep track of the policy version
// to detect policy changes
type Entry struct {
	sync.RWMutex

	opts           Options                         // options
	lists          *MetricLists                    // metric lists
	version        int                             // current policy version
	numWriters     int32                           // number of writers writing to this entry
	lastAccessInNs int64                           // last access time
	aggregations   map[policy.Policy]*list.Element // aggregations at different resolutions
	closed         bool                            // whether the entry is closed
}

// NewEntry creates a new entry
func NewEntry(lists *MetricLists, opts Options) *Entry {
	e := &Entry{
		opts:         opts,
		aggregations: make(map[policy.Policy]*list.Element),
	}
	e.ResetSetData(lists)
	return e
}

// IncWriter increases the writer count
func (e *Entry) IncWriter() { atomic.AddInt32(&e.numWriters, 1) }

// DecWriter decreases the writer count
func (e *Entry) DecWriter() { atomic.AddInt32(&e.numWriters, -1) }

// ResetSetData resets the entry and sets initial data
func (e *Entry) ResetSetData(lists *MetricLists) {
	e.closed = false
	e.lists = lists
	e.version = policy.InitPolicyVersion
	e.numWriters = 0
	e.recordLastAccessed(e.opts.ClockOptions().NowFn()())
}

// AddMetricWithPolicies adds a metric along with applicable policies
func (e *Entry) AddMetricWithPolicies(
	mu unaggregated.MetricUnion,
	policies policy.VersionedPolicies,
) error {
	// NB(xichen): it is important that we determine the current time
	// within the time lock. This ensures time ordering by wrapping
	// actions that need to happen before a given time within a read lock,
	// so it is guaranteed that actions before when a write lock is acquired
	// must have all completed. This is used to ensure we never write metrics
	// for times that have already been flushed.
	timeLock := e.opts.TimeLock()
	timeLock.RLock()
	defer timeLock.RUnlock()

	e.RLock()
	if e.closed {
		e.RUnlock()
		return errEntryClosed
	}

	currTime := e.opts.ClockOptions().NowFn()()
	e.recordLastAccessed(currTime)

	if !e.shouldUpdatePoliciesWithLock(currTime, policies.Version, policies.Cutover) {
		e.addMetricWithLock(currTime, mu)
		e.RUnlock()
		return nil
	}
	e.RUnlock()

	e.Lock()
	if e.closed {
		e.Unlock()
		return errEntryClosed
	}

	if e.shouldUpdatePoliciesWithLock(currTime, policies.Version, policies.Cutover) {
		if err := e.updatePoliciesWithLock(mu.Type, mu.ID, policies.Version, policies.Policies); err != nil {
			// NB(xichen): if an error occurred during policy update, the policies
			// will remain as they are, i.e., there are no half-updated policies
			e.Unlock()
			return err
		}
	}

	e.addMetricWithLock(currTime, mu)
	e.Unlock()

	return nil
}

// ShouldExpire returns whether the entry should expire
func (e *Entry) ShouldExpire(now time.Time) bool {
	e.RLock()
	if e.closed {
		e.RUnlock()
		return false
	}
	// Only expire the entry if there are no active writers
	// and it has reached its ttl since last accessed
	shouldExpire := e.writerCount() == 0 && now.After(e.lastAccessed().Add(e.opts.EntryTTL()))
	e.RUnlock()
	return shouldExpire
}

// Expire expires the entry
func (e *Entry) Expire() {
	e.Lock()
	if e.closed {
		e.Unlock()
		return
	}
	e.closed = true
	for p, agg := range e.aggregations {
		switch elem := agg.Value.(type) {
		case metricElem:
			elem.MarkAsTombstoned()
		default:
			// We should never get here
			panic(fmt.Errorf("unknown metric element type: %T", elem))
		}
		delete(e.aggregations, p)
	}
	e.lists = nil
	pool := e.opts.EntryPool()
	e.Unlock()

	pool.Put(e)
}

func (e *Entry) writerCount() int        { return int(atomic.LoadInt32(&e.numWriters)) }
func (e *Entry) lastAccessed() time.Time { return time.Unix(0, atomic.LoadInt64(&e.lastAccessInNs)) }

func (e *Entry) recordLastAccessed(currTime time.Time) {
	atomic.StoreInt64(&e.lastAccessInNs, currTime.UnixNano())
}

func (e *Entry) addMetricWithLock(timestamp time.Time, mu unaggregated.MetricUnion) {
	for _, elem := range e.aggregations {
		elem.Value.(metricElem).AddMetric(timestamp, mu)
	}
}

// If the current version is older than the incoming version,
// and we've surpassed the cutover, we should update the policies
func (e *Entry) shouldUpdatePoliciesWithLock(
	currTime time.Time,
	version int,
	cutover time.Time,
) bool {
	return e.version == policy.InitPolicyVersion || (e.version < version && !currTime.Before(cutover))
}

func (e *Entry) updatePoliciesWithLock(
	typ unaggregated.Type,
	id metric.ID,
	newVersion int,
	policies []policy.Policy,
) error {
	// We should update the policies first
	newAggregations := make(map[policy.Policy]*list.Element, len(policies))
	for _, policy := range policies {
		if elem, exists := e.aggregations[policy]; exists {
			newAggregations[policy] = elem
		} else {
			var newElem metricElem
			switch typ {
			case unaggregated.CounterType:
				newElem = e.opts.CounterElemPool().Get()
			case unaggregated.BatchTimerType:
				newElem = e.opts.TimerElemPool().Get()
			case unaggregated.GaugeType:
				newElem = e.opts.GaugeElemPool().Get()
			default:
				return fmt.Errorf("unrecognized element type:%v", typ)
			}
			newElem.ResetSetData(id, policy)
			list, err := e.lists.FindOrCreate(policy.Resolution.Window)
			if err != nil {
				return err
			}
			newListElem, err := list.PushBack(newElem)
			if err != nil {
				return err
			}
			newAggregations[policy] = newListElem
		}
	}

	// Mark the outdated elements as tombstoned
	for policy, elem := range e.aggregations {
		if _, exists := newAggregations[policy]; !exists {
			elem.Value.(metricElem).MarkAsTombstoned()
		}
	}

	// Replace the existing aggregations with new aggregations
	e.aggregations = newAggregations
	e.version = newVersion

	return nil
}
<commit_msg>Remove type switch<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package aggregator

import (
	"container/list"
	"errors"
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"github.com/m3db/m3metrics/metric"
	"github.com/m3db/m3metrics/metric/unaggregated"
	"github.com/m3db/m3metrics/policy"
)

var (
	errEntryClosed = errors.New("entry is closed")
)

// Entry stores metadata about current policies and aggregations
// for a metric. Note since the metric namespace is part of the
// metric ID, we only need to keep track of the policy version
// to detect policy changes
type Entry struct {
	sync.RWMutex

	opts           Options                         // options
	lists          *MetricLists                    // metric lists
	version        int                             // current policy version
	numWriters     int32                           // number of writers writing to this entry
	lastAccessInNs int64                           // last access time
	aggregations   map[policy.Policy]*list.Element // aggregations at different resolutions
	closed         bool                            // whether the entry is closed
}

// NewEntry creates a new entry
func NewEntry(lists *MetricLists, opts Options) *Entry {
	e := &Entry{
		opts:         opts,
		aggregations: make(map[policy.Policy]*list.Element),
	}
	e.ResetSetData(lists)
	return e
}

// IncWriter increases the writer count
func (e *Entry) IncWriter() { atomic.AddInt32(&e.numWriters, 1) }

// DecWriter decreases the writer count
func (e *Entry) DecWriter() { atomic.AddInt32(&e.numWriters, -1) }

// ResetSetData resets the entry and sets initial data
func (e *Entry) ResetSetData(lists *MetricLists) {
	e.closed = false
	e.lists = lists
	e.version = policy.InitPolicyVersion
	e.numWriters = 0
	e.recordLastAccessed(e.opts.ClockOptions().NowFn()())
}

// AddMetricWithPolicies adds a metric along with applicable policies
func (e *Entry) AddMetricWithPolicies(
	mu unaggregated.MetricUnion,
	policies policy.VersionedPolicies,
) error {
	// NB(xichen): it is important that we determine the current time
	// within the time lock. This ensures time ordering by wrapping
	// actions that need to happen before a given time within a read lock,
	// so it is guaranteed that actions before when a write lock is acquired
	// must have all completed. This is used to ensure we never write metrics
	// for times that have already been flushed.
	timeLock := e.opts.TimeLock()
	timeLock.RLock()
	defer timeLock.RUnlock()

	e.RLock()
	if e.closed {
		e.RUnlock()
		return errEntryClosed
	}

	currTime := e.opts.ClockOptions().NowFn()()
	e.recordLastAccessed(currTime)

	if !e.shouldUpdatePoliciesWithLock(currTime, policies.Version, policies.Cutover) {
		e.addMetricWithLock(currTime, mu)
		e.RUnlock()
		return nil
	}
	e.RUnlock()

	e.Lock()
	if e.closed {
		e.Unlock()
		return errEntryClosed
	}

	if e.shouldUpdatePoliciesWithLock(currTime, policies.Version, policies.Cutover) {
		if err := e.updatePoliciesWithLock(mu.Type, mu.ID, policies.Version, policies.Policies); err != nil {
			// NB(xichen): if an error occurred during policy update, the policies
			// will remain as they are, i.e., there are no half-updated policies
			e.Unlock()
			return err
		}
	}

	e.addMetricWithLock(currTime, mu)
	e.Unlock()

	return nil
}

// ShouldExpire returns whether the entry should expire
func (e *Entry) ShouldExpire(now time.Time) bool {
	e.RLock()
	if e.closed {
		e.RUnlock()
		return false
	}
	// Only expire the entry if there are no active writers
	// and it has reached its ttl since last accessed
	shouldExpire := e.writerCount() == 0 && now.After(e.lastAccessed().Add(e.opts.EntryTTL()))
	e.RUnlock()
	return shouldExpire
}

// Expire expires the entry
func (e *Entry) Expire() {
	e.Lock()
	if e.closed {
		e.Unlock()
		return
	}
	e.closed = true
	for p, agg := range e.aggregations {
		agg.Value.(metricElem).MarkAsTombstoned()
		delete(e.aggregations, p)
	}
	e.lists = nil
	pool := e.opts.EntryPool()
	e.Unlock()

	pool.Put(e)
}

func (e *Entry) writerCount() int        { return int(atomic.LoadInt32(&e.numWriters)) }
func (e *Entry) lastAccessed() time.Time { return time.Unix(0, atomic.LoadInt64(&e.lastAccessInNs)) }

func (e *Entry) recordLastAccessed(currTime time.Time) {
	atomic.StoreInt64(&e.lastAccessInNs, currTime.UnixNano())
}

func (e *Entry) addMetricWithLock(timestamp time.Time, mu unaggregated.MetricUnion) {
	for _, elem := range e.aggregations {
		elem.Value.(metricElem).AddMetric(timestamp, mu)
	}
}

// If the current version is older than the incoming version,
// and we've surpassed the cutover, we should update the policies
func (e *Entry) shouldUpdatePoliciesWithLock(
	currTime time.Time,
	version int,
	cutover time.Time,
) bool {
	return e.version == policy.InitPolicyVersion || (e.version < version && !currTime.Before(cutover))
}

func (e *Entry) updatePoliciesWithLock(
	typ unaggregated.Type,
	id metric.ID,
	newVersion int,
	policies []policy.Policy,
) error {
	// We should update the policies first
	newAggregations := make(map[policy.Policy]*list.Element, len(policies))
	for _, policy := range policies {
		if elem, exists := e.aggregations[policy]; exists {
			newAggregations[policy] = elem
		} else {
			var newElem metricElem
			switch typ {
			case unaggregated.CounterType:
				newElem = e.opts.CounterElemPool().Get()
			case unaggregated.BatchTimerType:
				newElem = e.opts.TimerElemPool().Get()
			case unaggregated.GaugeType:
				newElem = e.opts.GaugeElemPool().Get()
			default:
				return fmt.Errorf("unrecognized element type:%v", typ)
			}
			newElem.ResetSetData(id, policy)
			list, err := e.lists.FindOrCreate(policy.Resolution.Window)
			if err != nil {
				return err
			}
			newListElem, err := list.PushBack(newElem)
			if err != nil {
				return err
			}
			newAggregations[policy] = newListElem
		}
	}

	// Mark the outdated elements as tombstoned
	for policy, elem := range e.aggregations {
		if _, exists := newAggregations[policy]; !exists {
			elem.Value.(metricElem).MarkAsTombstoned()
		}
	}

	// Replace the existing aggregations with new aggregations
	e.aggregations = newAggregations
	e.version = newVersion

	return nil
}
<|endoftext|>


<commit_before>package regexputil

import (
	"reflect"
	"regexp"
	"testing"
)

var findStringSubmatchNamedMapTests = []struct {
	v    string
	v2   string
	want map[string]string
}{
	{`(?P<KEY>\w+):(?P<VAL>\w+)`, "num:123", map[string]string{"KEY": "num", "VAL": "123"}},
	{`(?P<first>\w+).(?P<second>\w+)`, "foo.bar", map[string]string{"first": "foo", "second": "bar"}},
}

func TestFindStringSubmatchNamedMap(t *testing.T) {
	for _, tt := range findStringSubmatchNamedMapTests {
		rx := regexp.MustCompile(tt.v)
		resMss := FindStringSubmatchNamedMap(rx, tt.v2)

		eq := reflect.DeepEqual(tt.want, resMss)
		if !eq {
			t.Errorf("regepxutil.FindStringSubmatchNamedMap() Error: with [%v][%v], want [%v], got [%v]",
				tt.v, tt.v2, tt.want, resMss)
		}
	}
}
<commit_msg>update style<commit_after>package regexputil

import (
	"reflect"
	"regexp"
	"testing"
)

var findStringSubmatchNamedMapTests = []struct {
	v    string
	v2   string
	want map[string]string
}{
	{`(?P<KEY>\w+):(?P<VAL>\w+)`, "num:123", map[string]string{"KEY": "num", "VAL": "123"}},
	{`(?P<first>\w+).(?P<second>\w+)`, "foo.bar", map[string]string{"first": "foo", "second": "bar"}},
}

func TestFindStringSubmatchNamedMap(t *testing.T) {
	for _, tt := range findStringSubmatchNamedMapTests {
		rx := regexp.MustCompile(tt.v)
		resMss := FindStringSubmatchNamedMap(rx, tt.v2)

		if eq := reflect.DeepEqual(tt.want, resMss); !eq {
			t.Errorf("regepxutil.FindStringSubmatchNamedMap() Error: with [%v][%v], want [%v], got [%v]",
				tt.v, tt.v2, tt.want, resMss)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package main

import (
	"fmt"
	"strings"
)

func unparse(n node) string {
	output := ""

	switch v := n.(type) {
	case *stmtlistNode:
		for _, child := range v.children {
			output += unparse(child) + "\n"
		}

	case *exprlistNode:
		if len(v.children) > 0 {
			output += unparse(v.children[0])
			for _, child := range v.children[1:] {
				output += ", " + unparse(child)
			}
		}

	case *condNode:
		if v.cond != nil {
			output += unparse(v.cond)
		}
		output += " {\n"
		for _, child := range v.children {
			output += unparse(child)
		}
		output += "}\n"

	case *regexNode:
		output += "/" + strings.Replace(v.pattern, "/", "\\/", -1) + "/"

	case *relNode:
		output += unparse(v.lhs)
		switch v.op {
		case LT:
			output += " < "
		case GT:
			output += " > "
		case LE:
			output += " <= "
		case GE:
			output += " >= "
		case EQ:
			output += " == "
		case NE:
			output += " != "
		}
		output += unparse(v.rhs)

	case *stringNode:
		output += "\"" + v.text + "\""

	case *idNode:
		output += v.name

	case *caprefNode:
		output += "$" + v.name

	case *builtinNode:
		output += v.name + "("
		if v.args != nil {
			output += unparse(v.args)
		}
		output += ")"

	case *additiveExprNode:
		output += unparse(v.lhs)
		output += fmt.Sprintf(" %c ", v.op)
		output += unparse(v.rhs)

	case *assignExprNode:
		output += unparse(v.lhs)
		output += " = "
		output += unparse(v.rhs)

	case *indexedExprNode:
		output += unparse(v.lhs)
		output += "["
		output += unparse(v.index)
		output += "]"

	case *declNode:
		switch v.kind {
		case Counter:
			output += "counter "
		case Gauge:
			output += "gauge "
		}
		output += v.name

	case *incExprNode:
		output += unparse(v.lhs)
		output += "++"

	case *incByExprNode:
		output += unparse(v.lhs)
		output += " += "
		output += unparse(v.rhs)

	case *numericExprNode:
		output += fmt.Sprintf("%d", v.value)

	case *defNode:
		output += fmt.Sprintf("def %s {\n", v.name)
		for _, child := range v.children {
			output += unparse(child)
		}
		output += "}\n"

	case *decoNode:
		output += fmt.Sprintf("@%s {\n", v.name)
		for _, child := range v.children {
			output += unparse(child)
		}
		output += "}\n"

	case *nextNode:
		output += "next\n"

	default:
		panic(fmt.Sprintf("unparser found undefined type %T", n))
	}
	return output
}
<commit_msg>Unparse dimensioned variables correctly.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package main

import (
	"fmt"
	"strings"
)

func unparse(n node) string {
	output := ""

	switch v := n.(type) {
	case *stmtlistNode:
		for _, child := range v.children {
			output += unparse(child) + "\n"
		}

	case *exprlistNode:
		if len(v.children) > 0 {
			output += unparse(v.children[0])
			for _, child := range v.children[1:] {
				output += ", " + unparse(child)
			}
		}

	case *condNode:
		if v.cond != nil {
			output += unparse(v.cond)
		}
		output += " {\n"
		for _, child := range v.children {
			output += unparse(child)
		}
		output += "}\n"

	case *regexNode:
		output += "/" + strings.Replace(v.pattern, "/", "\\/", -1) + "/"

	case *relNode:
		output += unparse(v.lhs)
		switch v.op {
		case LT:
			output += " < "
		case GT:
			output += " > "
		case LE:
			output += " <= "
		case GE:
			output += " >= "
		case EQ:
			output += " == "
		case NE:
			output += " != "
		}
		output += unparse(v.rhs)

	case *stringNode:
		output += "\"" + v.text + "\""

	case *idNode:
		output += v.name

	case *caprefNode:
		output += "$" + v.name

	case *builtinNode:
		output += v.name + "("
		if v.args != nil {
			output += unparse(v.args)
		}
		output += ")"

	case *additiveExprNode:
		output += unparse(v.lhs)
		output += fmt.Sprintf(" %c ", v.op)
		output += unparse(v.rhs)

	case *assignExprNode:
		output += unparse(v.lhs)
		output += " = "
		output += unparse(v.rhs)

	case *indexedExprNode:
		output += unparse(v.lhs)
		output += "["
		output += unparse(v.index)
		output += "]"

	case *declNode:
		switch v.kind {
		case Counter:
			output += "counter "
		case Gauge:
			output += "gauge "
		}
		output += v.name
		if len(v.keys) > 0 {
			output += " by " + strings.Join(v.keys, ", ")
		}

	case *incExprNode:
		output += unparse(v.lhs)
		output += "++"

	case *incByExprNode:
		output += unparse(v.lhs)
		output += " += "
		output += unparse(v.rhs)

	case *numericExprNode:
		output += fmt.Sprintf("%d", v.value)

	case *defNode:
		output += fmt.Sprintf("def %s {\n", v.name)
		for _, child := range v.children {
			output += unparse(child)
		}
		output += "}\n"

	case *decoNode:
		output += fmt.Sprintf("@%s {\n", v.name)
		for _, child := range v.children {
			output += unparse(child)
		}
		output += "}\n"

	case *nextNode:
		output += "next\n"

	default:
		panic(fmt.Sprintf("unparser found undefined type %T", n))
	}
	return output
}
<|endoftext|>


<commit_before>package iterator

import (
	"fmt"
	"strings"

	"github.com/google/cayley/graph"
)

// Not iterator acts like a complement for the primary iterator.
// It will return all the vertices which are not part of the primary iterator.
type Not struct {
	uid       uint64
	tags      graph.Tagger
	primaryIt graph.Iterator
	allIt     graph.Iterator
	result    graph.Value
	runstats  graph.IteratorStats
}

func NewNot(primaryIt, allIt graph.Iterator) *Not {
	return &Not{
		uid:       NextUID(),
		primaryIt: primaryIt,
		allIt:     allIt,
	}
}

func (it *Not) UID() uint64 {
	return it.uid
}

// Reset resets the internal iterators and the iterator itself.
func (it *Not) Reset() {
	it.result = nil
	it.primaryIt.Reset()
	it.allIt.Reset()
}

func (it *Not) Tagger() *graph.Tagger {
	return &it.tags
}

func (it *Not) TagResults(dst map[string]graph.Value) {
	for _, tag := range it.tags.Tags() {
		dst[tag] = it.Result()
	}

	for tag, value := range it.tags.Fixed() {
		dst[tag] = value
	}

	if it.primaryIt != nil {
		it.primaryIt.TagResults(dst)
	}
}

func (it *Not) Clone() graph.Iterator {
	not := NewNot(it.primaryIt.Clone(), it.allIt.Clone())
	not.tags.CopyFrom(it)
	return not
}

// SubIterators returns a slice of the sub iterators.
// The first iterator is the primary iterator, for which the complement
// is generated.
func (it *Not) SubIterators() []graph.Iterator {
	return []graph.Iterator{it.primaryIt, it.allIt}
}

// DEPRECATED
func (it *Not) ResultTree() *graph.ResultTree {
	tree := graph.NewResultTree(it.Result())
	tree.AddSubtree(it.primaryIt.ResultTree())
	tree.AddSubtree(it.allIt.ResultTree())
	return tree
}

// DebugString prints information about the iterator.
func (it *Not) DebugString(indent int) string {
	var tags string
	for _, k := range it.tags.Tags() {
		tags += fmt.Sprintf("%s;", k)
	}

	spaces := strings.Repeat(" ", indent+2)
	return fmt.Sprintf("%s(%s %d\n%stags:%v\n%sprimary_it:\n%s\n)",
		strings.Repeat(" ", indent),
		it.Type(),
		it.UID(),
		spaces,
		it.tags.Tags(),
		spaces,
		it.primaryIt.DebugString(indent+4),
	)
}

// Next advances the Not iterator. It returns whether there is another valid
// new value. It fetches the next value of the all iterator which is not
// contained by the primary iterator.
func (it *Not) Next() bool {
	graph.NextLogIn(it)
	it.runstats.Next += 1

	for graph.Next(it.allIt) {
		if curr := it.allIt.Result(); !it.primaryIt.Contains(curr) {
			it.result = curr
			it.runstats.ContainsNext += 1
			return graph.NextLogOut(it, curr, true)
		}
	}
	return graph.NextLogOut(it, nil, false)
}

func (it *Not) Result() graph.Value {
	return it.result
}

// Contains checks whether the passed value is part of the primary iterator's
// complement. For a valid value, it updates the Result returned by the iterator
// to the value itself.
func (it *Not) Contains(val graph.Value) bool {
	graph.ContainsLogIn(it, val)
	it.runstats.Contains += 1

	if it.primaryIt.Contains(val) {
		return graph.ContainsLogOut(it, val, false)
	}

	it.result = val
	return graph.ContainsLogOut(it, val, true)
}

// NextPath checks whether there is another path. Not applicable, hence it will
// return false.
func (it *Not) NextPath() bool {
	return false
}

func (it *Not) Close() {
	it.primaryIt.Close()
	it.allIt.Close()
}

func (it *Not) Type() graph.Type { return graph.Not }

func (it *Not) Optimize() (graph.Iterator, bool) {
	// TODO - consider wrapping the primaryIt with a MaterializeIt
	optimizedPrimaryIt, optimized := it.primaryIt.Optimize()
	if optimized {
		it.primaryIt = optimizedPrimaryIt
	}
	return it, optimized
}

func (it *Not) Stats() graph.IteratorStats {
	primaryStats := it.primaryIt.Stats()
	allStats := it.allIt.Stats()
	return graph.IteratorStats{
		NextCost:     allStats.NextCost + primaryStats.ContainsCost,
		ContainsCost: primaryStats.ContainsCost,
		Size:         allStats.Size - primaryStats.Size,
		Next:         it.runstats.Next,
		Contains:     it.runstats.Contains,
		ContainsNext: it.runstats.ContainsNext,
	}
}

func (it *Not) Size() (int64, bool) {
	return it.Stats().Size, false
}
<commit_msg>Fixed Optimize method for not iterator.<commit_after>package iterator

import (
	"fmt"
	"strings"

	"github.com/google/cayley/graph"
)

// Not iterator acts like a complement for the primary iterator.
// It will return all the vertices which are not part of the primary iterator.
type Not struct {
	uid       uint64
	tags      graph.Tagger
	primaryIt graph.Iterator
	allIt     graph.Iterator
	result    graph.Value
	runstats  graph.IteratorStats
}

func NewNot(primaryIt, allIt graph.Iterator) *Not {
	return &Not{
		uid:       NextUID(),
		primaryIt: primaryIt,
		allIt:     allIt,
	}
}

func (it *Not) UID() uint64 {
	return it.uid
}

// Reset resets the internal iterators and the iterator itself.
func (it *Not) Reset() {
	it.result = nil
	it.primaryIt.Reset()
	it.allIt.Reset()
}

func (it *Not) Tagger() *graph.Tagger {
	return &it.tags
}

func (it *Not) TagResults(dst map[string]graph.Value) {
	for _, tag := range it.tags.Tags() {
		dst[tag] = it.Result()
	}

	for tag, value := range it.tags.Fixed() {
		dst[tag] = value
	}

	if it.primaryIt != nil {
		it.primaryIt.TagResults(dst)
	}
}

func (it *Not) Clone() graph.Iterator {
	not := NewNot(it.primaryIt.Clone(), it.allIt.Clone())
	not.tags.CopyFrom(it)
	return not
}

// SubIterators returns a slice of the sub iterators.
// The first iterator is the primary iterator, for which the complement
// is generated.
func (it *Not) SubIterators() []graph.Iterator {
	return []graph.Iterator{it.primaryIt, it.allIt}
}

// DEPRECATED
func (it *Not) ResultTree() *graph.ResultTree {
	tree := graph.NewResultTree(it.Result())
	tree.AddSubtree(it.primaryIt.ResultTree())
	tree.AddSubtree(it.allIt.ResultTree())
	return tree
}

// DebugString prints information about the iterator.
func (it *Not) DebugString(indent int) string {
	var tags string
	for _, k := range it.tags.Tags() {
		tags += fmt.Sprintf("%s;", k)
	}

	spaces := strings.Repeat(" ", indent+2)
	return fmt.Sprintf("%s(%s %d\n%stags:%v\n%sprimary_it:\n%s\n%sall_it:\n%s\n%s)",
		strings.Repeat(" ", indent),
		it.Type(),
		it.UID(),
		spaces,
		it.tags.Tags(),
		spaces,
		it.primaryIt.DebugString(indent+4),
		spaces,
		it.allIt.DebugString(indent+4),
		strings.Repeat(" ", indent),
	)
}

// Next advances the Not iterator. It returns whether there is another valid
// new value. It fetches the next value of the all iterator which is not
// contained by the primary iterator.
func (it *Not) Next() bool {
	graph.NextLogIn(it)
	it.runstats.Next += 1

	for graph.Next(it.allIt) {
		if curr := it.allIt.Result(); !it.primaryIt.Contains(curr) {
			it.result = curr
			it.runstats.ContainsNext += 1
			return graph.NextLogOut(it, curr, true)
		}
	}
	return graph.NextLogOut(it, nil, false)
}

func (it *Not) Result() graph.Value {
	return it.result
}

// Contains checks whether the passed value is part of the primary iterator's
// complement. For a valid value, it updates the Result returned by the iterator
// to the value itself.
func (it *Not) Contains(val graph.Value) bool {
	graph.ContainsLogIn(it, val)
	it.runstats.Contains += 1

	if it.primaryIt.Contains(val) {
		return graph.ContainsLogOut(it, val, false)
	}

	it.result = val
	return graph.ContainsLogOut(it, val, true)
}

// NextPath checks whether there is another path. Not applicable, hence it will
// return false.
func (it *Not) NextPath() bool {
	return false
}

func (it *Not) Close() {
	it.primaryIt.Close()
	it.allIt.Close()
}

func (it *Not) Type() graph.Type { return graph.Not }

func (it *Not) Optimize() (graph.Iterator, bool) {
	// TODO - consider wrapping the primaryIt with a MaterializeIt
	optimizedPrimaryIt, optimized := it.primaryIt.Optimize()
	if optimized {
		it.primaryIt = optimizedPrimaryIt
	}
	return it, false
}

func (it *Not) Stats() graph.IteratorStats {
	primaryStats := it.primaryIt.Stats()
	allStats := it.allIt.Stats()
	return graph.IteratorStats{
		NextCost:     allStats.NextCost + primaryStats.ContainsCost,
		ContainsCost: primaryStats.ContainsCost,
		Size:         allStats.Size - primaryStats.Size,
		Next:         it.runstats.Next,
		Contains:     it.runstats.Contains,
		ContainsNext: it.runstats.ContainsNext,
	}
}

func (it *Not) Size() (int64, bool) {
	return it.Stats().Size, false
}
<|endoftext|>


<commit_before>package analyze

import (
	"regexp"

	"github.com/deckarep/golang-set"
	"github.com/jzelinskie/geddit"
)

func AnalyzeComments(comments []*geddit.Comment) error {
	r, err := regexp.Compile(`github\.com\/\w+\/\w+`)
	if err != nil {
		return err
	}
	for _, comment := range comments {
		if comment.Author == "github-stats-bot" {
			continue
		}
		if r.MatchString(comment.Body) {
			linkSet := mapset.NewSet()
			for _, link := range r.FindAllString(comment.Body, -1) {
				linkSet.Add(link)
			}
			var links []string
			for _, link := range linkSet.ToSlice() {
				links = append(links, link.(string))
			}
			//go postReply(comment, links)
		}
	}
	return nil
}

/*func postReply(comment *geddit.Comment, links []string) {
	for _, link := range links {
		var data map[string]interface{}
		if err := getStats(link, &data); err != nil {
			return
		}
		if data["message"] == "Not Found" {
			return
		}
	}
}

func getStats(link string, data *map[string]interface{}) error {
	res, err := http.Get("https://api.github.com/repos/" + link[11:])
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if err = json.NewDecoder(res.Body).Decode(&data); err != nil {
		return err
	}
	return nil
}*/
<commit_msg>added postReply() and getJson()<commit_after>package analyze

import (
	"encoding/json"
	"net/http"
	"regexp"

	"github.com/deckarep/golang-set"
	"github.com/jzelinskie/geddit"
)

func AnalyzeComments(comments []*geddit.Comment) error {
	r, err := regexp.Compile(`github\.com\/\w+\/\w+`)
	if err != nil {
		return err
	}
	for _, comment := range comments {
		if comment.Author == "github-stats-bot" {
			continue
		}
		if r.MatchString(comment.Body) {
			linkSet := mapset.NewSet()
			for _, link := range r.FindAllString(comment.Body, -1) {
				linkSet.Add(link)
			}
			var links []string
			for _, link := range linkSet.ToSlice() {
				links = append(links, link.(string))
			}
			go postReply(comment, links)
		}
	}
	return nil
}

func postReply(comment *geddit.Comment, links []string) {
	for _, link := range links {
		var data map[string]interface{}
		if err := getStats(link, &data); err != nil {
			return
		}
		if data["message"] == "Not Found" {
			return
		}
	}
}

func getStats(link string, data *map[string]interface{}) error {
	res, err := http.Get("https://api.github.com/repos/" + link[11:])
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if err = json.NewDecoder(res.Body).Decode(&data); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package util

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

	"github.com/go-aah/website/app/markdown"
	"github.com/go-aah/website/app/models"

	"aahframework.org/aah.v0"
	"aahframework.org/ahttp.v0"
	"aahframework.org/essentials.v0"
	"aahframework.org/log.v0"
)

var (
	releases      []string
	editURLPrefix string
)

// BranchName method returns the confirmed branch name
func BranchName(version string) string {
	releases, _ := aah.AppConfig().StringList("docs.releases")
	if version == releases[0] {
		return "master"
	}
	return version
}

// DocBaseDir method returns the aah documentation based directory.
func DocBaseDir() string {
	return filepath.Join(aah.AppConfig().StringDefault("docs.dir", ""), "aah-documentation")
}

// DocVersionBaseDir method returns the documentation dir path for given
// language and version.
func DocVersionBaseDir(version string) string {
	return filepath.Join(DocBaseDir(), version)
}

// RefreshDocContent method clone's the GitHub branch doc version wise into
// local and if already exits it takes a update from GitHub.
// It clears cache too.
func RefreshDocContent(pushEvent *models.GithubPushEvent) {
	version := pushEvent.BranchName()
	if version == "master" {
		version = releases[0]
	}

	if !ess.IsSliceContainsString(releases, version) {
		log.Warnf("Branch Name [%s] not found", version)
		return
	}

	GitRefresh(releases)

	log.Infof("BranchName: %s", version)
	docVersionBaseDir := DocVersionBaseDir(version)
	for _, commit := range pushEvent.Commits {
		log.Infof("CommitID: %s, Message: %s", commit.ID, commit.Message)
		log.Infof("Modified: %s, Removed: %s", commit.Modified, commit.Removed)

		for _, f := range commit.Modified {
			if strings.HasSuffix(f, "LICENSE") || strings.HasSuffix(f, "README.md") {
				continue
			}
			mdPath := FilePath(f, docVersionBaseDir)
			markdown.RefreshCacheByFile(mdPath)
		}

		for _, f := range commit.Removed {
			mdPath := FilePath(f, docVersionBaseDir)
			markdown.RemoveCacheByFile(mdPath)
		}
	}
}

// GitRefresh method clone's the GitHub branch doc version wise into
// local and if already exits it takes a update from GitHub.
func GitRefresh(releases []string) {
	for _, version := range releases {
		docDirPath := DocVersionBaseDir(version)
		branchName := BranchName(version)
		err := GitCloneAndPull(docDirPath, branchName)
		if err != nil {
			log.Error(err)
		}
	}
}

// ContentBasePath method returns the Markdown files base path.
func ContentBasePath() string {
	return filepath.Join(aah.AppVirtualBaseDir(), "content")
}

// FilePath method returns markdown file path from given path.
// it bacially remove any extension and adds ".md"
func FilePath(reqPath, prefix string) string {
	reqPath = strings.ToLower(TrimPrefixSlash(reqPath))
	reqPath = ess.StripExt(reqPath) + ".md"
	return filepath.Clean(filepath.Join(prefix, reqPath))
}

// TrimPrefixSlash method trims the prefix slash from the given path
func TrimPrefixSlash(str string) string {
	return strings.TrimPrefix(str, "/")
}

// CreateKey method creates markdown file name from request path.
func CreateKey(rpath string) string {
	key := ess.StripExt(TrimPrefixSlash(rpath))
	return strings.Replace(key, "/", "-", -1)
}

// PullGithubDocsAndLoadCache method pulls github docs and populate documentation
// in the cache
func PullGithubDocsAndLoadCache(e *aah.Event) {
	cfg := aah.AppConfig()
	editURLPrefix = cfg.StringDefault("docs.edit_url_prefix", "")
	releases, _ = cfg.StringList("docs.releases")

	keepLocalVersion := os.Getenv("KEEP_FILES")
	if len(keepLocalVersion) > 0 {
		return
	}

	docBasePath := DocBaseDir()

	if aah.AppProfile() == "prod" {
		ess.DeleteFiles(docBasePath)
	}

	_ = ess.MkDirAll(docBasePath, 0755)
	GitRefresh(releases)

	if cfg.BoolDefault("markdown.cache", false) {
		go markdown.LoadCache(filepath.Join(docBasePath, releases[0]))
		go markdown.LoadCache(ContentBasePath())
	}
}

// TmplDocURLc method compose documentation navi URL based on version
func TmplDocURLc(viewArgs map[string]interface{}, key string) template.HTML {
	params := viewArgs[aah.KeyViewArgRequestParams].(*ahttp.Params)
	version := params.PathValue("version")
	if !ess.IsSliceContainsString(releases, version) {
		version = releases[0]
	}

	fileName := aah.AppConfig().StringDefault(key, "")
	return template.HTML(fmt.Sprintf("/%s/%s", version, fileName))
}

// TmplDocEditURL method compose github documentation edit URL
func TmplDocEditURL(docFile string) template.URL {
	var pattern string
	if strings.HasPrefix(docFile, "/") {
		pattern = "%s%s"
	} else {
		pattern = "%s/%s"
	}
	return template.URL(fmt.Sprintf(pattern, editURLPrefix, docFile))
}
<commit_msg>now vfs provides fs indepentent so use path.Join<commit_after>package util

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

	"github.com/go-aah/website/app/markdown"
	"github.com/go-aah/website/app/models"

	"aahframework.org/aah.v0"
	"aahframework.org/ahttp.v0"
	"aahframework.org/essentials.v0"
	"aahframework.org/log.v0"
)

var (
	releases      []string
	editURLPrefix string
)

// BranchName method returns the confirmed branch name
func BranchName(version string) string {
	releases, _ := aah.AppConfig().StringList("docs.releases")
	if version == releases[0] {
		return "master"
	}
	return version
}

// DocBaseDir method returns the aah documentation based directory.
func DocBaseDir() string {
	return filepath.Join(aah.AppConfig().StringDefault("docs.dir", ""), "aah-documentation")
}

// DocVersionBaseDir method returns the documentation dir path for given
// language and version.
func DocVersionBaseDir(version string) string {
	return filepath.Join(DocBaseDir(), version)
}

// RefreshDocContent method clone's the GitHub branch doc version wise into
// local and if already exits it takes a update from GitHub.
// It clears cache too.
func RefreshDocContent(pushEvent *models.GithubPushEvent) {
	version := pushEvent.BranchName()
	if version == "master" {
		version = releases[0]
	}

	if !ess.IsSliceContainsString(releases, version) {
		log.Warnf("Branch Name [%s] not found", version)
		return
	}

	GitRefresh(releases)

	log.Infof("BranchName: %s", version)
	docVersionBaseDir := DocVersionBaseDir(version)
	for _, commit := range pushEvent.Commits {
		log.Infof("CommitID: %s, Message: %s", commit.ID, commit.Message)
		log.Infof("Modified: %s, Removed: %s", commit.Modified, commit.Removed)

		for _, f := range commit.Modified {
			if strings.HasSuffix(f, "LICENSE") || strings.HasSuffix(f, "README.md") {
				continue
			}
			mdPath := FilePath(f, docVersionBaseDir)
			markdown.RefreshCacheByFile(mdPath)
		}

		for _, f := range commit.Removed {
			mdPath := FilePath(f, docVersionBaseDir)
			markdown.RemoveCacheByFile(mdPath)
		}
	}
}

// GitRefresh method clone's the GitHub branch doc version wise into
// local and if already exits it takes a update from GitHub.
func GitRefresh(releases []string) {
	for _, version := range releases {
		docDirPath := DocVersionBaseDir(version)
		branchName := BranchName(version)
		err := GitCloneAndPull(docDirPath, branchName)
		if err != nil {
			log.Error(err)
		}
	}
}

// ContentBasePath method returns the Markdown files base path.
func ContentBasePath() string {
	return filepath.Join(aah.AppVirtualBaseDir(), "content")
}

// FilePath method returns markdown file path from given path.
// it bacially remove any extension and adds ".md"
func FilePath(reqPath, prefix string) string {
	reqPath = strings.ToLower(TrimPrefixSlash(reqPath))
	reqPath = ess.StripExt(reqPath) + ".md"
	return path.Clean(path.Join(prefix, reqPath))
}

// TrimPrefixSlash method trims the prefix slash from the given path
func TrimPrefixSlash(str string) string {
	return strings.TrimPrefix(str, "/")
}

// CreateKey method creates markdown file name from request path.
func CreateKey(rpath string) string {
	key := ess.StripExt(TrimPrefixSlash(rpath))
	return strings.Replace(key, "/", "-", -1)
}

// PullGithubDocsAndLoadCache method pulls github docs and populate documentation
// in the cache
func PullGithubDocsAndLoadCache(e *aah.Event) {
	cfg := aah.AppConfig()
	editURLPrefix = cfg.StringDefault("docs.edit_url_prefix", "")
	releases, _ = cfg.StringList("docs.releases")

	keepLocalVersion := os.Getenv("KEEP_FILES")
	if len(keepLocalVersion) > 0 {
		return
	}

	docBasePath := DocBaseDir()

	if aah.AppProfile() == "prod" {
		ess.DeleteFiles(docBasePath)
	}

	_ = ess.MkDirAll(docBasePath, 0755)
	GitRefresh(releases)

	if cfg.BoolDefault("markdown.cache", false) {
		go markdown.LoadCache(filepath.Join(docBasePath, releases[0]))
		go markdown.LoadCache(ContentBasePath())
	}
}

// TmplDocURLc method compose documentation navi URL based on version
func TmplDocURLc(viewArgs map[string]interface{}, key string) template.HTML {
	params := viewArgs[aah.KeyViewArgRequestParams].(*ahttp.Params)
	version := params.PathValue("version")
	if !ess.IsSliceContainsString(releases, version) {
		version = releases[0]
	}

	fileName := aah.AppConfig().StringDefault(key, "")
	return template.HTML(fmt.Sprintf("/%s/%s", version, fileName))
}

// TmplDocEditURL method compose github documentation edit URL
func TmplDocEditURL(docFile string) template.URL {
	var pattern string
	if strings.HasPrefix(docFile, "/") {
		pattern = "%s%s"
	} else {
		pattern = "%s/%s"
	}
	return template.URL(fmt.Sprintf(pattern, editURLPrefix, docFile))
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011-2013 Nan Deng
 * Copyright 2013-2017 Uniqush contributors.
 *
 * 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.
 *
 * This contains cloud messaging code specific to GCM.
 * Implementation details common to GCM and FCM are kept in srv/cloud_messaging
 */

package srv

import (
	"errors"

	"github.com/uniqush/uniqush-push/push"
	cm "github.com/uniqush/uniqush-push/srv/cloud_messaging"
)

const (
	// GCM endpoint
	gcmServiceURL string = "https://android.googleapis.com/gcm/send"
	// payload key to extract from push requests to uniqush
	gcmRawPayloadKey = "uniqush.payload.gcm"
	// initialism for log messages
	gcmInitialism = "GCM"
	// push service type(name), for requests to uniqush
	gcmPushServiceName = "gcm"
)

type gcmPushService struct {
	// There is only one Transport and one Client for connecting to gcm, shared by the set of PSPs with pushservicetype=gcm (whether or not this is using a sandbox)
	cm.PushServiceBase
}

var _ push.PushServiceType = &gcmPushService{}

func newGCMPushService() *gcmPushService {
	return &gcmPushService{
		PushServiceBase: cm.MakePushServiceBase(gcmInitialism, gcmRawPayloadKey, gcmServiceURL, gcmPushServiceName),
	}
}

func InstallGCM() {
	psm := push.GetPushServiceManager()
	psm.RegisterPushServiceType(newGCMPushService())
}

func (p *gcmPushService) BuildPushServiceProviderFromMap(kv map[string]string,
	psp *push.PushServiceProvider) error {
	if service, ok := kv["service"]; ok && len(service) > 0 {
		psp.FixedData["service"] = service
	} else {
		return errors.New("NoService")
	}

	if projectid, ok := kv["projectid"]; ok && len(projectid) > 0 {
		psp.FixedData["projectid"] = projectid
	} else {
		return errors.New("NoProjectID")
	}

	if authtoken, ok := kv["apikey"]; ok && len(authtoken) > 0 {
		psp.VolatileData["apikey"] = authtoken
	} else {
		return errors.New("NoAPIKey")
	}

	return nil
}
<commit_msg>Update GCM endpoint.<commit_after>/*
 * Copyright 2011-2013 Nan Deng
 * Copyright 2013-2017 Uniqush contributors.
 *
 * 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.
 *
 * This contains cloud messaging code specific to GCM.
 * Implementation details common to GCM and FCM are kept in srv/cloud_messaging
 */

package srv

import (
	"errors"

	"github.com/uniqush/uniqush-push/push"
	cm "github.com/uniqush/uniqush-push/srv/cloud_messaging"
)

const (
	// GCM endpoint
	gcmServiceURL string = "https://gcm-http.googleapis.com/gcm/send"
	// payload key to extract from push requests to uniqush
	gcmRawPayloadKey = "uniqush.payload.gcm"
	// initialism for log messages
	gcmInitialism = "GCM"
	// push service type(name), for requests to uniqush
	gcmPushServiceName = "gcm"
)

type gcmPushService struct {
	// There is only one Transport and one Client for connecting to gcm, shared by the set of PSPs with pushservicetype=gcm (whether or not this is using a sandbox)
	cm.PushServiceBase
}

var _ push.PushServiceType = &gcmPushService{}

func newGCMPushService() *gcmPushService {
	return &gcmPushService{
		PushServiceBase: cm.MakePushServiceBase(gcmInitialism, gcmRawPayloadKey, gcmServiceURL, gcmPushServiceName),
	}
}

func InstallGCM() {
	psm := push.GetPushServiceManager()
	psm.RegisterPushServiceType(newGCMPushService())
}

func (p *gcmPushService) BuildPushServiceProviderFromMap(kv map[string]string,
	psp *push.PushServiceProvider) error {
	if service, ok := kv["service"]; ok && len(service) > 0 {
		psp.FixedData["service"] = service
	} else {
		return errors.New("NoService")
	}

	if projectid, ok := kv["projectid"]; ok && len(projectid) > 0 {
		psp.FixedData["projectid"] = projectid
	} else {
		return errors.New("NoProjectID")
	}

	if authtoken, ok := kv["apikey"]; ok && len(authtoken) > 0 {
		psp.VolatileData["apikey"] = authtoken
	} else {
		return errors.New("NoAPIKey")
	}

	return nil
}
<|endoftext|>


<commit_before>package chunkstore

import (
    "compress/gzip"
    "compress/zlib"
    "encoding/binary"
    "fmt"
    "io"
    "os"
    "path"

    .   "chunkymonkey/types"
)

const (
    regionFileEdge       = 32
    regionFileEdgeShift  = 5
    regionFileSectorSize = 4096
)

type chunkStoreBeta struct {
    worldPath string
}

// Creates a ChunkStore that reads the Minecraft Beta world format.
func NewChunkStoreBeta(worldPath string) ChunkStore {
    return &chunkStoreBeta{
        worldPath: worldPath,
    }
}

func regionFilePath(worldPath string, chunkLoc *ChunkXZ) string {
    return path.Join(
        worldPath,
        "region",
        fmt.Sprintf(
            "r.%d.%d.mcr",
            chunkLoc.X>>regionFileEdgeShift,
            chunkLoc.Z>>regionFileEdgeShift,
        ),
    )
}

func (s *chunkStoreBeta) LoadChunk(chunkLoc *ChunkXZ) (reader ChunkReader, err os.Error) {
    // TODO cache limited number of likely-to-be-used regionFileReader objs
    filePath := regionFilePath(s.worldPath, chunkLoc)
    cfr, err := newRegionFileReader(filePath)
    if err != nil {
        return
    }

    return cfr.ReadChunkData(chunkLoc)
}

// A chunk file header entry.
type chunkOffset uint32

// Returns true if the offset value states that the chunk is present in the
// file.
func (o chunkOffset) IsPresent() bool {
    return o != 0
}

func (o chunkOffset) Get() (sectorCount, sectorIndex uint32) {
    sectorCount = uint32(o & 0xff)
    sectorIndex = uint32(o >> 8)
    return
}

// Represents a chunk file header containing chunk data offsets.
type regionFileHeader [regionFileEdge * regionFileEdge]chunkOffset

// Returns the chunk offset data for the given chunk. It assumes that chunkLoc
// is within the chunk file - discarding upper bits of the X and Z coords.
func (h regionFileHeader) GetOffset(chunkLoc *ChunkXZ) chunkOffset {
    x := chunkLoc.X & (regionFileEdge - 1)
    z := chunkLoc.Z & (regionFileEdge - 1)
    return h[x+(z<<regionFileEdgeShift)]
}

// Represents the header of a single chunk of data within a chunkfile.
type chunkDataHeader struct {
    DataSize uint32
    Version  byte
}

// Returns an io.Reader to correctly decompress data from the chunk data.
// The reader passed in must be just after the chunkDataHeader in the source
// data stream. The caller is responsible for closing the returned ReadCloser.
func (cdh *chunkDataHeader) GetDataReader(raw io.Reader) (output io.ReadCloser, err os.Error) {
    limitReader := io.LimitReader(raw, int64(cdh.DataSize))
    switch cdh.Version {
    case 1:
        output, err = gzip.NewReader(limitReader)
    case 2:
        output, err = zlib.NewReader(limitReader)
    default:
        err = os.NewError("Chunk data header contained unknown version number.")
    }
    return
}

// Handle on a chunk file - used to read chunk data from the file.
type regionFileReader struct {
    offsets  regionFileHeader
    filePath string
}

func newRegionFileReader(filePath string) (cfr *regionFileReader, err os.Error) {
    // TODO keep file open until the regionFileReader is got rid of.
    file, err := os.Open(filePath, os.O_RDONLY, 0)
    if err != nil {
        return
    }
    defer file.Close()

    cfr = &regionFileReader{
        filePath: filePath,
    }

    err = binary.Read(file, binary.BigEndian, &cfr.offsets)
    if err != nil {
        cfr = nil
        return
    }

    return
}

func (cfr *regionFileReader) ReadChunkData(chunkLoc *ChunkXZ) (r *chunkReader, err os.Error) {
    offset := cfr.offsets.GetOffset(chunkLoc)

    if !offset.IsPresent() {
        // Chunk doesn't exist in file
        err = nil
        return
    }

    file, err := os.Open(cfr.filePath, os.O_RDONLY, 0)
    if err != nil {
        return
    }
    defer file.Close()

    sectorCount, sectorIndex := offset.Get()

    if sectorIndex == 0 || sectorCount == 0 {
        err = os.NewError("Header gave bad chunk offset.")
    }

    file.Seek(int64(sectorIndex) * regionFileSectorSize, 0)

    // 5 is the size of chunkDataHeader in bytes.
    maxChunkDataSize := (sectorCount * regionFileSectorSize) - 5

    var header chunkDataHeader
    binary.Read(file, binary.BigEndian, &header)
    if header.DataSize > maxChunkDataSize {
        err = os.NewError("Chunk is too big for the sectors it is within.")
    }

    dataReader, err := header.GetDataReader(file)
    if err != nil {
        return
    }

    defer dataReader.Close()
    r, err = newChunkReader(dataReader)

    return
}
<commit_msg>gofmt run.<commit_after>package chunkstore

import (
    "compress/gzip"
    "compress/zlib"
    "encoding/binary"
    "fmt"
    "io"
    "os"
    "path"

    .   "chunkymonkey/types"
)

const (
    regionFileEdge       = 32
    regionFileEdgeShift  = 5
    regionFileSectorSize = 4096
)

type chunkStoreBeta struct {
    worldPath string
}

// Creates a ChunkStore that reads the Minecraft Beta world format.
func NewChunkStoreBeta(worldPath string) ChunkStore {
    return &chunkStoreBeta{
        worldPath: worldPath,
    }
}

func regionFilePath(worldPath string, chunkLoc *ChunkXZ) string {
    return path.Join(
        worldPath,
        "region",
        fmt.Sprintf(
            "r.%d.%d.mcr",
            chunkLoc.X>>regionFileEdgeShift,
            chunkLoc.Z>>regionFileEdgeShift,
        ),
    )
}

func (s *chunkStoreBeta) LoadChunk(chunkLoc *ChunkXZ) (reader ChunkReader, err os.Error) {
    // TODO cache limited number of likely-to-be-used regionFileReader objs
    filePath := regionFilePath(s.worldPath, chunkLoc)
    cfr, err := newRegionFileReader(filePath)
    if err != nil {
        return
    }

    return cfr.ReadChunkData(chunkLoc)
}

// A chunk file header entry.
type chunkOffset uint32

// Returns true if the offset value states that the chunk is present in the
// file.
func (o chunkOffset) IsPresent() bool {
    return o != 0
}

func (o chunkOffset) Get() (sectorCount, sectorIndex uint32) {
    sectorCount = uint32(o & 0xff)
    sectorIndex = uint32(o >> 8)
    return
}

// Represents a chunk file header containing chunk data offsets.
type regionFileHeader [regionFileEdge * regionFileEdge]chunkOffset

// Returns the chunk offset data for the given chunk. It assumes that chunkLoc
// is within the chunk file - discarding upper bits of the X and Z coords.
func (h regionFileHeader) GetOffset(chunkLoc *ChunkXZ) chunkOffset {
    x := chunkLoc.X & (regionFileEdge - 1)
    z := chunkLoc.Z & (regionFileEdge - 1)
    return h[x+(z<<regionFileEdgeShift)]
}

// Represents the header of a single chunk of data within a chunkfile.
type chunkDataHeader struct {
    DataSize uint32
    Version  byte
}

// Returns an io.Reader to correctly decompress data from the chunk data.
// The reader passed in must be just after the chunkDataHeader in the source
// data stream. The caller is responsible for closing the returned ReadCloser.
func (cdh *chunkDataHeader) GetDataReader(raw io.Reader) (output io.ReadCloser, err os.Error) {
    limitReader := io.LimitReader(raw, int64(cdh.DataSize))
    switch cdh.Version {
    case 1:
        output, err = gzip.NewReader(limitReader)
    case 2:
        output, err = zlib.NewReader(limitReader)
    default:
        err = os.NewError("Chunk data header contained unknown version number.")
    }
    return
}

// Handle on a chunk file - used to read chunk data from the file.
type regionFileReader struct {
    offsets  regionFileHeader
    filePath string
}

func newRegionFileReader(filePath string) (cfr *regionFileReader, err os.Error) {
    // TODO keep file open until the regionFileReader is got rid of.
    file, err := os.Open(filePath, os.O_RDONLY, 0)
    if err != nil {
        return
    }
    defer file.Close()

    cfr = &regionFileReader{
        filePath: filePath,
    }

    err = binary.Read(file, binary.BigEndian, &cfr.offsets)
    if err != nil {
        cfr = nil
        return
    }

    return
}

func (cfr *regionFileReader) ReadChunkData(chunkLoc *ChunkXZ) (r *chunkReader, err os.Error) {
    offset := cfr.offsets.GetOffset(chunkLoc)

    if !offset.IsPresent() {
        // Chunk doesn't exist in file
        err = nil
        return
    }

    file, err := os.Open(cfr.filePath, os.O_RDONLY, 0)
    if err != nil {
        return
    }
    defer file.Close()

    sectorCount, sectorIndex := offset.Get()

    if sectorIndex == 0 || sectorCount == 0 {
        err = os.NewError("Header gave bad chunk offset.")
    }

    file.Seek(int64(sectorIndex)*regionFileSectorSize, 0)

    // 5 is the size of chunkDataHeader in bytes.
    maxChunkDataSize := (sectorCount * regionFileSectorSize) - 5

    var header chunkDataHeader
    binary.Read(file, binary.BigEndian, &header)
    if header.DataSize > maxChunkDataSize {
        err = os.NewError("Chunk is too big for the sectors it is within.")
    }

    dataReader, err := header.GetDataReader(file)
    if err != nil {
        return
    }

    defer dataReader.Close()
    r, err = newChunkReader(dataReader)

    return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/nytlabs/streamtools/st/server"
	"github.com/nytlabs/streamtools/st/library"
	"github.com/nytlabs/streamtools/st/loghub"
	"log"
)

var (
	// port that streamtools reuns on
	port   = flag.String("port", "7070", "streamtools port")
	domain = flag.String("domain", "127.0.0.1", "streamtools domain")
)

func main() {
	flag.Parse()
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	library.Start()
	loghub.Start()

	s := server.NewServer()

	s.Id = "SERVER"
	s.Port = *port
	s.Domain = *domain

	s.Run()
}
<commit_msg>Added a command line version flag to st binary<commit_after>package main

import (
	"flag"
	"github.com/nytlabs/streamtools/st/library"
	"github.com/nytlabs/streamtools/st/loghub"
	"github.com/nytlabs/streamtools/st/server"
	"github.com/nytlabs/streamtools/st/util"
	"log"
	"os"
)

var (
	// port that streamtools reuns on
	port    = flag.String("port", "7070", "streamtools port")
	domain  = flag.String("domain", "127.0.0.1", "streamtools domain")
	version = flag.Bool("version", false, "prints current streamtools version")
)

func main() {
	flag.Parse()

	if *version {
		log.Println("Streamtools version:", util.VERSION)
		os.Exit(0)
	}

	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	library.Start()
	loghub.Start()

	s := server.NewServer()

	s.Id = "SERVER"
	s.Port = *port
	s.Domain = *domain

	s.Run()
}
<|endoftext|>


<commit_before>package ps

import (
	"strconv"
	"strings"
)

func getPermutation(n, k int) string {
	if n < 1 {
		return ""
	}
	nums := make([]int, n)
	for i := range nums {
		nums[i] = i + 1
	}
	res := make([]string, 0, k)
	genRes(&res, nums)
	for j := 1; j < k; j++ {
		nextPermutation(nums)
		genRes(&res, nums)
	}

	// var sb strings.Builder
	// for i := 0; i < n; i++ {
	// 	sb.WriteString(strconv.Itoa(i))
	// }
	// src := sb.String()
	// res := make([]string, 0, k)
	// res = append(res, src)
	// permute(&res, "", 0, src)
	return res[k-1]
}

// based on the top voted discussion
// time complexity O(N) Space complexity O(N)
func getKthPermutation(n, k int) string {
	if n < 1 {
		return ""
	}
	factorial := make([]int, n+1)
	factorial[0] = 1
	factor := 1
	for i := 1; i < n+1; i++ {
		factor *= i
		factorial[i] = factor
	}
	nums := make([]int, n)
	for i := 0; i < n; i++ {
		nums[i] = i + 1
	}
	k--
	var st strings.Builder
	for i := 1; i <= n; i++ {
		idx := k / factorial[n-i]
		st.WriteString(strconv.Itoa(nums[idx]))
		nums = append(nums[:idx], nums[idx+1:]...)
		k -= idx * factorial[n-i]
	}
	return st.String()
}

// just call nextPermutation k times
// src are monotonically increasing "123456...n"

func nextPermutation(nums []int) {
	i, j := len(nums)-2, len(nums)-1

	for i >= 0 && nums[i+1] < nums[i] {
		i--
	}
	if i >= 0 {
		for j >= 0 && nums[j] < nums[i] {
			j--
		}
	}
	// swap nums[i], nums[j]
	nums[i], nums[j] = nums[j], nums[i]
	reverse(nums, i+1, len(nums)-1)
}

func reverse(nums []int, left, right int) {
	for left < right {
		nums[left], nums[right] = nums[right], nums[left]
		left++
		right--
	}
}

// func nextPermutation(src string) string{
// 	n := len(src)
// 	i := n - 1
// 	for i >=0 && src[i-1] > src[i] {
// 		i--
// 	}
// 	if i > = 0 {
// 		j :=
// 	}
// }

func genRes(res *[]string, nums []int) {
	var st strings.Builder
	for i := range nums {
		st.WriteString(strconv.Itoa(nums[i]))
	}
	*res = append(*res, st.String())
}

// func permute(res *[]string, prefix string, pos int, s string) {
// 	if pos == len(s) {
// 		*res = append(*res, prefix)
// 		return
// 	}
// 	for i := pos; i < len(s); i++ {

// 	}
// }
<commit_msg>add comment<commit_after>package ps

import (
	"strconv"
	"strings"
)

func getPermutation(n, k int) string {
	if n < 1 {
		return ""
	}
	nums := make([]int, n)
	for i := range nums {
		nums[i] = i + 1
	}
	res := make([]string, 0, k)
	genRes(&res, nums)
	for j := 1; j < k; j++ {
		nextPermutation(nums)
		genRes(&res, nums)
	}

	// var sb strings.Builder
	// for i := 0; i < n; i++ {
	// 	sb.WriteString(strconv.Itoa(i))
	// }
	// src := sb.String()
	// res := make([]string, 0, k)
	// res = append(res, src)
	// permute(&res, "", 0, src)
	return res[k-1]
}

// based on the top voted discussion
// time complexity O(N) Space complexity O(N)
// the permutations are in order
// for example n=4 [1,2,3,4] k=14
// the permutation sequences are
// 1 + permutation_sequences(2,3,4)  total # is 6 = (n-1)!
// 2 + permutation_sequences(1,3,4)  total # is 6 = (n-1)!
// 3 + permutation_sequences(1,2,4)  total # is 6 = (n-1)!
// 4 + permutation_sequences(1,2,3)  total # is 6 = (n-1)!
// we should know that the 14th sequence should be in the 3rd set
// to get that  use this formular idx = k/(n-1)! = 13/6 = 2, so the first number is 3
// pick 3 out of [1,2,3,4] so the array becomes [1,2,4]
// then we update k, k = k - idx*(n-1)! # of skipped sequences
// then we continue to find the next bit.

func getKthPermutation(n, k int) string {
	if n < 1 {
		return ""
	}
	factorial := make([]int, n+1)
	factorial[0] = 1
	factor := 1
	for i := 1; i < n+1; i++ {
		factor *= i
		factorial[i] = factor
	}
	nums := make([]int, n)
	for i := 0; i < n; i++ {
		nums[i] = i + 1
	}
	k--
	var st strings.Builder
	for i := 1; i <= n; i++ {
		idx := k / factorial[n-i]
		st.WriteString(strconv.Itoa(nums[idx]))
		nums = append(nums[:idx], nums[idx+1:]...)
		k -= idx * factorial[n-i]
	}
	return st.String()
}

// just call nextPermutation k times
// src are monotonically increasing "123456...n"

func nextPermutation(nums []int) {
	i, j := len(nums)-2, len(nums)-1

	for i >= 0 && nums[i+1] < nums[i] {
		i--
	}
	if i >= 0 {
		for j >= 0 && nums[j] < nums[i] {
			j--
		}
	}
	// swap nums[i], nums[j]
	nums[i], nums[j] = nums[j], nums[i]
	reverse(nums, i+1, len(nums)-1)
}

func reverse(nums []int, left, right int) {
	for left < right {
		nums[left], nums[right] = nums[right], nums[left]
		left++
		right--
	}
}

// func nextPermutation(src string) string{
// 	n := len(src)
// 	i := n - 1
// 	for i >=0 && src[i-1] > src[i] {
// 		i--
// 	}
// 	if i > = 0 {
// 		j :=
// 	}
// }

func genRes(res *[]string, nums []int) {
	var st strings.Builder
	for i := range nums {
		st.WriteString(strconv.Itoa(nums[i]))
	}
	*res = append(*res, st.String())
}

// func permute(res *[]string, prefix string, pos int, s string) {
// 	if pos == len(s) {
// 		*res = append(*res, prefix)
// 		return
// 	}
// 	for i := pos; i < len(s); i++ {

// 	}
// }
<|endoftext|>


<commit_before>package digitalocean

import (
	"fmt"
	"log"
	"time"

	"github.com/digitalocean/godo"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceDigitalOceanFloatingIp() *schema.Resource {
	return &schema.Resource{
		Create: resourceDigitalOceanFloatingIpCreate,
		Read:   resourceDigitalOceanFloatingIpRead,
		Delete: resourceDigitalOceanFloatingIpDelete,

		Schema: map[string]*schema.Schema{
			"ip_address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"droplet_id": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: true,
			},
		},
	}
}

func resourceDigitalOceanFloatingIpCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	log.Printf("[INFO] Create a FloatingIP In a Region")
	regionOpts := &godo.FloatingIPCreateRequest{
		Region: d.Get("region").(string),
	}

	log.Printf("[DEBUG] FloatingIP Create: %#v", regionOpts)
	floatingIp, _, err := client.FloatingIPs.Create(regionOpts)
	if err != nil {
		return fmt.Errorf("Error creating FloatingIP: %s", err)
	}

	d.SetId(floatingIp.IP)

	if v, ok := d.GetOk("droplet_id"); ok {

		log.Printf("[INFO] Assigning the Floating IP to the Droplet %d", v.(int))
		action, _, err := client.FloatingIPActions.Assign(d.Id(), v.(int))
		if err != nil {
			return fmt.Errorf(
				"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
		}

		_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
		if unassignedErr != nil {
			return fmt.Errorf(
				"Error waiting for FloatingIP (%s) to be Assigned: %s", d.Id(), unassignedErr)
		}
	}

	return resourceDigitalOceanFloatingIpRead(d, meta)
}

func resourceDigitalOceanFloatingIpRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	log.Printf("[INFO] Reading the details of the FloatingIP %s", d.Id())
	floatingIp, _, err := client.FloatingIPs.Get(d.Id())
	if err != nil {
		return fmt.Errorf("Error retrieving FloatingIP: %s", err)
	}

	if floatingIp.Droplet != nil {
		log.Printf("[INFO] A droplet was detected on the FloatingIP so setting the Region based on the Droplet")
		log.Printf("[INFO] The region of the Droplet is %s", floatingIp.Droplet.Region.Slug)
		d.Set("region", floatingIp.Droplet.Region.Slug)
	} else {
		d.Set("region", floatingIp.Region.Slug)
	}

	d.Set("ip_address", floatingIp.IP)

	return nil
}

func resourceDigitalOceanFloatingIpDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	if _, ok := d.GetOk("droplet_id"); ok {
		log.Printf("[INFO] Unassigning the Floating IP from the Droplet")
		action, _, err := client.FloatingIPActions.Unassign(d.Id())
		if err != nil {
			return fmt.Errorf(
				"Error Unassigning FloatingIP (%s) from the droplet: %s", d.Id(), err)
		}

		_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
		if unassignedErr != nil {
			return fmt.Errorf(
				"Error waiting for FloatingIP (%s) to be unassigned: %s", d.Id(), unassignedErr)
		}
	}

	log.Printf("[INFO] Deleting FloatingIP: %s", d.Id())
	_, err := client.FloatingIPs.Delete(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting FloatingIP: %s", err)
	}

	d.SetId("")
	return nil
}

func waitForFloatingIPReady(
	d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}, actionId int) (interface{}, error) {
	log.Printf(
		"[INFO] Waiting for FloatingIP (%s) to have %s of %s",
		d.Id(), attribute, target)

	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     target,
		Refresh:    newFloatingIPStateRefreshFunc(d, attribute, meta, actionId),
		Timeout:    60 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,

		NotFoundChecks: 60,
	}

	return stateConf.WaitForState()
}

func newFloatingIPStateRefreshFunc(
	d *schema.ResourceData, attribute string, meta interface{}, actionId int) resource.StateRefreshFunc {
	client := meta.(*godo.Client)
	return func() (interface{}, string, error) {

		log.Printf("[INFO] Assigning the Floating IP to the Droplet")
		action, _, err := client.FloatingIPActions.Get(d.Id(), actionId)
		if err != nil {
			return nil, "", fmt.Errorf("Error retrieving FloatingIP (%s) ActionId (%d): %s", d.Id(), actionId, err)
		}

		log.Printf("[INFO] The FloatingIP Action Status is %s", action.Status)
		return &action, action.Status, nil
	}
}
<commit_msg>provider/digitalocean: allow reassignment of floating IPs<commit_after>package digitalocean

import (
	"fmt"
	"log"
	"time"

	"github.com/digitalocean/godo"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceDigitalOceanFloatingIp() *schema.Resource {
	return &schema.Resource{
		Create: resourceDigitalOceanFloatingIpCreate,
		Update: resourceDigitalOceanFloatingIpUpdate,
		Read:   resourceDigitalOceanFloatingIpRead,
		Delete: resourceDigitalOceanFloatingIpDelete,

		Schema: map[string]*schema.Schema{
			"ip_address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"droplet_id": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
			},
		},
	}
}

func resourceDigitalOceanFloatingIpCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	log.Printf("[INFO] Create a FloatingIP In a Region")
	regionOpts := &godo.FloatingIPCreateRequest{
		Region: d.Get("region").(string),
	}

	log.Printf("[DEBUG] FloatingIP Create: %#v", regionOpts)
	floatingIp, _, err := client.FloatingIPs.Create(regionOpts)
	if err != nil {
		return fmt.Errorf("Error creating FloatingIP: %s", err)
	}

	d.SetId(floatingIp.IP)

	if v, ok := d.GetOk("droplet_id"); ok {

		log.Printf("[INFO] Assigning the Floating IP to the Droplet %d", v.(int))
		action, _, err := client.FloatingIPActions.Assign(d.Id(), v.(int))
		if err != nil {
			return fmt.Errorf(
				"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
		}

		_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
		if unassignedErr != nil {
			return fmt.Errorf(
				"Error waiting for FloatingIP (%s) to be Assigned: %s", d.Id(), unassignedErr)
		}
	}

	return resourceDigitalOceanFloatingIpRead(d, meta)
}

func resourceDigitalOceanFloatingIpUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	if d.HasChange("droplet_id") {
		if v, ok := d.GetOk("droplet_id"); ok {
			log.Printf("[INFO] Assigning the Floating IP %s to the Droplet %d", d.Id(), v.(int))
			action, _, err := client.FloatingIPActions.Assign(d.Id(), v.(int))
			if err != nil {
				return fmt.Errorf(
					"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
			}

			_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
			if unassignedErr != nil {
				return fmt.Errorf(
					"Error waiting for FloatingIP (%s) to be Assigned: %s", d.Id(), unassignedErr)
			}
		} else {
			log.Printf("[INFO] Unassigning the Floating IP %s", d.Id())
			action, _, err := client.FloatingIPActions.Unassign(d.Id())
			if err != nil {
				return fmt.Errorf(
					"Error Unassigning FloatingIP (%s): %s", d.Id(), err)
			}

			_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
			if unassignedErr != nil {
				return fmt.Errorf(
					"Error waiting for FloatingIP (%s) to be Unassigned: %s", d.Id(), unassignedErr)
			}
		}
	}

	return resourceDigitalOceanFloatingIpRead(d, meta)
}

func resourceDigitalOceanFloatingIpRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	log.Printf("[INFO] Reading the details of the FloatingIP %s", d.Id())
	floatingIp, _, err := client.FloatingIPs.Get(d.Id())
	if err != nil {
		return fmt.Errorf("Error retrieving FloatingIP: %s", err)
	}

	if floatingIp.Droplet != nil {
		log.Printf("[INFO] A droplet was detected on the FloatingIP so setting the Region based on the Droplet")
		log.Printf("[INFO] The region of the Droplet is %s", floatingIp.Droplet.Region.Slug)
		d.Set("region", floatingIp.Droplet.Region.Slug)
	} else {
		d.Set("region", floatingIp.Region.Slug)
	}

	d.Set("ip_address", floatingIp.IP)

	return nil
}

func resourceDigitalOceanFloatingIpDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	if _, ok := d.GetOk("droplet_id"); ok {
		log.Printf("[INFO] Unassigning the Floating IP from the Droplet")
		action, _, err := client.FloatingIPActions.Unassign(d.Id())
		if err != nil {
			return fmt.Errorf(
				"Error Unassigning FloatingIP (%s) from the droplet: %s", d.Id(), err)
		}

		_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
		if unassignedErr != nil {
			return fmt.Errorf(
				"Error waiting for FloatingIP (%s) to be unassigned: %s", d.Id(), unassignedErr)
		}
	}

	log.Printf("[INFO] Deleting FloatingIP: %s", d.Id())
	_, err := client.FloatingIPs.Delete(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting FloatingIP: %s", err)
	}

	d.SetId("")
	return nil
}

func waitForFloatingIPReady(
	d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}, actionId int) (interface{}, error) {
	log.Printf(
		"[INFO] Waiting for FloatingIP (%s) to have %s of %s",
		d.Id(), attribute, target)

	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     target,
		Refresh:    newFloatingIPStateRefreshFunc(d, attribute, meta, actionId),
		Timeout:    60 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,

		NotFoundChecks: 60,
	}

	return stateConf.WaitForState()
}

func newFloatingIPStateRefreshFunc(
	d *schema.ResourceData, attribute string, meta interface{}, actionId int) resource.StateRefreshFunc {
	client := meta.(*godo.Client)
	return func() (interface{}, string, error) {

		log.Printf("[INFO] Assigning the Floating IP to the Droplet")
		action, _, err := client.FloatingIPActions.Get(d.Id(), actionId)
		if err != nil {
			return nil, "", fmt.Errorf("Error retrieving FloatingIP (%s) ActionId (%d): %s", d.Id(), actionId, err)
		}

		log.Printf("[INFO] The FloatingIP Action Status is %s", action.Status)
		return &action, action.Status, nil
	}
}
<|endoftext|>