<commit_before>// Copyright 2012 SocialCode. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package gelf

import (
	"bytes"
	"compress/gzip"
	"compress/zlib"
	"compress/flate"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"os"
	"path"
	"runtime"
	"strings"
	"sync"
	"time"
)

// Writer implements io.Writer and is used to send both discrete
// messages to a graylog2 server, or data from a stream-oriented
// interface (like the functions in log).
type Writer struct {
	mu               sync.Mutex
	conn             net.Conn
	hostname         string
	Facility         string // defaults to current process name
	CompressionLevel int    // one of the consts from compress/flate
	CompressionType  CompressType
}

// What compression type the writer should use when sending messages
// to the graylog2 server
type CompressType int

const (
	CompressGzip CompressType = iota
	CompressZlib
)

// Message represents the contents of the GELF message.  It is gzipped
// before sending.
//
// TODO: support optional ('_'-prefixed) fields?
type Message struct {
	Version  string `json:"version"`
	Host     string `json:"host"`
	Short    string `json:"short_message"`
	Full     string `json:"full_message"`
	TimeUnix int64  `json:"timestamp"`
	Level    int32  `json:"level"`
	Facility string `json:"facility"`
	File     string `json:"file"`
	Line     int    `json:"line"`
}

// Used to control GELF chunking.  Should be less than (MTU - len(UDP
// header)).
//
// TODO: generate dynamically using Path MTU Discovery?
const (
	ChunkSize = 1420
	chunkedHeaderLen = 12
	chunkedDataLen = ChunkSize - chunkedHeaderLen
)

var (
	magicChunked = []byte{0x1e, 0x0f}
	magicZlib = []byte{0x78, 0x9c}
	magicGzip = []byte{0x1f, 0x8b}
)

// numChunks returns the number of GELF chunks necessary to transmit
// the given compressed buffer.
func numChunks(b []byte) int {
	lenB := len(b)
	if lenB <= ChunkSize {
		return 1
	}
	return len(b)/chunkedDataLen + 1
}

// New returns a new GELF Writer.  This writer can be used to send the
// output of the standard Go log functions to a central GELF server by
// passing it to log.SetOutput()
func NewWriter(addr string) (*Writer, error) {
	var err error
	w := new(Writer)
	w.CompressionLevel = flate.BestSpeed

	if w.conn, err = net.Dial("udp", addr); err != nil {
		return nil, err
	}
	if w.hostname, err = os.Hostname(); err != nil {
		return nil, err
	}

	w.Facility = path.Base(os.Args[0])

	return w, nil
}

// writes the gzip compressed byte array to the connection as a series
// of GELF chunked messages.  The header format is documented at
// https://github.com/Graylog2/graylog2-docs/wiki/GELF as:
//
//     2-byte magic (0x1e 0x0f), 8 byte id, 1 byte sequence id, 1 byte
//     total, chunk-data
func (w *Writer) writeChunked(zBytes []byte) (err error) {
	b := make([]byte, 0, ChunkSize)
	buf := bytes.NewBuffer(b)
	nChunksI := numChunks(zBytes)
	if nChunksI > 255 {
		return fmt.Errorf("msg too large, would need %d chunks", nChunksI)
	}
	nChunks := uint8(nChunksI)
	// use urandom to get a unique message id
	msgId := make([]byte, 8)
	n, err := io.ReadFull(rand.Reader, msgId)
	if err != nil || n != 8 {
		return fmt.Errorf("rand.Reader: %d/%s", n, err)
	}

	bytesLeft := len(zBytes)
	for i := uint8(0); i < nChunks; i++ {
		buf.Reset()
		// manually write header.  Don't care about
		// host/network byte order, because the spec only
		// deals in individual bytes.
		buf.Write(magicChunked) //magic
		buf.Write(msgId)
		buf.WriteByte(i)
		buf.WriteByte(nChunks)
		// slice out our chunk from zBytes
		chunkLen := chunkedDataLen
		if chunkLen > bytesLeft {
			chunkLen = bytesLeft
		}
		off := int(i)*chunkedDataLen
		chunk := zBytes[off:off+chunkLen]
		buf.Write(chunk)

		// write this chunk, and make sure the write was good
		n, err := w.conn.Write(buf.Bytes())
		if err != nil {
			return fmt.Errorf("Write (chunk %d/%d): %s", i,
				nChunks, err)
		}
		if n != len(buf.Bytes()) {
			return fmt.Errorf("Write len: (chunk %d/%d) (%d/%d)",
				i, nChunks, n, len(buf.Bytes()))
		}

		bytesLeft -= chunkLen
	}
	// debugging
	if bytesLeft != 0 {
		panic("aw shit")
	}
	return nil
}

// WriteMessage sends the specified message to the GELF server
// specified in the call to New().  It assumes all the fields are
// filled out appropriately.  In general, clients will want to use
// Write, rather than WriteMessage.
func (w *Writer) WriteMessage(m *Message) (err error) {
	mBytes, err := json.Marshal(m)
	if err != nil {
		return
	}

	var zBuf bytes.Buffer
	var zw io.WriteCloser
	switch w.CompressionType {
	case CompressGzip:
		zw, err = gzip.NewWriterLevel(&zBuf, w.CompressionLevel)
	case CompressZlib:
		zw, err = zlib.NewWriterLevel(&zBuf, w.CompressionLevel)
	default:
		panic(fmt.Sprintf("unknown compression type %d",
			w.CompressionType))
	}
	if err != nil {
		return
	}
	if _, err = zw.Write(mBytes); err != nil {
		return
	}
	zw.Close()

	zBytes := zBuf.Bytes()
	if numChunks(zBytes) > 1 {
		// if we have to chunk, remove the magic header
		return w.writeChunked(zBytes[2:])
	}

	n, err := w.conn.Write(zBytes)
	if err != nil {
		return
	}
	if n != len(zBytes) {
		return fmt.Errorf("bad write (%d/%d)", n, len(zBytes))
	}

	return nil
}

/*
func (w *Writer) Alert(m string) (err error)
func (w *Writer) Close() error
func (w *Writer) Crit(m string) (err error)
func (w *Writer) Debug(m string) (err error)
func (w *Writer) Emerg(m string) (err error)
func (w *Writer) Err(m string) (err error)
func (w *Writer) Info(m string) (err error)
func (w *Writer) Notice(m string) (err error)
func (w *Writer) Warning(m string) (err error)
*/

// getCallerIgnoringLog returns the filename and the line info of a
// function further down in the call stack.  Passing 0 in as callDepth
// would return info on the function calling getCallerIgnoringLog, 1
// the parent function, and so on.  The exception is that if the frame
// that is pointed to is from the go log library, included with go, it
// is ignored, and the function that called e.g. log.Println() is
// returned.
func getCallerIgnoringLog(callDepth int) (file string, line int) {
	// bump by 1 to ignore the getCallerIgnoringLog (this) stackframe
	callDepth++

	for {
		var ok bool
		_, file, line, ok = runtime.Caller(callDepth)
		if !ok {
			file = "???"
			line = 0
			break
		}
		if !strings.HasSuffix(file, "/pkg/log/log.go") &&
			!strings.HasSuffix(file, "/pkg/io/multi.go") {
			break
		}
		callDepth++
	}
	return
}

// Write encodes the given string in a GELF message and sends it to
// the server specified in New().
func (w *Writer) Write(p []byte) (n int, err error) {

	// 1 for the function that called us.
	file, line := getCallerIgnoringLog(1)

	// remove trailing and leading whitespace
	p = bytes.TrimSpace(p)

	// If there are newlines in the message, use the first line
	// for the short message and set the full message to the
	// original input.  If the input has no newlines, stick the
	// whole thing in Short.
	short := p
	full := []byte("")
	if i := bytes.IndexRune(p, '\n'); i > 0 {
		short = p[:i]
		full = p
	}

	m := Message{
		Version:  "1.0",
		Host:     w.hostname,
		Short:    string(short),
		Full:     string(full),
		TimeUnix: time.Now().Unix(),
		Level:    6, // info
		Facility: w.Facility,
		File:     file,
		Line:     line,
	}

	if err = w.WriteMessage(&m); err != nil {
		return 0, err
	}

	return len(p), nil
}
<commit_msg>writer: for gzip/zlib, the 'magic header' is part of the encoding<commit_after>// Copyright 2012 SocialCode. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package gelf

import (
	"bytes"
	"compress/gzip"
	"compress/zlib"
	"compress/flate"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"os"
	"path"
	"runtime"
	"strings"
	"sync"
	"time"
)

// Writer implements io.Writer and is used to send both discrete
// messages to a graylog2 server, or data from a stream-oriented
// interface (like the functions in log).
type Writer struct {
	mu               sync.Mutex
	conn             net.Conn
	hostname         string
	Facility         string // defaults to current process name
	CompressionLevel int    // one of the consts from compress/flate
	CompressionType  CompressType
}

// What compression type the writer should use when sending messages
// to the graylog2 server
type CompressType int

const (
	CompressGzip CompressType = iota
	CompressZlib
)

// Message represents the contents of the GELF message.  It is gzipped
// before sending.
//
// TODO: support optional ('_'-prefixed) fields?
type Message struct {
	Version  string `json:"version"`
	Host     string `json:"host"`
	Short    string `json:"short_message"`
	Full     string `json:"full_message"`
	TimeUnix int64  `json:"timestamp"`
	Level    int32  `json:"level"`
	Facility string `json:"facility"`
	File     string `json:"file"`
	Line     int    `json:"line"`
}

// Used to control GELF chunking.  Should be less than (MTU - len(UDP
// header)).
//
// TODO: generate dynamically using Path MTU Discovery?
const (
	ChunkSize = 1420
	chunkedHeaderLen = 12
	chunkedDataLen = ChunkSize - chunkedHeaderLen
)

var (
	magicChunked = []byte{0x1e, 0x0f}
	magicZlib = []byte{0x78, 0x9c}
	magicGzip = []byte{0x1f, 0x8b}
)

// numChunks returns the number of GELF chunks necessary to transmit
// the given compressed buffer.
func numChunks(b []byte) int {
	lenB := len(b)
	if lenB <= ChunkSize {
		return 1
	}
	return len(b)/chunkedDataLen + 1
}

// New returns a new GELF Writer.  This writer can be used to send the
// output of the standard Go log functions to a central GELF server by
// passing it to log.SetOutput()
func NewWriter(addr string) (*Writer, error) {
	var err error
	w := new(Writer)
	w.CompressionLevel = flate.BestSpeed

	if w.conn, err = net.Dial("udp", addr); err != nil {
		return nil, err
	}
	if w.hostname, err = os.Hostname(); err != nil {
		return nil, err
	}

	w.Facility = path.Base(os.Args[0])

	return w, nil
}

// writes the gzip compressed byte array to the connection as a series
// of GELF chunked messages.  The header format is documented at
// https://github.com/Graylog2/graylog2-docs/wiki/GELF as:
//
//     2-byte magic (0x1e 0x0f), 8 byte id, 1 byte sequence id, 1 byte
//     total, chunk-data
func (w *Writer) writeChunked(zBytes []byte) (err error) {
	b := make([]byte, 0, ChunkSize)
	buf := bytes.NewBuffer(b)
	nChunksI := numChunks(zBytes)
	if nChunksI > 255 {
		return fmt.Errorf("msg too large, would need %d chunks", nChunksI)
	}
	nChunks := uint8(nChunksI)
	// use urandom to get a unique message id
	msgId := make([]byte, 8)
	n, err := io.ReadFull(rand.Reader, msgId)
	if err != nil || n != 8 {
		return fmt.Errorf("rand.Reader: %d/%s", n, err)
	}

	bytesLeft := len(zBytes)
	for i := uint8(0); i < nChunks; i++ {
		buf.Reset()
		// manually write header.  Don't care about
		// host/network byte order, because the spec only
		// deals in individual bytes.
		buf.Write(magicChunked) //magic
		buf.Write(msgId)
		buf.WriteByte(i)
		buf.WriteByte(nChunks)
		// slice out our chunk from zBytes
		chunkLen := chunkedDataLen
		if chunkLen > bytesLeft {
			chunkLen = bytesLeft
		}
		off := int(i)*chunkedDataLen
		chunk := zBytes[off:off+chunkLen]
		buf.Write(chunk)

		// write this chunk, and make sure the write was good
		n, err := w.conn.Write(buf.Bytes())
		if err != nil {
			return fmt.Errorf("Write (chunk %d/%d): %s", i,
				nChunks, err)
		}
		if n != len(buf.Bytes()) {
			return fmt.Errorf("Write len: (chunk %d/%d) (%d/%d)",
				i, nChunks, n, len(buf.Bytes()))
		}

		bytesLeft -= chunkLen
	}
	// debugging
	if bytesLeft != 0 {
		panic("aw shit")
	}
	return nil
}

// WriteMessage sends the specified message to the GELF server
// specified in the call to New().  It assumes all the fields are
// filled out appropriately.  In general, clients will want to use
// Write, rather than WriteMessage.
func (w *Writer) WriteMessage(m *Message) (err error) {
	mBytes, err := json.Marshal(m)
	if err != nil {
		return
	}

	var zBuf bytes.Buffer
	var zw io.WriteCloser
	switch w.CompressionType {
	case CompressGzip:
		zw, err = gzip.NewWriterLevel(&zBuf, w.CompressionLevel)
	case CompressZlib:
		zw, err = zlib.NewWriterLevel(&zBuf, w.CompressionLevel)
	default:
		panic(fmt.Sprintf("unknown compression type %d",
			w.CompressionType))
	}
	if err != nil {
		return
	}
	if _, err = zw.Write(mBytes); err != nil {
		return
	}
	zw.Close()

	zBytes := zBuf.Bytes()
	if numChunks(zBytes) > 1 {
		return w.writeChunked(zBytes)
	}

	n, err := w.conn.Write(zBytes)
	if err != nil {
		return
	}
	if n != len(zBytes) {
		return fmt.Errorf("bad write (%d/%d)", n, len(zBytes))
	}

	return nil
}

/*
func (w *Writer) Alert(m string) (err error)
func (w *Writer) Close() error
func (w *Writer) Crit(m string) (err error)
func (w *Writer) Debug(m string) (err error)
func (w *Writer) Emerg(m string) (err error)
func (w *Writer) Err(m string) (err error)
func (w *Writer) Info(m string) (err error)
func (w *Writer) Notice(m string) (err error)
func (w *Writer) Warning(m string) (err error)
*/

// getCallerIgnoringLog returns the filename and the line info of a
// function further down in the call stack.  Passing 0 in as callDepth
// would return info on the function calling getCallerIgnoringLog, 1
// the parent function, and so on.  The exception is that if the frame
// that is pointed to is from the go log library, included with go, it
// is ignored, and the function that called e.g. log.Println() is
// returned.
func getCallerIgnoringLog(callDepth int) (file string, line int) {
	// bump by 1 to ignore the getCallerIgnoringLog (this) stackframe
	callDepth++

	for {
		var ok bool
		_, file, line, ok = runtime.Caller(callDepth)
		if !ok {
			file = "???"
			line = 0
			break
		}
		if !strings.HasSuffix(file, "/pkg/log/log.go") &&
			!strings.HasSuffix(file, "/pkg/io/multi.go") {
			break
		}
		callDepth++
	}
	return
}

// Write encodes the given string in a GELF message and sends it to
// the server specified in New().
func (w *Writer) Write(p []byte) (n int, err error) {

	// 1 for the function that called us.
	file, line := getCallerIgnoringLog(1)

	// remove trailing and leading whitespace
	p = bytes.TrimSpace(p)

	// If there are newlines in the message, use the first line
	// for the short message and set the full message to the
	// original input.  If the input has no newlines, stick the
	// whole thing in Short.
	short := p
	full := []byte("")
	if i := bytes.IndexRune(p, '\n'); i > 0 {
		short = p[:i]
		full = p
	}

	m := Message{
		Version:  "1.0",
		Host:     w.hostname,
		Short:    string(short),
		Full:     string(full),
		TimeUnix: time.Now().Unix(),
		Level:    6, // info
		Facility: w.Facility,
		File:     file,
		Line:     line,
	}

	if err = w.WriteMessage(&m); err != nil {
		return 0, err
	}

	return len(p), nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"os"
	"strings"
	"sync"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"

	"code.google.com/p/go.net/html"
)

type directory struct {
	node
	de map[string]fuse.Dirent
	mu sync.Mutex
}

func (d directory) Attr() fuse.Attr {
	return fuse.Attr{
		Mode:  os.ModeDir | 0500,
		Uid:   MyUID,
		Gid:   MyGID,
		Nlink: 1,
	}
}

func NewDirectory(parent *directory, fs *filesystem, name string) directory {
	return directory{node{parent, fs, name}, map[string]fuse.Dirent{}, sync.Mutex{}}
}

func (d *directory) populate() (err fuse.Error) {
	d.mu.Lock()
	defer d.mu.Unlock()

	if len(d.de) > 0 {
		return nil
	}
	r, err := d.fs.client.Do(d.fs.NewRequest("GET", d.fullpath()+"/"))
	if err != nil {
		log.Println("ERROR:", err)
		return err
	}
	log.Println(d.fullpath(), r.Request.URL, r.Status)
	defer r.Body.Close()

	if r.StatusCode != http.StatusOK {
		switch r.StatusCode {
		case http.StatusForbidden, http.StatusUnauthorized:
			err = fuse.EPERM
		default:
			err = fuse.ENOENT
		}
	}

	switch strings.SplitN(r.Header.Get("Content-Type"), ";", 2)[0] {
	case "text/html":
		doc, err := html.Parse(r.Body)
		if err != nil {
			return err
		}
		var walk func(*html.Node)
		walk = func(n *html.Node) {
			if n.Type == html.ElementNode && n.Data == "a" {
				for _, a := range n.Attr {
					if a.Key == "href" {
						direntType := fuse.DT_File
						if strings.HasSuffix(a.Val, "/") {
							direntType = fuse.DT_Dir
						}
						name := strings.TrimRight(a.Val, "/")
						d.de[name] = fuse.Dirent{
							Name: name,
							Type: direntType,
						}
						log.Println(a.Val, direntType)
						break
					}
				}
			}
			for c := n.FirstChild; c != nil; c = c.NextSibling {
				walk(c)
			}
		}
		walk(doc)
	default:
		panic("Unsupported directory response.")
	}
	return
}

func (d directory) ReadDir(_ fs.Intr) (de []fuse.Dirent, err fuse.Error) {
	if err = d.populate(); nil == err {
		de = make([]fuse.Dirent, len(d.de))
		i := 0
		for _, v := range d.de {
			de[i] = v
			i++
		}
	}
	return
}

func (d directory) Lookup(name string, _ fs.Intr) (fs.Node, fuse.Error) {
	log.Printf("directory.Lookup(name=%s, path=%s)", name, d.fullpath())
	if err := d.populate(); err != nil {
		return nil, fuse.ENOENT
	}
	if de, ok := d.de[name]; ok {
		switch de.Type {
		case fuse.DT_Dir:
			return NewDirectory(&d, d.fs, name), nil
		case fuse.DT_File:
			return NewFile(&d, d.fs, name)
		default:
			panic("should not happen.")
		}
	}
	return nil, fuse.ENOENT
}
<commit_msg>Ignore lookups for some system specific (osx for now) names.<commit_after>package main

import (
	"log"
	"net/http"
	"os"
	"strings"
	"sync"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"

	"code.google.com/p/go.net/html"
)

type directory struct {
	node
	de map[string]fuse.Dirent
	mu sync.Mutex
}

func (d directory) Attr() fuse.Attr {
	return fuse.Attr{
		Mode:  os.ModeDir | 0500,
		Uid:   MyUID,
		Gid:   MyGID,
		Nlink: 1,
	}
}

func NewDirectory(parent *directory, fs *filesystem, name string) directory {
	return directory{node{parent, fs, name}, map[string]fuse.Dirent{}, sync.Mutex{}}
}

func (d *directory) populate() (err fuse.Error) {
	d.mu.Lock()
	defer d.mu.Unlock()

	if len(d.de) > 0 {
		return nil
	}
	r, err := d.fs.client.Do(d.fs.NewRequest("GET", d.fullpath()+"/"))
	if err != nil {
		log.Println("ERROR:", err)
		return err
	}
	log.Println(d.fullpath(), r.Request.URL, r.Status)
	defer r.Body.Close()

	if r.StatusCode != http.StatusOK {
		switch r.StatusCode {
		case http.StatusForbidden, http.StatusUnauthorized:
			err = fuse.EPERM
		default:
			err = fuse.ENOENT
		}
	}

	switch strings.SplitN(r.Header.Get("Content-Type"), ";", 2)[0] {
	case "text/html":
		doc, err := html.Parse(r.Body)
		if err != nil {
			return err
		}
		var walk func(*html.Node)
		walk = func(n *html.Node) {
			if n.Type == html.ElementNode && n.Data == "a" {
				for _, a := range n.Attr {
					if a.Key == "href" {
						direntType := fuse.DT_File
						if strings.HasSuffix(a.Val, "/") {
							direntType = fuse.DT_Dir
						}
						name := strings.TrimRight(a.Val, "/")
						d.de[name] = fuse.Dirent{
							Name: name,
							Type: direntType,
						}
						log.Println(a.Val, direntType)
						break
					}
				}
			}
			for c := n.FirstChild; c != nil; c = c.NextSibling {
				walk(c)
			}
		}
		walk(doc)
	default:
		panic("Unsupported directory response.")
	}
	return
}

func (d directory) ReadDir(_ fs.Intr) (de []fuse.Dirent, err fuse.Error) {
	if err = d.populate(); nil == err {
		de = make([]fuse.Dirent, len(d.de))
		i := 0
		for _, v := range d.de {
			de[i] = v
			i++
		}
	}
	return
}

var ignoreNames = map[string]struct{}{
	"Backups.backupdb": struct{}{},
	"mach_kernel":      struct{}{},
	".DS_Store":        struct{}{},
	".hidden":          struct{}{},
	"._.":              struct{}{},
}

func (d directory) Lookup(name string, _ fs.Intr) (fs.Node, fuse.Error) {
	if _, ignore := ignoreNames[name]; !ignore && !strings.HasPrefix(name, "._") {
		log.Printf("directory.Lookup(name=%s, path=%s)", name, d.fullpath())
		if err := d.populate(); err != nil {
			return nil, fuse.ENOENT
		}
		if de, ok := d.de[name]; ok {
			switch de.Type {
			case fuse.DT_Dir:
				return NewDirectory(&d, d.fs, name), nil
			case fuse.DT_File:
				return NewFile(&d, d.fs, name)
			default:
				panic("should not happen.")
			}
		}
	}
	return nil, fuse.ENOENT
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
)

type Sich int

const (
	Without Sich = iota
	Acusative
	Dative
)

type Word interface {
	GetGerman() string
	GetEnglish() []Meaning
	GetThird() []Meaning
	GetCategory() string
}

type Meaning struct {
	Main        string `bson:"main" json:"main"`
	Paranthases string `bson:"paranthases" json:"paranthases"`
}

func NewMeanings(allMeanings string) []Meaning {
	meanings := []Meaning{}

	for _, word := range strings.Split(allMeanings, ";") {
		meanings = append(meanings, Meaning{word, ""})
	}

	return meanings
}

type DefaultWord struct {
	German     string    `bson:"german" json:"german"`
	English    []Meaning `bson:"english" json:"english"`
	Third      []Meaning `bson:"third" json:"third"`
	Category   string    `bson:"category" json:"category"`
	User       string    `bson:"user" json:"user"`
	Multiplier int       `bson:"multiplier" json:"multiplier"`
	Ok         bool      `bson:"ok", json:"ok"`
}

func NewDefaultWord(german, english, third, category, user string, multiplier int) DefaultWord {
	return DefaultWord{german, NewMeanings(english), NewMeanings(third), category, user, multiplier, true}
}

func NewWord(german, english, third, category, user string, multiplier int, ok bool) *DefaultWord {
	return &DefaultWord{german, NewMeanings(english), NewMeanings(third), category, user, multiplier, ok}
}

func (w *DefaultWord) GetGerman() string {
	return w.German
}

func (w *DefaultWord) GetEnglish() []Meaning {
	return w.English
}

func (w *DefaultWord) GetThird() []Meaning {
	return w.Third
}

func (w *DefaultWord) GetCategory() string {
	return w.Category
}

type Verb struct {
	DefaultWord    `bson:"word" json:"word"`
	Auxiliary      []string `bson:"auxiliary" json:"auxiliary"`
	PastParticiple string   `bson:"pastParticiple" json:"pastParticiple"`
	Preterite      string   `bson:"preterite" json:"preterite"`
	Du             string   `bson:"du" json:"du"`
	Er             string   `bson:"er" json:"er"`
	Sich           Sich     `bson:"sich" json:"sich"`
	Arguments      []string `bson:"arguments" json:"arguments"`
}

func NewVerb(german, english, third, user string, multiplier int, verbRegexp *regexp.Regexp) *Verb {
	pastParticiple := ""
	preterite := ""
	du := ""
	er := ""
	sich := Without
	arguments := []string{}

	matches := verbRegexp.FindStringSubmatch(german)

	auxiliary := strings.Split(matches[1], "/")

	main := strings.Split(matches[2], ",")

	german = main[0]

	if len(main) == 2 || len(main) == 4 || len(main) > 5 {
		return nil
	}
	if len(main) > 2 {
		pastParticiple = main[1]
		preterite = main[2]
	}
	if len(main) > 3 {
		du = main[3]
		er = main[4]
	}

	if matches[3] != "" {
		arguments = strings.Split(matches[3], "+")

		if strings.Contains(arguments[0], "sich (A)") {
			arguments = arguments[1:]
			sich = Acusative
		}

		if strings.Contains(arguments[0], "sich (D)") {
			arguments = arguments[1:]
			sich = Dative
		}

		if strings.Contains(arguments[0], "sich") {
			return nil
		}
	}

	return &Verb{
		NewDefaultWord(german, english, third, "verb", user, multiplier),
		auxiliary,
		pastParticiple,
		preterite,
		du,
		er,
		sich,
		arguments,
	}
}

type Noun struct {
	DefaultWord `bson:"word" json:"word"`
	Plural      []string `bson:"plural" json:"plural"`
}

func NewNoun(german, english, third, user string, multiplier int, nounRegexp *regexp.Regexp) *Noun {
	matches := nounRegexp.FindAllStringSubmatch(german, -1)

	fmt.Printf("Matches: %q\n", matches)

	return &Noun{
		NewDefaultWord(german, english, third, "noun", user, multiplier),
		[]string{},
	}
}

type Adjective struct {
	DefaultWord `bson:"word" json:"word"`
	Comparative []string `bson:"comparative" json:"comparative"`
	Superlative []string `bson:"superlative" json:"superlative"`
}

func NewAdjective(german, english, third, user string, multiplier int) *Adjective {
	adjectiveParts := strings.Split(german, ",")

	comparative := []string{}
	superlative := []string{}

	if len(adjectiveParts) > 1 {
		comparative = strings.Split(adjectiveParts[1], "/")
	}
	if len(adjectiveParts) > 2 {
		superlative = strings.Split(adjectiveParts[2], "/")
	}

	return &Adjective{
		NewDefaultWord(german, english, third, "adjective", user, multiplier),
		comparative,
		superlative,
	}
}

func main() {
	/*
		session, err := mgo.Dial("localhost")
		if err != nil {
			panic(err)
		}
		defer session.Close()

		session.SetMode(mgo.Monotonic, true)
	*/
	nounRegexp := regexp.MustCompile("^([ers/]+) ([^,]+),(.*)")

	verbRegexp := regexp.MustCompile("^([sh/]+) ([^+]*)([+](.*))$")

	file, e := ioutil.ReadFile("./test.json")
	if e != nil {
		fmt.Printf("File error: %v\n", e)
		os.Exit(1)
	}

	//m := new(Dispatch)
	//var m interface{}
	dictionary := [][4]string{}
	json.Unmarshal(file, &dictionary)
	//fmt.Printf("Results: %v\n", dictionary)

	words := []Word{}

	multiplier := 5

	user := "peteraba"

	for _, word := range dictionary {
		var w Word

		switch word[3] {
		case "adj":
			w = NewAdjective(word[0], word[1], word[2], user, multiplier)
			break
		case "noun":
			if nounRegexp.MatchString(word[0]) {
				w = NewNoun(word[0], word[1], word[2], user, multiplier, nounRegexp)
			}
			break
		case "verb":
			if verbRegexp.MatchString(word[0]) {
				w = NewVerb(word[0], word[1], word[2], user, multiplier, verbRegexp)
			}
			break
		default:
			w = NewWord(word[0], word[1], word[2], word[3], user, multiplier, true)
		}

		if w == nil {
			w = NewWord(word[0], word[1], word[2], word[3], user, multiplier, false)
		}

		words = append(words, w)
	}

	/*for _, w := range words {
		fmt.Printf("Results: %v\n", w)
	}
	/*
		w1 := NewWord("h runternehmen, runternahmen, runtergenommen, runternimmst, runternimmt", "to take down", "levenni vmit (föntről)", "verb")
		w2 := NewWord("schlecht sein + für (A)", "to do wrong to sth", "rosszat tenni vminek", "verb")
		w3 := NewWord("h scheren, schoren/scherten, geschoren/geschert", "to shear (sheep), to cut, to trim (hair)", "nyírni, lenyírni", "verb")
		c1 := session.DB("test").C("word")
		err = c1.Insert(&w1, &w2, &w3, w1, w2, w3)
		if err != nil {
			log.Fatal(err)
		}

		v1 := NewVerb("h runternehmen, runternahmen, runtergenommen, runternimmst, runternimmt", "to take down", "levenni vmit (föntről)")
		v2 := NewVerb("schlecht sein + für (A)", "to do wrong to sth", "rosszat tenni vminek")
		v3 := NewVerb("h scheren, schoren/scherten, geschoren/geschert", "to shear (sheep), to cut, to trim (hair)", "nyírni, lenyírni")
		c2 := session.DB("test").C("verb")
		err = c2.Insert(&v1, &v2, &v3)
		if err != nil {
			log.Fatal(err)
		}

		n1 := NewNoun("r Arbeitsplatz,⍨e", "work place (both abstract or concrete)", "munkahely (absztrakt vagy konkrét)")
		n2 := NewNoun("r/s Hot Dog,~s", "hotdog", "hotdog")
		n3 := NewNoun("s Jurastudium, Jurastudien", "law studies", "jogi tanulmány")
		c3 := session.DB("test").C("noun")
		err = c3.Insert(&n1, &n2, &n3)
		if err != nil {
			log.Fatal(err)
		}

		a1 := NewAdjective("weich,~er,~esten", "soft", "puha")
		a2 := NewAdjective("ständig,-", "persistent; permanent", "állandó; állandóan, folyton")
		a3 := NewAdjective("schmal,~er/⍨er,~sten/⍨sten", "narrow", "keskeny, szűk")
		c4 := session.DB("test").C("adjective")
		err = c4.Insert(a1, a2, a3	if err != nil {
			log.Fatal(err)
		}*/
}

func log(err error) {
	fmt.Println(err)
}
<commit_msg>Verb parsing complete<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
)

type Sich string

const (
	Without   Sich = ""
	Acusative      = "a"
	Dative         = "d"
)

type Article string

const (
	Der Article = "r"
	Die         = "e"
	Das         = "s"
)

type Word interface {
	GetGerman() string
	GetEnglish() []Meaning
	GetThird() []Meaning
	GetCategory() string
}

type Meaning struct {
	Main        string `bson:"main" json:"main"`
	Paranthases string `bson:"paranthases" json:"paranthases"`
}

func NewMeanings(allMeanings string) []Meaning {
	meanings := []Meaning{}

	for _, word := range strings.Split(allMeanings, ";") {
		meanings = append(meanings, Meaning{word, ""})
	}

	return meanings
}

type DefaultWord struct {
	German     string    `bson:"german" json:"german"`
	English    []Meaning `bson:"english" json:"english"`
	Third      []Meaning `bson:"third" json:"third"`
	Category   string    `bson:"category" json:"category"`
	User       string    `bson:"user" json:"user"`
	Multiplier int       `bson:"multiplier" json:"multiplier"`
	Ok         bool      `bson:"ok", json:"ok"`
}

func NewDefaultWord(german, english, third, category, user string, multiplier int) DefaultWord {
	return DefaultWord{german, NewMeanings(english), NewMeanings(third), category, user, multiplier, true}
}

func NewWord(german, english, third, category, user string, multiplier int, ok bool) *DefaultWord {
	return &DefaultWord{german, NewMeanings(english), NewMeanings(third), category, user, multiplier, ok}
}

func (w *DefaultWord) GetGerman() string {
	return w.German
}

func (w *DefaultWord) GetEnglish() []Meaning {
	return w.English
}

func (w *DefaultWord) GetThird() []Meaning {
	return w.Third
}

func (w *DefaultWord) GetCategory() string {
	return w.Category
}

type Verb struct {
	DefaultWord    `bson:"word" json:"word"`
	Auxiliary      []string `bson:"auxiliary" json:"auxiliary"`
	PastParticiple []string `bson:"pastParticiple" json:"pastParticiple"`
	Preterite      []string `bson:"preterite" json:"preterite"`
	Ich            []string `bson:"ich" json:"ich"`
	Du             []string `bson:"du" json:"du"`
	Er             []string `bson:"er" json:"er"`
	Wir            []string `bson:"wir" json:"wir"`
	Ihr            []string `bson:"ihr" json:"ihr"`
	Sie            []string `bson:"sie" json:"sie"`
	Sich           Sich     `bson:"sich" json:"sich"`
	Arguments      []string `bson:"arguments" json:"arguments"`
}

type Superverb struct {
	Verb `bson:"verb" json:"verb"`
}

func NewVerb(german, english, third, user string, multiplier int, verbRegexp *regexp.Regexp) *Verb {
	pastParticiple := ""
	preterite := ""
	ich := ""
	du := ""
	er := ""
	wir := ""
	ihr := ""
	sie := ""

	matches := verbRegexp.FindStringSubmatch(german)

	main := strings.Split(matches[2], ",")
	switch len(main) {
	case 1:
		german = main[0]
		break
	case 3:
		german, pastParticiple, preterite = main[0], main[1], main[2]
		break
	case 5:
		german, pastParticiple, preterite, du, er = main[0], main[1], main[2], main[3], main[4]
		break
	case 9:
		german, ich, du, er, wir, ihr, sie, pastParticiple, preterite = main[0], main[1], main[2], main[3], main[4], main[5], main[6], main[7], main[8]
		break
	default:
		return nil
	}

	sich, arguments, err := parseArguments(matches[3])
	if err != nil {
		return nil
	}

	return &Verb{
		NewDefaultWord(german, english, third, "verb", user, multiplier),
		strings.Split(matches[1], "/"),
		strings.Split(pastParticiple, "/"),
		strings.Split(preterite, "/"),
		strings.Split(ich, "/"),
		strings.Split(du, "/"),
		strings.Split(er, "/"),
		strings.Split(wir, "/"),
		strings.Split(ihr, "/"),
		strings.Split(sie, "/"),
		sich,
		arguments,
	}
}

func parseArguments(rawArguments string) (Sich, []string, error) {
	if rawArguments == "" {
		return Without, []string{}, nil
	}
	arguments := strings.Split(rawArguments, "+")

	if strings.Contains(arguments[0], "sich (A)") {
		return Acusative, arguments[1:], nil
	}

	if strings.Contains(arguments[0], "sich (D)") {
		return Dative, arguments[1:], nil
	}

	if strings.Contains(arguments[0], "sich") {
		return Without, []string{}, errors.New("Sich definition is invalid")
	}

	return Without, []string{}, nil
}

type Noun struct {
	DefaultWord `bson:"word" json:"word"`
	Articles    []Article `bson:"article" json:"article"`
	Plural      []string  `bson:"plural" json:"plural"`
}

func NewNoun(german, english, third, user string, multiplier int, nounRegexp *regexp.Regexp) *Noun {
	matches := nounRegexp.FindStringSubmatch(german)

	articles := []Article{}
	for _, article := range strings.Split(matches[1], "/") {
		switch article {
		case "r":
			articles = append(articles, Der)
			break
		case "e":
			articles = append(articles, Die)
			break
		case "s":
			articles = append(articles, Das)
			break
		default:
			return nil
		}
	}

	return &Noun{
		NewDefaultWord(german, english, third, "noun", user, multiplier),
		articles,
		strings.Split(matches[3], "/"),
	}
}

type Adjective struct {
	DefaultWord `bson:"word" json:"word"`
	Comparative []string `bson:"comparative" json:"comparative"`
	Superlative []string `bson:"superlative" json:"superlative"`
}

func NewAdjective(german, english, third, user string, multiplier int) *Adjective {
	adjectiveParts := strings.Split(german, ",")

	comparative := []string{}
	superlative := []string{}

	if len(adjectiveParts) > 1 {
		comparative = strings.Split(adjectiveParts[1], "/")
	}
	if len(adjectiveParts) > 2 {
		superlative = strings.Split(adjectiveParts[2], "/")
	}

	return &Adjective{
		NewDefaultWord(german, english, third, "adjective", user, multiplier),
		comparative,
		superlative,
	}
}

func main() {
	/*
		session, err := mgo.Dial("localhost")
		if err != nil {
			panic(err)
		}
		defer session.Close()

		session.SetMode(mgo.Monotonic, true)
	*/
	nounRegexp := regexp.MustCompile("^([ers/]+) ([^,]+),(.*)")

	verbRegexp := regexp.MustCompile("^([sh/]+) ([^+]*)([+](.*))?$")

	file, e := ioutil.ReadFile("./test.json")
	if e != nil {
		fmt.Printf("File error: %v\n", e)
		os.Exit(1)
	}

	//m := new(Dispatch)
	//var m interface{}
	dictionary := [][4]string{}
	json.Unmarshal(file, &dictionary)
	//fmt.Printf("Results: %v\n", dictionary)

	words := []Word{}

	multiplier := 5

	user := "peteraba"

	for _, word := range dictionary {
		var w Word

		if word[1] == "" {
			continue
		}

		switch word[3] {
		case "adj":
			w = NewAdjective(word[0], word[1], word[2], user, multiplier)
			break
		case "noun":
			if nounRegexp.MatchString(word[0]) {
				w = NewNoun(word[0], word[1], word[2], user, multiplier, nounRegexp)
			}
			break
		case "verb":
			if verbRegexp.MatchString(word[0]) {
				w = NewVerb(word[0], word[1], word[2], user, multiplier, verbRegexp)
			}
			break
		default:
			w = NewWord(word[0], word[1], word[2], word[3], user, multiplier, true)
		}

		if w == nil {
			fmt.Printf("Failed: %v\n", word[0])
			w = NewWord(word[0], word[1], word[2], word[3], user, multiplier, false)
		}

		words = append(words, w)
	}

	/*for _, w := range words {
		fmt.Printf("Results: %v\n", w)
	}
	/*
		w1 := NewWord("h runternehmen, runternahmen, runtergenommen, runternimmst, runternimmt", "to take down", "levenni vmit (föntről)", "verb")
		w2 := NewWord("schlecht sein + für (A)", "to do wrong to sth", "rosszat tenni vminek", "verb")
		w3 := NewWord("h scheren, schoren/scherten, geschoren/geschert", "to shear (sheep), to cut, to trim (hair)", "nyírni, lenyírni", "verb")
		c1 := session.DB("test").C("word")
		err = c1.Insert(&w1, &w2, &w3, w1, w2, w3)
		if err != nil {
			log.Fatal(err)
		}

		v1 := NewVerb("h runternehmen, runternahmen, runtergenommen, runternimmst, runternimmt", "to take down", "levenni vmit (föntről)")
		v2 := NewVerb("schlecht sein + für (A)", "to do wrong to sth", "rosszat tenni vminek")
		v3 := NewVerb("h scheren, schoren/scherten, geschoren/geschert", "to shear (sheep), to cut, to trim (hair)", "nyírni, lenyírni")
		c2 := session.DB("test").C("verb")
		err = c2.Insert(&v1, &v2, &v3)
		if err != nil {
			log.Fatal(err)
		}

		n1 := NewNoun("r Arbeitsplatz,⍨e", "work place (both abstract or concrete)", "munkahely (absztrakt vagy konkrét)")
		n2 := NewNoun("r/s Hot Dog,~s", "hotdog", "hotdog")
		n3 := NewNoun("s Jurastudium, Jurastudien", "law studies", "jogi tanulmány")
		c3 := session.DB("test").C("noun")
		err = c3.Insert(&n1, &n2, &n3)
		if err != nil {
			log.Fatal(err)
		}

		a1 := NewAdjective("weich,~er,~esten", "soft", "puha")
		a2 := NewAdjective("ständig,-", "persistent; permanent", "állandó; állandóan, folyton")
		a3 := NewAdjective("schmal,~er/⍨er,~sten/⍨sten", "narrow", "keskeny, szűk")
		c4 := session.DB("test").C("adjective")
		err = c4.Insert(a1, a2, a3	if err != nil {
			log.Fatal(err)
		}*/
}

func log(err error) {
	fmt.Println(err)
}
<|endoftext|>


<commit_before>package scamp

import (
	"math/rand"
	"sync"
)

// type ClientChan chan *Client

// Client represents a scamp client
type Client struct {
	conn            *Connection
	serv            *Service
	requests        chan *Message
	openReplies     map[int]chan *Message
	openRepliesLock sync.Mutex
	isClosed        bool
	closedM         sync.Mutex
	sendM           sync.Mutex
	spIdent         string
}

// Dial calls DialConnection to establish a secure (tls) connection,
// and uses that connection to create a client
func Dial(connspec string) (client *Client, err error) {
	// Trace.Printf("Connecting to: `%s`", connspec)

	conn, err := DialConnection(connspec)
	if err != nil {
		return
	}
	client = NewClient(conn, "service-proxy")

	return
}

// NewClient takes a scamp connection and creates a new scamp client
func NewClient(conn *Connection, clientType string) (client *Client) {
	// Trace.Printf("client allocated")

	client = new(Client)
	client.conn = conn
	client.requests = make(chan *Message)
	client.openReplies = make(map[int]chan *Message)
	// clientID++
	// client.ID = clientID
	// if len(clientType) > 0 {
	// 	Warning.Printf("client %v created for %s\n", client.ID, clientType)
	// } else {
	// 	Warning.Printf("client %v created\n", client.ID)
	// }
	conn.SetClient(client)

	// grNum++
	// go client.splitReqsAndReps(grNum, clientID)
	go client.splitReqsAndReps()

	return
}

// SetService assigns a *Service to client.serv
func (client *Client) SetService(serv *Service) {
	client.serv = serv
}

// Send TODO: would be nice to have different code path for scamp responses
// so that we don't need to rely on garbage collection of channels
// when we're replying and don't expect or need a response
func (client *Client) Send(msg *Message) (responseChan chan *Message, err error) {
	client.sendM.Lock()
	defer client.sendM.Unlock()

	msg.RequestID = rand.Intn(10000)
	err = client.conn.Send(msg)
	if err != nil {
		// Trace.Printf("SCAMP send error: %s", err)
		return
	}

	if msg.MessageType == MessageTypeRequest {
		// Trace.Printf("sending request so waiting for reply")
		responseChan = make(chan *Message)
		client.openRepliesLock.Lock()
		client.openReplies[msg.RequestID] = responseChan
		client.openRepliesLock.Unlock()
	} else {
		// Trace.Printf("sending reply so done with this message")
	}

	return
}

// Close unlocks a client mutex and closes the connection
func (client *Client) Close() {
	if len(client.spIdent) > 0 {
		sp := DefaultCache.Retrieve(client.spIdent)
		if sp != nil {
			sp.client = nil
		}
	}

	client.closedM.Lock()
	defer client.closedM.Unlock()
	if client.isClosed {
		// Trace.Printf("client already closed. skipping shutdown.")
		return
	}

	// Trace.Printf("closing client...")
	// Trace.Printf("closing client conn...")
	client.closeConnection(client.conn)

	// Notify wrapper service that we're dead
	if client.serv != nil {
		// Trace.Printf("removing client from service...")
		client.serv.RemoveClient(client)
	}

	// Trace.Printf("marking client as closed...")
	client.isClosed = true
}

// closeConnection calls client.conn.Close() and sets the client.conn to nil
func (client *Client) closeConnection(conn *Connection) {
	if !client.conn.isClosed {
		client.conn.Close()
	}
	client.conn = nil
}

// func (client *Client) splitReqsAndReps(grNum, clientID int) (err error) {
func (client *Client) splitReqsAndReps() (err error) {
	var replyChan chan *Message

forLoop:
	for {
		// Trace.Printf("Entering forLoop splitReqsAndReps")
		select {
		case message, ok := <-client.conn.msgs:
			if !ok {
				// Trace.Printf("client.conn.msgs... CLOSED!")
				break forLoop
			}
			if message == nil {
				continue
			}

			// Trace.Printf("Splitting incoming message to reqs and reps")

			if message.MessageType == MessageTypeRequest {
				// interesting things happen if there are outstanding messages
				// and the client closes
				client.requests <- message
			} else if message.MessageType == MessageTypeReply {
				client.openRepliesLock.Lock()
				replyChan = client.openReplies[message.RequestID]
				if replyChan == nil {
					// Error.Printf("got an unexpected reply for requestId: %d. Skipping.", message.RequestID)
					client.openRepliesLock.Unlock()
					continue
				}

				delete(client.openReplies, message.RequestID)
				client.openRepliesLock.Unlock()

				replyChan <- message
			} else {
				// Trace.Printf("Could not handle msg, it's neither req or reply. Skipping.")
				continue
			}
		}
	}

	// Trace.Printf("done with SplitReqsAndReps")
	close(client.requests)
	client.openRepliesLock.Lock()
	for _, openReplyChan := range client.openReplies {
		close(openReplyChan)
	}
	client.openRepliesLock.Unlock()
	if !client.isClosed {
		client.Close()
	}

	return
}

// Incoming returns a client's MessageChan
func (client *Client) Incoming() chan *Message {
	return client.requests
}
<commit_msg>Revert "Previous request IDs would usually be `1`, which isn't very helpful"<commit_after>package scamp

import (
	"sync"
)

// type ClientChan chan *Client

// Client represents a scamp client
type Client struct {
	conn            *Connection
	serv            *Service
	requests        chan *Message
	openReplies     map[int]chan *Message
	openRepliesLock sync.Mutex
	isClosed        bool
	closedM         sync.Mutex
	sendM           sync.Mutex
	nextRequestID   int
	spIdent         string
}

// Dial calls DialConnection to establish a secure (tls) connection,
// and uses that connection to create a client
func Dial(connspec string) (client *Client, err error) {
	// Trace.Printf("Connecting to: `%s`", connspec)

	conn, err := DialConnection(connspec)
	if err != nil {
		return
	}
	client = NewClient(conn, "service-proxy")

	return
}

// NewClient takes a scamp connection and creates a new scamp client
func NewClient(conn *Connection, clientType string) (client *Client) {
	// Trace.Printf("client allocated")

	client = new(Client)
	client.conn = conn
	client.requests = make(chan *Message)
	client.openReplies = make(map[int]chan *Message)
	// clientID++
	// client.ID = clientID
	// if len(clientType) > 0 {
	// 	Warning.Printf("client %v created for %s\n", client.ID, clientType)
	// } else {
	// 	Warning.Printf("client %v created\n", client.ID)
	// }
	conn.SetClient(client)

	// grNum++
	// go client.splitReqsAndReps(grNum, clientID)
	go client.splitReqsAndReps()

	return
}

// SetService assigns a *Service to client.serv
func (client *Client) SetService(serv *Service) {
	client.serv = serv
}

// Send TODO: would be nice to have different code path for scamp responses
// so that we don't need to rely on garbage collection of channels
// when we're replying and don't expect or need a response
func (client *Client) Send(msg *Message) (responseChan chan *Message, err error) {
	client.sendM.Lock()
	defer client.sendM.Unlock()

	client.nextRequestID++
	msg.RequestID = client.nextRequestID
	err = client.conn.Send(msg)
	if err != nil {
		// Trace.Printf("SCAMP send error: %s", err)
		return
	}

	if msg.MessageType == MessageTypeRequest {
		// Trace.Printf("sending request so waiting for reply")
		responseChan = make(chan *Message)
		client.openRepliesLock.Lock()
		client.openReplies[msg.RequestID] = responseChan
		client.openRepliesLock.Unlock()
	} else {
		// Trace.Printf("sending reply so done with this message")
	}

	return
}

// Close unlocks a client mutex and closes the connection
func (client *Client) Close() {
	if len(client.spIdent) > 0 {
		sp := DefaultCache.Retrieve(client.spIdent)
		if sp != nil {
			sp.client = nil
		}
	}

	client.closedM.Lock()
	defer client.closedM.Unlock()
	if client.isClosed {
		// Trace.Printf("client already closed. skipping shutdown.")
		return
	}

	// Trace.Printf("closing client...")
	// Trace.Printf("closing client conn...")
	client.closeConnection(client.conn)

	// Notify wrapper service that we're dead
	if client.serv != nil {
		// Trace.Printf("removing client from service...")
		client.serv.RemoveClient(client)
	}

	// Trace.Printf("marking client as closed...")
	client.isClosed = true
}

// closeConnection calls client.conn.Close() and sets the client.conn to nil
func (client *Client) closeConnection(conn *Connection) {
	if !client.conn.isClosed {
		client.conn.Close()
	}
	client.conn = nil
}

//func (client *Client) splitReqsAndReps(grNum, clientID int) (err error) {
func (client *Client) splitReqsAndReps() (err error) {
	var replyChan chan *Message

forLoop:
	for {
		// Trace.Printf("Entering forLoop splitReqsAndReps")
		select {
		case message, ok := <-client.conn.msgs:
			if !ok {
				// Trace.Printf("client.conn.msgs... CLOSED!")
				break forLoop
			}
			if message == nil {
				continue
			}

			// Trace.Printf("Splitting incoming message to reqs and reps")

			if message.MessageType == MessageTypeRequest {
				// interesting things happen if there are outstanding messages
				// and the client closes
				client.requests <- message
			} else if message.MessageType == MessageTypeReply {
				client.openRepliesLock.Lock()
				replyChan = client.openReplies[message.RequestID]
				if replyChan == nil {
					// Error.Printf("got an unexpected reply for requestId: %d. Skipping.", message.RequestID)
					client.openRepliesLock.Unlock()
					continue
				}

				delete(client.openReplies, message.RequestID)
				client.openRepliesLock.Unlock()

				replyChan <- message
			} else {
				// Trace.Printf("Could not handle msg, it's neither req or reply. Skipping.")
				continue
			}
		}
	}

	// Trace.Printf("done with SplitReqsAndReps")
	close(client.requests)
	client.openRepliesLock.Lock()
	for _, openReplyChan := range client.openReplies {
		close(openReplyChan)
	}
	client.openRepliesLock.Unlock()
	if !client.isClosed {
		client.Close()
	}

	return
}

// Incoming returns a client's MessageChan
func (client *Client) Incoming() chan *Message {
	return client.requests
}
<|endoftext|>


<commit_before>// Copyright 2015 go-swagger maintainers
//
// 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 validate

import (
	"fmt"
	"reflect"

	"github.com/go-openapi/spec"
	"github.com/go-openapi/strfmt"
)

type schemaPropsValidator struct {
	Path            string
	In              string
	AllOf           []spec.Schema
	OneOf           []spec.Schema
	AnyOf           []spec.Schema
	Not             *spec.Schema
	Dependencies    spec.Dependencies
	anyOfValidators []SchemaValidator
	allOfValidators []SchemaValidator
	oneOfValidators []SchemaValidator
	notValidator    *SchemaValidator
	Root            interface{}
	KnownFormats    strfmt.Registry
}

func (s *schemaPropsValidator) SetPath(path string) {
	s.Path = path
}

func newSchemaPropsValidator(path string, in string, allOf, oneOf, anyOf []spec.Schema, not *spec.Schema, deps spec.Dependencies, root interface{}, formats strfmt.Registry) *schemaPropsValidator {
	var anyValidators []SchemaValidator
	for _, v := range anyOf {
		anyValidators = append(anyValidators, *NewSchemaValidator(&v, root, path, formats))
	}
	var allValidators []SchemaValidator
	for _, v := range allOf {
		allValidators = append(allValidators, *NewSchemaValidator(&v, root, path, formats))
	}
	var oneValidators []SchemaValidator
	for _, v := range oneOf {
		oneValidators = append(oneValidators, *NewSchemaValidator(&v, root, path, formats))
	}

	var notValidator *SchemaValidator
	if not != nil {
		notValidator = NewSchemaValidator(not, root, path, formats)
	}

	return &schemaPropsValidator{
		Path:            path,
		In:              in,
		AllOf:           allOf,
		OneOf:           oneOf,
		AnyOf:           anyOf,
		Not:             not,
		Dependencies:    deps,
		anyOfValidators: anyValidators,
		allOfValidators: allValidators,
		oneOfValidators: oneValidators,
		notValidator:    notValidator,
		Root:            root,
		KnownFormats:    formats,
	}
}

func (s *schemaPropsValidator) Applies(source interface{}, kind reflect.Kind) bool {
	r := reflect.TypeOf(source) == specSchemaType
	debugLog("schema props validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
	return r
}

func (s *schemaPropsValidator) Validate(data interface{}) *Result {
	mainResult := new(Result)

	// Intermediary error results

	// IMPORTANT! messages from underlying validators
	keepResultAnyOf := new(Result)
	keepResultOneOf := new(Result)
	keepResultAllOf := new(Result)

	// Validates at least one in anyOf schemas
	var firstSuccess *Result
	if len(s.anyOfValidators) > 0 {
		var bestFailures *Result
		succeededOnce := false
		for _, anyOfSchema := range s.anyOfValidators {
			result := anyOfSchema.Validate(data)
			// We keep inner IMPORTANT! errors no matter what MatchCount tells us
			keepResultAnyOf.Merge(result.keepRelevantErrors())
			if result.IsValid() {
				bestFailures = nil
				succeededOnce = true
				if firstSuccess == nil {
					firstSuccess = result
				}
				keepResultAnyOf = new(Result)
				break
			}
			// MatchCount is used to select errors from the schema with most positive checks
			if bestFailures == nil || result.MatchCount > bestFailures.MatchCount {
				bestFailures = result
			}
		}

		if !succeededOnce {
			mainResult.AddErrors(mustValidateAtLeastOneSchemaMsg(s.Path))
		}
		if bestFailures != nil {
			mainResult.Merge(bestFailures)
		} else if firstSuccess != nil {
			mainResult.Merge(firstSuccess)
		}
	}

	// Validates exactly one in oneOf schemas
	if len(s.oneOfValidators) > 0 {
		var bestFailures *Result
		var firstSuccess *Result
		validated := 0

		for _, oneOfSchema := range s.oneOfValidators {
			result := oneOfSchema.Validate(data)
			// We keep inner IMPORTANT! errors no matter what MatchCount tells us
			keepResultOneOf.Merge(result.keepRelevantErrors())
			if result.IsValid() {
				validated++
				bestFailures = nil
				if firstSuccess == nil {
					firstSuccess = result
				}
				keepResultOneOf = new(Result)
				continue
			}
			// MatchCount is used to select errors from the schema with most positive checks
			if validated == 0 && (bestFailures == nil || result.MatchCount > bestFailures.MatchCount) {
				bestFailures = result
			}
		}

		if validated != 1 {
			additionalMsg := ""
			if validated == 0 {
				additionalMsg = "Found none valid"
			} else {
				additionalMsg = fmt.Sprintf("Found %d valid alternatives", validated)
			}

			mainResult.AddErrors(mustValidateOnlyOneSchemaMsg(s.Path, additionalMsg))
			if bestFailures != nil {
				mainResult.Merge(bestFailures)
			}
		} else if firstSuccess != nil {
			mainResult.Merge(firstSuccess)
		}
	}

	// Validates all of allOf schemas
	if len(s.allOfValidators) > 0 {
		validated := 0

		for _, allOfSchema := range s.allOfValidators {
			result := allOfSchema.Validate(data)
			// We keep inner IMPORTANT! errors no matter what MatchCount tells us
			keepResultAllOf.Merge(result.keepRelevantErrors())
			//keepResultAllOf.Merge(result)
			if result.IsValid() {
				validated++
			}
			mainResult.Merge(result)
		}

		if validated != len(s.allOfValidators) {
			additionalMsg := ""
			if validated == 0 {
				additionalMsg = ". None validated"
			}

			mainResult.AddErrors(mustValidateAllSchemasMsg(s.Path, additionalMsg))
		}
	}

	if s.notValidator != nil {
		result := s.notValidator.Validate(data)
		// We keep inner IMPORTANT! errors no matter what MatchCount tells us
		if result.IsValid() {
			mainResult.AddErrors(mustNotValidatechemaMsg(s.Path))
		}
	}

	if s.Dependencies != nil && len(s.Dependencies) > 0 && reflect.TypeOf(data).Kind() == reflect.Map {
		val := data.(map[string]interface{})
		for key := range val {
			if dep, ok := s.Dependencies[key]; ok {

				if dep.Schema != nil {
					mainResult.Merge(NewSchemaValidator(dep.Schema, s.Root, s.Path+"."+key, s.KnownFormats).Validate(data))
					continue
				}

				if len(dep.Property) > 0 {
					for _, depKey := range dep.Property {
						if _, ok := val[depKey]; !ok {
							mainResult.AddErrors(hasADependencyMsg(s.Path, depKey))
						}
					}
				}
			}
		}
	}

	mainResult.Inc()
	// In the end we retain best failures for schema validation
	// plus, if any, composite errors which may explain special cases (tagged as IMPORTANT!).
	return mainResult.Merge(keepResultAllOf, keepResultOneOf, keepResultAnyOf)
}
<commit_msg>optimize: reduce quantor allocations<commit_after>// Copyright 2015 go-swagger maintainers
//
// 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 validate

import (
	"fmt"
	"reflect"

	"github.com/go-openapi/spec"
	"github.com/go-openapi/strfmt"
)

type schemaPropsValidator struct {
	Path            string
	In              string
	AllOf           []spec.Schema
	OneOf           []spec.Schema
	AnyOf           []spec.Schema
	Not             *spec.Schema
	Dependencies    spec.Dependencies
	anyOfValidators []SchemaValidator
	allOfValidators []SchemaValidator
	oneOfValidators []SchemaValidator
	notValidator    *SchemaValidator
	Root            interface{}
	KnownFormats    strfmt.Registry
}

func (s *schemaPropsValidator) SetPath(path string) {
	s.Path = path
}

func newSchemaPropsValidator(path string, in string, allOf, oneOf, anyOf []spec.Schema, not *spec.Schema, deps spec.Dependencies, root interface{}, formats strfmt.Registry) *schemaPropsValidator {
	anyValidators := make([]SchemaValidator, 0, len(anyOf))
	for _, v := range anyOf {
		anyValidators = append(anyValidators, *NewSchemaValidator(&v, root, path, formats))
	}
	allValidators := make([]SchemaValidator, 0, len(allOf))
	for _, v := range allOf {
		allValidators = append(allValidators, *NewSchemaValidator(&v, root, path, formats))
	}
	oneValidators := make([]SchemaValidator, 0, len(oneOf))
	for _, v := range oneOf {
		oneValidators = append(oneValidators, *NewSchemaValidator(&v, root, path, formats))
	}

	var notValidator *SchemaValidator
	if not != nil {
		notValidator = NewSchemaValidator(not, root, path, formats)
	}

	return &schemaPropsValidator{
		Path:            path,
		In:              in,
		AllOf:           allOf,
		OneOf:           oneOf,
		AnyOf:           anyOf,
		Not:             not,
		Dependencies:    deps,
		anyOfValidators: anyValidators,
		allOfValidators: allValidators,
		oneOfValidators: oneValidators,
		notValidator:    notValidator,
		Root:            root,
		KnownFormats:    formats,
	}
}

func (s *schemaPropsValidator) Applies(source interface{}, kind reflect.Kind) bool {
	r := reflect.TypeOf(source) == specSchemaType
	debugLog("schema props validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
	return r
}

func (s *schemaPropsValidator) Validate(data interface{}) *Result {
	mainResult := new(Result)

	// Intermediary error results

	// IMPORTANT! messages from underlying validators
	keepResultAnyOf := new(Result)
	keepResultOneOf := new(Result)
	keepResultAllOf := new(Result)

	// Validates at least one in anyOf schemas
	var firstSuccess *Result
	if len(s.anyOfValidators) > 0 {
		var bestFailures *Result
		succeededOnce := false
		for _, anyOfSchema := range s.anyOfValidators {
			result := anyOfSchema.Validate(data)
			// We keep inner IMPORTANT! errors no matter what MatchCount tells us
			keepResultAnyOf.Merge(result.keepRelevantErrors())
			if result.IsValid() {
				bestFailures = nil
				succeededOnce = true
				if firstSuccess == nil {
					firstSuccess = result
				}
				keepResultAnyOf = new(Result)
				break
			}
			// MatchCount is used to select errors from the schema with most positive checks
			if bestFailures == nil || result.MatchCount > bestFailures.MatchCount {
				bestFailures = result
			}
		}

		if !succeededOnce {
			mainResult.AddErrors(mustValidateAtLeastOneSchemaMsg(s.Path))
		}
		if bestFailures != nil {
			mainResult.Merge(bestFailures)
		} else if firstSuccess != nil {
			mainResult.Merge(firstSuccess)
		}
	}

	// Validates exactly one in oneOf schemas
	if len(s.oneOfValidators) > 0 {
		var bestFailures *Result
		var firstSuccess *Result
		validated := 0

		for _, oneOfSchema := range s.oneOfValidators {
			result := oneOfSchema.Validate(data)
			// We keep inner IMPORTANT! errors no matter what MatchCount tells us
			keepResultOneOf.Merge(result.keepRelevantErrors())
			if result.IsValid() {
				validated++
				bestFailures = nil
				if firstSuccess == nil {
					firstSuccess = result
				}
				keepResultOneOf = new(Result)
				continue
			}
			// MatchCount is used to select errors from the schema with most positive checks
			if validated == 0 && (bestFailures == nil || result.MatchCount > bestFailures.MatchCount) {
				bestFailures = result
			}
		}

		if validated != 1 {
			additionalMsg := ""
			if validated == 0 {
				additionalMsg = "Found none valid"
			} else {
				additionalMsg = fmt.Sprintf("Found %d valid alternatives", validated)
			}

			mainResult.AddErrors(mustValidateOnlyOneSchemaMsg(s.Path, additionalMsg))
			if bestFailures != nil {
				mainResult.Merge(bestFailures)
			}
		} else if firstSuccess != nil {
			mainResult.Merge(firstSuccess)
		}
	}

	// Validates all of allOf schemas
	if len(s.allOfValidators) > 0 {
		validated := 0

		for _, allOfSchema := range s.allOfValidators {
			result := allOfSchema.Validate(data)
			// We keep inner IMPORTANT! errors no matter what MatchCount tells us
			keepResultAllOf.Merge(result.keepRelevantErrors())
			//keepResultAllOf.Merge(result)
			if result.IsValid() {
				validated++
			}
			mainResult.Merge(result)
		}

		if validated != len(s.allOfValidators) {
			additionalMsg := ""
			if validated == 0 {
				additionalMsg = ". None validated"
			}

			mainResult.AddErrors(mustValidateAllSchemasMsg(s.Path, additionalMsg))
		}
	}

	if s.notValidator != nil {
		result := s.notValidator.Validate(data)
		// We keep inner IMPORTANT! errors no matter what MatchCount tells us
		if result.IsValid() {
			mainResult.AddErrors(mustNotValidatechemaMsg(s.Path))
		}
	}

	if s.Dependencies != nil && len(s.Dependencies) > 0 && reflect.TypeOf(data).Kind() == reflect.Map {
		val := data.(map[string]interface{})
		for key := range val {
			if dep, ok := s.Dependencies[key]; ok {

				if dep.Schema != nil {
					mainResult.Merge(NewSchemaValidator(dep.Schema, s.Root, s.Path+"."+key, s.KnownFormats).Validate(data))
					continue
				}

				if len(dep.Property) > 0 {
					for _, depKey := range dep.Property {
						if _, ok := val[depKey]; !ok {
							mainResult.AddErrors(hasADependencyMsg(s.Path, depKey))
						}
					}
				}
			}
		}
	}

	mainResult.Inc()
	// In the end we retain best failures for schema validation
	// plus, if any, composite errors which may explain special cases (tagged as IMPORTANT!).
	return mainResult.Merge(keepResultAllOf, keepResultOneOf, keepResultAnyOf)
}
<|endoftext|>


<commit_before>package files

import (
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"

	"github.com/cozy/cozy-stack/web/middlewares"
	"github.com/gin-gonic/gin"
	"github.com/spf13/afero"
	"github.com/stretchr/testify/assert"
)

var ts *httptest.Server
var instance *middlewares.Instance

func injectInstance(instance *middlewares.Instance) gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Set("instance", instance)
	}
}

func TestUploadWithNoType(t *testing.T) {
	buf := strings.NewReader("foo")
	res, err := http.Post(ts.URL+"/files/123", "text/plain", buf)
	assert.NoError(t, err)
	assert.Equal(t, 422, res.StatusCode)
	res.Body.Close()
}

func TestUploadWithNoName(t *testing.T) {
	buf := strings.NewReader("foo")
	res, err := http.Post(ts.URL+"/files/123?Type=io.cozy.files", "text/plain", buf)
	assert.NoError(t, err)
	assert.Equal(t, 422, res.StatusCode)
	res.Body.Close()
}

func TestUploadSuccess(t *testing.T) {
	foo := []byte{'f', 'o', 'o'}
	body := strings.NewReader(string(foo))
	res, err := http.Post(ts.URL+"/files/123?Type=io.cozy.files&Name=bar", "text/plain", body)
	assert.NoError(t, err)
	assert.Equal(t, 201, res.StatusCode)
	res.Body.Close()
	storage, _ := instance.GetStorageProvider()
	buf, err := afero.ReadFile(*storage, "123/bar")
	assert.NoError(t, err)
	assert.Equal(t, foo, buf)
}

func TestMain(m *testing.M) {
	gin.SetMode(gin.TestMode)
	instance = &middlewares.Instance{
		Domain:     "test",
		StorageURL: "mem://test",
	}
	router := gin.New()
	router.Use(injectInstance(instance))
	router.POST("/files/:folder-id", Upload)
	ts = httptest.NewServer(router)
	defer ts.Close()
	os.Exit(m.Run())
}
<commit_msg>Refactor the upload test<commit_after>package files

import (
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"

	"github.com/cozy/cozy-stack/web/middlewares"
	"github.com/gin-gonic/gin"
	"github.com/spf13/afero"
	"github.com/stretchr/testify/assert"
)

var ts *httptest.Server
var instance *middlewares.Instance

func injectInstance(instance *middlewares.Instance) gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Set("instance", instance)
	}
}

func upload(t *testing.T, path, contentType, body string) *http.Response {
	buf := strings.NewReader(body)
	res, err := http.Post(ts.URL+path, contentType, buf)
	assert.NoError(t, err)
	return res
}

func TestUploadWithNoType(t *testing.T) {
	res := upload(t, "/files/123", "text/plain", "foo")
	assert.Equal(t, 422, res.StatusCode)
	res.Body.Close()
}

func TestUploadWithNoName(t *testing.T) {
	res := upload(t, "/files/123?Type=io.cozy.files", "text/plain", "foo")
	assert.Equal(t, 422, res.StatusCode)
	res.Body.Close()
}

func TestUploadSuccess(t *testing.T) {
	body := "foo"
	res := upload(t, "/files/123?Type=io.cozy.files&Name=bar", "text/plain", body)
	assert.Equal(t, 201, res.StatusCode)
	res.Body.Close()

	storage, _ := instance.GetStorageProvider()
	buf, err := afero.ReadFile(*storage, "123/bar")
	assert.NoError(t, err)
	assert.Equal(t, body, string(buf))
}

func TestMain(m *testing.M) {
	gin.SetMode(gin.TestMode)
	instance = &middlewares.Instance{
		Domain:     "test",
		StorageURL: "mem://test",
	}
	router := gin.New()
	router.Use(injectInstance(instance))
	router.POST("/files/:folder-id", Upload)
	ts = httptest.NewServer(router)
	defer ts.Close()
	os.Exit(m.Run())
}
<|endoftext|>


<commit_before><commit_msg>[auth] Retry calls to slow GKE metadata server when starting.<commit_after><|endoftext|>


<commit_before><commit_msg>Added test for GetItemById<commit_after><|endoftext|>


<commit_before>// This file was auto-generated by pgen.
// Editing is not advised.

package pgen

type Lookup struct {
	Term  Term
	NTerm NTerm
}

type Token interface{}

type Rule []Token

var Table = map[Lookup]Rule{
	{Term: newTerm("id"), NTerm: newNTerm("argdecls")}:      newRule(newTerm("id"), newNTerm("argdecls")),
	{Term: newTerm("=>"), NTerm: newNTerm("argdecls")}:      newRule(newEpsilon()),
	{Term: newTerm("["), NTerm: newNTerm("args")}:           newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("switch"), NTerm: newNTerm("args")}:      newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("("), NTerm: newNTerm("args")}:           newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("number"), NTerm: newNTerm("args")}:      newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("string"), NTerm: newNTerm("args")}:      newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("id"), NTerm: newNTerm("args")}:          newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("["), NTerm: newNTerm("args")}:           newRule(newEpsilon()),
	{Term: newTerm("switch"), NTerm: newNTerm("args")}:      newRule(newEpsilon()),
	{Term: newTerm(";"), NTerm: newNTerm("args")}:           newRule(newEpsilon()),
	{Term: newTerm("default"), NTerm: newNTerm("args")}:     newRule(newEpsilon()),
	{Term: newTerm("}"), NTerm: newNTerm("args")}:           newRule(newEpsilon()),
	{Term: newTerm("string"), NTerm: newNTerm("args")}:      newRule(newEpsilon()),
	{Term: newTerm("number"), NTerm: newNTerm("args")}:      newRule(newEpsilon()),
	{Term: newTerm("->"), NTerm: newNTerm("args")}:          newRule(newEpsilon()),
	{Term: newTerm("=>"), NTerm: newNTerm("args")}:          newRule(newEpsilon()),
	{Term: newTerm("id"), NTerm: newNTerm("args")}:          newRule(newEpsilon()),
	{Term: newTerm("("), NTerm: newNTerm("args")}:           newRule(newEpsilon()),
	{Term: newTerm("{"), NTerm: newNTerm("args")}:           newRule(newEpsilon()),
	{Term: newTerm("["), NTerm: newNTerm("array")}:          newRule(newTerm("["), newNTerm("exprs"), newNTerm("optend"), newTerm("]")),
	{Term: newTerm("->"), NTerm: newNTerm("chain")}:         newRule(newTerm("->"), newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("("), NTerm: newNTerm("chain")}:          newRule(newEpsilon()),
	{Term: newTerm("string"), NTerm: newNTerm("chain")}:     newRule(newEpsilon()),
	{Term: newTerm("=>"), NTerm: newNTerm("chain")}:         newRule(newEpsilon()),
	{Term: newTerm("}"), NTerm: newNTerm("chain")}:          newRule(newEpsilon()),
	{Term: newTerm(";"), NTerm: newNTerm("chain")}:          newRule(newEpsilon()),
	{Term: newTerm("id"), NTerm: newNTerm("chain")}:         newRule(newEpsilon()),
	{Term: newTerm("number"), NTerm: newNTerm("chain")}:     newRule(newEpsilon()),
	{Term: newTerm("switch"), NTerm: newNTerm("chain")}:     newRule(newEpsilon()),
	{Term: newTerm("{"), NTerm: newNTerm("chain")}:          newRule(newEpsilon()),
	{Term: newTerm("["), NTerm: newNTerm("chain")}:          newRule(newEpsilon()),
	{Term: newTerm("default"), NTerm: newNTerm("chain")}:    newRule(newEpsilon()),
	{Term: newTerm("("), NTerm: newNTerm("compound")}:       newRule(newTerm("("), newNTerm("exprs"), newNTerm("optend"), newTerm(")")),
	{Term: newTerm("string"), NTerm: newNTerm("decl")}:      newRule(newNTerm("import")),
	{Term: newTerm("id"), NTerm: newNTerm("decl")}:          newRule(newNTerm("funcdecl")),
	{Term: newTerm("id"), NTerm: newNTerm("expr")}:          newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("["), NTerm: newNTerm("expr")}:           newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("switch"), NTerm: newNTerm("expr")}:      newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("("), NTerm: newNTerm("expr")}:           newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("number"), NTerm: newNTerm("expr")}:      newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("string"), NTerm: newNTerm("expr")}:      newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("string"), NTerm: newNTerm("exprs")}:     newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm("id"), NTerm: newNTerm("exprs")}:         newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm("["), NTerm: newNTerm("exprs")}:          newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm("switch"), NTerm: newNTerm("exprs")}:     newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm("("), NTerm: newNTerm("exprs")}:          newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm("number"), NTerm: newNTerm("exprs")}:     newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm(";"), NTerm: newNTerm("exprs")}:          newRule(newEpsilon()),
	{Term: newTerm(")"), NTerm: newNTerm("exprs")}:          newRule(newEpsilon()),
	{Term: newTerm("]"), NTerm: newNTerm("exprs")}:          newRule(newEpsilon()),
	{Term: newTerm("id"), NTerm: newNTerm("func")}:          newRule(newTerm("id"), newNTerm("subfunc")),
	{Term: newTerm("id"), NTerm: newNTerm("funcdecl")}:      newRule(newTerm("id"), newNTerm("argdecls"), newTerm("=>"), newNTerm("expr"), newTerm(";")),
	{Term: newTerm("string"), NTerm: newNTerm("import")}:    newRule(newTerm("string"), newTerm("=>"), newTerm("id"), newTerm(";")),
	{Term: newTerm(";"), NTerm: newNTerm("optend")}:         newRule(newTerm(";")),
	{Term: newTerm(")"), NTerm: newNTerm("optend")}:         newRule(newEpsilon()),
	{Term: newTerm("]"), NTerm: newNTerm("optend")}:         newRule(newEpsilon()),
	{Term: newTerm("string"), NTerm: newNTerm("script")}:    newRule(newNTerm("decl"), newNTerm("script")),
	{Term: newTerm("id"), NTerm: newNTerm("script")}:        newRule(newNTerm("decl"), newNTerm("script")),
	{Term: newTerm("id"), NTerm: newNTerm("single")}:        newRule(newNTerm("func")),
	{Term: newTerm("["), NTerm: newNTerm("single")}:         newRule(newNTerm("array")),
	{Term: newTerm("switch"), NTerm: newNTerm("single")}:    newRule(newNTerm("switch")),
	{Term: newTerm("("), NTerm: newNTerm("single")}:         newRule(newNTerm("compound")),
	{Term: newTerm("number"), NTerm: newNTerm("single")}:    newRule(newTerm("number")),
	{Term: newTerm("string"), NTerm: newNTerm("single")}:    newRule(newTerm("string")),
	{Term: newTerm("."), NTerm: newNTerm("subfunc")}:        newRule(newTerm("."), newTerm("id")),
	{Term: newTerm("=>"), NTerm: newNTerm("subfunc")}:       newRule(newEpsilon()),
	{Term: newTerm("("), NTerm: newNTerm("subfunc")}:        newRule(newEpsilon()),
	{Term: newTerm("}"), NTerm: newNTerm("subfunc")}:        newRule(newEpsilon()),
	{Term: newTerm("["), NTerm: newNTerm("subfunc")}:        newRule(newEpsilon()),
	{Term: newTerm("string"), NTerm: newNTerm("subfunc")}:   newRule(newEpsilon()),
	{Term: newTerm("id"), NTerm: newNTerm("subfunc")}:       newRule(newEpsilon()),
	{Term: newTerm("->"), NTerm: newNTerm("subfunc")}:       newRule(newEpsilon()),
	{Term: newTerm("{"), NTerm: newNTerm("subfunc")}:        newRule(newEpsilon()),
	{Term: newTerm(";"), NTerm: newNTerm("subfunc")}:        newRule(newEpsilon()),
	{Term: newTerm("default"), NTerm: newNTerm("subfunc")}:  newRule(newEpsilon()),
	{Term: newTerm("switch"), NTerm: newNTerm("subfunc")}:   newRule(newEpsilon()),
	{Term: newTerm("number"), NTerm: newNTerm("subfunc")}:   newRule(newEpsilon()),
	{Term: newTerm("switch"), NTerm: newNTerm("switch")}:    newRule(newTerm("switch"), newNTerm("expr"), newTerm("{"), newNTerm("switches"), newTerm("}")),
	{Term: newTerm("default"), NTerm: newNTerm("switches")}: newRule(newTerm("default"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("("), NTerm: newNTerm("switches")}:       newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("number"), NTerm: newNTerm("switches")}:  newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("string"), NTerm: newNTerm("switches")}:  newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("id"), NTerm: newNTerm("switches")}:      newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("["), NTerm: newNTerm("switches")}:       newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("switch"), NTerm: newNTerm("switches")}:  newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("}"), NTerm: newNTerm("switches")}:       newRule(newEpsilon()),
}
<commit_msg>ast/internal/pgen: Regenerate.<commit_after>// This file was auto-generated by pgen.
// Editing is not advised.

package pgen

type Lookup struct {
	Term  Term
	NTerm NTerm
}

type Token interface{}

type Rule []Token

var Table = map[Lookup]Rule{
	{Term: newTerm("id"), NTerm: newNTerm("argdecls")}:      newRule(newTerm("id"), newNTerm("argdecls")),
	{Term: newTerm("=>"), NTerm: newNTerm("argdecls")}:      newRule(newEpsilon()),
	{Term: newTerm("("), NTerm: newNTerm("args")}:           newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("number"), NTerm: newNTerm("args")}:      newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("string"), NTerm: newNTerm("args")}:      newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("id"), NTerm: newNTerm("args")}:          newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("["), NTerm: newNTerm("args")}:           newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("switch"), NTerm: newNTerm("args")}:      newRule(newNTerm("single"), newNTerm("args")),
	{Term: newTerm("id"), NTerm: newNTerm("args")}:          newRule(newEpsilon()),
	{Term: newTerm("=>"), NTerm: newNTerm("args")}:          newRule(newEpsilon()),
	{Term: newTerm("number"), NTerm: newNTerm("args")}:      newRule(newEpsilon()),
	{Term: newTerm("["), NTerm: newNTerm("args")}:           newRule(newEpsilon()),
	{Term: newTerm("{"), NTerm: newNTerm("args")}:           newRule(newEpsilon()),
	{Term: newTerm("switch"), NTerm: newNTerm("args")}:      newRule(newEpsilon()),
	{Term: newTerm("default"), NTerm: newNTerm("args")}:     newRule(newEpsilon()),
	{Term: newTerm(";"), NTerm: newNTerm("args")}:           newRule(newEpsilon()),
	{Term: newTerm("string"), NTerm: newNTerm("args")}:      newRule(newEpsilon()),
	{Term: newTerm("}"), NTerm: newNTerm("args")}:           newRule(newEpsilon()),
	{Term: newTerm("->"), NTerm: newNTerm("args")}:          newRule(newEpsilon()),
	{Term: newTerm("("), NTerm: newNTerm("args")}:           newRule(newEpsilon()),
	{Term: newTerm("["), NTerm: newNTerm("array")}:          newRule(newTerm("["), newNTerm("exprs"), newNTerm("optend"), newTerm("]")),
	{Term: newTerm("->"), NTerm: newNTerm("chain")}:         newRule(newTerm("->"), newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("switch"), NTerm: newNTerm("chain")}:     newRule(newEpsilon()),
	{Term: newTerm("default"), NTerm: newNTerm("chain")}:    newRule(newEpsilon()),
	{Term: newTerm("number"), NTerm: newNTerm("chain")}:     newRule(newEpsilon()),
	{Term: newTerm("}"), NTerm: newNTerm("chain")}:          newRule(newEpsilon()),
	{Term: newTerm("id"), NTerm: newNTerm("chain")}:         newRule(newEpsilon()),
	{Term: newTerm("["), NTerm: newNTerm("chain")}:          newRule(newEpsilon()),
	{Term: newTerm("=>"), NTerm: newNTerm("chain")}:         newRule(newEpsilon()),
	{Term: newTerm("{"), NTerm: newNTerm("chain")}:          newRule(newEpsilon()),
	{Term: newTerm("("), NTerm: newNTerm("chain")}:          newRule(newEpsilon()),
	{Term: newTerm("string"), NTerm: newNTerm("chain")}:     newRule(newEpsilon()),
	{Term: newTerm(";"), NTerm: newNTerm("chain")}:          newRule(newEpsilon()),
	{Term: newTerm("("), NTerm: newNTerm("compound")}:       newRule(newTerm("("), newNTerm("exprs"), newNTerm("optend"), newTerm(")")),
	{Term: newTerm("id"), NTerm: newNTerm("decl")}:          newRule(newNTerm("funcdecl")),
	{Term: newTerm("string"), NTerm: newNTerm("decl")}:      newRule(newNTerm("import")),
	{Term: newTerm("("), NTerm: newNTerm("expr")}:           newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("number"), NTerm: newNTerm("expr")}:      newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("string"), NTerm: newNTerm("expr")}:      newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("id"), NTerm: newNTerm("expr")}:          newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("["), NTerm: newNTerm("expr")}:           newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("switch"), NTerm: newNTerm("expr")}:      newRule(newNTerm("single"), newNTerm("args"), newNTerm("chain")),
	{Term: newTerm("string"), NTerm: newNTerm("exprs")}:     newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm("id"), NTerm: newNTerm("exprs")}:         newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm("["), NTerm: newNTerm("exprs")}:          newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm("switch"), NTerm: newNTerm("exprs")}:     newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm("("), NTerm: newNTerm("exprs")}:          newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm("number"), NTerm: newNTerm("exprs")}:     newRule(newNTerm("expr"), newTerm(";"), newNTerm("exprs")),
	{Term: newTerm(";"), NTerm: newNTerm("exprs")}:          newRule(newEpsilon()),
	{Term: newTerm(")"), NTerm: newNTerm("exprs")}:          newRule(newEpsilon()),
	{Term: newTerm("]"), NTerm: newNTerm("exprs")}:          newRule(newEpsilon()),
	{Term: newTerm("id"), NTerm: newNTerm("func")}:          newRule(newTerm("id"), newNTerm("subfunc")),
	{Term: newTerm("id"), NTerm: newNTerm("funcdecl")}:      newRule(newTerm("id"), newNTerm("argdecls"), newTerm("=>"), newNTerm("expr"), newTerm(";")),
	{Term: newTerm("string"), NTerm: newNTerm("import")}:    newRule(newTerm("string"), newTerm("=>"), newTerm("id"), newTerm(";")),
	{Term: newTerm(";"), NTerm: newNTerm("optend")}:         newRule(newTerm(";")),
	{Term: newTerm("]"), NTerm: newNTerm("optend")}:         newRule(newEpsilon()),
	{Term: newTerm(")"), NTerm: newNTerm("optend")}:         newRule(newEpsilon()),
	{Term: newTerm("id"), NTerm: newNTerm("script")}:        newRule(newNTerm("decl"), newNTerm("script")),
	{Term: newTerm("string"), NTerm: newNTerm("script")}:    newRule(newNTerm("decl"), newNTerm("script")),
	{Term: newTerm("("), NTerm: newNTerm("single")}:         newRule(newNTerm("compound")),
	{Term: newTerm("number"), NTerm: newNTerm("single")}:    newRule(newTerm("number")),
	{Term: newTerm("string"), NTerm: newNTerm("single")}:    newRule(newTerm("string")),
	{Term: newTerm("id"), NTerm: newNTerm("single")}:        newRule(newNTerm("func")),
	{Term: newTerm("["), NTerm: newNTerm("single")}:         newRule(newNTerm("array")),
	{Term: newTerm("switch"), NTerm: newNTerm("single")}:    newRule(newNTerm("switch")),
	{Term: newTerm("."), NTerm: newNTerm("subfunc")}:        newRule(newTerm("."), newTerm("id")),
	{Term: newTerm("string"), NTerm: newNTerm("subfunc")}:   newRule(newEpsilon()),
	{Term: newTerm("}"), NTerm: newNTerm("subfunc")}:        newRule(newEpsilon()),
	{Term: newTerm("switch"), NTerm: newNTerm("subfunc")}:   newRule(newEpsilon()),
	{Term: newTerm("->"), NTerm: newNTerm("subfunc")}:       newRule(newEpsilon()),
	{Term: newTerm("("), NTerm: newNTerm("subfunc")}:        newRule(newEpsilon()),
	{Term: newTerm("=>"), NTerm: newNTerm("subfunc")}:       newRule(newEpsilon()),
	{Term: newTerm("default"), NTerm: newNTerm("subfunc")}:  newRule(newEpsilon()),
	{Term: newTerm("number"), NTerm: newNTerm("subfunc")}:   newRule(newEpsilon()),
	{Term: newTerm("id"), NTerm: newNTerm("subfunc")}:       newRule(newEpsilon()),
	{Term: newTerm("["), NTerm: newNTerm("subfunc")}:        newRule(newEpsilon()),
	{Term: newTerm(";"), NTerm: newNTerm("subfunc")}:        newRule(newEpsilon()),
	{Term: newTerm("{"), NTerm: newNTerm("subfunc")}:        newRule(newEpsilon()),
	{Term: newTerm("switch"), NTerm: newNTerm("switch")}:    newRule(newTerm("switch"), newNTerm("expr"), newTerm("{"), newNTerm("switches"), newTerm("}")),
	{Term: newTerm("id"), NTerm: newNTerm("switches")}:      newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("["), NTerm: newNTerm("switches")}:       newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("switch"), NTerm: newNTerm("switches")}:  newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("("), NTerm: newNTerm("switches")}:       newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("number"), NTerm: newNTerm("switches")}:  newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("string"), NTerm: newNTerm("switches")}:  newRule(newNTerm("expr"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("default"), NTerm: newNTerm("switches")}: newRule(newTerm("default"), newTerm("=>"), newNTerm("expr"), newNTerm("switches")),
	{Term: newTerm("}"), NTerm: newNTerm("switches")}:       newRule(newEpsilon()),
}
<|endoftext|>


<commit_before>package geo

import (
	"encoding/json"
	"github.com/buckhx/diglet/util"
	"github.com/deckarep/golang-set"
	"github.com/kpawlik/geojson"
	"io/ioutil"
)

type GeojsonSource struct {
	path   string
	filter mapset.Set
}

func NewGeojsonSource(path string, filter []string) *GeojsonSource {
	var set mapset.Set
	if filter == nil {
		set = nil
	} else {
		set = mapset.NewSet()
		for _, k := range filter {
			set.Add(k)
		}
	}
	return &GeojsonSource{path, set}
}

func (gj *GeojsonSource) Publish() (features chan *Feature, err error) {
	collection := readGeoJson(gj.path)
	return publishFeatureCollection(collection), nil
}

// Flatten all the points of a feature into single list. This can hel in identifying which tiles are going to be
// created
func GeojsonFeatureAdapter(gj *geojson.Feature) (feature *Feature, err error) {
	// TODO: This sucks... I just want to switch on Coordinates.(type)
	igeom, err := gj.GetGeometry()
	if igeom == nil || err != nil {
		err = util.Errorf("Invalid geojson feature %q", gj)
		return
	}
	feature = NewFeature(igeom.GetType())
	//TODO filter properties
	feature.Properties = gj.Properties
	feature.Properties["id"] = gj.Id
	//TODO if id == nil assign a fake one
	feature.Type = igeom.GetType()
	switch geom := igeom.(type) {
	case *geojson.Point:
		shape := coordinatesAdapter(geojson.Coordinates{geom.Coordinates})
		feature.AddShape(shape)
	case *geojson.LineString:
		shape := coordinatesAdapter(geom.Coordinates)
		feature.AddShape(shape)
	case *geojson.MultiPoint:
		shape := coordinatesAdapter(geom.Coordinates)
		feature.AddShape(shape)
	case *geojson.MultiLineString:
		for _, line := range geom.Coordinates {
			shape := coordinatesAdapter(line)
			feature.AddShape(shape)
		}
	case *geojson.Polygon:
		// mvt need exterior ring to be clockwise
		// and interior rings to counter-clockwise
		exterior := true
		for _, line := range geom.Coordinates {
			shape := coordinatesAdapter(line)
			if exterior {
				if !shape.IsClockwise() {
					shape.Reverse()
				}
				exterior = false
			} else {
				if shape.IsClockwise() {
					shape.Reverse()
				}
			}
			feature.AddShape(shape)
		}
	case *geojson.MultiPolygon:
		for _, multiline := range geom.Coordinates {
			exterior := true
			for _, line := range multiline {
				shape := coordinatesAdapter(line)
				if exterior {
					if !shape.IsClockwise() {
						shape.Reverse()
					}
					exterior = false
				} else {
					if shape.IsClockwise() {
						shape.Reverse()
					}
				}
				feature.AddShape(shape)
			}
		}
	default:
		feature = nil

		err = util.Errorf("Invalid Coordinate Type in GeoJson %q", geom)
	}
	return
}

func UnmarshalGeojsonFeature(raw string) (feature *geojson.Feature, err error) {
	err = json.Unmarshal([]byte(raw), &feature)
	return
}

func coordinatesAdapter(line geojson.Coordinates) (shape *Shape) {
	shape = MakeShape(len(line))
	for i, point := range line {
		lat := float64(point[1])
		lon := float64(point[0])
		coord := Coordinate{Lat: lat, Lon: lon}
		shape.Coordinates[i] = coord
	}
	return
}

func readGeoJson(path string) (features *geojson.FeatureCollection) {
	file, err := ioutil.ReadFile(path)
	if err != nil {
		util.Check(err)
	}
	if err := json.Unmarshal(file, &features); err != nil {
		util.Check(err)
	}
	return features
}

func publishFeatureCollection(collection *geojson.FeatureCollection) (features chan *Feature) {
	features = make(chan *Feature, 10)
	go func() {
		defer close(features)
		for _, feature := range collection.Features {
			f, err := GeojsonFeatureAdapter(feature)
			util.Warn(err, "feature publishing")
			features <- f
		}
	}()
	return
}
<commit_msg>nil properties<commit_after>package geo

import (
	"encoding/json"
	"github.com/buckhx/diglet/util"
	"github.com/deckarep/golang-set"
	"github.com/kpawlik/geojson"
	"io/ioutil"
)

type GeojsonSource struct {
	path   string
	filter mapset.Set
}

func NewGeojsonSource(path string, filter []string) *GeojsonSource {
	var set mapset.Set
	if filter == nil {
		set = nil
	} else {
		set = mapset.NewSet()
		for _, k := range filter {
			set.Add(k)
		}
	}
	return &GeojsonSource{path, set}
}

func (gj *GeojsonSource) Publish() (features chan *Feature, err error) {
	collection := readGeoJson(gj.path)
	return publishFeatureCollection(collection), nil
}

// Flatten all the points of a feature into single list. This can hel in identifying which tiles are going to be
// created
func GeojsonFeatureAdapter(gj *geojson.Feature) (feature *Feature, err error) {
	// TODO: This sucks... I just want to switch on Coordinates.(type)
	igeom, err := gj.GetGeometry()
	if igeom == nil || err != nil {
		err = util.Errorf("Invalid geojson feature %q", gj)
		return
	}
	feature = NewFeature(igeom.GetType())
	//TODO filter properties
	feature.Properties = gj.Properties
	if feature.Properties != nil {
		feature.Properties["id"] = gj.Id
	}
	//TODO if id == nil assign a fake one
	feature.Type = igeom.GetType()
	switch geom := igeom.(type) {
	case *geojson.Point:
		shape := coordinatesAdapter(geojson.Coordinates{geom.Coordinates})
		feature.AddShape(shape)
	case *geojson.LineString:
		shape := coordinatesAdapter(geom.Coordinates)
		feature.AddShape(shape)
	case *geojson.MultiPoint:
		shape := coordinatesAdapter(geom.Coordinates)
		feature.AddShape(shape)
	case *geojson.MultiLineString:
		for _, line := range geom.Coordinates {
			shape := coordinatesAdapter(line)
			feature.AddShape(shape)
		}
	case *geojson.Polygon:
		// mvt need exterior ring to be clockwise
		// and interior rings to counter-clockwise
		exterior := true
		for _, line := range geom.Coordinates {
			shape := coordinatesAdapter(line)
			if exterior {
				if !shape.IsClockwise() {
					shape.Reverse()
				}
				exterior = false
			} else {
				if shape.IsClockwise() {
					shape.Reverse()
				}
			}
			feature.AddShape(shape)
		}
	case *geojson.MultiPolygon:
		for _, multiline := range geom.Coordinates {
			exterior := true
			for _, line := range multiline {
				shape := coordinatesAdapter(line)
				if exterior {
					if !shape.IsClockwise() {
						shape.Reverse()
					}
					exterior = false
				} else {
					if shape.IsClockwise() {
						shape.Reverse()
					}
				}
				feature.AddShape(shape)
			}
		}
	default:
		feature = nil

		err = util.Errorf("Invalid Coordinate Type in GeoJson %q", geom)
	}
	return
}

func UnmarshalGeojsonFeature(raw string) (feature *geojson.Feature, err error) {
	err = json.Unmarshal([]byte(raw), &feature)
	return
}

func coordinatesAdapter(line geojson.Coordinates) (shape *Shape) {
	shape = MakeShape(len(line))
	for i, point := range line {
		lat := float64(point[1])
		lon := float64(point[0])
		coord := Coordinate{Lat: lat, Lon: lon}
		shape.Coordinates[i] = coord
	}
	return
}

func readGeoJson(path string) (features *geojson.FeatureCollection) {
	file, err := ioutil.ReadFile(path)
	if err != nil {
		util.Check(err)
	}
	if err := json.Unmarshal(file, &features); err != nil {
		util.Check(err)
	}
	return features
}

func publishFeatureCollection(collection *geojson.FeatureCollection) (features chan *Feature) {
	features = make(chan *Feature, 10)
	go func() {
		defer close(features)
		for _, feature := range collection.Features {
			f, err := GeojsonFeatureAdapter(feature)
			util.Warn(err, "feature publishing")
			features <- f
		}
	}()
	return
}
<|endoftext|>