<commit_before>package main

import (
	"container/list"
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"sync"
	"unicode/utf8"
)

// Weight is a similarity weight for a mora.
type Weight struct {
	consonant, vowel float64
}

// Rapper makes nice lyrics.
type Rapper struct {
	weights   []Weight
	maxWeight float64
	thresh    float64
	tryNum    int
}

// DefaultRapper returns default rapper
func DefaultRapper() (*Rapper, error) {
	weights, err := parseWeights()
	if err != nil {
		return nil, fmt.Errorf("cannot create rapper: weights: %w", err)
	}
	thresh, err := strconv.ParseFloat(os.Getenv("THRESH"), 64)
	if err != nil {
		return nil, fmt.Errorf("cannot create rapper: thresh: %w", err)
	}
	tryNum, err := strconv.Atoi(os.Getenv("TRY_NUM"))
	if err != nil {
		return nil, fmt.Errorf("cannot create rapper: tryNum: %w", err)
	}

	var maxWeight float64
	for _, weight := range weights {
		maxWeight += weight.consonant
		maxWeight += weight.vowel
	}

	return &Rapper{
		weights:   weights,
		maxWeight: maxWeight,
		thresh:    thresh,
		tryNum:    tryNum,
	}, nil
}

func parseWeights() (weights []Weight, err error) {
	for _, str := range strings.Split(os.Getenv("CONSONANT_WEIGHTS"), ",") {
		var val float64
		val, err = strconv.ParseFloat(str, 64)
		if err != nil {
			return
		}
		weights = append(weights, Weight{consonant: val})
	}
	for i, str := range strings.Split(os.Getenv("VOWEL_WEIGHTS"), ",") {
		var val float64
		val, err = strconv.ParseFloat(str, 64)
		if err != nil {
			return
		}
		if len(weights) < i+1 {
			err = errors.New("CONSONANT_WEIGHTS len and VOWEL_WEIGHTS are not equal")
			return
		}
		weights[i].vowel = val
	}
	return
}

// LaunchRapServer launches multi RapServer.
func (rap *Rapper) LaunchRapServer(chLyric chan<- Lyric, chSentence <-chan Sentence) error {
	for _, str := range strings.Split(os.Getenv("LYRIC_LINE_NUM"), ",") {
		val, err := strconv.Atoi(str)
		if err != nil {
			return fmt.Errorf("invalid LYRIC_LINE_NUM: %w", err)
		}

		go rap.RapServer(chLyric, chSentence, val)
	}

	return nil
}

// RapServer make lyrics forever.
func (rap *Rapper) RapServer(chLyric chan<- Lyric, chSentence <-chan Sentence, lineNum int) {
mainLoop:
	for {
		lyric := []Sentence{<-chSentence}
	lyricLoop:
		for len(lyric) < lineNum {
			for try := 0; try < rap.tryNum; try++ {
				// find pronounceable sentence
				var sentence Sentence
				for {
					sentence = <-chSentence
					if isValidRapSentence(sentence) {
						break
					}
				}

				// judge the lyric is valid
				if rap.IsAppendable(lyric, sentence) {
					lyric = append(lyric, sentence)
					continue lyricLoop
				}
			}
			continue mainLoop
		}
		chLyric <- lyric
	}
}

// isValidRapSentence returns whether the sentence is valid for lyric.
func isValidRapSentence(sentence Sentence) bool {
	return true && // for easy comment out
		sentence.IsPronounceable() &&
		sentence[len(sentence)-1].ConjugatedForm2 != "連用タ接続" && // 「なかっ」
		sentence[len(sentence)-1].ConjugatedForm2 != "連用形" && // 「（ありがとう）ござい」
		sentence[len(sentence)-1].ConjugatedForm2 != "未然形" && // 「い（ない）」
		sentence[len(sentence)-1].PartOfSpeech != "助詞" && // 「〇〇の」
		(sentence[len(sentence)-1].PartOfSpeechSection1 != "接尾" ||
			sentence[len(sentence)-1].PartOfSpeechSection2 != "人名") && // 「〇〇さん」
		true // for easy comment out
}

// IsAppendable returns if sentence is suitable for lyric
func (rap *Rapper) IsAppendable(lyric Lyric, sentence Sentence) bool {
	// rhyming
	if rap.Distance(lyric[len(lyric)-1], sentence) < rap.thresh {
		return false
	}

	// similarity
	length := utf8.RuneCountInString(sentence.String())
	for _, line := range lyric {
		if l := utf8.RuneCountInString(line.String()); l < length {
			length = l
		}
	}
	sentenceRune := []rune(sentence.String())
	sentenceSuffix := string(sentenceRune[len(sentenceRune)-length:])
	for _, line := range lyric {
		lineRune := []rune(line.String())
		lineSuffix := string(lineRune[len(lineRune)-length:])
		if lineSuffix == sentenceSuffix {
			return false
		}
	}

	return true
}

// Distance is a similarity of two sentence.
func (rap *Rapper) Distance(sen1, sen2 Sentence) float64 {
	morae1, ok := sen1.Morae()
	if !ok {
		return 0.0
	}
	morae2, ok := sen2.Morae()
	if !ok {
		return 0.0
	}

	minLength := len(rap.weights)
	if len(morae1) < minLength {
		minLength = len(morae1)
	}
	if len(morae2) < minLength {
		minLength = len(morae2)
	}

	var sum float64
	for i := 0; i < minLength; i++ {
		weight := rap.weights[len(rap.weights)-1-i]
		mora1 := morae1[len(morae1)-1-i]
		mora2 := morae2[len(morae2)-1-i]

		if mora1.consonant == mora2.consonant {
			sum += weight.consonant
		}
		if mora1.vowel == mora2.vowel {
			sum += weight.vowel
		}
	}

	return sum / rap.maxWeight
}

// LyricStorage stores rhymes.
type LyricStorage struct {
	maxLen int
	length int
	mu     *sync.Mutex
	lyrics *list.List
}

// NewLyricStorage returns new LyricStorage.
func NewLyricStorage(maxLen int) *LyricStorage {
	return &LyricStorage{
		maxLen: maxLen,
		mu:     new(sync.Mutex),
		lyrics: list.New(),
	}
}

// PushServer receive lyrics forever.
func (ls *LyricStorage) PushServer(chLyric <-chan Lyric) {
	for lyric := range chLyric {
		ls.Push(lyric)
	}
}

// Push adds lyric.
func (ls *LyricStorage) Push(lyric Lyric) {
	ls.mu.Lock()
	defer ls.mu.Unlock()

	ls.lyrics.PushFront(lyric)
	ls.length++
	if ls.length > ls.maxLen {
		ls.lyrics.Remove(ls.lyrics.Back())
		ls.length--
	}
}

// Pop returns newest lyric
func (ls *LyricStorage) Pop() Lyric {
	ls.mu.Lock()
	defer ls.mu.Unlock()

	if ls.length == 0 {
		return nil
	}

	lyric := ls.lyrics.Front().Value.(Lyric)
	ls.lyrics.Remove(ls.lyrics.Front())
	ls.length--
	return lyric
}

// ContinueLyric returns most suitable lyric.
func (ls *LyricStorage) ContinueLyric(rapper *Rapper, sentence Sentence) Lyric {
	ls.mu.Lock()
	defer ls.mu.Unlock()

	if ls.length == 0 {
		return nil
	}

	most := ls.lyrics.Front()
	distance := rapper.Distance(sentence, most.Value.(Lyric)[0])
	for e := ls.lyrics.Front().Next(); e != nil; e = e.Next() {
		if d := rapper.Distance(sentence, e.Value.(Lyric)[0]); d > distance {
			most = e
			distance = d
		}
	}
	ls.lyrics.Remove(most)
	ls.length--
	return most.Value.(Lyric)
}
<commit_msg>末尾1字が同じだったらlyricに含めないことにした<commit_after>package main

import (
	"container/list"
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"sync"
)

// Weight is a similarity weight for a mora.
type Weight struct {
	consonant, vowel float64
}

// Rapper makes nice lyrics.
type Rapper struct {
	weights   []Weight
	maxWeight float64
	thresh    float64
	tryNum    int
}

// DefaultRapper returns default rapper
func DefaultRapper() (*Rapper, error) {
	weights, err := parseWeights()
	if err != nil {
		return nil, fmt.Errorf("cannot create rapper: weights: %w", err)
	}
	thresh, err := strconv.ParseFloat(os.Getenv("THRESH"), 64)
	if err != nil {
		return nil, fmt.Errorf("cannot create rapper: thresh: %w", err)
	}
	tryNum, err := strconv.Atoi(os.Getenv("TRY_NUM"))
	if err != nil {
		return nil, fmt.Errorf("cannot create rapper: tryNum: %w", err)
	}

	var maxWeight float64
	for _, weight := range weights {
		maxWeight += weight.consonant
		maxWeight += weight.vowel
	}

	return &Rapper{
		weights:   weights,
		maxWeight: maxWeight,
		thresh:    thresh,
		tryNum:    tryNum,
	}, nil
}

func parseWeights() (weights []Weight, err error) {
	for _, str := range strings.Split(os.Getenv("CONSONANT_WEIGHTS"), ",") {
		var val float64
		val, err = strconv.ParseFloat(str, 64)
		if err != nil {
			return
		}
		weights = append(weights, Weight{consonant: val})
	}
	for i, str := range strings.Split(os.Getenv("VOWEL_WEIGHTS"), ",") {
		var val float64
		val, err = strconv.ParseFloat(str, 64)
		if err != nil {
			return
		}
		if len(weights) < i+1 {
			err = errors.New("CONSONANT_WEIGHTS len and VOWEL_WEIGHTS are not equal")
			return
		}
		weights[i].vowel = val
	}
	return
}

// LaunchRapServer launches multi RapServer.
func (rap *Rapper) LaunchRapServer(chLyric chan<- Lyric, chSentence <-chan Sentence) error {
	for _, str := range strings.Split(os.Getenv("LYRIC_LINE_NUM"), ",") {
		val, err := strconv.Atoi(str)
		if err != nil {
			return fmt.Errorf("invalid LYRIC_LINE_NUM: %w", err)
		}

		go rap.RapServer(chLyric, chSentence, val)
	}

	return nil
}

// RapServer make lyrics forever.
func (rap *Rapper) RapServer(chLyric chan<- Lyric, chSentence <-chan Sentence, lineNum int) {
mainLoop:
	for {
		lyric := []Sentence{<-chSentence}
	lyricLoop:
		for len(lyric) < lineNum {
			for try := 0; try < rap.tryNum; try++ {
				// find pronounceable sentence
				var sentence Sentence
				for {
					sentence = <-chSentence
					if isValidRapSentence(sentence) {
						break
					}
				}

				// judge the lyric is valid
				if rap.IsAppendable(lyric, sentence) {
					lyric = append(lyric, sentence)
					continue lyricLoop
				}
			}
			continue mainLoop
		}
		chLyric <- lyric
	}
}

// isValidRapSentence returns whether the sentence is valid for lyric.
func isValidRapSentence(sentence Sentence) bool {
	return true && // for easy comment out
		sentence.IsPronounceable() &&
		sentence[len(sentence)-1].ConjugatedForm2 != "連用タ接続" && // 「なかっ」
		sentence[len(sentence)-1].ConjugatedForm2 != "連用形" && // 「（ありがとう）ござい」
		sentence[len(sentence)-1].ConjugatedForm2 != "未然形" && // 「い（ない）」
		sentence[len(sentence)-1].PartOfSpeech != "助詞" && // 「〇〇の」
		(sentence[len(sentence)-1].PartOfSpeechSection1 != "接尾" ||
			sentence[len(sentence)-1].PartOfSpeechSection2 != "人名") && // 「〇〇さん」
		true // for easy comment out
}

// IsAppendable returns if sentence is suitable for lyric
func (rap *Rapper) IsAppendable(lyric Lyric, sentence Sentence) bool {
	// rhyming
	if rap.Distance(lyric[len(lyric)-1], sentence) < rap.thresh {
		return false
	}

	// similarity
	// If sentences ends same character, return false.
	lastSentenceRune := []rune(lyric[len(lyric)-1].String())
	newSentenceRune := []rune(sentence.String())
	if lastSentenceRune[len(lastSentenceRune)-1] == newSentenceRune[len(newSentenceRune)-1] {
		return false
	}

	return true
}

// Distance is a similarity of two sentence.
func (rap *Rapper) Distance(sen1, sen2 Sentence) float64 {
	morae1, ok := sen1.Morae()
	if !ok {
		return 0.0
	}
	morae2, ok := sen2.Morae()
	if !ok {
		return 0.0
	}

	minLength := len(rap.weights)
	if len(morae1) < minLength {
		minLength = len(morae1)
	}
	if len(morae2) < minLength {
		minLength = len(morae2)
	}

	var sum float64
	for i := 0; i < minLength; i++ {
		weight := rap.weights[len(rap.weights)-1-i]
		mora1 := morae1[len(morae1)-1-i]
		mora2 := morae2[len(morae2)-1-i]

		if mora1.consonant == mora2.consonant {
			sum += weight.consonant
		}
		if mora1.vowel == mora2.vowel {
			sum += weight.vowel
		}
	}

	return sum / rap.maxWeight
}

// LyricStorage stores rhymes.
type LyricStorage struct {
	maxLen int
	length int
	mu     *sync.Mutex
	lyrics *list.List
}

// NewLyricStorage returns new LyricStorage.
func NewLyricStorage(maxLen int) *LyricStorage {
	return &LyricStorage{
		maxLen: maxLen,
		mu:     new(sync.Mutex),
		lyrics: list.New(),
	}
}

// PushServer receive lyrics forever.
func (ls *LyricStorage) PushServer(chLyric <-chan Lyric) {
	for lyric := range chLyric {
		ls.Push(lyric)
	}
}

// Push adds lyric.
func (ls *LyricStorage) Push(lyric Lyric) {
	ls.mu.Lock()
	defer ls.mu.Unlock()

	ls.lyrics.PushFront(lyric)
	ls.length++
	if ls.length > ls.maxLen {
		ls.lyrics.Remove(ls.lyrics.Back())
		ls.length--
	}
}

// Pop returns newest lyric
func (ls *LyricStorage) Pop() Lyric {
	ls.mu.Lock()
	defer ls.mu.Unlock()

	if ls.length == 0 {
		return nil
	}

	lyric := ls.lyrics.Front().Value.(Lyric)
	ls.lyrics.Remove(ls.lyrics.Front())
	ls.length--
	return lyric
}

// ContinueLyric returns most suitable lyric.
func (ls *LyricStorage) ContinueLyric(rapper *Rapper, sentence Sentence) Lyric {
	ls.mu.Lock()
	defer ls.mu.Unlock()

	if ls.length == 0 {
		return nil
	}

	most := ls.lyrics.Front()
	distance := rapper.Distance(sentence, most.Value.(Lyric)[0])
	for e := ls.lyrics.Front().Next(); e != nil; e = e.Next() {
		if d := rapper.Distance(sentence, e.Value.(Lyric)[0]); d > distance {
			most = e
			distance = d
		}
	}
	ls.lyrics.Remove(most)
	ls.length--
	return most.Value.(Lyric)
}
<|endoftext|>


<commit_before>package gweb

import (
	"encoding/json"
	"log"
	"net/http"
	"strings"

	. "github.com/eynstudio/gobreak"
)

const (
	GET  = "GET"
	POST = "POST"
	PUT  = "PUT"
	DEL  = "DELETE"
)

type Req struct {
	*http.Request
	*urlParts
	Token string
}

func NewReq(r *http.Request) *Req {
	rr := &Req{Request: r}
	rr.parseToken()
	rr.urlParts = newUrlParts(rr.Url())
	return rr
}

func (p *Req) parseToken() {
	if authHeader := p.Header.Get("Authorization"); authHeader == "" {
		return
	} else if tokens := strings.Split(authHeader, " "); len(tokens) != 2 {
		return
	} else {
		p.Token = tokens[1]
	}
}

func (p *Req) Url() string     { return p.URL.Path }
func (p *Req) HasToken() bool  { return len(p.Token) > 0 }
func (p *Req) JMethod() string { return p.Header.Get("jBreak-Method") }

func (p *Req) JsonBody(m T) bool {
	if p.IsJsonContent() && p.Body != nil {
		defer p.Body.Close()
		if err := json.NewDecoder(p.Body).Decode(&m); err != nil {
			log.Println(err)
			return false
		}
		return true
	}
	return false
}

func (p *Req) IsJsonContent() bool {
	return strings.Contains(p.Header.Get("Content-Type"), "application/json")
}
func (p *Req) IsAcceptJson() bool { return strings.Contains(p.Header.Get("Accept"), "application/json") }

type urlPart struct {
	path string
}

type urlParts struct {
	curIdx int
	parts  []*urlPart
}

func newUrlParts(path string) *urlParts {
	m := &urlParts{}
	m.parseParts(path)
	return m
}

func (p *urlParts) parseParts(path string) {
	parts := strings.Split(path, "/")
	for _, it := range parts {
		p.parts = append(p.parts, &urlPart{it})
	}
}
func (p *urlParts) moveNextPart()     { p.curIdx += 1 }
func (p *urlParts) hasNextPart() bool { return p.curIdx < len(p.parts)-1 }
func (p *urlParts) CurPart() *urlPart { return p.parts[p.curIdx] }
func (p *urlParts) NextPart() *urlPart {
	if p.hasNextPart() {
		return p.parts[p.curIdx+1]
	}
	return nil
}
<commit_msg>update<commit_after>package gweb

import (
	"encoding/json"
	"log"
	"net/http"
	"strings"

	. "github.com/eynstudio/gobreak"
	"github.com/eynstudio/gobreak/db/filter"
)

const (
	GET  = "GET"
	POST = "POST"
	PUT  = "PUT"
	DEL  = "DELETE"
)

type Req struct {
	*http.Request
	*urlParts
	Token string
}

func NewReq(r *http.Request) *Req {
	rr := &Req{Request: r}
	rr.parseToken()
	rr.urlParts = newUrlParts(rr.Url())
	return rr
}

func (p *Req) parseToken() {
	if authHeader := p.Header.Get("Authorization"); authHeader == "" {
		return
	} else if tokens := strings.Split(authHeader, " "); len(tokens) != 2 {
		return
	} else {
		p.Token = tokens[1]
	}
}

func (p *Req) Url() string     { return p.URL.Path }
func (p *Req) HasToken() bool  { return len(p.Token) > 0 }
func (p *Req) JMethod() string { return p.Header.Get("jBreak-Method") }
func (p *Req) IsJPage() bool   { return p.JMethod() == "Page" }
func (p *Req) IsJList() bool   { return p.JMethod() == "List" }
func (p *Req) JPage() *filter.PageFilter {
	var pf filter.PageFilter
	if p.IsJsonContent() && p.IsJPage() && p.JsonBody(&pf) {
		return &pf
	}
	return nil
}

func (p *Req) JsonBody(m T) bool {
	if p.IsJsonContent() && p.Body != nil {
		defer p.Body.Close()
		if err := json.NewDecoder(p.Body).Decode(&m); err != nil {
			log.Println(err)
			return false
		}
		return true
	}
	return false
}

func (p *Req) IsJsonContent() bool {
	return strings.Contains(p.Header.Get("Content-Type"), "application/json")
}
func (p *Req) IsAcceptJson() bool { return strings.Contains(p.Header.Get("Accept"), "application/json") }

type urlPart struct {
	path string
}

type urlParts struct {
	curIdx int
	parts  []*urlPart
}

func newUrlParts(path string) *urlParts {
	m := &urlParts{}
	m.parseParts(path)
	return m
}

func (p *urlParts) parseParts(path string) {
	parts := strings.Split(path, "/")
	for _, it := range parts {
		p.parts = append(p.parts, &urlPart{it})
	}
}
func (p *urlParts) moveNextPart()     { p.curIdx += 1 }
func (p *urlParts) hasNextPart() bool { return p.curIdx < len(p.parts)-1 }
func (p *urlParts) CurPart() *urlPart { return p.parts[p.curIdx] }
func (p *urlParts) NextPart() *urlPart {
	if p.hasNextPart() {
		return p.parts[p.curIdx+1]
	}
	return nil
}
<|endoftext|>


<commit_before>package req

const (
	hdrUserAgentKey   = "User-Agent"
	hdrUserAgentValue = "req/v2 (https://github.com/imroc/req)"
	hdrContentTypeKey = "Content-Type"
	plainTextType     = "text/plain; charset=utf-8"
	jsonContentType   = "application/json; charset=utf-8"
	xmlContentType    = "text/xml; charset=utf-8"
	formContentType   = "application/x-www-form-urlencoded"
)
<commit_msg>update default UserAgent to v3<commit_after>package req

const (
	hdrUserAgentKey   = "User-Agent"
	hdrUserAgentValue = "req/v3 (https://github.com/imroc/req)"
	hdrContentTypeKey = "Content-Type"
	plainTextType     = "text/plain; charset=utf-8"
	jsonContentType   = "application/json; charset=utf-8"
	xmlContentType    = "text/xml; charset=utf-8"
	formContentType   = "application/x-www-form-urlencoded"
)
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"log"
	"net"
)

func main() {
	ln, err := net.Listen("tcp", ":5901")
	if err != nil {
		log.Fatal(err)
	}
	for {
		c, err := ln.Accept()
		if err != nil {
			log.Fatal(err)
		}
		go handle(c)
	}
}

const (
	v3           = "RFB 003.003\n"
	v7           = "RFB 003.007\n"
	v8           = "RFB 003.008\n"
	authNone     = 1
	statusOK     = 0
	statusFailed = 1
)

func handle(c net.Conn) {
	defer c.Close()
	defer func() {
		e := recover()
		if e != nil {
			log.Printf("Client disconnect: %v", e)
		}
	}()

	br := bufio.NewReader(c)
	bw := bufio.NewWriter(c)

	readByte := func(which string) byte {
		b, err := br.ReadByte()
		if err != nil {
			panic(fmt.Sprintf("Error reading client byte for %q: %v", which, err))
		}
		return b
	}
	w := func(v interface{}) {
		binary.Write(bw, binary.BigEndian, v)
	}

	bw.WriteString("RFB 003.008\n")
	bw.Flush()
	sl, err := br.ReadSlice('\n')
	if err != nil {
		log.Printf("reading client protocol version: %v", err)
		return
	}
	ver := string(sl)
	log.Printf("client wants: %q", ver)
	switch ver {
	case v3, v7, v8: // cool.
	default:
		panic(fmt.Sprintf("bogus client-requested security type %q", ver))
	}

	// Auth
	if ver >= v7 {
		// Just 1 auth type supported: 1 (no auth)
		bw.WriteString("\x01\x01")
		bw.Flush()
		wanted := readByte("6.1.2:client requested security-type")
		if wanted != authNone {
			log.Printf("client wanted auth type %d, not None", int(wanted))
			return
		}
	} else {
		// Old way. Just tell client we're doing no auth.
		w(uint32(authNone))
		bw.Flush()
	}

	if ver >= v8 {
		// 6.1.3. SecurityResult
		w(uint32(statusOK))
		bw.Flush()
	}

	log.Printf("reading client init")

	// ClientInit
	wantShared := readByte("shared-flag") != 0
	_ = wantShared

	// 6.3.2. ServerInit
	width, height := 1024, 768
	w(uint16(width))
	w(uint16(height))
	w(uint8(32))   // bits-per-pixel
	w(uint8(32))   // depth
	w(uint8(1))    // big-endian-flag
	w(uint8(1))    // true-colour-flag
	w(uint16(255)) // red-max
	w(uint16(255)) // green-max
	w(uint16(255)) // blue-max
	w(uint8(16))   // red-shift
	w(uint8(8))    // green-shift
	w(uint8(0))    // blue-shift
	w(uint8(0))    // pad1
	w(uint8(0))    // pad2
	w(uint8(0))    // pad3
	bw.Flush()

	serverName := "rfb-go"
	w(int32(len(serverName)))
	bw.WriteString(serverName)
	bw.Flush()

	log.Printf("TODO")
	select {}
}
<commit_msg>SetEncodings<commit_after>package main

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"log"
	"net"
)

func main() {
	ln, err := net.Listen("tcp", ":5901")
	if err != nil {
		log.Fatal(err)
	}
	for {
		c, err := ln.Accept()
		if err != nil {
			log.Fatal(err)
		}
		conn := &Conn{
			c:  c,
			br: bufio.NewReader(c),
			bw: bufio.NewWriter(c),
		}
		go conn.serve()
	}
}

const (
	v3              = "RFB 003.003\n"
	v7              = "RFB 003.007\n"
	v8              = "RFB 003.008\n"
	authNone        = 1
	statusOK        = 0
	statusFailed    = 1
	cmdSetEncodings = 2
)

type Conn struct {
	c  net.Conn
	br *bufio.Reader
	bw *bufio.Writer
}

func (c *Conn) readByte(what string) byte {
	b, err := c.br.ReadByte()
	if err != nil {
		c.failf("reading client byte for %q: %v", what, err)
	}
	return b
}

func (c *Conn) read(what string, v interface{}) {
	err := binary.Read(c.br, binary.BigEndian, v)
	if err != nil {
		c.failf("reading from client into %T for %q: %v", v, what, err)
	}
}

func (c *Conn) w(v interface{}) {
	binary.Write(c.bw, binary.BigEndian, v)
}

func (c *Conn) flush() {
	c.bw.Flush()
}

func (c *Conn) failf(format string, args ...interface{}) {
	panic(fmt.Sprintf(format, args...))
}

func (c *Conn) serve() {
	defer c.c.Close()
	defer func() {
		e := recover()
		if e != nil {
			log.Printf("Client disconnect: %v", e)
		}
	}()

	c.bw.WriteString("RFB 003.008\n")
	c.flush()
	sl, err := c.br.ReadSlice('\n')
	if err != nil {
		c.failf("reading client protocol version: %v", err)
	}
	ver := string(sl)
	log.Printf("client wants: %q", ver)
	switch ver {
	case v3, v7, v8: // cool.
	default:
		c.failf("bogus client-requested security type %q", ver)
	}

	// Auth
	if ver >= v7 {
		// Just 1 auth type supported: 1 (no auth)
		c.bw.WriteString("\x01\x01")
		c.flush()
		wanted := c.readByte("6.1.2:client requested security-type")
		if wanted != authNone {
			c.failf("client wanted auth type %d, not None", int(wanted))
		}
	} else {
		// Old way. Just tell client we're doing no auth.
		c.w(uint32(authNone))
		c.flush()
	}

	if ver >= v8 {
		// 6.1.3. SecurityResult
		c.w(uint32(statusOK))
		c.flush()
	}

	log.Printf("reading client init")

	// ClientInit
	wantShared := c.readByte("shared-flag") != 0
	_ = wantShared

	// 6.3.2. ServerInit
	width, height := 1024, 768
	c.w(uint16(width))
	c.w(uint16(height))
	c.w(uint8(32))   // bits-per-pixel
	c.w(uint8(32))   // depth
	c.w(uint8(1))    // big-endian-flag
	c.w(uint8(1))    // true-colour-flag
	c.w(uint16(255)) // red-max
	c.w(uint16(255)) // green-max
	c.w(uint16(255)) // blue-max
	c.w(uint8(16))   // red-shift
	c.w(uint8(8))    // green-shift
	c.w(uint8(0))    // blue-shift
	c.w(uint8(0))    // pad1
	c.w(uint8(0))    // pad2
	c.w(uint8(0))    // pad3
	serverName := "rfb-go"
	c.w(int32(len(serverName)))
	c.bw.WriteString(serverName)
	c.flush()

	for {
		cmd := c.readByte("6.4:client-server-packet-type")
		log.Printf("got command type %d from client", int(cmd))
		switch cmd {
		case cmdSetEncodings:
			c.handleSetEncodings()
		default:
			c.failf("unsupported command type %d from client", int(cmd))
		}
	}
}

func (c *Conn) handleSetEncodings() {
	c.readByte("6.4.2:padding")
	var numEncodings uint16
	c.read("6.4.2:number-of-encodings", &numEncodings)
	var encType []int32
	for i := 0; i < int(numEncodings); i++ {
		var t int32
		c.read("encoding-type", &t)
		encType = append(encType, t)
	}
	log.Printf("Client encodings: %#v", encType)
}
<|endoftext|>


<commit_before>package main

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

var cmdRun = &Command{
	Run:   runRun,
	Usage: "run [-e env] [-c concurrency] [-p port]",
	Short: "Run a one-off command",
	Long: `
Run a one-off command

Examples:

  forego run bin/migrate
`,
}

func init() {
	cmdRun.Flag.StringVar(&flagEnv, "e", ".env", "env")
}

func runRun(cmd *Command, args []string) {
	if flagEnv == "" {
		root, _ := os.Getwd()
		flagEnv = filepath.Join(root, ".env")
	}

	env, err := ReadEnv(flagEnv)
	handleError(err)

	ps := NewProcess(strings.Join(args, " "), env)
	ps.Interactive = true
	ps.Stdin = os.Stdin
	ps.Stdout = os.Stdout
	ps.Stderr = os.Stderr
	ps.Start()
	ps.Wait()
}
<commit_msg>Remove concurrency flag from run command<commit_after>package main

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

var cmdRun = &Command{
	Run:   runRun,
	Usage: "run [-e env] [-p port]",
	Short: "Run a one-off command",
	Long: `
Run a one-off command

Examples:

  forego run bin/migrate
`,
}

func init() {
	cmdRun.Flag.StringVar(&flagEnv, "e", ".env", "env")
}

func runRun(cmd *Command, args []string) {
	if flagEnv == "" {
		root, _ := os.Getwd()
		flagEnv = filepath.Join(root, ".env")
	}

	env, err := ReadEnv(flagEnv)
	handleError(err)

	ps := NewProcess(strings.Join(args, " "), env)
	ps.Interactive = true
	ps.Stdin = os.Stdin
	ps.Stdout = os.Stdout
	ps.Stderr = os.Stderr
	ps.Start()
	ps.Wait()
}
<|endoftext|>


<commit_before>package dockercommand

import (
	docker "github.com/fsouza/go-dockerclient"
)

type RunOptions struct {
	Image       string
	Cmd         []string
	VolumeBinds []string
	Links       []string
	Detach      bool
	Env         map[string]string
}

func (dock *Docker) Run(options *RunOptions) (*Container, error) {
	if err := dock.pullImageIfNotExist(options.Image); err != nil {
		return nil, err
	}

	container, err := dock.client.CreateContainer(docker.CreateContainerOptions{
		Config: &docker.Config{
			Image: options.Image,
			Cmd:   options.Cmd,
			Env:   convertEnvMapToSlice(options.Env),
		},
	})
	if err != nil {
		return nil, err
	}

	err = dock.client.StartContainer(container.ID, &docker.HostConfig{
		Binds: options.VolumeBinds,
		Links: options.Links,
	})
	if err != nil {
		return nil, err
	}

	containerWrapper := &Container{
		info:   container,
		client: dock.client,
	}

	if !options.Detach {
		_, err = dock.client.WaitContainer(container.ID)
		if err != nil {
			return nil, err
		}
	}
	return containerWrapper, nil
}
<commit_msg>add Name<commit_after>package dockercommand

import (
	docker "github.com/fsouza/go-dockerclient"
)

type RunOptions struct {
	Name        string
	Image       string
	Cmd         []string
	VolumeBinds []string
	Links       []string
	Detach      bool
	Env         map[string]string
}

func (dock *Docker) Run(options *RunOptions) (*Container, error) {
	if err := dock.pullImageIfNotExist(options.Image); err != nil {
		return nil, err
	}

	container, err := dock.client.CreateContainer(docker.CreateContainerOptions{
		Name: options.Name,
		Config: &docker.Config{
			Image: options.Image,
			Cmd:   options.Cmd,
			Env:   convertEnvMapToSlice(options.Env),
		},
	})
	if err != nil {
		return nil, err
	}

	err = dock.client.StartContainer(container.ID, &docker.HostConfig{
		Binds: options.VolumeBinds,
		Links: options.Links,
	})
	if err != nil {
		return nil, err
	}

	containerWrapper := &Container{
		info:   container,
		client: dock.client,
	}

	if !options.Detach {
		_, err = dock.client.WaitContainer(container.ID)
		if err != nil {
			return nil, err
		}
	}
	return containerWrapper, nil
}
<|endoftext|>


<commit_before>// Copyright 2016-2018 Authors of Cilium
//
// 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 cache

import (
	"context"
	"reflect"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/pkg/allocator"
	"github.com/cilium/cilium/pkg/identity"
	identitymodel "github.com/cilium/cilium/pkg/identity/model"
	"github.com/cilium/cilium/pkg/idpool"
	"github.com/cilium/cilium/pkg/kvstore"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
)

var (
	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "identity-cache")
)

// IdentityCache is a cache of identity to labels mapping
type IdentityCache map[identity.NumericIdentity]labels.LabelArray

// IdentitiesModel is a wrapper so that we can implement the sort.Interface
// to sort the slice by ID
type IdentitiesModel []*models.Identity

// Less returns true if the element in index `i` is lower than the element
// in index `j`
func (s IdentitiesModel) Less(i, j int) bool {
	return s[i].ID < s[j].ID
}

// GetIdentityCache returns a cache of all known identities
func (m *CachingIdentityAllocator) GetIdentityCache() IdentityCache {
	log.Debug("getting identity cache for identity allocator manager")
	cache := IdentityCache{}

	if m.IdentityAllocator != nil {

		m.IdentityAllocator.ForeachCache(func(id idpool.ID, val allocator.AllocatorKey) {
			if val != nil {
				if gi, ok := val.(GlobalIdentity); ok {
					cache[identity.NumericIdentity(id)] = gi.LabelArray
				} else {
					log.Warningf("Ignoring unknown identity type '%s': %+v",
						reflect.TypeOf(val), val)
				}
			}
		})
	}

	for key, identity := range identity.ReservedIdentityCache {
		cache[key] = identity.Labels.LabelArray()
	}

	if m.localIdentities != nil {
		for _, identity := range m.localIdentities.GetIdentities() {
			cache[identity.ID] = identity.Labels.LabelArray()
		}
	}

	return cache
}

// GetIdentities returns all known identities
func (m *CachingIdentityAllocator) GetIdentities() IdentitiesModel {
	identities := IdentitiesModel{}

	m.IdentityAllocator.ForeachCache(func(id idpool.ID, val allocator.AllocatorKey) {
		if gi, ok := val.(GlobalIdentity); ok {
			identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(id), gi.LabelArray)
			identities = append(identities, identitymodel.CreateModel(identity))
		}

	})
	// append user reserved identities
	for _, v := range identity.ReservedIdentityCache {
		identities = append(identities, identitymodel.CreateModel(v))
	}

	for _, v := range m.localIdentities.GetIdentities() {
		identities = append(identities, identitymodel.CreateModel(v))
	}

	return identities
}

type identityWatcher struct {
	stopChan chan bool
	owner    IdentityAllocatorOwner
}

// collectEvent records the 'event' as an added or deleted identity,
// and makes sure that any identity is present in only one of the sets
// (added or deleted).
func collectEvent(event allocator.AllocatorEvent, added, deleted IdentityCache) bool {
	id := identity.NumericIdentity(event.ID)
	// Only create events have the key
	if event.Typ == kvstore.EventTypeCreate {
		if gi, ok := event.Key.(GlobalIdentity); ok {
			// Un-delete the added ID if previously
			// 'deleted' so that collected events can be
			// processed in any order.
			delete(deleted, id)
			added[id] = gi.LabelArray
			return true
		}
		log.Warningf("collectEvent: Ignoring unknown identity type '%s': %+v",
			reflect.TypeOf(event.Key), event.Key)
		return false
	}
	// Reverse an add when subsequently deleted
	delete(added, id)
	// record the id deleted even if an add was reversed, as the
	// id may also have previously existed, in which case the
	// result is not no-op!
	deleted[id] = labels.LabelArray{}

	return true
}

// watch starts the identity watcher
func (w *identityWatcher) watch(events allocator.AllocatorEventChan) {

	go func() {
		for {
			added := IdentityCache{}
			deleted := IdentityCache{}

		First:
			for {
				// Wait for one identity add or delete or stop
				select {
				case event, ok := <-events:
					if !ok {
						// 'events' was closed
						return
					}
					// Collect first added and deleted labels
					switch event.Typ {
					case kvstore.EventTypeCreate, kvstore.EventTypeDelete:
						if collectEvent(event, added, deleted) {
							// First event collected
							break First
						}
					default:
						// Ignore modify events
					}
				case <-w.stopChan:
					return
				}
			}

		More:
			for {
				// see if there is more, but do not wait nor stop
				select {
				case event, ok := <-events:
					if !ok {
						// 'events' was closed
						break More
					}
					// Collect more added and deleted labels
					switch event.Typ {
					case kvstore.EventTypeCreate, kvstore.EventTypeDelete:
						collectEvent(event, added, deleted)
					default:
						// Ignore modify events
					}
				default:
					// No more events available without blocking
					break More
				}
			}
			// Issue collected updates
			w.owner.UpdateIdentities(added, deleted) // disjoint sets
		}
	}()
}

// stop stops the identity watcher
func (w *identityWatcher) stop() {
	close(w.stopChan)
}

// LookupIdentity looks up the identity by its labels but does not create it.
// This function will first search through the local cache, then the caches for
// remote kvstores and finally fall back to the main kvstore
func (m *CachingIdentityAllocator) LookupIdentity(ctx context.Context, lbls labels.Labels) *identity.Identity {
	if reservedIdentity := identity.LookupReservedIdentityByLabels(lbls); reservedIdentity != nil {
		return reservedIdentity
	}

	if identity := m.localIdentities.lookup(lbls); identity != nil {
		return identity
	}

	if !identity.RequiresGlobalIdentity(lbls) || m.IdentityAllocator == nil {
		return nil
	}

	lblArray := lbls.LabelArray()
	id, err := m.IdentityAllocator.GetIncludeRemoteCaches(ctx, GlobalIdentity{lblArray})
	if err != nil {
		return nil
	}

	if id == idpool.NoID {
		return nil
	}

	return identity.NewIdentityFromLabelArray(identity.NumericIdentity(id), lblArray)
}

var unknownIdentity = identity.NewIdentity(identity.IdentityUnknown, labels.Labels{labels.IDNameUnknown: labels.NewLabel(labels.IDNameUnknown, "", labels.LabelSourceReserved)})

// LookupIdentityByID returns the identity by ID. This function will first
// search through the local cache, then the caches for remote kvstores and
// finally fall back to the main kvstore
func (m *CachingIdentityAllocator) LookupIdentityByID(ctx context.Context, id identity.NumericIdentity) *identity.Identity {
	if id == identity.IdentityUnknown {
		return unknownIdentity
	}

	if identity := identity.LookupReservedIdentity(id); identity != nil {
		return identity
	}

	if identity := m.localIdentities.lookupByID(id); identity != nil {
		return identity
	}

	if id.HasLocalScope() || m.IdentityAllocator == nil {
		return nil
	}

	allocatorKey, err := m.IdentityAllocator.GetByIDIncludeRemoteCaches(ctx, idpool.ID(id))
	if err != nil {
		return nil
	}

	if gi, ok := allocatorKey.(GlobalIdentity); ok {
		return identity.NewIdentityFromLabelArray(id, gi.LabelArray)
	}

	return nil
}
<commit_msg>identity: Fix nil pointer panic in LookupIdentityByID<commit_after>// Copyright 2016-2018 Authors of Cilium
//
// 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 cache

import (
	"context"
	"reflect"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/pkg/allocator"
	"github.com/cilium/cilium/pkg/identity"
	identitymodel "github.com/cilium/cilium/pkg/identity/model"
	"github.com/cilium/cilium/pkg/idpool"
	"github.com/cilium/cilium/pkg/kvstore"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
)

var (
	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "identity-cache")
)

// IdentityCache is a cache of identity to labels mapping
type IdentityCache map[identity.NumericIdentity]labels.LabelArray

// IdentitiesModel is a wrapper so that we can implement the sort.Interface
// to sort the slice by ID
type IdentitiesModel []*models.Identity

// Less returns true if the element in index `i` is lower than the element
// in index `j`
func (s IdentitiesModel) Less(i, j int) bool {
	return s[i].ID < s[j].ID
}

// GetIdentityCache returns a cache of all known identities
func (m *CachingIdentityAllocator) GetIdentityCache() IdentityCache {
	log.Debug("getting identity cache for identity allocator manager")
	cache := IdentityCache{}

	if m.IdentityAllocator != nil {

		m.IdentityAllocator.ForeachCache(func(id idpool.ID, val allocator.AllocatorKey) {
			if val != nil {
				if gi, ok := val.(GlobalIdentity); ok {
					cache[identity.NumericIdentity(id)] = gi.LabelArray
				} else {
					log.Warningf("Ignoring unknown identity type '%s': %+v",
						reflect.TypeOf(val), val)
				}
			}
		})
	}

	for key, identity := range identity.ReservedIdentityCache {
		cache[key] = identity.Labels.LabelArray()
	}

	if m.localIdentities != nil {
		for _, identity := range m.localIdentities.GetIdentities() {
			cache[identity.ID] = identity.Labels.LabelArray()
		}
	}

	return cache
}

// GetIdentities returns all known identities
func (m *CachingIdentityAllocator) GetIdentities() IdentitiesModel {
	identities := IdentitiesModel{}

	m.IdentityAllocator.ForeachCache(func(id idpool.ID, val allocator.AllocatorKey) {
		if gi, ok := val.(GlobalIdentity); ok {
			identity := identity.NewIdentityFromLabelArray(identity.NumericIdentity(id), gi.LabelArray)
			identities = append(identities, identitymodel.CreateModel(identity))
		}

	})
	// append user reserved identities
	for _, v := range identity.ReservedIdentityCache {
		identities = append(identities, identitymodel.CreateModel(v))
	}

	for _, v := range m.localIdentities.GetIdentities() {
		identities = append(identities, identitymodel.CreateModel(v))
	}

	return identities
}

type identityWatcher struct {
	stopChan chan bool
	owner    IdentityAllocatorOwner
}

// collectEvent records the 'event' as an added or deleted identity,
// and makes sure that any identity is present in only one of the sets
// (added or deleted).
func collectEvent(event allocator.AllocatorEvent, added, deleted IdentityCache) bool {
	id := identity.NumericIdentity(event.ID)
	// Only create events have the key
	if event.Typ == kvstore.EventTypeCreate {
		if gi, ok := event.Key.(GlobalIdentity); ok {
			// Un-delete the added ID if previously
			// 'deleted' so that collected events can be
			// processed in any order.
			delete(deleted, id)
			added[id] = gi.LabelArray
			return true
		}
		log.Warningf("collectEvent: Ignoring unknown identity type '%s': %+v",
			reflect.TypeOf(event.Key), event.Key)
		return false
	}
	// Reverse an add when subsequently deleted
	delete(added, id)
	// record the id deleted even if an add was reversed, as the
	// id may also have previously existed, in which case the
	// result is not no-op!
	deleted[id] = labels.LabelArray{}

	return true
}

// watch starts the identity watcher
func (w *identityWatcher) watch(events allocator.AllocatorEventChan) {

	go func() {
		for {
			added := IdentityCache{}
			deleted := IdentityCache{}

		First:
			for {
				// Wait for one identity add or delete or stop
				select {
				case event, ok := <-events:
					if !ok {
						// 'events' was closed
						return
					}
					// Collect first added and deleted labels
					switch event.Typ {
					case kvstore.EventTypeCreate, kvstore.EventTypeDelete:
						if collectEvent(event, added, deleted) {
							// First event collected
							break First
						}
					default:
						// Ignore modify events
					}
				case <-w.stopChan:
					return
				}
			}

		More:
			for {
				// see if there is more, but do not wait nor stop
				select {
				case event, ok := <-events:
					if !ok {
						// 'events' was closed
						break More
					}
					// Collect more added and deleted labels
					switch event.Typ {
					case kvstore.EventTypeCreate, kvstore.EventTypeDelete:
						collectEvent(event, added, deleted)
					default:
						// Ignore modify events
					}
				default:
					// No more events available without blocking
					break More
				}
			}
			// Issue collected updates
			w.owner.UpdateIdentities(added, deleted) // disjoint sets
		}
	}()
}

// stop stops the identity watcher
func (w *identityWatcher) stop() {
	close(w.stopChan)
}

// isLocalIdentityAllocatorInitialized returns true if m.localIdentities is not nil.
func (m *CachingIdentityAllocator) isLocalIdentityAllocatorInitialized() bool {
	select {
	case <-m.localIdentityAllocatorInitialized:
		return m.localIdentities != nil
	default:
		return false
	}
}

// isGlobalIdentityAllocatorInitialized returns true if m.IdentityAllocator is not nil.
// Note: This does not mean that the identities have been synchronized,
// see WaitForInitialGlobalIdentities to wait for a fully populated cache.
func (m *CachingIdentityAllocator) isGlobalIdentityAllocatorInitialized() bool {
	select {
	case <-m.globalIdentityAllocatorInitialized:
		return m.IdentityAllocator != nil
	default:
		return false
	}
}

// LookupIdentity looks up the identity by its labels but does not create it.
// This function will first search through the local cache, then the caches for
// remote kvstores and finally fall back to the main kvstore.
// May return nil for lookups if the allocator has not yet been synchronized.
func (m *CachingIdentityAllocator) LookupIdentity(ctx context.Context, lbls labels.Labels) *identity.Identity {
	if reservedIdentity := identity.LookupReservedIdentityByLabels(lbls); reservedIdentity != nil {
		return reservedIdentity
	}

	if !m.isLocalIdentityAllocatorInitialized() {
		return nil
	}

	if identity := m.localIdentities.lookup(lbls); identity != nil {
		return identity
	}

	if !identity.RequiresGlobalIdentity(lbls) || !m.isGlobalIdentityAllocatorInitialized() {
		return nil
	}

	lblArray := lbls.LabelArray()
	id, err := m.IdentityAllocator.GetIncludeRemoteCaches(ctx, GlobalIdentity{lblArray})
	if err != nil {
		return nil
	}

	if id == idpool.NoID {
		return nil
	}

	return identity.NewIdentityFromLabelArray(identity.NumericIdentity(id), lblArray)
}

var unknownIdentity = identity.NewIdentity(identity.IdentityUnknown, labels.Labels{labels.IDNameUnknown: labels.NewLabel(labels.IDNameUnknown, "", labels.LabelSourceReserved)})

// LookupIdentityByID returns the identity by ID. This function will first
// search through the local cache, then the caches for remote kvstores and
// finally fall back to the main kvstore
// May return nil for lookups if the allocator has not yet been synchronized.
func (m *CachingIdentityAllocator) LookupIdentityByID(ctx context.Context, id identity.NumericIdentity) *identity.Identity {
	if id == identity.IdentityUnknown {
		return unknownIdentity
	}

	if identity := identity.LookupReservedIdentity(id); identity != nil {
		return identity
	}

	if !m.isLocalIdentityAllocatorInitialized() {
		return nil
	}

	if identity := m.localIdentities.lookupByID(id); identity != nil {
		return identity
	}

	if !m.isGlobalIdentityAllocatorInitialized() || id.HasLocalScope() {
		return nil
	}

	allocatorKey, err := m.IdentityAllocator.GetByIDIncludeRemoteCaches(ctx, idpool.ID(id))
	if err != nil {
		return nil
	}

	if gi, ok := allocatorKey.(GlobalIdentity); ok {
		return identity.NewIdentityFromLabelArray(id, gi.LabelArray)
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 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 securitycontext

import (
	"fmt"
	"strings"

	"k8s.io/api/core/v1"
	api "k8s.io/kubernetes/pkg/apis/core"
)

// HasPrivilegedRequest returns the value of SecurityContext.Privileged, taking into account
// the possibility of nils
func HasPrivilegedRequest(container *v1.Container) bool {
	if container.SecurityContext == nil {
		return false
	}
	if container.SecurityContext.Privileged == nil {
		return false
	}
	return *container.SecurityContext.Privileged
}

// HasCapabilitiesRequest returns true if Adds or Drops are defined in the security context
// capabilities, taking into account nils
func HasCapabilitiesRequest(container *v1.Container) bool {
	if container.SecurityContext == nil {
		return false
	}
	if container.SecurityContext.Capabilities == nil {
		return false
	}
	return len(container.SecurityContext.Capabilities.Add) > 0 || len(container.SecurityContext.Capabilities.Drop) > 0
}

const expectedSELinuxFields = 4

// ParseSELinuxOptions parses a string containing a full SELinux context
// (user, role, type, and level) into an SELinuxOptions object.  If the
// context is malformed, an error is returned.
func ParseSELinuxOptions(context string) (*v1.SELinuxOptions, error) {
	fields := strings.SplitN(context, ":", expectedSELinuxFields)

	if len(fields) != expectedSELinuxFields {
		return nil, fmt.Errorf("expected %v fields in selinux; got %v (context: %v)", expectedSELinuxFields, len(fields), context)
	}

	return &v1.SELinuxOptions{
		User:  fields[0],
		Role:  fields[1],
		Type:  fields[2],
		Level: fields[3],
	}, nil
}

// HasNonRootUID returns true if the runAsUser is set and is greater than 0.
func HasRootUID(container *v1.Container) bool {
	if container.SecurityContext == nil {
		return false
	}
	if container.SecurityContext.RunAsUser == nil {
		return false
	}
	return *container.SecurityContext.RunAsUser == 0
}

// HasRunAsUser determines if the sc's runAsUser field is set.
func HasRunAsUser(container *v1.Container) bool {
	return container.SecurityContext != nil && container.SecurityContext.RunAsUser != nil
}

// HasRootRunAsUser returns true if the run as user is set and it is set to 0.
func HasRootRunAsUser(container *v1.Container) bool {
	return HasRunAsUser(container) && HasRootUID(container)
}

func DetermineEffectiveSecurityContext(pod *v1.Pod, container *v1.Container) *v1.SecurityContext {
	effectiveSc := securityContextFromPodSecurityContext(pod)
	containerSc := container.SecurityContext

	if effectiveSc == nil && containerSc == nil {
		return nil
	}
	if effectiveSc != nil && containerSc == nil {
		return effectiveSc
	}
	if effectiveSc == nil && containerSc != nil {
		return containerSc
	}

	if containerSc.SELinuxOptions != nil {
		effectiveSc.SELinuxOptions = new(v1.SELinuxOptions)
		*effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions
	}

	if containerSc.Capabilities != nil {
		effectiveSc.Capabilities = new(v1.Capabilities)
		*effectiveSc.Capabilities = *containerSc.Capabilities
	}

	if containerSc.Privileged != nil {
		effectiveSc.Privileged = new(bool)
		*effectiveSc.Privileged = *containerSc.Privileged
	}

	if containerSc.RunAsUser != nil {
		effectiveSc.RunAsUser = new(int64)
		*effectiveSc.RunAsUser = *containerSc.RunAsUser
	}

	if containerSc.RunAsNonRoot != nil {
		effectiveSc.RunAsNonRoot = new(bool)
		*effectiveSc.RunAsNonRoot = *containerSc.RunAsNonRoot
	}

	if containerSc.ReadOnlyRootFilesystem != nil {
		effectiveSc.ReadOnlyRootFilesystem = new(bool)
		*effectiveSc.ReadOnlyRootFilesystem = *containerSc.ReadOnlyRootFilesystem
	}

	if containerSc.AllowPrivilegeEscalation != nil {
		effectiveSc.AllowPrivilegeEscalation = new(bool)
		*effectiveSc.AllowPrivilegeEscalation = *containerSc.AllowPrivilegeEscalation
	}

	return effectiveSc
}

func securityContextFromPodSecurityContext(pod *v1.Pod) *v1.SecurityContext {
	if pod.Spec.SecurityContext == nil {
		return nil
	}

	synthesized := &v1.SecurityContext{}

	if pod.Spec.SecurityContext.SELinuxOptions != nil {
		synthesized.SELinuxOptions = &v1.SELinuxOptions{}
		*synthesized.SELinuxOptions = *pod.Spec.SecurityContext.SELinuxOptions
	}
	if pod.Spec.SecurityContext.RunAsUser != nil {
		synthesized.RunAsUser = new(int64)
		*synthesized.RunAsUser = *pod.Spec.SecurityContext.RunAsUser
	}

	if pod.Spec.SecurityContext.RunAsNonRoot != nil {
		synthesized.RunAsNonRoot = new(bool)
		*synthesized.RunAsNonRoot = *pod.Spec.SecurityContext.RunAsNonRoot
	}

	return synthesized
}

// TODO: remove the duplicate code
func InternalDetermineEffectiveSecurityContext(pod *api.Pod, container *api.Container) *api.SecurityContext {
	effectiveSc := internalSecurityContextFromPodSecurityContext(pod)
	containerSc := container.SecurityContext

	if effectiveSc == nil && containerSc == nil {
		return nil
	}
	if effectiveSc != nil && containerSc == nil {
		return effectiveSc
	}
	if effectiveSc == nil && containerSc != nil {
		return containerSc
	}

	if containerSc.SELinuxOptions != nil {
		effectiveSc.SELinuxOptions = new(api.SELinuxOptions)
		*effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions
	}

	if containerSc.Capabilities != nil {
		effectiveSc.Capabilities = new(api.Capabilities)
		*effectiveSc.Capabilities = *containerSc.Capabilities
	}

	if containerSc.Privileged != nil {
		effectiveSc.Privileged = new(bool)
		*effectiveSc.Privileged = *containerSc.Privileged
	}

	if containerSc.RunAsUser != nil {
		effectiveSc.RunAsUser = new(int64)
		*effectiveSc.RunAsUser = *containerSc.RunAsUser
	}

	if containerSc.RunAsNonRoot != nil {
		effectiveSc.RunAsNonRoot = new(bool)
		*effectiveSc.RunAsNonRoot = *containerSc.RunAsNonRoot
	}

	if containerSc.ReadOnlyRootFilesystem != nil {
		effectiveSc.ReadOnlyRootFilesystem = new(bool)
		*effectiveSc.ReadOnlyRootFilesystem = *containerSc.ReadOnlyRootFilesystem
	}

	if containerSc.AllowPrivilegeEscalation != nil {
		effectiveSc.AllowPrivilegeEscalation = new(bool)
		*effectiveSc.AllowPrivilegeEscalation = *containerSc.AllowPrivilegeEscalation
	}

	return effectiveSc
}

func internalSecurityContextFromPodSecurityContext(pod *api.Pod) *api.SecurityContext {
	if pod.Spec.SecurityContext == nil {
		return nil
	}

	synthesized := &api.SecurityContext{}

	if pod.Spec.SecurityContext.SELinuxOptions != nil {
		synthesized.SELinuxOptions = &api.SELinuxOptions{}
		*synthesized.SELinuxOptions = *pod.Spec.SecurityContext.SELinuxOptions
	}
	if pod.Spec.SecurityContext.RunAsUser != nil {
		synthesized.RunAsUser = new(int64)
		*synthesized.RunAsUser = *pod.Spec.SecurityContext.RunAsUser
	}

	if pod.Spec.SecurityContext.RunAsNonRoot != nil {
		synthesized.RunAsNonRoot = new(bool)
		*synthesized.RunAsNonRoot = *pod.Spec.SecurityContext.RunAsNonRoot
	}

	return synthesized
}

// AddNoNewPrivileges returns if we should add the no_new_privs option.
func AddNoNewPrivileges(sc *v1.SecurityContext) bool {
	if sc == nil {
		return false
	}

	// handle the case where the user did not set the default and did not explicitly set allowPrivilegeEscalation
	if sc.AllowPrivilegeEscalation == nil {
		return false
	}

	// handle the case where defaultAllowPrivilegeEscalation is false or the user explicitly set allowPrivilegeEscalation to true/false
	return !*sc.AllowPrivilegeEscalation
}
<commit_msg>remove duplicate code<commit_after>/*
Copyright 2014 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 securitycontext

import (
	"fmt"
	"strings"

	"k8s.io/api/core/v1"
)

// HasPrivilegedRequest returns the value of SecurityContext.Privileged, taking into account
// the possibility of nils
func HasPrivilegedRequest(container *v1.Container) bool {
	if container.SecurityContext == nil {
		return false
	}
	if container.SecurityContext.Privileged == nil {
		return false
	}
	return *container.SecurityContext.Privileged
}

// HasCapabilitiesRequest returns true if Adds or Drops are defined in the security context
// capabilities, taking into account nils
func HasCapabilitiesRequest(container *v1.Container) bool {
	if container.SecurityContext == nil {
		return false
	}
	if container.SecurityContext.Capabilities == nil {
		return false
	}
	return len(container.SecurityContext.Capabilities.Add) > 0 || len(container.SecurityContext.Capabilities.Drop) > 0
}

const expectedSELinuxFields = 4

// ParseSELinuxOptions parses a string containing a full SELinux context
// (user, role, type, and level) into an SELinuxOptions object.  If the
// context is malformed, an error is returned.
func ParseSELinuxOptions(context string) (*v1.SELinuxOptions, error) {
	fields := strings.SplitN(context, ":", expectedSELinuxFields)

	if len(fields) != expectedSELinuxFields {
		return nil, fmt.Errorf("expected %v fields in selinux; got %v (context: %v)", expectedSELinuxFields, len(fields), context)
	}

	return &v1.SELinuxOptions{
		User:  fields[0],
		Role:  fields[1],
		Type:  fields[2],
		Level: fields[3],
	}, nil
}

// HasNonRootUID returns true if the runAsUser is set and is greater than 0.
func HasRootUID(container *v1.Container) bool {
	if container.SecurityContext == nil {
		return false
	}
	if container.SecurityContext.RunAsUser == nil {
		return false
	}
	return *container.SecurityContext.RunAsUser == 0
}

// HasRunAsUser determines if the sc's runAsUser field is set.
func HasRunAsUser(container *v1.Container) bool {
	return container.SecurityContext != nil && container.SecurityContext.RunAsUser != nil
}

// HasRootRunAsUser returns true if the run as user is set and it is set to 0.
func HasRootRunAsUser(container *v1.Container) bool {
	return HasRunAsUser(container) && HasRootUID(container)
}

func DetermineEffectiveSecurityContext(pod *v1.Pod, container *v1.Container) *v1.SecurityContext {
	effectiveSc := securityContextFromPodSecurityContext(pod)
	containerSc := container.SecurityContext

	if effectiveSc == nil && containerSc == nil {
		return nil
	}
	if effectiveSc != nil && containerSc == nil {
		return effectiveSc
	}
	if effectiveSc == nil && containerSc != nil {
		return containerSc
	}

	if containerSc.SELinuxOptions != nil {
		effectiveSc.SELinuxOptions = new(v1.SELinuxOptions)
		*effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions
	}

	if containerSc.Capabilities != nil {
		effectiveSc.Capabilities = new(v1.Capabilities)
		*effectiveSc.Capabilities = *containerSc.Capabilities
	}

	if containerSc.Privileged != nil {
		effectiveSc.Privileged = new(bool)
		*effectiveSc.Privileged = *containerSc.Privileged
	}

	if containerSc.RunAsUser != nil {
		effectiveSc.RunAsUser = new(int64)
		*effectiveSc.RunAsUser = *containerSc.RunAsUser
	}

	if containerSc.RunAsNonRoot != nil {
		effectiveSc.RunAsNonRoot = new(bool)
		*effectiveSc.RunAsNonRoot = *containerSc.RunAsNonRoot
	}

	if containerSc.ReadOnlyRootFilesystem != nil {
		effectiveSc.ReadOnlyRootFilesystem = new(bool)
		*effectiveSc.ReadOnlyRootFilesystem = *containerSc.ReadOnlyRootFilesystem
	}

	if containerSc.AllowPrivilegeEscalation != nil {
		effectiveSc.AllowPrivilegeEscalation = new(bool)
		*effectiveSc.AllowPrivilegeEscalation = *containerSc.AllowPrivilegeEscalation
	}

	return effectiveSc
}

func securityContextFromPodSecurityContext(pod *v1.Pod) *v1.SecurityContext {
	if pod.Spec.SecurityContext == nil {
		return nil
	}

	synthesized := &v1.SecurityContext{}

	if pod.Spec.SecurityContext.SELinuxOptions != nil {
		synthesized.SELinuxOptions = &v1.SELinuxOptions{}
		*synthesized.SELinuxOptions = *pod.Spec.SecurityContext.SELinuxOptions
	}
	if pod.Spec.SecurityContext.RunAsUser != nil {
		synthesized.RunAsUser = new(int64)
		*synthesized.RunAsUser = *pod.Spec.SecurityContext.RunAsUser
	}

	if pod.Spec.SecurityContext.RunAsNonRoot != nil {
		synthesized.RunAsNonRoot = new(bool)
		*synthesized.RunAsNonRoot = *pod.Spec.SecurityContext.RunAsNonRoot
	}

	return synthesized
}

// AddNoNewPrivileges returns if we should add the no_new_privs option.
func AddNoNewPrivileges(sc *v1.SecurityContext) bool {
	if sc == nil {
		return false
	}

	// handle the case where the user did not set the default and did not explicitly set allowPrivilegeEscalation
	if sc.AllowPrivilegeEscalation == nil {
		return false
	}

	// handle the case where defaultAllowPrivilegeEscalation is false or the user explicitly set allowPrivilegeEscalation to true/false
	return !*sc.AllowPrivilegeEscalation
}
<|endoftext|>


<commit_before>package proxy

import (
	"encoding/base64"
	"time"

	"github.com/centrifugal/centrifugo/v3/internal/clientcontext"
	"github.com/centrifugal/centrifugo/v3/internal/proxyproto"
	"github.com/centrifugal/centrifugo/v3/internal/rule"

	"github.com/centrifugal/centrifuge"
	"github.com/prometheus/client_golang/prometheus"
)

// SubscribeHandlerConfig ...
type SubscribeHandlerConfig struct {
	Proxy SubscribeProxy
}

// SubscribeHandler ...
type SubscribeHandler struct {
	config    SubscribeHandlerConfig
	summary   prometheus.Observer
	histogram prometheus.Observer
	errors    prometheus.Counter
}

// NewSubscribeHandler ...
func NewSubscribeHandler(c SubscribeHandlerConfig) *SubscribeHandler {
	return &SubscribeHandler{
		config:    c,
		summary:   proxyCallDurationSummary.WithLabelValues(c.Proxy.Protocol(), "subscribe"),
		histogram: proxyCallDurationHistogram.WithLabelValues(c.Proxy.Protocol(), "subscribe"),
		errors:    proxyCallErrorCount.WithLabelValues(c.Proxy.Protocol(), "subscribe"),
	}
}

// SubscribeHandlerFunc ...
type SubscribeHandlerFunc func(*centrifuge.Client, centrifuge.SubscribeEvent, rule.ChannelOptions) (centrifuge.SubscribeReply, error)

// Handle Subscribe.
func (h *SubscribeHandler) Handle(node *centrifuge.Node) SubscribeHandlerFunc {
	return func(client *centrifuge.Client, e centrifuge.SubscribeEvent, chOpts rule.ChannelOptions) (centrifuge.SubscribeReply, error) {
		started := time.Now()

		req := &proxyproto.SubscribeRequest{
			Client:    client.ID(),
			Protocol:  string(client.Transport().Protocol()),
			Transport: client.Transport().Name(),
			Encoding:  getEncoding(h.config.Proxy.UseBase64()),

			User:    client.UserID(),
			Channel: e.Channel,
			Token:   e.Token,
		}
		if h.config.Proxy.IncludeMeta() {
			if connMeta, ok := clientcontext.GetContextConnectionMeta(client.Context()); ok {
				req.Meta = proxyproto.Raw(connMeta.Meta)
			}
		}
		subscribeRep, err := h.config.Proxy.ProxySubscribe(client.Context(), req)
		duration := time.Since(started).Seconds()
		if err != nil {
			select {
			case <-client.Context().Done():
				// Client connection already closed.
				return centrifuge.SubscribeReply{}, centrifuge.DisconnectNormal
			default:
			}
			h.summary.Observe(duration)
			h.histogram.Observe(duration)
			h.errors.Inc()
			node.Log(centrifuge.NewLogEntry(centrifuge.LogLevelError, "error proxying subscribe", map[string]interface{}{"error": err.Error()}))
			return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
		}
		h.summary.Observe(duration)
		h.histogram.Observe(duration)

		if subscribeRep.Disconnect != nil {
			return centrifuge.SubscribeReply{}, proxyproto.DisconnectFromProto(subscribeRep.Disconnect)
		}
		if subscribeRep.Error != nil {
			return centrifuge.SubscribeReply{}, proxyproto.ErrorFromProto(subscribeRep.Error)
		}

		presence := chOpts.Presence
		joinLeave := chOpts.JoinLeave
		useRecover := chOpts.Recover
		position := chOpts.Position

		var info []byte
		if subscribeRep.Result != nil {
			if subscribeRep.Result.B64Info != "" {
				decodedInfo, err := base64.StdEncoding.DecodeString(subscribeRep.Result.B64Info)
				if err != nil {
					node.Log(centrifuge.NewLogEntry(centrifuge.LogLevelError, "error decoding base64 info", map[string]interface{}{"client": client.ID(), "error": err.Error()}))
					return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
				}
				info = decodedInfo
			} else {
				info = subscribeRep.Result.Info
			}

			result := subscribeRep.Result

			if result.Override != nil && result.Override.Presence != nil {
				presence = result.Override.Presence.Value
			}
			if result.Override != nil && result.Override.JoinLeave != nil {
				joinLeave = result.Override.JoinLeave.Value
			}
			if result.Override != nil && result.Override.Recover != nil {
				useRecover = result.Override.Recover.Value
			}
			if result.Override != nil && result.Override.Position != nil {
				position = result.Override.Position.Value
			}
		}

		return centrifuge.SubscribeReply{
			Options: centrifuge.SubscribeOptions{
				ChannelInfo: info,
				Presence:    presence,
				JoinLeave:   joinLeave,
				Recover:     useRecover,
				Position:    position,
			},
			ClientSideRefresh: true,
		}, nil
	}
}
<commit_msg>proxy data in subscribe result<commit_after>package proxy

import (
	"encoding/base64"
	"time"

	"github.com/centrifugal/centrifugo/v3/internal/clientcontext"
	"github.com/centrifugal/centrifugo/v3/internal/proxyproto"
	"github.com/centrifugal/centrifugo/v3/internal/rule"

	"github.com/centrifugal/centrifuge"
	"github.com/prometheus/client_golang/prometheus"
)

// SubscribeHandlerConfig ...
type SubscribeHandlerConfig struct {
	Proxy SubscribeProxy
}

// SubscribeHandler ...
type SubscribeHandler struct {
	config    SubscribeHandlerConfig
	summary   prometheus.Observer
	histogram prometheus.Observer
	errors    prometheus.Counter
}

// NewSubscribeHandler ...
func NewSubscribeHandler(c SubscribeHandlerConfig) *SubscribeHandler {
	return &SubscribeHandler{
		config:    c,
		summary:   proxyCallDurationSummary.WithLabelValues(c.Proxy.Protocol(), "subscribe"),
		histogram: proxyCallDurationHistogram.WithLabelValues(c.Proxy.Protocol(), "subscribe"),
		errors:    proxyCallErrorCount.WithLabelValues(c.Proxy.Protocol(), "subscribe"),
	}
}

// SubscribeHandlerFunc ...
type SubscribeHandlerFunc func(*centrifuge.Client, centrifuge.SubscribeEvent, rule.ChannelOptions) (centrifuge.SubscribeReply, error)

// Handle Subscribe.
func (h *SubscribeHandler) Handle(node *centrifuge.Node) SubscribeHandlerFunc {
	return func(client *centrifuge.Client, e centrifuge.SubscribeEvent, chOpts rule.ChannelOptions) (centrifuge.SubscribeReply, error) {
		started := time.Now()

		req := &proxyproto.SubscribeRequest{
			Client:    client.ID(),
			Protocol:  string(client.Transport().Protocol()),
			Transport: client.Transport().Name(),
			Encoding:  getEncoding(h.config.Proxy.UseBase64()),

			User:    client.UserID(),
			Channel: e.Channel,
			Token:   e.Token,
		}
		if h.config.Proxy.IncludeMeta() {
			if connMeta, ok := clientcontext.GetContextConnectionMeta(client.Context()); ok {
				req.Meta = proxyproto.Raw(connMeta.Meta)
			}
		}
		subscribeRep, err := h.config.Proxy.ProxySubscribe(client.Context(), req)
		duration := time.Since(started).Seconds()
		if err != nil {
			select {
			case <-client.Context().Done():
				// Client connection already closed.
				return centrifuge.SubscribeReply{}, centrifuge.DisconnectNormal
			default:
			}
			h.summary.Observe(duration)
			h.histogram.Observe(duration)
			h.errors.Inc()
			node.Log(centrifuge.NewLogEntry(centrifuge.LogLevelError, "error proxying subscribe", map[string]interface{}{"error": err.Error()}))
			return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
		}
		h.summary.Observe(duration)
		h.histogram.Observe(duration)

		if subscribeRep.Disconnect != nil {
			return centrifuge.SubscribeReply{}, proxyproto.DisconnectFromProto(subscribeRep.Disconnect)
		}
		if subscribeRep.Error != nil {
			return centrifuge.SubscribeReply{}, proxyproto.ErrorFromProto(subscribeRep.Error)
		}

		presence := chOpts.Presence
		joinLeave := chOpts.JoinLeave
		useRecover := chOpts.Recover
		position := chOpts.Position

		var info []byte
		var data []byte
		if subscribeRep.Result != nil {
			if subscribeRep.Result.B64Info != "" {
				decodedInfo, err := base64.StdEncoding.DecodeString(subscribeRep.Result.B64Info)
				if err != nil {
					node.Log(centrifuge.NewLogEntry(centrifuge.LogLevelError, "error decoding base64 info", map[string]interface{}{"client": client.ID(), "error": err.Error()}))
					return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
				}
				info = decodedInfo
			} else {
				info = subscribeRep.Result.Info
			}
			if subscribeRep.Result.B64Data != "" {
				decodedData, err := base64.StdEncoding.DecodeString(subscribeRep.Result.B64Data)
				if err != nil {
					node.Log(centrifuge.NewLogEntry(centrifuge.LogLevelError, "error decoding base64 data", map[string]interface{}{"client": client.ID(), "error": err.Error()}))
					return centrifuge.SubscribeReply{}, centrifuge.ErrorInternal
				}
				data = decodedData
			} else {
				data = subscribeRep.Result.Data
			}

			result := subscribeRep.Result

			if result.Override != nil && result.Override.Presence != nil {
				presence = result.Override.Presence.Value
			}
			if result.Override != nil && result.Override.JoinLeave != nil {
				joinLeave = result.Override.JoinLeave.Value
			}
			if result.Override != nil && result.Override.Recover != nil {
				useRecover = result.Override.Recover.Value
			}
			if result.Override != nil && result.Override.Position != nil {
				position = result.Override.Position.Value
			}
		}

		return centrifuge.SubscribeReply{
			Options: centrifuge.SubscribeOptions{
				ChannelInfo: info,
				Presence:    presence,
				JoinLeave:   joinLeave,
				Recover:     useRecover,
				Position:    position,
				Data:        data,
			},
			ClientSideRefresh: true,
		}, nil
	}
}
<|endoftext|>


<commit_before>package venue

import "testing"

// "image"
// "testing"

// func TestOverlay(t *testing.T) {
// 	tests := []struct {
// 		a, b, c *image.RGBA
// 	}{
// 		{ // 0, 0 is painted; overlay at 1, 1.
// 			&image.RGBA{
// 				[]uint8{255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// 				8, image.Rectangle{image.Point{0, 0}, image.Point{2, 2}}},
// 			&image.RGBA{
// 				[]uint8{255, 255, 255, 255},
// 				4, image.Rectangle{image.Point{1, 1}, image.Point{2, 2}}},
// 			&image.RGBA{
// 				[]uint8{255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255},
// 				8, image.Rectangle{image.Point{0, 0}, image.Point{2, 2}}},
// 		},
// 		{ // 0, 0 and 1, 1 are painted; overlay new 1, 1.
// 			&image.RGBA{
// 				[]uint8{255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255},
// 				8, image.Rectangle{image.Point{0, 0}, image.Point{2, 2}}},
// 			&image.RGBA{
// 				[]uint8{127, 127, 127, 255},
// 				4, image.Rectangle{image.Point{1, 1}, image.Point{2, 2}}},
// 			&image.RGBA{
// 				[]uint8{255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 255},
// 				8, image.Rectangle{image.Point{0, 0}, image.Point{2, 2}}},
// 		},
// 	}

// 	for _, tt := range tests {
// 		Overlay(tt.a, tt.b)
// 		if got, want := tt.a.Pix, tt.c.Pix; !EqualSlices(got, want) {
// 			t.Errorf("Overlay() failed; Pix got = %v, want = %v", got, want)
// 		}
// 	}
// }

func TestAbs(t *testing.T) {
	tests := []struct {
		val, abs int
	}{
		{1, 1},
		{0, 0},
		{-1, 1},
	}

	for _, tt := range tests {
		if got, want := abs(tt.val), tt.abs; got != want {
			t.Errorf("abs(): got = %v, want = %v", got, want)
		}
	}
}

func equalSlices(x, y interface{}) bool {
	// Special cases.
	switch {
	case x == nil && y == nil:
		return true
	case x == nil || y == nil:
		return false
	}

	switch x.(type) {
	case []uint8:
		if len(x.([]uint8)) != len(y.([]uint8)) {
			return false
		}
		for i, v := range x.([]uint8) {
			if v != y.([]uint8)[i] {
				return false
			}
		}
	}
	return true
}
<commit_msg>support []uint32] in equalSlices()<commit_after>package venue

import (
	"fmt"
	"reflect"
	"testing"
)

// "image"
// "testing"

// func TestOverlay(t *testing.T) {
// 	tests := []struct {
// 		a, b, c *image.RGBA
// 	}{
// 		{ // 0, 0 is painted; overlay at 1, 1.
// 			&image.RGBA{
// 				[]uint8{255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// 				8, image.Rectangle{image.Point{0, 0}, image.Point{2, 2}}},
// 			&image.RGBA{
// 				[]uint8{255, 255, 255, 255},
// 				4, image.Rectangle{image.Point{1, 1}, image.Point{2, 2}}},
// 			&image.RGBA{
// 				[]uint8{255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255},
// 				8, image.Rectangle{image.Point{0, 0}, image.Point{2, 2}}},
// 		},
// 		{ // 0, 0 and 1, 1 are painted; overlay new 1, 1.
// 			&image.RGBA{
// 				[]uint8{255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255},
// 				8, image.Rectangle{image.Point{0, 0}, image.Point{2, 2}}},
// 			&image.RGBA{
// 				[]uint8{127, 127, 127, 255},
// 				4, image.Rectangle{image.Point{1, 1}, image.Point{2, 2}}},
// 			&image.RGBA{
// 				[]uint8{255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 255},
// 				8, image.Rectangle{image.Point{0, 0}, image.Point{2, 2}}},
// 		},
// 	}

// 	for _, tt := range tests {
// 		Overlay(tt.a, tt.b)
// 		if got, want := tt.a.Pix, tt.c.Pix; !EqualSlices(got, want) {
// 			t.Errorf("Overlay() failed; Pix got = %v, want = %v", got, want)
// 		}
// 	}
// }

func TestAbs(t *testing.T) {
	tests := []struct {
		val, abs int
	}{
		{1, 1},
		{0, 0},
		{-1, 1},
	}

	for _, tt := range tests {
		if got, want := abs(tt.val), tt.abs; got != want {
			t.Errorf("abs(): got = %v, want = %v", got, want)
		}
	}
}

func equalSlices(x, y interface{}) bool {
	// Special cases.
	switch {
	case x == nil && y == nil:
		return true
	case x == nil || y == nil:
		return false
	}

	switch x.(type) {
	case []uint8:
		if len(x.([]uint8)) != len(y.([]uint8)) {
			return false
		}
		for i, v := range x.([]uint8) {
			if v != y.([]uint8)[i] {
				return false
			}
		}
	case []uint32:
		if len(x.([]uint32)) != len(y.([]uint32)) {
			return false
		}
		for i, v := range x.([]uint32) {
			if v != y.([]uint32)[i] {
				return false
			}
		}
	default:
		panic(fmt.Sprintf("unrecognized type %v", reflect.TypeOf(x)))
	}
	return true
}
<|endoftext|>


<commit_before>package deje

type Document struct {
	Channel    IRCLocation
	Events     EventSet
	Syncs      SyncSet
	Timestamps TimestampSet `json:""`
}

func NewDocument() Document {
	return Document{
		Events: make(EventSet),
		Syncs:  make(SyncSet),
	}
}
<commit_msg>Split off DocumentFile type for serialization/deserialization<commit_after>package deje

// A document is a single managed DEJE object, associated with
// a single immutable IRCLocation, and self-describing its
// actions and permissions as part of the content.
//
// The content of a Document is the result of applying the
// "official" chain of history, in much the same way that the
// Bitcoin ledger is the result of playing through the transactions
// in every block of the longest valid blockchain.
type Document struct {
	Channel    IRCLocation
	Events     EventSet
	Syncs      SyncSet
	Timestamps TimestampSet `json:""`
}

// Used for serializing and deserializing docs to files.
//
// This allows us to use more complicated structures for actual
// documents, that allow for storing Timestamps, and other data
// that we must not trust the file to provide.
type DocumentFile struct {
	Channel IRCLocation
	Events  EventSet
	Syncs   SyncSet
}

// Create a new, blank Document, with fields initialized.
func NewDocument() Document {
	return Document{
		Events: make(EventSet),
		Syncs:  make(SyncSet),
	}
}

// Copies the data from a DocumentFile into a Document.
func (d *Document) FromFile(df *DocumentFile) {
	d.Channel = df.Channel
	d.Events = df.Events
	d.Syncs = df.Syncs
}

// Copies the data from a Document into a DocumentFile.
func (d *Document) ToFile() *DocumentFile {
	return &DocumentFile{
		Channel: d.Channel,
		Events:  d.Events,
		Syncs:   d.Syncs,
	}
}
<|endoftext|>


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

/*

	Package flag implements command-line flag parsing.
	Package microdata implements a HTML microdata parser. It depends on the
	golang.org/x/net/html HTML5-compliant parser.

	Usage:

	Pass a reader, content-type and a base URL to the ParseHTML function.
		data, err := microdata.ParseHTML(reader, contentType, baseURL)
		items := data.Items

	Pass an URL to the ParseURL function.
		data, _ := microdata.ParseURL("http://example.com/blogposting")
		items := data.Items
*/

package microdata

import (
	"bytes"
	"io"
	"net/http"
	"net/url"
	"strings"

	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
	"golang.org/x/net/html/charset"
)

type Microdata struct {
	Items []*Item `json:"items"`
}

// addItem adds the item to the items list.
func (m *Microdata) addItem(item *Item) {
	m.Items = append(m.Items, item)
}

type ValueList []interface{}

type PropertyMap map[string]ValueList

type Item struct {
	Types      []string    `json:"type"`
	Properties PropertyMap `json:"properties"`
	Id         string      `json:"id,omitempty"`
}

// addString adds the property, value pair to the properties map. It appends to any
// existing property.
func (i *Item) addString(property, value string) {
	i.Properties[property] = append(i.Properties[property], value)
}

// addItem adds the property, value pair to the properties map. It appends to any
// existing property.
func (i *Item) addItem(property string, value *Item) {
	i.Properties[property] = append(i.Properties[property], value)
}

// addType adds the value to the types list.
func (i *Item) addType(value string) {
	i.Types = append(i.Types, value)
}

// NewItem returns a new Item.
func NewItem() *Item {
	return &Item{
		Types:      make([]string, 0),
		Properties: make(PropertyMap, 0),
	}
}

type parser struct {
	tree            *html.Node
	data            *Microdata
	baseURL         *url.URL
	identifiedNodes map[string]*html.Node
}

// parse returns the microdata from the parser's node tree.
func (p *parser) parse() (*Microdata, error) {
	toplevelNodes := []*html.Node{}

	walkNodes(p.tree, func(n *html.Node) {
		if _, ok := getAttr("itemscope", n); ok {
			if _, ok := getAttr("itemprop", n); !ok {
				toplevelNodes = append(toplevelNodes, n)
			}
		}
		if id, ok := getAttr("id", n); ok {
			p.identifiedNodes[id] = n
		}
	})

	for _, node := range toplevelNodes {
		item := NewItem()
		p.data.addItem(item)
		p.readAttr(item, node)
		p.readItem(item, node, true)
	}

	return p.data, nil
}

// readItem traverses the given node tree, applying relevant attributes to the
// given item.
func (p *parser) readItem(item *Item, node *html.Node, isToplevel bool) {
	itemprops, hasProp := getAttr("itemprop", node)
	_, hasScope := getAttr("itemscope", node)

	switch {
	case hasScope && hasProp:
		subItem := NewItem()
		p.readAttr(subItem, node)
		for _, propName := range strings.Split(itemprops, " ") {
			if len(propName) > 0 {
				item.addItem(propName, subItem)
			}
		}
		for c := node.FirstChild; c != nil; c = c.NextSibling {
			p.readItem(subItem, c, false)
		}
		return
	case !hasScope && hasProp:
		if s := p.getValue(node); len(s) > 0 {
			for _, propName := range strings.Split(itemprops, " ") {
				if len(propName) > 0 {
					item.addString(propName, s)
				}
			}
		}
	case hasScope && !hasProp && !isToplevel:
		return
	}

	for c := node.FirstChild; c != nil; c = c.NextSibling {
		p.readItem(item, c, false)
	}
}

// readAttr applies relevant attributes from the given node to the given item.
func (p *parser) readAttr(item *Item, node *html.Node) {
	if s, ok := getAttr("itemtype", node); ok {
		for _, itemtype := range strings.Split(s, " ") {
			if len(itemtype) > 0 {
				item.addType(itemtype)
			}
		}

		if s, ok := getAttr("itemid", node); ok {
			if u, err := p.baseURL.Parse(s); err == nil {
				item.Id = u.String()
			}
		}
	}

	if s, ok := getAttr("itemref", node); ok {
		for _, itemref := range strings.Split(s, " ") {
			if len(itemref) > 0 {
				if n, ok := p.identifiedNodes[itemref]; ok {
					p.readItem(item, n, false)
				}
			}
		}
	}
}

// getValue returns the value of the property, value pair in the given node.
func (p *parser) getValue(node *html.Node) string {
	var propValue string

	switch node.DataAtom {
	case atom.Meta:
		if value, ok := getAttr("content", node); ok {
			propValue = value
		}
	case atom.Audio, atom.Embed, atom.Iframe, atom.Img, atom.Source, atom.Track, atom.Video:
		if value, ok := getAttr("src", node); ok {
			if u, err := p.baseURL.Parse(value); err == nil {
				propValue = u.String()
			}
		}
	case atom.A, atom.Area, atom.Link:
		if value, ok := getAttr("href", node); ok {
			if u, err := p.baseURL.Parse(value); err == nil {
				propValue = u.String()
			}
		}
	case atom.Data, atom.Meter:
		if value, ok := getAttr("value", node); ok {
			propValue = value
		}
	case atom.Time:
		if value, ok := getAttr("datetime", node); ok {
			propValue = value
		}
	default:
		var buf bytes.Buffer
		walkNodes(node, func(n *html.Node) {
			if n.Type == html.TextNode {
				buf.WriteString(n.Data)
			}
		})
		propValue = buf.String()
	}

	return propValue
}

// newParser returns a parser that converts the content of r to UTF-8 based on the content type of r.
func newParser(r io.Reader, contentType string, baseURL *url.URL) (*parser, error) {
	r, err := charset.NewReader(r, contentType)
	if err != nil {
		return nil, err
	}

	tree, err := html.Parse(r)
	if err != nil {
		return nil, err
	}

	return &parser{
		tree:            tree,
		data:            &Microdata{},
		baseURL:         baseURL,
		identifiedNodes: make(map[string]*html.Node),
	}, nil
}

// getAttr returns the value associated with the given attribute from the given node.
func getAttr(attribute string, node *html.Node) (string, bool) {
	for _, attr := range node.Attr {
		if attribute == attr.Key {
			return attr.Val, true
		}
	}
	return "", false
}

// walkNodes traverses the node tree executing the given functions.
func walkNodes(n *html.Node, f func(*html.Node)) {
	if n != nil {
		f(n)
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			walkNodes(c, f)
		}
	}
}

// ParseHTML parses the HTML document available in the given reader and returns
// the microdata. The given url is used to resolve the URLs in the
// attributes. The given contentType is used convert the content of r to UTF-8.
func ParseHTML(r io.Reader, contentType string, u *url.URL) (*Microdata, error) {
	p, err := newParser(r, contentType, u)
	if err != nil {
		return nil, err
	}
	return p.parse()
}

// ParseURL parses the HTML document available at the given URL and returns the
// microdata.
func ParseURL(urlStr string) (*Microdata, error) {
	var data *Microdata

	u, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	resp, err := http.DefaultClient.Get(urlStr)
	if err != nil {
		return data, err
	}

	contentType := resp.Header.Get("Content-Type")

	p, err := newParser(resp.Body, contentType, u)
	if err != nil {
		return nil, err
	}

	return p.parse()
}
<commit_msg>Parse the content attribute in other tags besides the meta tag.<commit_after>// Copyright 2015 Lars Wiegman. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.

/*

	Package flag implements command-line flag parsing.
	Package microdata implements a HTML microdata parser. It depends on the
	golang.org/x/net/html HTML5-compliant parser.

	Usage:

	Pass a reader, content-type and a base URL to the ParseHTML function.
		data, err := microdata.ParseHTML(reader, contentType, baseURL)
		items := data.Items

	Pass an URL to the ParseURL function.
		data, _ := microdata.ParseURL("http://example.com/blogposting")
		items := data.Items
*/

package microdata

import (
	"bytes"
	"io"
	"net/http"
	"net/url"
	"strings"

	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
	"golang.org/x/net/html/charset"
)

type Microdata struct {
	Items []*Item `json:"items"`
}

// addItem adds the item to the items list.
func (m *Microdata) addItem(item *Item) {
	m.Items = append(m.Items, item)
}

type ValueList []interface{}

type PropertyMap map[string]ValueList

type Item struct {
	Types      []string    `json:"type"`
	Properties PropertyMap `json:"properties"`
	Id         string      `json:"id,omitempty"`
}

// addString adds the property, value pair to the properties map. It appends to any
// existing property.
func (i *Item) addString(property, value string) {
	i.Properties[property] = append(i.Properties[property], value)
}

// addItem adds the property, value pair to the properties map. It appends to any
// existing property.
func (i *Item) addItem(property string, value *Item) {
	i.Properties[property] = append(i.Properties[property], value)
}

// addType adds the value to the types list.
func (i *Item) addType(value string) {
	i.Types = append(i.Types, value)
}

// NewItem returns a new Item.
func NewItem() *Item {
	return &Item{
		Types:      make([]string, 0),
		Properties: make(PropertyMap, 0),
	}
}

type parser struct {
	tree            *html.Node
	data            *Microdata
	baseURL         *url.URL
	identifiedNodes map[string]*html.Node
}

// parse returns the microdata from the parser's node tree.
func (p *parser) parse() (*Microdata, error) {
	toplevelNodes := []*html.Node{}

	walkNodes(p.tree, func(n *html.Node) {
		if _, ok := getAttr("itemscope", n); ok {
			if _, ok := getAttr("itemprop", n); !ok {
				toplevelNodes = append(toplevelNodes, n)
			}
		}
		if id, ok := getAttr("id", n); ok {
			p.identifiedNodes[id] = n
		}
	})

	for _, node := range toplevelNodes {
		item := NewItem()
		p.data.addItem(item)
		p.readAttr(item, node)
		p.readItem(item, node, true)
	}

	return p.data, nil
}

// readItem traverses the given node tree, applying relevant attributes to the
// given item.
func (p *parser) readItem(item *Item, node *html.Node, isToplevel bool) {
	itemprops, hasProp := getAttr("itemprop", node)
	_, hasScope := getAttr("itemscope", node)

	switch {
	case hasScope && hasProp:
		subItem := NewItem()
		p.readAttr(subItem, node)
		for _, propName := range strings.Split(itemprops, " ") {
			if len(propName) > 0 {
				item.addItem(propName, subItem)
			}
		}
		for c := node.FirstChild; c != nil; c = c.NextSibling {
			p.readItem(subItem, c, false)
		}
		return
	case !hasScope && hasProp:
		if s := p.getValue(node); len(s) > 0 {
			for _, propName := range strings.Split(itemprops, " ") {
				if len(propName) > 0 {
					item.addString(propName, s)
				}
			}
		}
	case hasScope && !hasProp && !isToplevel:
		return
	}

	for c := node.FirstChild; c != nil; c = c.NextSibling {
		p.readItem(item, c, false)
	}
}

// readAttr applies relevant attributes from the given node to the given item.
func (p *parser) readAttr(item *Item, node *html.Node) {
	if s, ok := getAttr("itemtype", node); ok {
		for _, itemtype := range strings.Split(s, " ") {
			if len(itemtype) > 0 {
				item.addType(itemtype)
			}
		}

		if s, ok := getAttr("itemid", node); ok {
			if u, err := p.baseURL.Parse(s); err == nil {
				item.Id = u.String()
			}
		}
	}

	if s, ok := getAttr("itemref", node); ok {
		for _, itemref := range strings.Split(s, " ") {
			if len(itemref) > 0 {
				if n, ok := p.identifiedNodes[itemref]; ok {
					p.readItem(item, n, false)
				}
			}
		}
	}
}

// getValue returns the value of the property, value pair in the given node.
func (p *parser) getValue(node *html.Node) string {
	var propValue string

	switch node.DataAtom {
	case atom.Meta:
		if value, ok := getAttr("content", node); ok {
			propValue = value
		}
	case atom.Audio, atom.Embed, atom.Iframe, atom.Img, atom.Source, atom.Track, atom.Video:
		if value, ok := getAttr("src", node); ok {
			if u, err := p.baseURL.Parse(value); err == nil {
				propValue = u.String()
			}
		}
	case atom.A, atom.Area, atom.Link:
		if value, ok := getAttr("href", node); ok {
			if u, err := p.baseURL.Parse(value); err == nil {
				propValue = u.String()
			}
		}
	case atom.Data, atom.Meter:
		if value, ok := getAttr("value", node); ok {
			propValue = value
		}
	case atom.Time:
		if value, ok := getAttr("datetime", node); ok {
			propValue = value
		}
	default:
		// The "content" attribute can be found on other tags besides the meta tag.
		if value, ok := getAttr("content", node); ok {
			propValue = value
			break
		}

		var buf bytes.Buffer
		walkNodes(node, func(n *html.Node) {
			if n.Type == html.TextNode {
				buf.WriteString(n.Data)
			}
		})
		propValue = buf.String()
	}

	return propValue
}

// newParser returns a parser that converts the content of r to UTF-8 based on the content type of r.
func newParser(r io.Reader, contentType string, baseURL *url.URL) (*parser, error) {
	r, err := charset.NewReader(r, contentType)
	if err != nil {
		return nil, err
	}

	tree, err := html.Parse(r)
	if err != nil {
		return nil, err
	}

	return &parser{
		tree:            tree,
		data:            &Microdata{},
		baseURL:         baseURL,
		identifiedNodes: make(map[string]*html.Node),
	}, nil
}

// getAttr returns the value associated with the given attribute from the given node.
func getAttr(attribute string, node *html.Node) (string, bool) {
	for _, attr := range node.Attr {
		if attribute == attr.Key {
			return attr.Val, true
		}
	}
	return "", false
}

// walkNodes traverses the node tree executing the given functions.
func walkNodes(n *html.Node, f func(*html.Node)) {
	if n != nil {
		f(n)
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			walkNodes(c, f)
		}
	}
}

// ParseHTML parses the HTML document available in the given reader and returns
// the microdata. The given url is used to resolve the URLs in the
// attributes. The given contentType is used convert the content of r to UTF-8.
func ParseHTML(r io.Reader, contentType string, u *url.URL) (*Microdata, error) {
	p, err := newParser(r, contentType, u)
	if err != nil {
		return nil, err
	}
	return p.parse()
}

// ParseURL parses the HTML document available at the given URL and returns the
// microdata.
func ParseURL(urlStr string) (*Microdata, error) {
	var data *Microdata

	u, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	resp, err := http.DefaultClient.Get(urlStr)
	if err != nil {
		return data, err
	}

	contentType := resp.Header.Get("Content-Type")

	p, err := newParser(resp.Body, contentType, u)
	if err != nil {
		return nil, err
	}

	return p.parse()
}
<|endoftext|>