<commit_before>// Streaming relation (overlap, distance, KNN) testing of (any number of) sorted files of intervals.
package irelate

import (
	"container/heap"
	"log"
	"os"
	"strings"

	"vbom.ml/util/sortorder"
)

// Relatable provides all the methods for irelate to function.
// See Interval in interval.go for a class that satisfies this interface.
// Related() likely returns and AddRelated() likely appends to a slice of
// relatables. Note that for performance reasons, Relatable should be implemented
// as a pointer to your data-structure (see Interval).
type Relatable interface {
	Chrom() string
	Start() uint32
	End() uint32
	Related() []Relatable // A slice of related Relatable's filled by IRelate
	AddRelated(Relatable) // Adds to the slice of relatables
	Source() uint32       // Internally marks the source (file/stream) of the Relatable
	SetSource(source uint32)
}

// RelatableChannel
type RelatableChannel chan Relatable

func relate(a Relatable, b Relatable, relativeTo int) {
	if a.Source() != b.Source() {
		if relativeTo == -1 {
			a.AddRelated(b)
			b.AddRelated(a)
		} else {
			if uint32(relativeTo) == a.Source() {
				a.AddRelated(b)
			}
			if uint32(relativeTo) == b.Source() {
				b.AddRelated(a)
			}
		}
	}
}

func Less(a Relatable, b Relatable) bool {
	if a.Chrom() != b.Chrom() {
		return a.Chrom() < b.Chrom()
	}
	return a.Start() < b.Start() // || (a.Start() == b.Start() && a.End() < b.End())
}

func SameChrom(a, b string) bool {
	if a == b {
		return true
	}
	return stripChr(a) == stripChr(b)
}

func stripChr(c string) string {
	if strings.HasPrefix(c, "chr") {
		return c[3:]
	}
	return c
}

// 1, 2, 3 ... 9, 10, 11...
func NaturalLessPrefix(a Relatable, b Relatable) bool {
	if !SameChrom(a.Chrom(), b.Chrom()) {
		return sortorder.NaturalLess(stripChr(a.Chrom()), stripChr(b.Chrom()))
	}
	return a.Start() < b.Start() || (a.Start() == b.Start() && a.End() < b.End())

}

// 1, 10, 11... 19, 2, 20, 21 ...
func LessPrefix(a Relatable, b Relatable) bool {
	if !SameChrom(a.Chrom(), b.Chrom()) {
		return stripChr(a.Chrom()) < stripChr(b.Chrom())
	}
	return a.Start() < b.Start() || (a.Start() == b.Start() && a.End() < b.End())
}

// CheckRelatedByOverlap returns true if Relatables overlap.
func CheckRelatedByOverlap(a Relatable, b Relatable) bool {
	return (b.Start() < a.End()) && (b.Chrom() == a.Chrom())
	// note with distance == 0 this just overlap.
	//distance := uint32(0)
	//return (b.Start()-distance < a.End()) && (b.Chrom() == a.Chrom())
}

// handles chromomomes like 'chr1' from one org and '1' from another.
func CheckOverlapPrefix(a Relatable, b Relatable) bool {
	if b.Start() < a.End() {
		return SameChrom(a.Chrom(), b.Chrom())
	}
	return false
}

// CheckKNN relates an interval to its k-nearest neighbors.
// The reporting function will have to do some filtering since this is only
// guaranteed to associate *at least* k neighbors, but it could be returning extra.
func CheckKNN(a Relatable, b Relatable) bool {
	// the first n checked would be the n_closest, but need to consider ties
	// the report function can decide what to do with them.
	k := 4
	r := a.Related()
	if len(r) >= k {
		// TODO: double-check this.
		return r[len(r)-1].Start()-a.End() < b.Start()-a.End()
	}
	return true
}

// filter rewrites the input-slice to remove nils.
func filter(s []Relatable, nils int) []Relatable {
	if len(s) == nils {
		return s[:0]
	}

	j := 0
	for _, v := range s {
		if v != nil {
			s[j] = v
			j++
		}
	}
	return s[:j]
}

// Send the relatables to the channel in sorted order.
// Check that we couldn't later get an item with a lower start from the current cache.
func sendSortedRelatables(sendQ *relatableQueue, cache []Relatable, out chan Relatable, less func(a, b Relatable) bool) {
	var j int
	for j = 0; j < len((*sendQ).rels) && (len(cache) == 0 || less((*sendQ).rels[j].(Relatable), cache[0])); j++ {
	}
	for i := 0; i < j; i++ {
		out <- heap.Pop(sendQ).(Relatable)
	}
}

// IRelate provides the basis for flexible overlap/proximity/k-nearest neighbor
// testing. IRelate receives merged, ordered Relatables via stream and takes
// function that checks if they are related (see CheckRelatedByOverlap).
// It is guaranteed that !Less(b, a) is true (we can't guarantee that Less(a, b)
// is true since they may have the same start). Once checkRelated returns false,
// it is assumed that no other `b` Relatables could possibly be related to `a`
// and so `a` is sent to the returnQ.
// streams are a variable number of channels that send intervals.
func IRelate(checkRelated func(a, b Relatable) bool,
	relativeTo int,
	less func(a, b Relatable) bool,
	streams ...RelatableChannel) chan Relatable {

	// we infer the chromosome order by the order that we see from source 0.
	stream := Merge(less, relativeTo, streams...)
	out := make(chan Relatable, 64)
	go func() {

		// use the cache to keep relatables to test against.
		cache := make([]Relatable, 1, 1024)
		cache[0] = <-stream

		// Use sendQ to make sure we output in sorted order.
		// We know we can print something when sendQ.minStart < cache.minStart
		sendQ := relatableQueue{make([]Relatable, 0, 1024), less}
		nils := 0

		// TODO:if we know the ends are sorted (in addition to start) then we have some additional
		// optimizations. As soon as checkRelated is false, then all others in the cache before that
		// should be true... binary search if endSorted and len(cache) > 20?
		//endSorted := true
		for interval := range stream {

			for i, c := range cache {
				// tried using futures for checkRelated to parallelize... got slower
				if c == nil {
					continue
				}
				if checkRelated(c, interval) {
					relate(c, interval, relativeTo)
				} else {
					if relativeTo == -1 || c.Source() == uint32(relativeTo) {
						heap.Push(&sendQ, c)
					}
					cache[i] = nil
					nils++
				}
			}

			// only do this when we have a lot of nils as it's expensive to create a new slice.
			if nils > 1 {
				// remove nils from the cache (must do this before sending)
				cache, nils = filter(cache, nils), 0
				// send the elements from cache in order.
				// use heuristic to minimize the sending.
				if len(sendQ.rels) > 12 {
					sendSortedRelatables(&sendQ, cache, out, less)
				}
			}
			cache = append(cache, interval)

		}
		for _, c := range filter(cache, nils) {
			if c.Source() == uint32(relativeTo) || relativeTo == -1 {
				heap.Push(&sendQ, c)
			}
		}
		for i := 0; i < len(sendQ.rels); i++ {
			out <- sendQ.rels[i]
		}
		close(out)
	}()
	return out
}

// Merge accepts channels of Relatables and merges them in order.
// Streams of Relatable's from different source must be merged to send
// to IRelate.
// This uses a priority queue and acts like python's heapq.merge.
func Merge(less func(a, b Relatable) bool, relativeTo int, streams ...RelatableChannel) RelatableChannel {
	verbose := os.Getenv("IRELATE_VERBOSE") == "TRUE"
	q := relatableQueue{make([]Relatable, 0, len(streams)), less}
	seen := make(map[string]struct{})
	for i, stream := range streams {
		interval := <-stream
		if interval != nil {
			interval.SetSource(uint32(i))
			heap.Push(&q, interval)
		}
	}

	ch := make(chan Relatable, 8)
	go func() {
		var interval Relatable
		sentinel := struct{}{}
		lastChrom := ""
		// heuristic to use this to stop when end of query records is reached.
		j := -1000
		for len(q.rels) > 0 {
			interval = heap.Pop(&q).(Relatable)
			source := interval.Source()
			ch <- interval
			if interval.Chrom() != lastChrom {
				lastChrom = interval.Chrom()
				if _, ok := seen[lastChrom]; ok {
					log.Println("warning: chromosomes must be in different order between files or the chromosome sort order is not as expected.")
					log.Printf("warning: overlaps will likely be missed after this chrom: %s from source: %d\n", lastChrom, interval.Source())
				}
				seen[lastChrom] = sentinel
				if verbose {
					log.Printf("on chromosome: %s\n", lastChrom)
				}
			}
			// pull the next interval from the same source.
			next_interval, ok := <-streams[source]
			if ok {
				next_interval.SetSource(source)
				heap.Push(&q, next_interval)
				j--
				if j == 0 {
					break
				}
			} else {
				if int(source) == relativeTo {
					// we pull in 200K more records and then stop. to make sure we get anything that might
					// relate to last query
					j = 200000
				}
			}
		}
		close(ch)
	}()
	return ch
}
<commit_msg>check by prefix<commit_after>// Streaming relation (overlap, distance, KNN) testing of (any number of) sorted files of intervals.
package irelate

import (
	"container/heap"
	"log"
	"os"
	"strings"

	"vbom.ml/util/sortorder"
)

// Relatable provides all the methods for irelate to function.
// See Interval in interval.go for a class that satisfies this interface.
// Related() likely returns and AddRelated() likely appends to a slice of
// relatables. Note that for performance reasons, Relatable should be implemented
// as a pointer to your data-structure (see Interval).
type Relatable interface {
	Chrom() string
	Start() uint32
	End() uint32
	Related() []Relatable // A slice of related Relatable's filled by IRelate
	AddRelated(Relatable) // Adds to the slice of relatables
	Source() uint32       // Internally marks the source (file/stream) of the Relatable
	SetSource(source uint32)
}

// RelatableChannel
type RelatableChannel chan Relatable

func relate(a Relatable, b Relatable, relativeTo int) {
	if a.Source() != b.Source() {
		if relativeTo == -1 {
			a.AddRelated(b)
			b.AddRelated(a)
		} else {
			if uint32(relativeTo) == a.Source() {
				a.AddRelated(b)
			}
			if uint32(relativeTo) == b.Source() {
				b.AddRelated(a)
			}
		}
	}
}

func Less(a Relatable, b Relatable) bool {
	if a.Chrom() != b.Chrom() {
		return a.Chrom() < b.Chrom()
	}
	return a.Start() < b.Start() // || (a.Start() == b.Start() && a.End() < b.End())
}

func SameChrom(a, b string) bool {
	if a == b {
		return true
	}
	return stripChr(a) == stripChr(b)
}

func stripChr(c string) string {
	if strings.HasPrefix(c, "chr") {
		return c[3:]
	}
	return c
}

// 1, 2, 3 ... 9, 10, 11...
func NaturalLessPrefix(a Relatable, b Relatable) bool {
	if !SameChrom(a.Chrom(), b.Chrom()) {
		return sortorder.NaturalLess(stripChr(a.Chrom()), stripChr(b.Chrom()))
	}
	return a.Start() < b.Start() || (a.Start() == b.Start() && a.End() < b.End())

}

// 1, 10, 11... 19, 2, 20, 21 ...
func LessPrefix(a Relatable, b Relatable) bool {
	if !SameChrom(a.Chrom(), b.Chrom()) {
		return stripChr(a.Chrom()) < stripChr(b.Chrom())
	}
	return a.Start() < b.Start() || (a.Start() == b.Start() && a.End() < b.End())
}

// CheckRelatedByOverlap returns true if Relatables overlap.
func CheckRelatedByOverlap(a Relatable, b Relatable) bool {
	return (b.Start() < a.End()) && (b.Chrom() == a.Chrom())
	// note with distance == 0 this just overlap.
	//distance := uint32(0)
	//return (b.Start()-distance < a.End()) && (b.Chrom() == a.Chrom())
}

// handles chromomomes like 'chr1' from one org and '1' from another.
func CheckOverlapPrefix(a Relatable, b Relatable) bool {
	if b.Start() < a.End() {
		return SameChrom(a.Chrom(), b.Chrom())
	}
	return false
}

// CheckKNN relates an interval to its k-nearest neighbors.
// The reporting function will have to do some filtering since this is only
// guaranteed to associate *at least* k neighbors, but it could be returning extra.
func CheckKNN(a Relatable, b Relatable) bool {
	// the first n checked would be the n_closest, but need to consider ties
	// the report function can decide what to do with them.
	k := 4
	r := a.Related()
	if len(r) >= k {
		// TODO: double-check this.
		return r[len(r)-1].Start()-a.End() < b.Start()-a.End()
	}
	return true
}

// filter rewrites the input-slice to remove nils.
func filter(s []Relatable, nils int) []Relatable {
	if len(s) == nils {
		return s[:0]
	}

	j := 0
	for _, v := range s {
		if v != nil {
			s[j] = v
			j++
		}
	}
	return s[:j]
}

// Send the relatables to the channel in sorted order.
// Check that we couldn't later get an item with a lower start from the current cache.
func sendSortedRelatables(sendQ *relatableQueue, cache []Relatable, out chan Relatable, less func(a, b Relatable) bool) {
	var j int
	for j = 0; j < len((*sendQ).rels) && (len(cache) == 0 || less((*sendQ).rels[j].(Relatable), cache[0])); j++ {
	}
	for i := 0; i < j; i++ {
		out <- heap.Pop(sendQ).(Relatable)
	}
}

// IRelate provides the basis for flexible overlap/proximity/k-nearest neighbor
// testing. IRelate receives merged, ordered Relatables via stream and takes
// function that checks if they are related (see CheckRelatedByOverlap).
// It is guaranteed that !Less(b, a) is true (we can't guarantee that Less(a, b)
// is true since they may have the same start). Once checkRelated returns false,
// it is assumed that no other `b` Relatables could possibly be related to `a`
// and so `a` is sent to the returnQ.
// streams are a variable number of channels that send intervals.
func IRelate(checkRelated func(a, b Relatable) bool,
	relativeTo int,
	less func(a, b Relatable) bool,
	streams ...RelatableChannel) chan Relatable {

	// we infer the chromosome order by the order that we see from source 0.
	stream := Merge(less, relativeTo, streams...)
	out := make(chan Relatable, 64)
	go func() {

		// use the cache to keep relatables to test against.
		cache := make([]Relatable, 1, 1024)
		cache[0] = <-stream

		// Use sendQ to make sure we output in sorted order.
		// We know we can print something when sendQ.minStart < cache.minStart
		sendQ := relatableQueue{make([]Relatable, 0, 1024), less}
		nils := 0

		// TODO:if we know the ends are sorted (in addition to start) then we have some additional
		// optimizations. As soon as checkRelated is false, then all others in the cache before that
		// should be true... binary search if endSorted and len(cache) > 20?
		//endSorted := true
		for interval := range stream {

			for i, c := range cache {
				// tried using futures for checkRelated to parallelize... got slower
				if c == nil {
					continue
				}
				if checkRelated(c, interval) {
					relate(c, interval, relativeTo)
				} else {
					if relativeTo == -1 || c.Source() == uint32(relativeTo) {
						heap.Push(&sendQ, c)
					}
					cache[i] = nil
					nils++
				}
			}

			// only do this when we have a lot of nils as it's expensive to create a new slice.
			if nils > 1 {
				// remove nils from the cache (must do this before sending)
				cache, nils = filter(cache, nils), 0
				// send the elements from cache in order.
				// use heuristic to minimize the sending.
				if len(sendQ.rels) > 12 {
					sendSortedRelatables(&sendQ, cache, out, less)
				}
			}
			cache = append(cache, interval)

		}
		for _, c := range filter(cache, nils) {
			if c.Source() == uint32(relativeTo) || relativeTo == -1 {
				heap.Push(&sendQ, c)
			}
		}
		for i := 0; i < len(sendQ.rels); i++ {
			out <- sendQ.rels[i]
		}
		close(out)
	}()
	return out
}

// Merge accepts channels of Relatables and merges them in order.
// Streams of Relatable's from different source must be merged to send
// to IRelate.
// This uses a priority queue and acts like python's heapq.merge.
func Merge(less func(a, b Relatable) bool, relativeTo int, streams ...RelatableChannel) RelatableChannel {
	verbose := os.Getenv("IRELATE_VERBOSE") == "TRUE"
	q := relatableQueue{make([]Relatable, 0, len(streams)), less}
	seen := make(map[string]struct{})
	for i, stream := range streams {
		interval := <-stream
		if interval != nil {
			interval.SetSource(uint32(i))
			heap.Push(&q, interval)
		}
	}

	ch := make(chan Relatable, 8)
	go func() {
		var interval Relatable
		sentinel := struct{}{}
		lastChrom := ""
		// heuristic to use this to stop when end of query records is reached.
		j := -1000
		for len(q.rels) > 0 {
			interval = heap.Pop(&q).(Relatable)
			source := interval.Source()
			ch <- interval
			if SameChrom(interval.Chrom(), lastChrom) {
				lastChrom = stripChr(interval.Chrom())
				if _, ok := seen[lastChrom]; ok {
					log.Println("warning: chromosomes must be in different order between files or the chromosome sort order is not as expected.")
					log.Printf("warning: overlaps will likely be missed after this chrom: %s from source: %d\n", lastChrom, interval.Source())
				}
				seen[lastChrom] = sentinel
				if verbose {
					log.Printf("on chromosome: %s\n", lastChrom)
				}
			}
			// pull the next interval from the same source.
			next_interval, ok := <-streams[source]
			if ok {
				next_interval.SetSource(source)
				heap.Push(&q, next_interval)
				j--
				if j == 0 {
					break
				}
			} else {
				if int(source) == relativeTo {
					// we pull in 200K more records and then stop. to make sure we get anything that might
					// relate to last query
					j = 200000
				}
			}
		}
		close(ch)
	}()
	return ch
}
<|endoftext|>


<commit_before>package shutdown

import (
	"context"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

var (
	// Timeout ...
	Timeout time.Duration

	// Logger ...
	Logger LogPrinter

	names = map[os.Signal]string{
		syscall.SIGINT:  "SIGINT",
		syscall.SIGTERM: "SIGTERM",
	}

	shutdowners = []Shutdowner{}
	sw          signalWaiter
)

// Shutdowner represents convenient alias for user-defined callback
type Shutdowner func(ctx context.Context)

// Add func registers user-defined Shutdowner to be handled gracefully
func Add(s Shutdowner) {
	shutdowners = append(shutdowners, s)
}

// Wait for shutdown signal and handle it!
func Wait() {
	if Logger == nil {
		Logger = log.New(ioutil.Discard, "", 0)
	}

	if Timeout == 0 {
		Timeout = 5 * time.Second
	}

	if sw == nil {
		sw = osSignalWaiter{}
	}

	sig := sw.wait()
	Logger.Printf("Signal '%s' recieved.", names[sig])

	ctx, cancel := context.WithTimeout(context.Background(), Timeout)
	defer cancel()

	var wg sync.WaitGroup
	wg.Add(len(shutdowners))

	for _, cb := range shutdowners {
		go func(s Shutdowner) {
			defer wg.Done()
			s(ctx)
		}(cb)
	}

	completed := make(chan struct{})
	go func() {
		defer close(completed)
		wg.Wait()
	}()

	select {
	case <-completed:
		Logger.Printf("All shutdowners are finished")
	case <-ctx.Done():
		Logger.Printf("Shutdowners was timed out: %v", ctx.Err())
	}
}

// LogPrinter ...
type LogPrinter interface {
	Printf(format string, v ...interface{})
}

func waitSignal() os.Signal {
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	return <-ch
}

type signalWaiter interface {
	wait() os.Signal
}

type osSignalWaiter struct{}

func (w osSignalWaiter) wait() os.Signal {
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	return <-ch
}
<commit_msg>Removed redundant code<commit_after>package shutdown

import (
	"context"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

var (
	// Timeout ...
	Timeout time.Duration

	// Logger ...
	Logger LogPrinter

	names = map[os.Signal]string{
		syscall.SIGINT:  "SIGINT",
		syscall.SIGTERM: "SIGTERM",
	}

	shutdowners = []Shutdowner{}
	sw          signalWaiter
)

// Shutdowner represents convenient alias for user-defined callback
type Shutdowner func(ctx context.Context)

// Add func registers user-defined Shutdowner to be handled gracefully
func Add(s Shutdowner) {
	shutdowners = append(shutdowners, s)
}

// Wait for shutdown signal and handle it!
func Wait() {
	if Logger == nil {
		Logger = log.New(ioutil.Discard, "", 0)
	}

	if Timeout == 0 {
		Timeout = 5 * time.Second
	}

	if sw == nil {
		sw = osSignalWaiter{}
	}

	sig := sw.wait()
	Logger.Printf("Signal '%s' recieved.", names[sig])

	ctx, cancel := context.WithTimeout(context.Background(), Timeout)
	defer cancel()

	var wg sync.WaitGroup
	wg.Add(len(shutdowners))

	for _, cb := range shutdowners {
		go func(s Shutdowner) {
			defer wg.Done()
			s(ctx)
		}(cb)
	}

	completed := make(chan struct{})
	go func() {
		defer close(completed)
		wg.Wait()
	}()

	select {
	case <-completed:
		Logger.Printf("All shutdowners are finished")
	case <-ctx.Done():
		Logger.Printf("Shutdowners was timed out: %v", ctx.Err())
	}
}

// LogPrinter ...
type LogPrinter interface {
	Printf(format string, v ...interface{})
}

type signalWaiter interface {
	wait() os.Signal
}

type osSignalWaiter struct{}

func (w osSignalWaiter) wait() os.Signal {
	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	return <-ch
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"runtime"
	"time"

	"github.com/jinzhu/gorm"
)

type Data interface {
	post(url string, includeHidden bool) (*Entry, error)
	postID(url string) (id int64, err error)
	posts(limit, offset int, includeHidden bool) ([]*Entry, error)
	titles(limit int, includeHidden bool) ([]EntryLink, error)
	titlesByTag(tag string, includeHidden bool) ([]EntryLink, error)
	allComments() ([]*CommentWithPostTitle, error)
	numPosts(includeHidden bool) (int, error)
	author(username string) (*Author, error)
	deleteComment(id string) error
	deletePost(url string) error
	updateComment(id, text string) error
	commenterID(c *Commenter) (id int64, err error)
	insertCommenter(c *Commenter) (id int64, err error)
	insertComment(commenterID, postID int64, body string) (id int64, err error)
	insertPost(e *EntryTable) (id int64, err error)
	updatePost(e *EntryTable) error
	updateTags(tags []*Tag, postID int64) error
	queryAllTags() ([]*Tag, error)
	begin() error
	commit()
	rollback()
}

type DbData struct {
	db *gorm.DB
	tx *gorm.DB
}

func InitDB(conn string) *DbData {
	db, err := gorm.Open("postgres", conn)
	err = db.DB().Ping()
	if err != nil {
		panic(err)
	}
	db.SingularTable(true)
	return &DbData{
		db: &db,
		tx: nil,
	}
}

func notInXactionErr() error {
	pc, _, _, ok := runtime.Caller(1)
	if !ok {
		panic("runtime.Caller(1) != ok, dafuq?")
	}
	funcName := runtime.FuncForPC(pc).Name()
	msg := "Error! %s() can only be called within transaction!"
	return fmt.Errorf(msg, funcName)
}

func (dd *DbData) begin() error {
	dd.tx = dd.db.Begin()
	return dd.tx.Error
}

func (dd *DbData) commit() {
	dd.tx.Commit()
	logger.LogIf(dd.db.Error)
	dd.tx = nil
}

func (dd *DbData) rollback() {
	if dd.tx == nil {
		return
	}
	dd.tx.Rollback()
	logger.LogIf(dd.db.Error)
	dd.tx = nil
}

func (dd *DbData) post(url string, includeHidden bool) (*Entry, error) {
	posts, err := queryPosts(dd, -1, -1, url, includeHidden)
	if err != nil {
		return nil, err
	}
	if len(posts) != 1 {
		msg := "DbData.post(%q) should return 1 post, but returned %d"
		return nil, fmt.Errorf(msg, url, len(posts))
	}
	return posts[0], nil
}

func (dd *DbData) postID(url string) (int64, error) {
	var post Entry
	rows := dd.db.Table("post").Where("url = ?", url).Select("id")
	err := rows.First(&post).Error
	return post.Id, err
}

func (dd *DbData) posts(limit, offset int, includeHidden bool) ([]*Entry, error) {
	return queryPosts(dd, limit, offset, "", includeHidden)
}

func (dd *DbData) numPosts(includeHidden bool) (int, error) {
	var count int
	if includeHidden {
		dd.db.Table("post").Count(&count)
	} else {
		dd.db.Table("post").Where("hidden=?", false).Count(&count)
	}
	return count, dd.db.Error
}

func (dd *DbData) titles(limit int, includeHidden bool) ([]EntryLink, error) {
	var results []EntryLink
	posts := dd.db.Table("post").Select("title, url, hidden")
	if !includeHidden {
		posts = posts.Where("hidden=?", false)
	}
	err := posts.Order("date desc").Limit(limit).Scan(&results).Error
	return results, err
}

func (dd *DbData) titlesByTag(tag string, includeHidden bool) ([]EntryLink, error) {
	var postIDs []int64
	var results []EntryLink
	join := "inner join tag on tagmap.tag_id = tag.id"
	rows := dd.db.Table("tagmap").Joins(join).Where("tag.tag=?", tag)
	err := rows.Pluck("post_id", &postIDs).Error
	if err != nil {
		return nil, err
	}
	columns := "title, url, hidden"
	posts := dd.db.Table("post").Select(columns).Where("id in (?)", postIDs)
	if !includeHidden {
		posts = posts.Where("hidden=?", false)
	}
	err = posts.Order("date desc").Scan(&results).Error
	return results, err
}

func (dd *DbData) allComments() ([]*CommentWithPostTitle, error) {
	var results []*CommentWithPostTitle
	sel := `commenter.name, commenter.email, commenter.www, commenter.ip,
		comment.id, comment.timestamp, comment.body,
		post.title, post.url`
	join := `right join comment on commenter.id = comment.commenter_id
		inner join post on comment.post_id = post.id`
	joined := dd.db.Table("commenter").Select(sel).Joins(join)
	err := joined.Order("comment.timestamp desc").Scan(&results).Error
	// TODO: there's an identical loop in queryComments, but it loops over
	// []Comment instead of []CommentWithPostTitle. Would be nice to unify.
	for _, c := range results {
		c.EmailHash = Md5Hash(c.Email)
		c.Time = time.Unix(c.Timestamp, 0).Format("2006-01-02 15:04")
		c.Body = sanitizeHTML(mdToHTML(c.RawBody))
	}
	return results, err
}

func (dd *DbData) commenterID(c *Commenter) (id int64, err error) {
	where := "name = ? and email = ? and www = ?"
	err = dd.db.Select("id").Where(where, c.Name, c.Email, c.Website).Scan(&id).Error
	return
}

func (dd *DbData) insertCommenter(c *Commenter) (id int64, err error) {
	if dd.tx == nil {
		return -1, notInXactionErr()
	}
	entry := CommenterTable{Id: 0, Commenter: *c}
	err = dd.tx.Save(&entry).Error
	return entry.Id, err
}

func (dd *DbData) insertComment(commenterID, postID int64, body string) (id int64, err error) {
	if dd.tx == nil {
		return -1, notInXactionErr()
	}
	c := CommentTable{
		CommenterID: commenterID,
		PostID:      postID,
		RawBody:     body,
		Timestamp:   time.Now().Unix(),
	}
	err = dd.tx.Save(&c).Error
	return c.CommentID, err
}

func (dd *DbData) insertPost(e *EntryTable) (id int64, err error) {
	if dd.tx == nil {
		return -1, notInXactionErr()
	}
	err = dd.tx.Save(e).Error
	return e.Id, err
}

func (dd *DbData) updatePost(e *EntryTable) error {
	if dd.tx == nil {
		return notInXactionErr()
	}
	return dd.tx.Save(e).Error
}

func (dd *DbData) updateTags(tags []*Tag, postID int64) error {
	if dd.tx == nil {
		return notInXactionErr()
	}
	dd.tx.Where("post_id = ?", postID).Delete(TagMap{})
	for _, t := range tags {
		tagID, err := insertOrGetTagID(dd.tx, t)
		if err != nil {
			return err
		}
		err = updateTagMap(dd.tx, postID, tagID)
		if err != nil {
			return err
		}
	}
	return nil
}

func (dd *DbData) author(username string) (*Author, error) {
	var a Author
	err := dd.db.Where("disp_name = ?", username).First(&a).Error
	return &a, err
}

func (dd *DbData) deleteComment(id string) error {
	return dd.db.Where("id=?", id).Delete(CommentTable{}).Error
}

func (dd *DbData) deletePost(url string) error {
	return dd.db.Where("url=?", url).Delete(Entry{}).Error
}

func (dd *DbData) updateComment(id, text string) error {
	return dd.db.Model(CommentTable{}).Where("id=?", id).Update("body", text).Error
}

func queryPosts(dd *DbData, limit, offset int, url string,
	includeHidden bool) ([]*Entry, error) {
	var results []*Entry
	cols := `author.disp_name, post.id, post.title, post.date, post.body,
		post.url, post.hidden`
	join := "inner join author on post.author_id=author.id"
	posts := dd.db.Table("post").Select(cols).Joins(join)
	if !includeHidden {
		posts = posts.Where("hidden=?", false)
	}
	if url != "" {
		posts = posts.Where("url=?", url)
	}
	rows := posts.Order("date desc").Limit(limit).Offset(offset)
	err := rows.Scan(&results).Error
	for _, p := range results {
		p.Body = sanitizeTrustedHTML(mdToHTML(p.RawBody))
		p.Date = time.Unix(p.UnixDate, 0).Format("2006-01-02")
		p.Tags = queryTags(dd.db, p.Id)
		p.Comments = queryComments(dd.db, p.Id)
	}
	return results, err
}

func queryTags(db *gorm.DB, postID int64) []*Tag {
	var results []*Tag
	join := "inner join tagmap on tagmap.tag_id = tag.id"
	tables := db.Table("tag").Select("tag.tag").Joins(join)
	tables.Where("tagmap.post_id = ?", postID).Scan(&results)
	return results // TODO: err
}

func (dd *DbData) queryAllTags() ([]*Tag, error) {
	var tags []*Tag
	err := dd.db.Find(&tags).Error
	return tags, err
}

func queryComments(db *gorm.DB, postID int64) []*Comment {
	var comments []*Comment
	join := "inner join commenter on comment.commenter_id = commenter.id"
	order := "timestamp asc"
	tables := db.Table("comment").Select("*").Joins(join)
	rows := tables.Where("post_id = ?", postID).Order(order)
	err := rows.Scan(&comments).Error
	logger.LogIff(err, "error querying comments")
	for _, c := range comments {
		c.EmailHash = Md5Hash(c.Email)
		c.Time = time.Unix(c.Timestamp, 0).Format("2006-01-02 15:04")
		c.Body = sanitizeHTML(mdToHTML(c.RawBody))
	}
	return comments
}

func insertOrGetTagID(db *gorm.DB, tag *Tag) (tagID int64, err error) {
	var result Tag
	err = db.Where("tag = ?", tag.Name).First(&result).Error
	switch err {
	case nil:
		return result.Id, nil
	case gorm.RecordNotFound:
		err = db.Save(tag).Error
		return tag.Id, err
	default:
		logger.Log(err)
		return -1, err
	}
}

func updateTagMap(db *gorm.DB, postID int64, tagID int64) error {
	return db.Save(&TagMap{TagID: tagID, EntryID: postID}).Error
}
<commit_msg>Log error<commit_after>package main

import (
	"fmt"
	"runtime"
	"time"

	"github.com/jinzhu/gorm"
)

type Data interface {
	post(url string, includeHidden bool) (*Entry, error)
	postID(url string) (id int64, err error)
	posts(limit, offset int, includeHidden bool) ([]*Entry, error)
	titles(limit int, includeHidden bool) ([]EntryLink, error)
	titlesByTag(tag string, includeHidden bool) ([]EntryLink, error)
	allComments() ([]*CommentWithPostTitle, error)
	numPosts(includeHidden bool) (int, error)
	author(username string) (*Author, error)
	deleteComment(id string) error
	deletePost(url string) error
	updateComment(id, text string) error
	commenterID(c *Commenter) (id int64, err error)
	insertCommenter(c *Commenter) (id int64, err error)
	insertComment(commenterID, postID int64, body string) (id int64, err error)
	insertPost(e *EntryTable) (id int64, err error)
	updatePost(e *EntryTable) error
	updateTags(tags []*Tag, postID int64) error
	queryAllTags() ([]*Tag, error)
	begin() error
	commit()
	rollback()
}

type DbData struct {
	db *gorm.DB
	tx *gorm.DB
}

func InitDB(conn string) *DbData {
	db, err := gorm.Open("postgres", conn)
	err = db.DB().Ping()
	if err != nil {
		panic(err)
	}
	db.SingularTable(true)
	return &DbData{
		db: &db,
		tx: nil,
	}
}

func notInXactionErr() error {
	pc, _, _, ok := runtime.Caller(1)
	if !ok {
		panic("runtime.Caller(1) != ok, dafuq?")
	}
	funcName := runtime.FuncForPC(pc).Name()
	msg := "Error! %s() can only be called within transaction!"
	return fmt.Errorf(msg, funcName)
}

func (dd *DbData) begin() error {
	dd.tx = dd.db.Begin()
	return dd.tx.Error
}

func (dd *DbData) commit() {
	dd.tx.Commit()
	logger.LogIf(dd.db.Error)
	dd.tx = nil
}

func (dd *DbData) rollback() {
	if dd.tx == nil {
		return
	}
	dd.tx.Rollback()
	logger.LogIf(dd.db.Error)
	dd.tx = nil
}

func (dd *DbData) post(url string, includeHidden bool) (*Entry, error) {
	posts, err := queryPosts(dd, -1, -1, url, includeHidden)
	if err != nil {
		return nil, err
	}
	if len(posts) != 1 {
		msg := "DbData.post(%q) should return 1 post, but returned %d"
		return nil, fmt.Errorf(msg, url, len(posts))
	}
	return posts[0], nil
}

func (dd *DbData) postID(url string) (int64, error) {
	var post Entry
	rows := dd.db.Table("post").Where("url = ?", url).Select("id")
	err := rows.First(&post).Error
	return post.Id, err
}

func (dd *DbData) posts(limit, offset int, includeHidden bool) ([]*Entry, error) {
	return queryPosts(dd, limit, offset, "", includeHidden)
}

func (dd *DbData) numPosts(includeHidden bool) (int, error) {
	var count int
	if includeHidden {
		dd.db.Table("post").Count(&count)
	} else {
		dd.db.Table("post").Where("hidden=?", false).Count(&count)
	}
	return count, dd.db.Error
}

func (dd *DbData) titles(limit int, includeHidden bool) ([]EntryLink, error) {
	var results []EntryLink
	posts := dd.db.Table("post").Select("title, url, hidden")
	if !includeHidden {
		posts = posts.Where("hidden=?", false)
	}
	err := posts.Order("date desc").Limit(limit).Scan(&results).Error
	return results, err
}

func (dd *DbData) titlesByTag(tag string, includeHidden bool) ([]EntryLink, error) {
	var postIDs []int64
	var results []EntryLink
	join := "inner join tag on tagmap.tag_id = tag.id"
	rows := dd.db.Table("tagmap").Joins(join).Where("tag.tag=?", tag)
	err := rows.Pluck("post_id", &postIDs).Error
	if err != nil {
		return nil, err
	}
	columns := "title, url, hidden"
	posts := dd.db.Table("post").Select(columns).Where("id in (?)", postIDs)
	if !includeHidden {
		posts = posts.Where("hidden=?", false)
	}
	err = posts.Order("date desc").Scan(&results).Error
	return results, err
}

func (dd *DbData) allComments() ([]*CommentWithPostTitle, error) {
	var results []*CommentWithPostTitle
	sel := `commenter.name, commenter.email, commenter.www, commenter.ip,
		comment.id, comment.timestamp, comment.body,
		post.title, post.url`
	join := `right join comment on commenter.id = comment.commenter_id
		inner join post on comment.post_id = post.id`
	joined := dd.db.Table("commenter").Select(sel).Joins(join)
	err := joined.Order("comment.timestamp desc").Scan(&results).Error
	// TODO: there's an identical loop in queryComments, but it loops over
	// []Comment instead of []CommentWithPostTitle. Would be nice to unify.
	for _, c := range results {
		c.EmailHash = Md5Hash(c.Email)
		c.Time = time.Unix(c.Timestamp, 0).Format("2006-01-02 15:04")
		c.Body = sanitizeHTML(mdToHTML(c.RawBody))
	}
	return results, err
}

func (dd *DbData) commenterID(c *Commenter) (id int64, err error) {
	where := "name = ? and email = ? and www = ?"
	err = dd.db.Select("id").Where(where, c.Name, c.Email, c.Website).Scan(&id).Error
	return
}

func (dd *DbData) insertCommenter(c *Commenter) (id int64, err error) {
	if dd.tx == nil {
		return -1, notInXactionErr()
	}
	entry := CommenterTable{Id: 0, Commenter: *c}
	err = dd.tx.Save(&entry).Error
	return entry.Id, err
}

func (dd *DbData) insertComment(commenterID, postID int64, body string) (id int64, err error) {
	if dd.tx == nil {
		return -1, notInXactionErr()
	}
	c := CommentTable{
		CommenterID: commenterID,
		PostID:      postID,
		RawBody:     body,
		Timestamp:   time.Now().Unix(),
	}
	err = dd.tx.Save(&c).Error
	return c.CommentID, err
}

func (dd *DbData) insertPost(e *EntryTable) (id int64, err error) {
	if dd.tx == nil {
		return -1, notInXactionErr()
	}
	err = dd.tx.Save(e).Error
	return e.Id, err
}

func (dd *DbData) updatePost(e *EntryTable) error {
	if dd.tx == nil {
		return notInXactionErr()
	}
	return dd.tx.Save(e).Error
}

func (dd *DbData) updateTags(tags []*Tag, postID int64) error {
	if dd.tx == nil {
		return notInXactionErr()
	}
	dd.tx.Where("post_id = ?", postID).Delete(TagMap{})
	for _, t := range tags {
		tagID, err := insertOrGetTagID(dd.tx, t)
		if err != nil {
			return err
		}
		err = updateTagMap(dd.tx, postID, tagID)
		if err != nil {
			return err
		}
	}
	return nil
}

func (dd *DbData) author(username string) (*Author, error) {
	var a Author
	err := dd.db.Where("disp_name = ?", username).First(&a).Error
	return &a, err
}

func (dd *DbData) deleteComment(id string) error {
	return dd.db.Where("id=?", id).Delete(CommentTable{}).Error
}

func (dd *DbData) deletePost(url string) error {
	return dd.db.Where("url=?", url).Delete(Entry{}).Error
}

func (dd *DbData) updateComment(id, text string) error {
	return dd.db.Model(CommentTable{}).Where("id=?", id).Update("body", text).Error
}

func queryPosts(dd *DbData, limit, offset int, url string,
	includeHidden bool) ([]*Entry, error) {
	var results []*Entry
	cols := `author.disp_name, post.id, post.title, post.date, post.body,
		post.url, post.hidden`
	join := "inner join author on post.author_id=author.id"
	posts := dd.db.Table("post").Select(cols).Joins(join)
	if !includeHidden {
		posts = posts.Where("hidden=?", false)
	}
	if url != "" {
		posts = posts.Where("url=?", url)
	}
	rows := posts.Order("date desc").Limit(limit).Offset(offset)
	err := rows.Scan(&results).Error
	for _, p := range results {
		p.Body = sanitizeTrustedHTML(mdToHTML(p.RawBody))
		p.Date = time.Unix(p.UnixDate, 0).Format("2006-01-02")
		p.Tags = queryTags(dd.db, p.Id)
		p.Comments = queryComments(dd.db, p.Id)
	}
	return results, err
}

func queryTags(db *gorm.DB, postID int64) []*Tag {
	var results []*Tag
	join := "inner join tagmap on tagmap.tag_id = tag.id"
	tables := db.Table("tag").Select("tag.tag").Joins(join)
	tables.Where("tagmap.post_id = ?", postID).Scan(&results)
	logger.LogIff(db.Error, "error querying tags for post %d", postID)
	return results
}

func (dd *DbData) queryAllTags() ([]*Tag, error) {
	var tags []*Tag
	err := dd.db.Find(&tags).Error
	return tags, err
}

func queryComments(db *gorm.DB, postID int64) []*Comment {
	var comments []*Comment
	join := "inner join commenter on comment.commenter_id = commenter.id"
	order := "timestamp asc"
	tables := db.Table("comment").Select("*").Joins(join)
	rows := tables.Where("post_id = ?", postID).Order(order)
	err := rows.Scan(&comments).Error
	logger.LogIff(err, "error querying comments")
	for _, c := range comments {
		c.EmailHash = Md5Hash(c.Email)
		c.Time = time.Unix(c.Timestamp, 0).Format("2006-01-02 15:04")
		c.Body = sanitizeHTML(mdToHTML(c.RawBody))
	}
	return comments
}

func insertOrGetTagID(db *gorm.DB, tag *Tag) (tagID int64, err error) {
	var result Tag
	err = db.Where("tag = ?", tag.Name).First(&result).Error
	switch err {
	case nil:
		return result.Id, nil
	case gorm.RecordNotFound:
		err = db.Save(tag).Error
		return tag.Id, err
	default:
		logger.Log(err)
		return -1, err
	}
}

func updateTagMap(db *gorm.DB, postID int64, tagID int64) error {
	return db.Save(&TagMap{TagID: tagID, EntryID: postID}).Error
}
<|endoftext|>


<commit_before>// Copyright 2012 Ric Szopa (Ryszard) <ryszard.szopa@gmail.com> All
// rights reserved.  Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Package skiplist implements skip list based maps and sets. For more
// information about skip lists take a look at
// http://en.wikipedia.org/wiki/Skip_list.

package skiplist

import "math/rand"

// TODO(ryszard):
//   - A separately seeded source of randomness
//   - Make maxLevel configurable
//   - Sets.

const p = 0.5
const maxLevel = 32 // maybe this should be configurable

type node struct {
	forward    []*node
	key, value interface{}
}

func (n *node) Next() *node {
	return n.forward[0]
}

func (n node) HasNext() bool {
	return n.Next() != nil
}

func (n *node) Key() interface{} {
	return n.key
}

func (n *node) Value() interface{} {
	return n.value
}

type SkipList struct {
	lessThan func(l, r interface{}) bool
	header   *node
}

// Len returns the length of s.
func (s *SkipList) Len() (i int) {
	for node := s.Front(); node != nil; node = node.Next() {
		i++
	}
	return
}

func (s *SkipList) Front() *node {
	return s.header.Next()
}

func (s *SkipList) level() int {
	return len(s.header.forward) - 1
}

func (s *SkipList) LessThan(l, r interface{}) bool {
	// nil is the maximum
	if l == nil {
		return false
	}
	return s.lessThan(l, r)
}

// Returns a new random level in 1..maxLevel.
func (s SkipList) randomLevel() (n int) {
	for n = 0; n < maxLevel && rand.Float64() < p; n++ {
	}
	return
}

// Get returns the value associated with key from s (nil if the key is
// not present in s). The second return value is true when the key is
// present.
func (s *SkipList) Get(key interface{}) (value interface{}, present bool) {
	candidate := s.getPath(nil, key)

	if candidate != nil && candidate.key == key {
		return candidate.value, true
	}

	return nil, false
}

// getPath populates update with nodes that constitute the path to the
// node that may contain key. The candidate node will be returned. If
// update is nil, it will be left alone (the candidate node will still
// be returned). If update is not nil, but it doesn't have enough
// slots for all the nodes in the path, getPath will panic.
func (s *SkipList) getPath(update []*node, key interface{}) *node {
	current := s.header
	for i := s.level(); i >= 0; i-- {
		for current.forward[i] != nil && s.LessThan(current.forward[i].key, key) {
			current = current.forward[i]
		}
		if update != nil {
			update[i] = current
		}
	}
	return current.Next()
}

// Sets set the value associated with key in s.
func (s *SkipList) Set(key, value interface{}) {

	// s.level starts from 0, so we need to allocate one
	update := make([]*node, s.level()+1, maxLevel)
	candidate := s.getPath(update, key)

	if candidate != nil && candidate.key == key {
		candidate.value = value
		return
	}

	newLevel := s.randomLevel()

	if currentLevel := s.level(); newLevel > currentLevel {
		// there are no pointers for the higher levels in
		// update. Header should be there. Also add higher
		// level links to the header.
		for i := currentLevel + 1; i <= newLevel; i++ {
			update = append(update, s.header)
			s.header.forward = append(s.header.forward, nil)
		}
	}

	newNode := &node{make([]*node, newLevel+1, maxLevel), key, value}

	for i := 0; i <= newLevel; i++ {
		newNode.forward[i] = update[i].forward[i]
		update[i].forward[i] = newNode
	}
}

// Delete removes node with key key from s and returns its value. A
// second value, a boolean, is return to indicate if key was present
// in s.
func (s *SkipList) Delete(key interface{}) (value interface{}, present bool) {
	update := make([]*node, s.level()+1, maxLevel)
	candidate := s.getPath(update, key)

	if candidate.key != key {
		return nil, false
	}

	for i := 0; i <= s.level() && update[i].forward[i] == candidate; i++ {
		update[i].forward[i] = candidate.forward[i]
	}

	for s.level() > 0 && s.header.forward[s.level()] == nil {
		s.header.forward = s.header.forward[:s.level()-1]
	}

	return candidate.Value(), true
}

// New returns a new SkipList that will use lessThan as the comparison
// function. lessThan should be linear order on keys you intend to use
// with the SkipList.
func NewMap(lessThan func(l, r interface{}) bool) *SkipList {
	return &SkipList{lessThan, &node{[]*node{nil}, nil, nil}}
}

type Comparable interface {
	LessThan(Comparable) bool
}

// NewComparable returns a SkipList that accepts skiplist.Comparable
// objects as keys.
func NewComparableMap() (s *SkipList) {
	comparator := func(left, right interface{}) bool {
		return left.(Comparable).LessThan(right.(Comparable))
	}
	return NewMap(comparator)

}

// NewIntKey returns a SkipList that accepts int keys.
func NewIntMap() *SkipList {
	return NewMap(func(l, r interface{}) bool {
		return l.(int) < r.(int)
	})
}

// NewStringMap returns a SkipList accepting strings as keys.
func NewStringMap() *SkipList {
	return NewMap(func(l, r interface{}) bool {
		return l.(string) < r.(string)
	})
}
<commit_msg>comments<commit_after>// Copyright 2012 Ric Szopa (Ryszard) <ryszard.szopa@gmail.com> All
// rights reserved.  Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Package skiplist implements skip list based maps and sets. For more
// information about skip lists take a look at
// http://en.wikipedia.org/wiki/Skip_list.

package skiplist

import "math/rand"

// TODO(ryszard):
//   - A separately seeded source of randomness
//   - Make maxLevel configurable
//   - Sets.

const p = 0.5
const maxLevel = 32 // maybe this should be configurable

type node struct {
	forward    []*node
	key, value interface{}
}

func (n *node) Next() *node {
	return n.forward[0]
}

func (n node) HasNext() bool {
	return n.Next() != nil
}

func (n *node) Key() interface{} {
	return n.key
}

func (n *node) Value() interface{} {
	return n.value
}

type SkipList struct {
	lessThan func(l, r interface{}) bool
	header   *node
}

// Len returns the length of s.
func (s *SkipList) Len() (i int) {
	for node := s.Front(); node != nil; node = node.Next() {
		i++
	}
	return
}

// Front returns the first element of s in a way suitable for
// iteration.
func (s *SkipList) Front() *node {
	return s.header.Next()
}

func (s *SkipList) level() int {
	return len(s.header.forward) - 1
}

func (s *SkipList) LessThan(l, r interface{}) bool {
	// nil is the maximum
	if l == nil {
		return false
	}
	return s.lessThan(l, r)
}

// Returns a new random level.
func (s SkipList) randomLevel() (n int) {
	for n = 0; n < maxLevel && rand.Float64() < p; n++ {
	}
	return
}

// Get returns the value associated with key from s (nil if the key is
// not present in s). The second return value is true when the key is
// present.
func (s *SkipList) Get(key interface{}) (value interface{}, present bool) {
	candidate := s.getPath(nil, key)

	if candidate != nil && candidate.key == key {
		return candidate.value, true
	}

	return nil, false
}

// getPath populates update with nodes that constitute the path to the
// node that may contain key. The candidate node will be returned. If
// update is nil, it will be left alone (the candidate node will still
// be returned). If update is not nil, but it doesn't have enough
// slots for all the nodes in the path, getPath will panic.
func (s *SkipList) getPath(update []*node, key interface{}) *node {
	current := s.header
	for i := s.level(); i >= 0; i-- {
		for current.forward[i] != nil && s.LessThan(current.forward[i].key, key) {
			current = current.forward[i]
		}
		if update != nil {
			update[i] = current
		}
	}
	return current.Next()
}

// Sets set the value associated with key in s.
func (s *SkipList) Set(key, value interface{}) {

	// s.level starts from 0, so we need to allocate one
	update := make([]*node, s.level()+1, maxLevel)
	candidate := s.getPath(update, key)

	if candidate != nil && candidate.key == key {
		candidate.value = value
		return
	}

	newLevel := s.randomLevel()

	if currentLevel := s.level(); newLevel > currentLevel {
		// there are no pointers for the higher levels in
		// update. Header should be there. Also add higher
		// level links to the header.
		for i := currentLevel + 1; i <= newLevel; i++ {
			update = append(update, s.header)
			s.header.forward = append(s.header.forward, nil)
		}
	}

	newNode := &node{make([]*node, newLevel+1, maxLevel), key, value}

	for i := 0; i <= newLevel; i++ {
		newNode.forward[i] = update[i].forward[i]
		update[i].forward[i] = newNode
	}
}

// Delete removes node with key key from s and returns its value. A
// second value, a boolean, is return to indicate if key was present
// in s.
func (s *SkipList) Delete(key interface{}) (value interface{}, present bool) {
	update := make([]*node, s.level()+1, maxLevel)
	candidate := s.getPath(update, key)

	if candidate.key != key {
		return nil, false
	}

	for i := 0; i <= s.level() && update[i].forward[i] == candidate; i++ {
		update[i].forward[i] = candidate.forward[i]
	}

	for s.level() > 0 && s.header.forward[s.level()] == nil {
		s.header.forward = s.header.forward[:s.level()-1]
	}

	return candidate.Value(), true
}

// New returns a new SkipList that will use lessThan as the comparison
// function. lessThan should be linear order on keys you intend to use
// with the SkipList.
func NewMap(lessThan func(l, r interface{}) bool) *SkipList {
	return &SkipList{lessThan, &node{[]*node{nil}, nil, nil}}
}

type Comparable interface {
	LessThan(Comparable) bool
}

// NewComparable returns a SkipList that accepts skiplist.Comparable
// objects as keys.
func NewComparableMap() (s *SkipList) {
	comparator := func(left, right interface{}) bool {
		return left.(Comparable).LessThan(right.(Comparable))
	}
	return NewMap(comparator)

}

// NewIntKey returns a SkipList that accepts int keys.
func NewIntMap() *SkipList {
	return NewMap(func(l, r interface{}) bool {
		return l.(int) < r.(int)
	})
}

// NewStringMap returns a SkipList accepting strings as keys.
func NewStringMap() *SkipList {
	return NewMap(func(l, r interface{}) bool {
		return l.(string) < r.(string)
	})
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2015 James Garfield

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 sliceops

import (
	"sort"
)

type I interface{}
type Slice []I

type _Sorter struct {
	Slice
	LessFunc func(I, I) bool
}

func (s _Sorter) Less(i, j int) bool {
	return s.LessFunc(s.Slice[i], s.Slice[j])
}

func (s Slice) Len() int {
	return len(s)
}

func (s Slice) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s Slice) All(fn func(I) bool) bool {
	for _, v := range s {
		if !fn(v) {
			return false
		}
	}
	return true
}

func (s Slice) Any(fn func(I) bool) bool {
	for _, v := range s {
		if fn(v) {
			return true
		}
	}
	return false
}

func (s Slice) Count(fn func(I) bool) int {
	count := 0
	for _, v := range s {
		if fn(v) {
			count += 1
		}
	}
	return count
}

func (s Slice) Each(fn func(I)) {
	for _, v := range s {
		fn(v)
	}
}

func (s Slice) First(fn func(I) bool) (match I, found bool) {
	for _, v := range s {
		if fn(v) {
			match = v
			found = true
			break
		}
	}
	return
}

func (s Slice) Sort(less func(I, I) bool) {
	sort.Sort(_Sorter{s, less})
}

func (s Slice) Where(fn func(I) bool) (result Slice) {
	for _, v := range s {
		if fn(v) {
			result = append(result, v)
		}
	}
	return result
}

//Return a new slice of elements that have been removed from this slice
func (s *Slice) Extract(fn func(I) bool) (removed Slice) {
	pos := 0
	kept := *s
	for i := 0; i < kept.Len(); i++ {
		if fn(kept[i]) {
			removed = append(removed, kept[i])
		} else {
			kept[pos] = kept[i]
			pos++
		}
	}

	kept = kept[:pos:pos]
	*s = kept
	return removed
}
<commit_msg>Comments<commit_after>/*
The MIT License (MIT)

Copyright (c) 2015 James Garfield

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 sliceops

import (
	"sort"
)

//Impl Types: Requires a slice of any type (interface{})
type I interface{}
type Slice []I

//Related Type: Enables sorting as a slice operation
type _Sorter struct {
	Slice
	LessFunc func(I, I) bool
}

func (s _Sorter) Less(i, j int) bool {
	return s.LessFunc(s.Slice[i], s.Slice[j])
}

func (s Slice) Len() int {
	return len(s)
}

func (s Slice) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

//Sorts the slice in-place using the related type sorter
func (s Slice) Sort(less func(I, I) bool) {
	sort.Sort(_Sorter{s, less})
}

//Returns true if all elements in the slice return true for the provided function
func (s Slice) All(fn func(I) bool) bool {
	for _, v := range s {
		if !fn(v) {
			return false
		}
	}
	return true
}

//Returns true if any elements in the slice return true for the provided function
func (s Slice) Any(fn func(I) bool) bool {
	for _, v := range s {
		if fn(v) {
			return true
		}
	}
	return false
}

//Returns the number of elements in the slice that return true for the provided function
func (s Slice) Count(fn func(I) bool) int {
	count := 0
	for _, v := range s {
		if fn(v) {
			count += 1
		}
	}
	return count
}

//Run the provided function on each element of the slice
func (s Slice) Each(fn func(I)) {
	for _, v := range s {
		fn(v)
	}
}

//Return the first element in the slice to return true for the provided function
func (s Slice) First(fn func(I) bool) (match I, found bool) {
	for _, v := range s {
		if fn(v) {
			match = v
			found = true
			break
		}
	}
	return
}

//Return a new slice of elements that return true for the provided function
func (s Slice) Where(fn func(I) bool) (result Slice) {
	for _, v := range s {
		if fn(v) {
			result = append(result, v)
		}
	}
	return result
}

//Return a new slice of elements that have been removed from this slice
func (s *Slice) Extract(fn func(I) bool) (removed Slice) {
	pos := 0
	kept := *s
	for i := 0; i < kept.Len(); i++ {
		if fn(kept[i]) {
			removed = append(removed, kept[i])
		} else {
			kept[pos] = kept[i]
			pos++
		}
	}

	kept = kept[:pos:pos]
	*s = kept
	return removed
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package v1

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/golang/glog"
	mayav1 "github.com/kubernetes-incubator/external-storage/openebs/types/v1"
	yaml "gopkg.in/yaml.v2"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

const (
	timeout = 60 * time.Second
)

//OpenEBSVolumeInterface Interface to bind methods
type OpenEBSVolumeInterface interface {
	CreateVolume(mayav1.VolumeSpec) (string, error)
	ListVolume(string, interface{}) error
	DeleteVolume(string) error
}

//MayaInterface interface to hold maya specific methods
type MayaInterface interface {
	GetMayaClusterIP(kubernetes.Interface) (string, error)
}

//OpenEBSVolume struct
type OpenEBSVolume struct{}

//GetMayaClusterIP returns maya-apiserver IP address
func (v OpenEBSVolume) GetMayaClusterIP(client kubernetes.Interface) (string, error) {
	clusterIP := "127.0.0.1"

	//Fetch the Maya ClusterIP using the Maya API Server Service
	sc, err := client.CoreV1().Services("default").Get("maya-apiserver-service", metav1.GetOptions{})
	if err != nil {
		glog.Errorf("Error getting maya-apiserver IP Address: %v", err)
	}

	clusterIP = sc.Spec.ClusterIP
	glog.V(2).Infof("Maya Cluster IP: %v", clusterIP)

	return clusterIP, err
}

// CreateVolume to create the Vsm through a API call to m-apiserver
func (v OpenEBSVolume) CreateVolume(vs mayav1.VolumeSpec) (string, error) {

	addr := os.Getenv("MAPI_ADDR")
	if addr == "" {
		err := errors.New("MAPI_ADDR environment variable not set")
		glog.Errorf("Error getting maya-apiserver IP Address: %v", err)
		return "Error getting maya-apiserver IP Address", err
	}
	url := addr + "/latest/volumes/"

	vs.Kind = "PersistentVolumeClaim"
	vs.APIVersion = "v1"

	//Marshal serializes the value provided into a YAML document
	yamlValue, _ := yaml.Marshal(vs)

	glog.V(2).Infof("[DEBUG] volume Spec Created:\n%v\n", string(yamlValue))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(yamlValue))

	req.Header.Add("Content-Type", "application/yaml")

	c := &http.Client{
		Timeout: timeout,
	}
	resp, err := c.Do(req)
	if err != nil {
		glog.Errorf("Error when connecting maya-apiserver %v", err)
		return "Could not connect to maya-apiserver", err
	}
	defer resp.Body.Close()

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		glog.Errorf("Unable to read response from maya-apiserver %v", err)
		return "Unable to read response from maya-apiserver", err
	}

	code := resp.StatusCode
	if code != http.StatusOK {
		glog.Errorf("Status error: %v\n", http.StatusText(code))
		return "HTTP Status error from maya-apiserver", err
	}

	glog.Infof("volume Successfully Created:\n%v\n", string(data))
	return "volume Successfully Created", nil
}

// ListVolume to get the info of Vsm through a API call to m-apiserver
func (v OpenEBSVolume) ListVolume(vname string, obj interface{}) error {

	addr := os.Getenv("MAPI_ADDR")
	if addr == "" {
		err := errors.New("MAPI_ADDR environment variable not set")
		glog.Errorf("Error getting mayaapi-server IP Address: %v", err)
		return err
	}
	url := addr + "/latest/volumes/info/" + vname

	glog.V(2).Infof("[DEBUG] Get details for Volume :%v", string(vname))

	req, err := http.NewRequest("GET", url, nil)
	c := &http.Client{
		Timeout: timeout,
	}
	resp, err := c.Do(req)
	if err != nil {
		glog.Errorf("Error when connecting to maya-apiserver %v", err)
		return err
	}
	defer resp.Body.Close()

	code := resp.StatusCode
	if code != http.StatusOK {
		glog.Errorf("HTTP Status error from maya-apiserver: %v\n", http.StatusText(code))
		return err
	}
	glog.V(2).Info("volume Details Successfully Retrieved")
	return json.NewDecoder(resp.Body).Decode(obj)
}

// DeleteVolume to get delete Vsm through a API call to m-apiserver
func (v OpenEBSVolume) DeleteVolume(vname string) error {

	addr := os.Getenv("MAPI_ADDR")
	if addr == "" {
		err := errors.New("MAPI_ADDR environment variable not set")
		glog.Errorf("Error getting maya-api-server IP Address: %v", err)
		return err
	}
	url := addr + "/latest/volumes/delete/" + vname

	glog.V(2).Infof("[DEBUG] Delete Volume :%v", string(vname))

	req, err := http.NewRequest("GET", url, nil)
	c := &http.Client{
		Timeout: timeout,
	}
	resp, err := c.Do(req)
	if err != nil {
		glog.Errorf("Error when connecting to maya-apiserver  %v", err)
		return err
	}
	defer resp.Body.Close()

	code := resp.StatusCode
	if code != http.StatusOK {
		glog.Errorf("HTTP Status error from maya-apiserver: %v\n", http.StatusText(code))
		return err
	}
	glog.Info("volume Deleted Successfully initiated")
	return nil
}
<commit_msg>Allow openebs provisioner to identify namespace<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package v1

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/golang/glog"
	mayav1 "github.com/kubernetes-incubator/external-storage/openebs/types/v1"
	yaml "gopkg.in/yaml.v2"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

const (
	timeout = 60 * time.Second
)

//OpenEBSVolumeInterface Interface to bind methods
type OpenEBSVolumeInterface interface {
	CreateVolume(mayav1.VolumeSpec) (string, error)
	ListVolume(string, interface{}) error
	DeleteVolume(string) error
}

//MayaInterface interface to hold maya specific methods
type MayaInterface interface {
	GetMayaClusterIP(kubernetes.Interface) (string, error)
}

//OpenEBSVolume struct
type OpenEBSVolume struct{}

//GetMayaClusterIP returns maya-apiserver IP address
func (v OpenEBSVolume) GetMayaClusterIP(client kubernetes.Interface) (string, error) {
	clusterIP := "127.0.0.1"

	namespace := os.Getenv("OPENEBS_NAMESPACE")
	if namespace == "" {
		namespace = "default"
	}

	glog.Info("OpenEBS volume provisioner namespace ", namespace)
	//Fetch the Maya ClusterIP using the Maya API Server Service
	sc, err := client.CoreV1().Services(namespace).Get("maya-apiserver-service", metav1.GetOptions{})
	if err != nil {
		glog.Errorf("Error getting maya-apiserver IP Address: %v", err)
	}

	clusterIP = sc.Spec.ClusterIP
	glog.V(2).Infof("Maya Cluster IP: %v", clusterIP)

	return clusterIP, err
}

// CreateVolume to create the Vsm through a API call to m-apiserver
func (v OpenEBSVolume) CreateVolume(vs mayav1.VolumeSpec) (string, error) {

	addr := os.Getenv("MAPI_ADDR")
	if addr == "" {
		err := errors.New("MAPI_ADDR environment variable not set")
		glog.Errorf("Error getting maya-apiserver IP Address: %v", err)
		return "Error getting maya-apiserver IP Address", err
	}
	url := addr + "/latest/volumes/"

	vs.Kind = "PersistentVolumeClaim"
	vs.APIVersion = "v1"

	//Marshal serializes the value provided into a YAML document
	yamlValue, _ := yaml.Marshal(vs)

	glog.V(2).Infof("[DEBUG] volume Spec Created:\n%v\n", string(yamlValue))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(yamlValue))

	req.Header.Add("Content-Type", "application/yaml")

	c := &http.Client{
		Timeout: timeout,
	}
	resp, err := c.Do(req)
	if err != nil {
		glog.Errorf("Error when connecting maya-apiserver %v", err)
		return "Could not connect to maya-apiserver", err
	}
	defer resp.Body.Close()

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		glog.Errorf("Unable to read response from maya-apiserver %v", err)
		return "Unable to read response from maya-apiserver", err
	}

	code := resp.StatusCode
	if code != http.StatusOK {
		glog.Errorf("Status error: %v\n", http.StatusText(code))
		return "HTTP Status error from maya-apiserver", err
	}

	glog.Infof("volume Successfully Created:\n%v\n", string(data))
	return "volume Successfully Created", nil
}

// ListVolume to get the info of Vsm through a API call to m-apiserver
func (v OpenEBSVolume) ListVolume(vname string, obj interface{}) error {

	addr := os.Getenv("MAPI_ADDR")
	if addr == "" {
		err := errors.New("MAPI_ADDR environment variable not set")
		glog.Errorf("Error getting mayaapi-server IP Address: %v", err)
		return err
	}
	url := addr + "/latest/volumes/info/" + vname

	glog.V(2).Infof("[DEBUG] Get details for Volume :%v", string(vname))

	req, err := http.NewRequest("GET", url, nil)
	c := &http.Client{
		Timeout: timeout,
	}
	resp, err := c.Do(req)
	if err != nil {
		glog.Errorf("Error when connecting to maya-apiserver %v", err)
		return err
	}
	defer resp.Body.Close()

	code := resp.StatusCode
	if code != http.StatusOK {
		glog.Errorf("HTTP Status error from maya-apiserver: %v\n", http.StatusText(code))
		return err
	}
	glog.V(2).Info("volume Details Successfully Retrieved")
	return json.NewDecoder(resp.Body).Decode(obj)
}

// DeleteVolume to get delete Vsm through a API call to m-apiserver
func (v OpenEBSVolume) DeleteVolume(vname string) error {

	addr := os.Getenv("MAPI_ADDR")
	if addr == "" {
		err := errors.New("MAPI_ADDR environment variable not set")
		glog.Errorf("Error getting maya-api-server IP Address: %v", err)
		return err
	}
	url := addr + "/latest/volumes/delete/" + vname

	glog.V(2).Infof("[DEBUG] Delete Volume :%v", string(vname))

	req, err := http.NewRequest("GET", url, nil)
	c := &http.Client{
		Timeout: timeout,
	}
	resp, err := c.Do(req)
	if err != nil {
		glog.Errorf("Error when connecting to maya-apiserver  %v", err)
		return err
	}
	defer resp.Body.Close()

	code := resp.StatusCode
	if code != http.StatusOK {
		glog.Errorf("HTTP Status error from maya-apiserver: %v\n", http.StatusText(code))
		return err
	}
	glog.Info("volume Deleted Successfully initiated")
	return nil
}
<|endoftext|>


<commit_before>package cloudflare

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/pkg/errors"
)

// SpectrumApplication defines a single Spectrum Application.
type SpectrumApplication struct {
	ID            string                        `json:"id,omitempty"`
	Protocol      string                        `json:"protocol,omitempty"`
	IPv4          bool                          `json:"ipv4,omitempty"`
	DNS           SpectrumApplicationDNS        `json:"dns,omitempty"`
	OriginDirect  []string                      `json:"origin_direct,omitempty"`
	OriginPort    int                           `json:"origin_port,omitempty"`
	OriginDNS     *SpectrumApplicationOriginDNS `json:"origin_dns,omitempty"`
	IPFirewall    bool                          `json:"ip_firewall,omitempty"`
	ProxyProtocol bool                          `json:"proxy_protocol,omitempty"`
	TLS           string                        `json:"tls,omitempty"`
	CreatedOn     *time.Time                    `json:"created_on,omitempty"`
	ModifiedOn    *time.Time                    `json:"modified_on,omitempty"`
}

// SpectrumApplicationDNS holds the external DNS configuration for a Spectrum
// Application.
type SpectrumApplicationDNS struct {
	Type string `json:"type"`
	Name string `json:"name"`
}

// SpectrumApplicationOriginDNS holds the origin DNS configuration for a Spectrum
// Application.
type SpectrumApplicationOriginDNS struct {
	Name string `json:"name"`
}

// SpectrumApplicationDetailResponse is the structure of the detailed response
// from the API.
type SpectrumApplicationDetailResponse struct {
	Response
	Result SpectrumApplication `json:"result"`
}

// SpectrumApplicationsDetailResponse is the structure of the detailed response
// from the API.
type SpectrumApplicationsDetailResponse struct {
	Response
	Result []SpectrumApplication `json:"result"`
}

// SpectrumApplications fetches all of the Spectrum applications for a zone.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#list-spectrum-applications
func (api *API) SpectrumApplications(zoneID string) ([]SpectrumApplication, error) {
	uri := "/zones/" + zoneID + "/spectrum/apps"

	res, err := api.makeRequest("GET", uri, nil)
	if err != nil {
		return []SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
	}

	var spectrumApplications SpectrumApplicationsDetailResponse
	err = json.Unmarshal(res, &spectrumApplications)
	if err != nil {
		return []SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
	}

	return spectrumApplications.Result, nil
}

// SpectrumApplication fetches a single Spectrum application based on the ID.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#list-spectrum-applications
func (api *API) SpectrumApplication(zoneID string, applicationID string) (SpectrumApplication, error) {
	uri := fmt.Sprintf(
		"/zones/%s/spectrum/apps/%s",
		zoneID,
		applicationID,
	)

	res, err := api.makeRequest("GET", uri, nil)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
	}

	var spectrumApplication SpectrumApplicationDetailResponse
	err = json.Unmarshal(res, &spectrumApplication)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
	}

	return spectrumApplication.Result, nil
}

// CreateSpectrumApplication creates a new Spectrum application.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#create-a-spectrum-application
func (api *API) CreateSpectrumApplication(zoneID string, appDetails SpectrumApplication) (SpectrumApplication, error) {
	uri := "/zones/" + zoneID + "/spectrum/apps"

	res, err := api.makeRequest("POST", uri, appDetails)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
	}

	var spectrumApplication SpectrumApplicationDetailResponse
	err = json.Unmarshal(res, &spectrumApplication)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
	}

	return spectrumApplication.Result, nil
}

// UpdateSpectrumApplication updates an existing Spectrum application.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#update-a-spectrum-application
func (api *API) UpdateSpectrumApplication(zoneID, appID string, appDetails SpectrumApplication) (SpectrumApplication, error) {
	uri := fmt.Sprintf(
		"/zones/%s/spectrum/apps/%s",
		zoneID,
		appID,
	)

	res, err := api.makeRequest("PUT", uri, appDetails)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
	}

	var spectrumApplication SpectrumApplicationDetailResponse
	err = json.Unmarshal(res, &spectrumApplication)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
	}

	return spectrumApplication.Result, nil
}

// DeleteSpectrumApplication removes a Spectrum application based on the ID.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#delete-a-spectrum-application
func (api *API) DeleteSpectrumApplication(zoneID string, applicationID string) error {
	uri := fmt.Sprintf(
		"/zones/%s/spectrum/apps/%s",
		zoneID,
		applicationID,
	)

	_, err := api.makeRequest("DELETE", uri, nil)
	if err != nil {
		return errors.Wrap(err, errMakeRequestError)
	}

	return nil
}
<commit_msg>add support for modifying spectrum app traffic type (#350)<commit_after>package cloudflare

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/pkg/errors"
)

// SpectrumApplication defines a single Spectrum Application.
type SpectrumApplication struct {
	ID            string                        `json:"id,omitempty"`
	Protocol      string                        `json:"protocol,omitempty"`
	IPv4          bool                          `json:"ipv4,omitempty"`
	DNS           SpectrumApplicationDNS        `json:"dns,omitempty"`
	OriginDirect  []string                      `json:"origin_direct,omitempty"`
	OriginPort    int                           `json:"origin_port,omitempty"`
	OriginDNS     *SpectrumApplicationOriginDNS `json:"origin_dns,omitempty"`
	IPFirewall    bool                          `json:"ip_firewall,omitempty"`
	ProxyProtocol bool                          `json:"proxy_protocol,omitempty"`
	TLS           string                        `json:"tls,omitempty"`
	TrafficType   string                        `json:"traffic_type,omitempty"`
	CreatedOn     *time.Time                    `json:"created_on,omitempty"`
	ModifiedOn    *time.Time                    `json:"modified_on,omitempty"`
}

// SpectrumApplicationDNS holds the external DNS configuration for a Spectrum
// Application.
type SpectrumApplicationDNS struct {
	Type string `json:"type"`
	Name string `json:"name"`
}

// SpectrumApplicationOriginDNS holds the origin DNS configuration for a Spectrum
// Application.
type SpectrumApplicationOriginDNS struct {
	Name string `json:"name"`
}

// SpectrumApplicationDetailResponse is the structure of the detailed response
// from the API.
type SpectrumApplicationDetailResponse struct {
	Response
	Result SpectrumApplication `json:"result"`
}

// SpectrumApplicationsDetailResponse is the structure of the detailed response
// from the API.
type SpectrumApplicationsDetailResponse struct {
	Response
	Result []SpectrumApplication `json:"result"`
}

// SpectrumApplications fetches all of the Spectrum applications for a zone.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#list-spectrum-applications
func (api *API) SpectrumApplications(zoneID string) ([]SpectrumApplication, error) {
	uri := "/zones/" + zoneID + "/spectrum/apps"

	res, err := api.makeRequest("GET", uri, nil)
	if err != nil {
		return []SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
	}

	var spectrumApplications SpectrumApplicationsDetailResponse
	err = json.Unmarshal(res, &spectrumApplications)
	if err != nil {
		return []SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
	}

	return spectrumApplications.Result, nil
}

// SpectrumApplication fetches a single Spectrum application based on the ID.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#list-spectrum-applications
func (api *API) SpectrumApplication(zoneID string, applicationID string) (SpectrumApplication, error) {
	uri := fmt.Sprintf(
		"/zones/%s/spectrum/apps/%s",
		zoneID,
		applicationID,
	)

	res, err := api.makeRequest("GET", uri, nil)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
	}

	var spectrumApplication SpectrumApplicationDetailResponse
	err = json.Unmarshal(res, &spectrumApplication)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
	}

	return spectrumApplication.Result, nil
}

// CreateSpectrumApplication creates a new Spectrum application.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#create-a-spectrum-application
func (api *API) CreateSpectrumApplication(zoneID string, appDetails SpectrumApplication) (SpectrumApplication, error) {
	uri := "/zones/" + zoneID + "/spectrum/apps"

	res, err := api.makeRequest("POST", uri, appDetails)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
	}

	var spectrumApplication SpectrumApplicationDetailResponse
	err = json.Unmarshal(res, &spectrumApplication)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
	}

	return spectrumApplication.Result, nil
}

// UpdateSpectrumApplication updates an existing Spectrum application.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#update-a-spectrum-application
func (api *API) UpdateSpectrumApplication(zoneID, appID string, appDetails SpectrumApplication) (SpectrumApplication, error) {
	uri := fmt.Sprintf(
		"/zones/%s/spectrum/apps/%s",
		zoneID,
		appID,
	)

	res, err := api.makeRequest("PUT", uri, appDetails)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errMakeRequestError)
	}

	var spectrumApplication SpectrumApplicationDetailResponse
	err = json.Unmarshal(res, &spectrumApplication)
	if err != nil {
		return SpectrumApplication{}, errors.Wrap(err, errUnmarshalError)
	}

	return spectrumApplication.Result, nil
}

// DeleteSpectrumApplication removes a Spectrum application based on the ID.
//
// API reference: https://developers.cloudflare.com/spectrum/api-reference/#delete-a-spectrum-application
func (api *API) DeleteSpectrumApplication(zoneID string, applicationID string) error {
	uri := fmt.Sprintf(
		"/zones/%s/spectrum/apps/%s",
		zoneID,
		applicationID,
	)

	_, err := api.makeRequest("DELETE", uri, nil)
	if err != nil {
		return errors.Wrap(err, errMakeRequestError)
	}

	return nil
}
<|endoftext|>


<commit_before>// package peer implements an object used to represent peers in the ipfs network.
package peer

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"strings"

	ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
	b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58"
	mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"

	ic "github.com/ipfs/go-libp2p/p2p/crypto"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
	logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
)

var log = logging.Logger("peer")

// ID represents the identity of a peer.
type ID string

// Pretty returns a b58-encoded string of the ID
func (id ID) Pretty() string {
	return IDB58Encode(id)
}

func (id ID) Loggable() map[string]interface{} {
	return map[string]interface{}{
		"peerID": id.Pretty(),
	}
}

// String prints out the peer.
//
// TODO(brian): ensure correctness at ID generation and
// enforce this by only exposing functions that generate
// IDs safely. Then any peer.ID type found in the
// codebase is known to be correct.
func (id ID) String() string {
	pid := id.Pretty()

	//All sha256 nodes start with Qm
	//We can skip the Qm to make the peer.ID more useful
	if strings.HasPrefix(pid, "gx/Qm") {
		pid = pid[2:]
	}

	maxRunes := 6
	if len(pid) < maxRunes {
		maxRunes = len(pid)
	}
	return fmt.Sprintf("<peer.ID %s>", pid[:maxRunes])
}

// MatchesPrivateKey tests whether this ID was derived from sk
func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool {
	return id.MatchesPublicKey(sk.GetPublic())
}

// MatchesPublicKey tests whether this ID was derived from pk
func (id ID) MatchesPublicKey(pk ic.PubKey) bool {
	oid, err := IDFromPublicKey(pk)
	if err != nil {
		return false
	}
	return oid == id
}

// IDFromString cast a string to ID type, and validate
// the id to make sure it is a multihash.
func IDFromString(s string) (ID, error) {
	if _, err := mh.Cast([]byte(s)); err != nil {
		return ID(""), err
	}
	return ID(s), nil
}

// IDFromBytes cast a string to ID type, and validate
// the id to make sure it is a multihash.
func IDFromBytes(b []byte) (ID, error) {
	if _, err := mh.Cast(b); err != nil {
		return ID(""), err
	}
	return ID(b), nil
}

// IDB58Decode returns a b58-decoded Peer
func IDB58Decode(s string) (ID, error) {
	m, err := mh.FromB58String(s)
	if err != nil {
		return "", err
	}
	return ID(m), err
}

// IDB58Encode returns b58-encoded string
func IDB58Encode(id ID) string {
	return b58.Encode([]byte(id))
}

// IDHexDecode returns a b58-decoded Peer
func IDHexDecode(s string) (ID, error) {
	m, err := mh.FromHexString(s)
	if err != nil {
		return "", err
	}
	return ID(m), err
}

// IDHexEncode returns b58-encoded string
func IDHexEncode(id ID) string {
	return hex.EncodeToString([]byte(id))
}

// IDFromPublicKey returns the Peer ID corresponding to pk
func IDFromPublicKey(pk ic.PubKey) (ID, error) {
	b, err := pk.Bytes()
	if err != nil {
		return "", err
	}
	hash := u.Hash(b)
	return ID(hash), nil
}

// IDFromPrivateKey returns the Peer ID corresponding to sk
func IDFromPrivateKey(sk ic.PrivKey) (ID, error) {
	return IDFromPublicKey(sk.GetPublic())
}

// Map maps a Peer ID to a struct.
type Set map[ID]struct{}

// PeerInfo is a small struct used to pass around a peer with
// a set of addresses (and later, keys?). This is not meant to be
// a complete view of the system, but rather to model updates to
// the peerstore. It is used by things like the routing system.
type PeerInfo struct {
	ID    ID
	Addrs []ma.Multiaddr
}

func (pi *PeerInfo) MarshalJSON() ([]byte, error) {
	out := make(map[string]interface{})
	out["ID"] = IDB58Encode(pi.ID)
	var addrs []string
	for _, a := range pi.Addrs {
		addrs = append(addrs, a.String())
	}
	out["Addrs"] = addrs
	return json.Marshal(out)
}

func (pi *PeerInfo) UnmarshalJSON(b []byte) error {
	var data map[string]interface{}
	err := json.Unmarshal(b, &data)
	if err != nil {
		return err
	}
	pid, err := IDB58Decode(data["ID"].(string))
	if err != nil {
		return err
	}
	pi.ID = pid
	addrs, ok := data["Addrs"].([]interface{})
	if ok {
		for _, a := range addrs {
			pi.Addrs = append(pi.Addrs, ma.StringCast(a.(string)))
		}
	}
	return nil
}

// IDSlice for sorting peers
type IDSlice []ID

func (es IDSlice) Len() int           { return len(es) }
func (es IDSlice) Swap(i, j int)      { es[i], es[j] = es[j], es[i] }
func (es IDSlice) Less(i, j int) bool { return string(es[i]) < string(es[j]) }
<commit_msg>make PeerInfo loggable<commit_after>// package peer implements an object used to represent peers in the ipfs network.
package peer

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"strings"

	ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
	b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58"
	mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"

	ic "github.com/ipfs/go-libp2p/p2p/crypto"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
	logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
)

var log = logging.Logger("peer")

// ID represents the identity of a peer.
type ID string

// Pretty returns a b58-encoded string of the ID
func (id ID) Pretty() string {
	return IDB58Encode(id)
}

func (id ID) Loggable() map[string]interface{} {
	return map[string]interface{}{
		"peerID": id.Pretty(),
	}
}

// String prints out the peer.
//
// TODO(brian): ensure correctness at ID generation and
// enforce this by only exposing functions that generate
// IDs safely. Then any peer.ID type found in the
// codebase is known to be correct.
func (id ID) String() string {
	pid := id.Pretty()

	//All sha256 nodes start with Qm
	//We can skip the Qm to make the peer.ID more useful
	if strings.HasPrefix(pid, "gx/Qm") {
		pid = pid[2:]
	}

	maxRunes := 6
	if len(pid) < maxRunes {
		maxRunes = len(pid)
	}
	return fmt.Sprintf("<peer.ID %s>", pid[:maxRunes])
}

// MatchesPrivateKey tests whether this ID was derived from sk
func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool {
	return id.MatchesPublicKey(sk.GetPublic())
}

// MatchesPublicKey tests whether this ID was derived from pk
func (id ID) MatchesPublicKey(pk ic.PubKey) bool {
	oid, err := IDFromPublicKey(pk)
	if err != nil {
		return false
	}
	return oid == id
}

// IDFromString cast a string to ID type, and validate
// the id to make sure it is a multihash.
func IDFromString(s string) (ID, error) {
	if _, err := mh.Cast([]byte(s)); err != nil {
		return ID(""), err
	}
	return ID(s), nil
}

// IDFromBytes cast a string to ID type, and validate
// the id to make sure it is a multihash.
func IDFromBytes(b []byte) (ID, error) {
	if _, err := mh.Cast(b); err != nil {
		return ID(""), err
	}
	return ID(b), nil
}

// IDB58Decode returns a b58-decoded Peer
func IDB58Decode(s string) (ID, error) {
	m, err := mh.FromB58String(s)
	if err != nil {
		return "", err
	}
	return ID(m), err
}

// IDB58Encode returns b58-encoded string
func IDB58Encode(id ID) string {
	return b58.Encode([]byte(id))
}

// IDHexDecode returns a b58-decoded Peer
func IDHexDecode(s string) (ID, error) {
	m, err := mh.FromHexString(s)
	if err != nil {
		return "", err
	}
	return ID(m), err
}

// IDHexEncode returns b58-encoded string
func IDHexEncode(id ID) string {
	return hex.EncodeToString([]byte(id))
}

// IDFromPublicKey returns the Peer ID corresponding to pk
func IDFromPublicKey(pk ic.PubKey) (ID, error) {
	b, err := pk.Bytes()
	if err != nil {
		return "", err
	}
	hash := u.Hash(b)
	return ID(hash), nil
}

// IDFromPrivateKey returns the Peer ID corresponding to sk
func IDFromPrivateKey(sk ic.PrivKey) (ID, error) {
	return IDFromPublicKey(sk.GetPublic())
}

// Map maps a Peer ID to a struct.
type Set map[ID]struct{}

// PeerInfo is a small struct used to pass around a peer with
// a set of addresses (and later, keys?). This is not meant to be
// a complete view of the system, but rather to model updates to
// the peerstore. It is used by things like the routing system.
type PeerInfo struct {
	ID    ID
	Addrs []ma.Multiaddr
}

func (pi *PeerInfo) Loggable() map[string]interface{} {
	return map[string]interface{}{
		"peerID": pi.ID.Pretty(),
		"addrs":  pi.Addrs,
	}
}

func (pi *PeerInfo) MarshalJSON() ([]byte, error) {
	out := make(map[string]interface{})
	out["ID"] = IDB58Encode(pi.ID)
	var addrs []string
	for _, a := range pi.Addrs {
		addrs = append(addrs, a.String())
	}
	out["Addrs"] = addrs
	return json.Marshal(out)
}

func (pi *PeerInfo) UnmarshalJSON(b []byte) error {
	var data map[string]interface{}
	err := json.Unmarshal(b, &data)
	if err != nil {
		return err
	}
	pid, err := IDB58Decode(data["ID"].(string))
	if err != nil {
		return err
	}
	pi.ID = pid
	addrs, ok := data["Addrs"].([]interface{})
	if ok {
		for _, a := range addrs {
			pi.Addrs = append(pi.Addrs, ma.StringCast(a.(string)))
		}
	}
	return nil
}

// IDSlice for sorting peers
type IDSlice []ID

func (es IDSlice) Len() int           { return len(es) }
func (es IDSlice) Swap(i, j int)      { es[i], es[j] = es[j], es[i] }
func (es IDSlice) Less(i, j int) bool { return string(es[i]) < string(es[j]) }
<|endoftext|>


<commit_before>package main

type CallFrame struct {
	parent    *CallFrame
	var_table map[string]Object
	stack     []Object
	me        Object
}

type GobiesVM struct {
	instList       []Instruction
	callFrameStack []*CallFrame
	consts         map[string]*RObject
	symbols        map[string]int
}

func initVM() *GobiesVM {
	VM := &GobiesVM{}
	top := initCallFrame()
	VM.callFrameStack = append(VM.callFrameStack, top)
	VM.consts = make(map[string]*RObject)
	VM.initConsts()
	VM.symbols = make(map[string]int)
	top.me = initRKernel()
	return VM
}

func initCallFrame() *CallFrame {
	frame := &CallFrame{}
	frame.var_table = make(map[string]Object)
	return frame
}

func (VM *GobiesVM) initConsts() {
	VM.consts["RString"] = initRString()
	VM.consts["RFixnum"] = initRFixnum()
	VM.consts["RArray"] = initRArray()
	VM.consts["RHash"] = initRHash()
	VM.consts["IO"] = initRIO()
}

func (obj *RObject) methodLookup(method_name string) *RMethod {
	if val, ok := obj.methods[method_name]; ok {
		return val
	}
	if obj.class != nil {
		return obj.class.methodLookup(method_name)
	}
	return nil
}

func (currentCallFrame *CallFrame) variableLookup(var_name string) Object {
	if obj, ok := currentCallFrame.var_table[var_name]; ok {
		return obj
	}
	if currentCallFrame.parent != nil {
		return currentCallFrame.parent.variableLookup(var_name)
	}
	return nil
}

func (VM *GobiesVM) executeBytecode(instList []Instruction) {
	if instList == nil {
		instList = VM.instList
	}
	for _, v := range instList {
		currentCallFrame := VM.callFrameStack[len(VM.callFrameStack)-1]
		switch v.inst_type {
		case BC_PUTSELF:
			currentCallFrame.stack = append(currentCallFrame.stack, currentCallFrame.me)
		case BC_PUTNIL:
			currentCallFrame.stack = append(currentCallFrame.stack, nil)
		case BC_PUTOBJ:
			currentCallFrame.stack = append(currentCallFrame.stack, v.obj)
		case BC_PUTTRUE:
		case BC_PUTFALSE:
		case BC_SETLOCAL:
			top := currentCallFrame.stack[len(currentCallFrame.stack)-1]
			currentCallFrame.var_table[v.obj.(string)] = top
			currentCallFrame.stack = currentCallFrame.stack[0 : len(currentCallFrame.stack)-1]
		case BC_GETLOCAL:
			currentCallFrame.stack = append(currentCallFrame.stack, currentCallFrame.variableLookup(v.obj.(string)))
		case BC_SETGLOBAL:
		case BC_GETGLOBAL:
		case BC_SETSYMBOL:
		case BC_GETSYMBOL:
		case BC_SETCONST:
		case BC_GETCONST:
			currentCallFrame.stack = append(currentCallFrame.stack, VM.consts[v.obj.(string)])
		case BC_SETIVAR:
		case BC_GETIVAR:
		case BC_SETCVAR:
		case BC_GETCVAR:
		case BC_SEND:
			// fmt.Println(currentCallFrame.stack)
			argLists := currentCallFrame.stack[len(currentCallFrame.stack)-(v.argc+1):] // argc + 1 ensures inclusion of receiver
			currentCallFrame.stack = currentCallFrame.stack[:len(currentCallFrame.stack)-(v.argc+1)]
			recv := argLists[0].(*RObject)
			argLists = argLists[1:]
			return_val := recv.methodLookup(v.obj.(string)).gofunc(VM, recv, argLists)
			if return_val != nil {
				currentCallFrame.stack = append(currentCallFrame.stack, return_val)
			}
		case BC_JUMP:
		}
	}
}

func (VM *GobiesVM) executeBlock(block *RObject, args []*RObject) {
	// Create clean call frame
	currentCallFrame := initCallFrame()
	currentCallFrame.parent = VM.callFrameStack[len(VM.callFrameStack)-1]
	currentCallFrame.me = currentCallFrame.parent.me
	VM.callFrameStack = append(VM.callFrameStack, currentCallFrame)

	// Fill in arguments to current call frame
	if block.ivars["params"] != nil {
		params := block.ivars["params"].(*RObject).ivars["array"].([]*RObject)
		for i, v := range params {
			var_name := v.val.str
			currentCallFrame.var_table[var_name] = args[i]
		}
	}

	// Execute block definition
	VM.executeBytecode(block.methods["def"].def)

	// Pop temporary call frame
	VM.callFrameStack = VM.callFrameStack[:len(VM.callFrameStack)-1]
}
<commit_msg>Make objects which are local variable named instead of anonymous<commit_after>package main

type CallFrame struct {
	parent    *CallFrame
	var_table map[string]Object
	stack     []Object
	me        Object
}

type GobiesVM struct {
	instList       []Instruction
	callFrameStack []*CallFrame
	consts         map[string]*RObject
	symbols        map[string]int
}

func initVM() *GobiesVM {
	VM := &GobiesVM{}
	top := initCallFrame()
	VM.callFrameStack = append(VM.callFrameStack, top)
	VM.consts = make(map[string]*RObject)
	VM.initConsts()
	VM.symbols = make(map[string]int)
	top.me = initRKernel()
	return VM
}

func initCallFrame() *CallFrame {
	frame := &CallFrame{}
	frame.var_table = make(map[string]Object)
	return frame
}

func (VM *GobiesVM) initConsts() {
	VM.consts["RString"] = initRString()
	VM.consts["RFixnum"] = initRFixnum()
	VM.consts["RArray"] = initRArray()
	VM.consts["RHash"] = initRHash()
	VM.consts["IO"] = initRIO()
}

func (obj *RObject) methodLookup(method_name string) *RMethod {
	if val, ok := obj.methods[method_name]; ok {
		return val
	}
	if obj.class != nil {
		return obj.class.methodLookup(method_name)
	}
	return nil
}

func (currentCallFrame *CallFrame) variableLookup(var_name string) Object {
	if obj, ok := currentCallFrame.var_table[var_name]; ok {
		return obj
	}
	if currentCallFrame.parent != nil {
		return currentCallFrame.parent.variableLookup(var_name)
	}
	return nil
}

func (VM *GobiesVM) executeBytecode(instList []Instruction) {
	if instList == nil {
		instList = VM.instList
	}
	for _, v := range instList {
		currentCallFrame := VM.callFrameStack[len(VM.callFrameStack)-1]
		switch v.inst_type {
		case BC_PUTSELF:
			currentCallFrame.stack = append(currentCallFrame.stack, currentCallFrame.me)
		case BC_PUTNIL:
			currentCallFrame.stack = append(currentCallFrame.stack, nil)
		case BC_PUTOBJ:
			currentCallFrame.stack = append(currentCallFrame.stack, v.obj)
		case BC_PUTTRUE:
		case BC_PUTFALSE:
		case BC_SETLOCAL:
			top := currentCallFrame.stack[len(currentCallFrame.stack)-1]
			currentCallFrame.var_table[v.obj.(string)] = top
			top.(*RObject).name = v.obj.(string)                                               // Change object from anonymous to named
			currentCallFrame.stack = currentCallFrame.stack[0 : len(currentCallFrame.stack)-1] // Pop object from stack
		case BC_GETLOCAL:
			currentCallFrame.stack = append(currentCallFrame.stack, currentCallFrame.variableLookup(v.obj.(string)))
		case BC_SETGLOBAL:
		case BC_GETGLOBAL:
		case BC_SETSYMBOL:
		case BC_GETSYMBOL:
		case BC_SETCONST:
		case BC_GETCONST:
			currentCallFrame.stack = append(currentCallFrame.stack, VM.consts[v.obj.(string)])
		case BC_SETIVAR:
		case BC_GETIVAR:
		case BC_SETCVAR:
		case BC_GETCVAR:
		case BC_SEND:
			// fmt.Println(currentCallFrame.stack)
			argLists := currentCallFrame.stack[len(currentCallFrame.stack)-(v.argc+1):] // argc + 1 ensures inclusion of receiver
			currentCallFrame.stack = currentCallFrame.stack[:len(currentCallFrame.stack)-(v.argc+1)]
			recv := argLists[0].(*RObject)
			argLists = argLists[1:]
			return_val := recv.methodLookup(v.obj.(string)).gofunc(VM, recv, argLists)
			if return_val != nil {
				currentCallFrame.stack = append(currentCallFrame.stack, return_val)
			}
		case BC_JUMP:
		}
	}
}

func (VM *GobiesVM) executeBlock(block *RObject, args []*RObject) {
	// Create clean call frame
	currentCallFrame := initCallFrame()
	currentCallFrame.parent = VM.callFrameStack[len(VM.callFrameStack)-1]
	currentCallFrame.me = currentCallFrame.parent.me
	VM.callFrameStack = append(VM.callFrameStack, currentCallFrame)

	// Fill in arguments to current call frame
	if block.ivars["params"] != nil {
		params := block.ivars["params"].(*RObject).ivars["array"].([]*RObject)
		for i, v := range params {
			var_name := v.val.str
			currentCallFrame.var_table[var_name] = args[i]
		}
	}

	// Execute block definition
	VM.executeBytecode(block.methods["def"].def)

	// Pop temporary call frame
	VM.callFrameStack = VM.callFrameStack[:len(VM.callFrameStack)-1]
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"
)

const (
	StaticPollNum  = 3
	StaticPollTime = 500
)

var static State

type SyncRequest struct {
	Added   map[string]File
	Changed map[string]File
	Unmod   map[string]File
}

func NewSyncRequest() *SyncRequest {
	added := make(map[string]File)
	changed := make(map[string]File)
	unmod := make(map[string]File)
	return &SyncRequest{Changed: changed, Unmod: unmod, Added: added}
}

type SyncResponse struct {
	Update map[string]File
	Delete []string
}

func Sync(w http.ResponseWriter, r *http.Request) {
	syncReq := NewSyncRequest()
	err := json.NewDecoder(r.Body).Decode(&syncReq)
	if err != nil {
		log.Fatal(err)
	}

	resp := SyncPoll(syncReq)

	js, err := json.Marshal(resp)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func SyncPoll(syncReq *SyncRequest) SyncResponse {
	update := make(map[string]File)
	del := make([]string, 0)

	for key, clientFile := range syncReq.Added {
		serverFile, prs := static.Files[key]
		if !prs {
			static.Files[key] = clientFile
		} else {
			update[key] = serverFile
		}
	}

	for key, clientFile := range syncReq.Changed {
		static.Files[key] = clientFile
	}

	for i := 0; i < StaticPollNum; i++ {
		for key, clientFile := range syncReq.Unmod {
			serverFile, prs := static.Files[key]
			if prs && serverFile.Hash != clientFile.Hash {
				update[key] = serverFile
			} else if !prs {
				del = append(del, key)
			}
		}

		for key, serverFile := range static.Files {
			_, prs1 := syncReq.Added[key]
			_, prs2 := syncReq.Changed[key]
			_, prs3 := syncReq.Unmod[key]
			if !(prs1 || prs2 || prs3) {
				update[key] = serverFile
			}
		}

		if len(update) > 0 || len(del) > 0 {
			break
		} else {
			time.Sleep(StaticPollTime * time.Millisecond)
		}
	}

	return SyncResponse{Update: update, Delete: del}
}

type ReadRequest struct {
	Key    string
	Target File
}

func Read(w http.ResponseWriter, r *http.Request) {
	var readReq ReadRequest
	err := json.NewDecoder(r.Body).Decode(&readReq)
	if err != nil {
		fmt.Println("error in read")
		log.Fatal(err)
	}

	resp := ReadPoll(readReq)

	js, err := json.Marshal(resp)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func ReadPoll(readReq ReadRequest) File {
	var target File
	for i := 0; i < StaticPollNum; i++ {
		liveFile, livePrs := static.Files[readReq.Key]
		if livePrs {
			target = liveFile
			break
		}
		serverFile, prs := static.Files[readReq.Key]
		target = serverFile
		if prs && serverFile.Hash != readReq.Target.Hash {
			break
		}
		time.Sleep(StaticPollTime * time.Millisecond)
	}
	return target
}
<commit_msg>static to live bug<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"
)

const (
	StaticPollNum  = 3
	StaticPollTime = 500
)

var static State

type SyncRequest struct {
	Added   map[string]File
	Changed map[string]File
	Unmod   map[string]File
}

func NewSyncRequest() *SyncRequest {
	added := make(map[string]File)
	changed := make(map[string]File)
	unmod := make(map[string]File)
	return &SyncRequest{Changed: changed, Unmod: unmod, Added: added}
}

type SyncResponse struct {
	Update map[string]File
	Delete []string
}

func Sync(w http.ResponseWriter, r *http.Request) {
	syncReq := NewSyncRequest()
	err := json.NewDecoder(r.Body).Decode(&syncReq)
	if err != nil {
		log.Fatal(err)
	}

	resp := SyncPoll(syncReq)

	js, err := json.Marshal(resp)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func SyncPoll(syncReq *SyncRequest) SyncResponse {
	update := make(map[string]File)
	del := make([]string, 0)

	for key, clientFile := range syncReq.Added {
		serverFile, prs := static.Files[key]
		if !prs {
			static.Files[key] = clientFile
		} else {
			update[key] = serverFile
		}
	}

	for key, clientFile := range syncReq.Changed {
		static.Files[key] = clientFile
	}

	for i := 0; i < StaticPollNum; i++ {
		for key, clientFile := range syncReq.Unmod {
			serverFile, prs := static.Files[key]
			if prs && serverFile.Hash != clientFile.Hash {
				update[key] = serverFile
			} else if !prs {
				del = append(del, key)
			}
		}

		for key, serverFile := range static.Files {
			_, prs1 := syncReq.Added[key]
			_, prs2 := syncReq.Changed[key]
			_, prs3 := syncReq.Unmod[key]
			if !(prs1 || prs2 || prs3) {
				update[key] = serverFile
			}
		}

		if len(update) > 0 || len(del) > 0 {
			break
		} else {
			time.Sleep(StaticPollTime * time.Millisecond)
		}
	}

	return SyncResponse{Update: update, Delete: del}
}

type ReadRequest struct {
	Key    string
	Target File
}

func Read(w http.ResponseWriter, r *http.Request) {
	var readReq ReadRequest
	err := json.NewDecoder(r.Body).Decode(&readReq)
	if err != nil {
		fmt.Println("error in read")
		log.Fatal(err)
	}

	resp := ReadPoll(readReq)

	js, err := json.Marshal(resp)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func ReadPoll(readReq ReadRequest) File {
	var target File
	for i := 0; i < StaticPollNum; i++ {
		liveFile, livePrs := live.Files[readReq.Key]
		if livePrs {
			target = liveFile
			break
		}
		serverFile, prs := static.Files[readReq.Key]
		target = serverFile
		if prs && serverFile.Hash != readReq.Target.Hash {
			break
		}
		time.Sleep(StaticPollTime * time.Millisecond)
	}
	return target
}
<|endoftext|>