<commit_before>package gdbm

import (
	"io/ioutil"
	"math/rand"
	"os"
	"reflect"
	"strconv"
	"testing"
)

func mockDb(f func(*Database)) {
	tmp, err := ioutil.TempFile("", "go-gdbm-test_")
	if err != nil {
		panic(err)
	}
	defer os.Remove(tmp.Name())
	defer tmp.Close()

	db, err := Open(tmp.Name())
	if err != nil {
		panic(err)
	}
	defer db.Close()

	f(db)
}

func TestOpenDatabase(t *testing.T) {
	mockDb(func(_ *Database) {})
}

func TestFetchNotPresent(t *testing.T) {
	mockDb(func(d *Database) {
		value := d.Fetch([]byte{1, 2, 3})
		if value != nil {
			t.Errorf("expected nil but got %v", value)
		}
	})
}

func TestStore(t *testing.T) {
	mockDb(func(d *Database) {
		expect := []byte{4, 2}
		d.Store([]byte{1, 2, 3}, expect)
		if value := d.Fetch([]byte{8, 7}); value != nil {
			t.Errorf("expected nil for non-existent key, but got %v", value)
		}
		value := d.Fetch([]byte{1, 2, 3})
		if value == nil {
			t.Errorf("expected %v but got nil", expect)
		} else if !reflect.DeepEqual(value, expect) {
			t.Errorf("expected %v but got %v", expect, value)
		}
	})
}

func TestEmptySlices(t *testing.T) {
	mockDb(func(d *Database) {
		hello := []byte("Hello World!")
		empty := []byte{}
		d.Store(empty, hello)
		if v := d.Fetch(empty); !reflect.DeepEqual(v, hello) {
			t.Errorf("expected %v but got %v", hello, v)
		}
		d.Store(hello, empty)
		if v := d.Fetch(hello); !reflect.DeepEqual(v, empty) {
			t.Errorf("expected %v but got %v", empty, v)
		}
	})
}

func TestExists(t *testing.T) {
	mockDb(func(d *Database) {
		key := []byte("thekey")
		d.Store(key, []byte("lol"))
		if !d.Exists(key) {
			t.Fail()
		}
		if d.Exists([]byte("nope")) {
			t.Fail()
		}
	})
}

func TestDelete(t *testing.T) {
	mockDb(func(d *Database) {
		key, value := []byte{1, 2, 3}, []byte{4, 5, 6}
		d.Store(key, value)
		if v := d.Fetch(key); !reflect.DeepEqual(value, v) {
			t.Errorf("expected %v but got %v", value, v)
		}
		d.Store(key, nil)
		if v := d.Fetch(key); v != nil {
			t.Errorf("expected nil but got %v")
		}
	})
}

func TestIterate(t *testing.T) {
	mockDb(func(d *Database) {
		keys := []string{"gdbm", "has", "a", "nice", "API"}
		for _, key := range keys {
			d.Store([]byte(key), []byte{23, 42})
		}
		present := make(map[string]bool)
		d.Iterate(func(key []byte) bool {
			skey := string(key)
			if present[skey] {
				t.Errorf("key %v already present", key)
			}
			present[skey] = true
			return true
		})
		for _, key := range keys {
			if !present[string(key)] {
				t.Errorf("key %q not handled by Iterate", string(key))
			}
		}
	})
}

func TestIterateCancel(t *testing.T) {
	mockDb(func(d *Database) {
		for i := 0; i < 10; i++ {
			d.Store([]byte{byte(i)}, []byte{23, 42})
		}
		n := 0
		d.Iterate(func(key []byte) bool {
			n++
			return n < 2
		})
		if n != 2 {
			t.Fail()
		}
	})
}

func populate(d *Database, n int) {
	for i := 0; i < n; i++ {
		key := []byte(strconv.Itoa(i))
		d.Store(key, key)
	}
}

func BenchmarkFetch(b *testing.B) {
	const maxKey = 10000
	mockDb(func(d *Database) {
		populate(d, maxKey)
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			key := []byte(strconv.Itoa(rand.Intn(maxKey)))
			data := d.Fetch(key)
			if !reflect.DeepEqual(key, data) {
				b.Fatalf("incorrect value for %v: %v", key, data)
			}
		}
	})
}

func BenchmarkReplace(b *testing.B) {
	const maxKey = 10000
	mockDb(func(d *Database) {
		populate(d, maxKey)
		b.ResetTimer()
		value := maxKey + 1
		for i := 0; i < b.N; i++ {
			key := []byte(strconv.Itoa(rand.Intn(maxKey)))
			data := []byte(strconv.Itoa(value))
			value++
			d.Store(key, data)
		}
	})
}

func BenchmarkStore(b *testing.B) {
	mockDb(func(d *Database) {
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			key := []byte(strconv.Itoa(i))
			d.Store(key, key)
		}
	})
}
<commit_msg>Added TestOpenFail<commit_after>package gdbm

import (
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"testing"
)

func mockDb(f func(*Database)) {
	tmp, err := ioutil.TempFile("", "go-gdbm-test_")
	if err != nil {
		panic(err)
	}
	defer os.Remove(tmp.Name())
	defer tmp.Close()

	db, err := Open(tmp.Name())
	if err != nil {
		panic(err)
	}
	defer db.Close()

	f(db)
}

func TestOpenDatabase(t *testing.T) {
	mockDb(func(_ *Database) {})
}

func TestOpenFail(t *testing.T) {
	dir, err := ioutil.TempDir("", "go-gdbm-test_")
	if err != nil {
		t.Fatal(err)
	}
	defer os.Remove(dir)

	file := filepath.Join(dir, "doesnt-exist")
	db, err := OpenConfig(&Config{
		File: file,
		Mode: Writer,
	})

	if db != nil {
		db.Close()
		os.Remove(file)
		t.Error("non-nil Database returned")
	} else if err == nil {
		t.Error("nil Database and nil error returned")
	} else if !os.IsNotExist(err) {
		t.Error("unexpected error:", err)
	}
}

func TestFetchNotPresent(t *testing.T) {
	mockDb(func(d *Database) {
		value := d.Fetch([]byte{1, 2, 3})
		if value != nil {
			t.Errorf("expected nil but got %v", value)
		}
	})
}

func TestStore(t *testing.T) {
	mockDb(func(d *Database) {
		expect := []byte{4, 2}
		d.Store([]byte{1, 2, 3}, expect)
		if value := d.Fetch([]byte{8, 7}); value != nil {
			t.Errorf("expected nil for non-existent key, but got %v", value)
		}
		value := d.Fetch([]byte{1, 2, 3})
		if value == nil {
			t.Errorf("expected %v but got nil", expect)
		} else if !reflect.DeepEqual(value, expect) {
			t.Errorf("expected %v but got %v", expect, value)
		}
	})
}

func TestEmptySlices(t *testing.T) {
	mockDb(func(d *Database) {
		hello := []byte("Hello World!")
		empty := []byte{}
		d.Store(empty, hello)
		if v := d.Fetch(empty); !reflect.DeepEqual(v, hello) {
			t.Errorf("expected %v but got %v", hello, v)
		}
		d.Store(hello, empty)
		if v := d.Fetch(hello); !reflect.DeepEqual(v, empty) {
			t.Errorf("expected %v but got %v", empty, v)
		}
	})
}

func TestExists(t *testing.T) {
	mockDb(func(d *Database) {
		key := []byte("thekey")
		d.Store(key, []byte("lol"))
		if !d.Exists(key) {
			t.Fail()
		}
		if d.Exists([]byte("nope")) {
			t.Fail()
		}
	})
}

func TestDelete(t *testing.T) {
	mockDb(func(d *Database) {
		key, value := []byte{1, 2, 3}, []byte{4, 5, 6}
		d.Store(key, value)
		if v := d.Fetch(key); !reflect.DeepEqual(value, v) {
			t.Errorf("expected %v but got %v", value, v)
		}
		d.Store(key, nil)
		if v := d.Fetch(key); v != nil {
			t.Errorf("expected nil but got %v")
		}
	})
}

func TestIterate(t *testing.T) {
	mockDb(func(d *Database) {
		keys := []string{"gdbm", "has", "a", "nice", "API"}
		for _, key := range keys {
			d.Store([]byte(key), []byte{23, 42})
		}
		present := make(map[string]bool)
		d.Iterate(func(key []byte) bool {
			skey := string(key)
			if present[skey] {
				t.Errorf("key %v already present", key)
			}
			present[skey] = true
			return true
		})
		for _, key := range keys {
			if !present[string(key)] {
				t.Errorf("key %q not handled by Iterate", string(key))
			}
		}
	})
}

func TestIterateCancel(t *testing.T) {
	mockDb(func(d *Database) {
		for i := 0; i < 10; i++ {
			d.Store([]byte{byte(i)}, []byte{23, 42})
		}
		n := 0
		d.Iterate(func(key []byte) bool {
			n++
			return n < 2
		})
		if n != 2 {
			t.Fail()
		}
	})
}

func populate(d *Database, n int) {
	for i := 0; i < n; i++ {
		key := []byte(strconv.Itoa(i))
		d.Store(key, key)
	}
}

func BenchmarkFetch(b *testing.B) {
	const maxKey = 10000
	mockDb(func(d *Database) {
		populate(d, maxKey)
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			key := []byte(strconv.Itoa(rand.Intn(maxKey)))
			data := d.Fetch(key)
			if !reflect.DeepEqual(key, data) {
				b.Fatalf("incorrect value for %v: %v", key, data)
			}
		}
	})
}

func BenchmarkReplace(b *testing.B) {
	const maxKey = 10000
	mockDb(func(d *Database) {
		populate(d, maxKey)
		b.ResetTimer()
		value := maxKey + 1
		for i := 0; i < b.N; i++ {
			key := []byte(strconv.Itoa(rand.Intn(maxKey)))
			data := []byte(strconv.Itoa(value))
			value++
			d.Store(key, data)
		}
	})
}

func BenchmarkStore(b *testing.B) {
	mockDb(func(d *Database) {
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			key := []byte(strconv.Itoa(i))
			d.Store(key, key)
		}
	})
}
<|endoftext|>


<commit_before>package gdbm

import (
	"os"
	"testing"
)

// Tests that the database is recreated everytime when opened in "c" mode.
// Ensures that the file exists and that there are no key-value pairs.
func TestRecreate(t *testing.T) {
	db, err := Open("test.gdbm", "c")
	defer db.Close()

	if err != nil {
		t.Error("Couldn't create new database")
	}

	f, err := Open("test.gdbm", "r")
	defer f.Close()

	if os.IsExist(err) {
		t.Error("Database wasn't actually created")
	}

	// TODO: test for no keys
}

// TODO: test other initializers

// Ensure that the database doesn't allow a Reader type to call an database-
// modifying operation such as Insert().
func TestWriteErrorWhenReader(t *testing.T) {
	// Ensure the db exists for this test
	db, err := Open("test.gdbm", "c")
	db.Close()

	db, err = Open("test.gdbm", "r")
	defer db.Close()

	if err != nil {
		t.Error("Couldn't read database")
	}

	err = db.Insert("foo", "bar")
	if err == nil {
		t.Error("Database let readonly client write")
	}
}

// Tests to make sure that inserting a key, then replacing its old value with a
// new one will not return an error (as would happen if you were to call
// Insert() again rather than Replace()) and that the key is actually updated.
func TestReplace(t *testing.T) {
	db, err := Open("test.gdbm", "c")
	defer db.Close()

	if err != nil {
		t.Error("Couldn't create database")
	}

	err = db.Insert("foo", "bar")
	err = db.Replace("foo", "biz")
	key, err := db.Fetch("foo")
	if err != nil || key != "biz" {
		t.Error("Replace didn't update key correctly")
	}
}

// Ensures that if a key k is inserted into the database, calling Exists(k)
// returns true - indicating that the insertion was successful.
func TestExists(t *testing.T) {
	db, err := Open("test.gdbm", "c")
	defer db.Close()

	if err != nil {
		t.Error("Couldn't create database")
	}

	err = db.Insert("foo", "bar")
	exists := db.Exists("foo")
	if !exists {
		t.Error("Inserted key reported as not existing")
	}
}

// Test to make sure that if a key is inserted then deleted, that it no longer
// returns true for Exists(key).
func TestDelete(t *testing.T) {
	db, err := Open("test.gdbm", "c")
	defer db.Close()

	db.Insert("foo", "bar")
	err = db.Delete("foo")
	exists := db.Exists("foo")
	if err != nil || exists {
		t.Error("Delete()ed key not removed")
	}
}

// Ensure the Reorganize() function doesn't halt execution.
func TestReorganize(t *testing.T) {
	// No values to test, but testing as a sanity test - if something does go
	// wrong and the program crashes, this'll let us know Reorganize() is
	// broken. ;)
	db, _ := Open("test.gdbm", "c")
	defer db.Close()
	db.Reorganize()
}

// Ensure the Sync() function doesn't halt execution.
func TestSync(t *testing.T) {
	// Same as TestReorganize() w/r/t no return value, etc.
	db, _ := Open("test.gdbm", "c")
	defer db.Close()
	db.Sync()
}
<commit_msg>adding test for the Version string<commit_after>package gdbm

import (
	"os"
	"testing"
)

// Test that GDBM version is returned
func TestVersion(t *testing.T) {
	vers := Version()
	if len(vers) == 0 {
		t.Error("version string is not present")
	}
}

// Tests that the database is recreated everytime when opened in "c" mode.
// Ensures that the file exists and that there are no key-value pairs.
func TestRecreate(t *testing.T) {
	db, err := Open("test.gdbm", "c")
	defer db.Close()

	if err != nil {
		t.Error("Couldn't create new database")
	}

	f, err := Open("test.gdbm", "r")
	defer f.Close()

	if os.IsExist(err) {
		t.Error("Database wasn't actually created")
	}

	// TODO: test for no keys
}

// TODO: test other initializers

// Ensure that the database doesn't allow a Reader type to call an database-
// modifying operation such as Insert().
func TestWriteErrorWhenReader(t *testing.T) {
	// Ensure the db exists for this test
	db, err := Open("test.gdbm", "c")
	db.Close()

	db, err = Open("test.gdbm", "r")
	defer db.Close()

	if err != nil {
		t.Error("Couldn't read database")
	}

	err = db.Insert("foo", "bar")
	if err == nil {
		t.Error("Database let readonly client write")
	}
}

// Tests to make sure that inserting a key, then replacing its old value with a
// new one will not return an error (as would happen if you were to call
// Insert() again rather than Replace()) and that the key is actually updated.
func TestReplace(t *testing.T) {
	db, err := Open("test.gdbm", "c")
	defer db.Close()

	if err != nil {
		t.Error("Couldn't create database")
	}

	err = db.Insert("foo", "bar")
	err = db.Replace("foo", "biz")
	key, err := db.Fetch("foo")
	if err != nil || key != "biz" {
		t.Error("Replace didn't update key correctly")
	}
}

// Ensures that if a key k is inserted into the database, calling Exists(k)
// returns true - indicating that the insertion was successful.
func TestExists(t *testing.T) {
	db, err := Open("test.gdbm", "c")
	defer db.Close()

	if err != nil {
		t.Error("Couldn't create database")
	}

	err = db.Insert("foo", "bar")
	exists := db.Exists("foo")
	if !exists {
		t.Error("Inserted key reported as not existing")
	}
}

// Test to make sure that if a key is inserted then deleted, that it no longer
// returns true for Exists(key).
func TestDelete(t *testing.T) {
	db, err := Open("test.gdbm", "c")
	defer db.Close()

	db.Insert("foo", "bar")
	err = db.Delete("foo")
	exists := db.Exists("foo")
	if err != nil || exists {
		t.Error("Delete()ed key not removed")
	}
}

// Ensure the Reorganize() function doesn't halt execution.
func TestReorganize(t *testing.T) {
	// No values to test, but testing as a sanity test - if something does go
	// wrong and the program crashes, this'll let us know Reorganize() is
	// broken. ;)
	db, _ := Open("test.gdbm", "c")
	defer db.Close()
	db.Reorganize()
}

// Ensure the Sync() function doesn't halt execution.
func TestSync(t *testing.T) {
	// Same as TestReorganize() w/r/t no return value, etc.
	db, _ := Open("test.gdbm", "c")
	defer db.Close()
	db.Sync()
}
<|endoftext|>


<commit_before>package extension

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/kayex/sirius"
	"github.com/kayex/sirius/text"
	"net/http"
)

type IPLookup struct{}

func (ipl *IPLookup) Run(m sirius.Message, cfg sirius.ExtensionConfig) (sirius.MessageAction, error) {
	cmd, match := m.Command("ip")

	if !match {
		return sirius.NoAction(), nil
	}

	ip := cmd.Arg(0)

	if ip == "" {
		return sirius.NoAction(), nil
	}

	err, info := ipLookup(ip)

	if err != nil {
		return nil, errors.New(fmt.Sprintf("IP Lookup error: %v", err))
	}

	// Output format:
	//
	// `IP`
	// City, Country (`COUNTRY CODE`)
	// ISP
	output := fmt.Sprintf("%v\n"+
		"%v, %v (%v)\n"+
		"%v",
		text.Code(ip),
		info.City,
		info.Country,
		text.Code(info.CountryCode),
		info.ISP)
	edit := m.EditText().Set(output)

	return edit, nil
}

func ipLookup(ip string) (error, *iPInfo) {
	url := "http://ip-api.com/json/" + ip

	c := &http.Client{}
	r, err := c.Get(url)

	if err != nil {
		return err, nil
	}
	defer r.Body.Close()

	var info *iPInfo
	err = json.NewDecoder(r.Body).Decode(info)

	return nil, info
}

type iPInfo struct {
	City        string `json:"city"`
	Country     string `json:"country"`
	CountryCode string `json:"countryCode"`
	ISP         string `json:"isp"`
}
<commit_msg>Pass struct by reference<commit_after>package extension

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/kayex/sirius"
	"github.com/kayex/sirius/text"
	"net/http"
)

type IPLookup struct{}

func (ipl *IPLookup) Run(m sirius.Message, cfg sirius.ExtensionConfig) (sirius.MessageAction, error) {
	cmd, match := m.Command("ip")

	if !match {
		return sirius.NoAction(), nil
	}

	ip := cmd.Arg(0)

	if ip == "" {
		return sirius.NoAction(), nil
	}

	err, info := ipLookup(ip)

	if err != nil {
		return nil, errors.New(fmt.Sprintf("IP Lookup error: %v", err))
	}

	// Output format:
	//
	// `IP`
	// City, Country (`COUNTRY CODE`)
	// ISP
	output := fmt.Sprintf("%v\n"+
		"%v, %v (%v)\n"+
		"%v",
		text.Code(ip),
		info.City,
		info.Country,
		text.Code(info.CountryCode),
		info.ISP)
	edit := m.EditText().Set(output)

	return edit, nil
}

func ipLookup(ip string) (error, *iPInfo) {
	url := "http://ip-api.com/json/" + ip

	c := &http.Client{}
	r, err := c.Get(url)

	if err != nil {
		return err, nil
	}
	defer r.Body.Close()

	var info iPInfo
	err = json.NewDecoder(r.Body).Decode(&info)

	return nil, &info
}

type iPInfo struct {
	City        string `json:"city"`
	Country     string `json:"country"`
	CountryCode string `json:"countryCode"`
	ISP         string `json:"isp"`
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"net"
	"os"
	"strings"
	"time"
)

// http://www.faa.gov/nextgen/programs/adsb/wsa/media/GDL90_Public_ICD_RevA.PDF

const (
	ipadAddr                = "192.168.10.255:4000" // Port 4000 for FreeFlight RANGR.
	maxDatagramSize         = 8192
	UPLINK_BLOCK_DATA_BITS  = 576
	UPLINK_BLOCK_BITS       = (UPLINK_BLOCK_DATA_BITS + 160)
	UPLINK_BLOCK_DATA_BYTES = (UPLINK_BLOCK_DATA_BITS / 8)
	UPLINK_BLOCK_BYTES      = (UPLINK_BLOCK_BITS / 8)

	UPLINK_FRAME_BLOCKS     = 6
	UPLINK_FRAME_DATA_BITS  = (UPLINK_FRAME_BLOCKS * UPLINK_BLOCK_DATA_BITS)
	UPLINK_FRAME_BITS       = (UPLINK_FRAME_BLOCKS * UPLINK_BLOCK_BITS)
	UPLINK_FRAME_DATA_BYTES = (UPLINK_FRAME_DATA_BITS / 8)
	UPLINK_FRAME_BYTES      = (UPLINK_FRAME_BITS / 8)

	// assume 6 byte frames: 2 header bytes, 4 byte payload
	// (TIS-B heartbeat with one address, or empty FIS-B APDU)
	UPLINK_MAX_INFO_FRAMES = (424 / 6)
)

var Crc16Table [256]uint16
var outConn *net.UDPConn

// Construct the CRC table. Adapted from FAA ref above.
func crcInit() {
	var i uint16
	var bitctr uint16
	var crc uint16
	for i = 0; i < 256; i++ {
		crc = (i << 8)
		for bitctr = 0; bitctr < 8; bitctr++ {
			z := uint16(0)
			if (crc & 0x8000) != 0 {
				z = 0x1021
			}
			crc = (crc << 1) ^ z
		}
		Crc16Table[i] = crc
	}
}

// Compute CRC. Adapted from FAA ref above.
func crcCompute(data []byte) uint16 {
	ret := uint16(0)
	for i := 0; i < len(data); i++ {
		ret = Crc16Table[ret>>8] ^ (ret << 8) ^ uint16(data[i])
	}
	return ret
}

func prepareMessage(data []byte) []byte {
	tmp := []byte{0x7E} // Flag start.
	// Compute CRC before modifying the message.
	crc := crcCompute(data)

	// Copy the message over, escaping 0x7E (Flag Byte) and 0x7D (Control-Escape).
	for i := 0; i < len(data); i++ {
		mv := data[i]
		if (mv == 0x7E) || (mv == 0x7D) {
			mv = mv ^ 0x20
			tmp = append(tmp, 0x7D)
		}
		tmp = append(tmp, mv)
	}

	// Add the two CRC16 bytes.
	tmp = append(tmp, byte(crc&0xFF))
	tmp = append(tmp, byte(crc>>8))

	tmp = append(tmp, 0x7E) // Flag end.

	return tmp
}

func makeHeartbeat() []byte {
	msg := make([]byte, 7)
	// See p.10.
	msg[0] = 0x00 // Message type "Heartbeat".
	msg[1] = 0x01 // "UAT Initialized".
	nowUTC := time.Now().UTC()
	// Seconds since 0000Z.
	midnightUTC := time.Date(nowUTC.Year(), nowUTC.Month(), nowUTC.Day(), 0, 0, 0, 0, time.UTC)
	secondsSinceMidnightUTC := uint32(nowUTC.Sub(midnightUTC).Seconds())

	msg[2] = byte((secondsSinceMidnightUTC >> 16) << 7)
	msg[3] = byte((secondsSinceMidnightUTC & 0xFF))
	msg[4] = byte((secondsSinceMidnightUTC & 0xFFFF) >> 8)

	// TODO. Number of uplink messages. See p.12.
	// msg[5]
	// msg[6]

	return prepareMessage(msg)
}

func relayUplinkMessage(msg []byte) {
	ret := make([]byte, len(msg)+4)
	// See p.15.
	ret[0] = 0x07 // Uplink message ID.
	ret[1] = 0x00 //TODO: Time.
	ret[2] = 0x00 //TODO: Time.
	ret[3] = 0x00 //TODO: Time.

	for i := 0; i < len(msg); i++ {
		ret[i+4] = msg[i]
	}

	outConn.Write(prepareMessage(ret))
}

func heartBeatSender() {
	for {
		outConn.Write(makeHeartbeat())
		time.Sleep(1 * time.Second)
	}
}

func parseInput(buf string) []byte {
	buf = strings.Trim(buf, "\r\n") // Remove newlines.
	x := strings.Split(buf, ";")    // We want to discard everything before the first ';'.
	if len(x) == 0 {
		return nil
	}
	s := x[0]
	if len(s) == 0 {
		return nil
	}
	if s[0] != '+' {
		return nil // Only want + ("Uplink") messages currently. - (Downlink) or messages that start with other are discarded.
	}

	s = s[1:]

	if len(s)%2 != 0 { // Bad format.
		return nil
	}

	if len(s)/2 != UPLINK_FRAME_DATA_BYTES {
		fmt.Printf("UPLINK_FRAME_DATA_BYTES=%d, len(s)=%d\n", UPLINK_FRAME_DATA_BYTES, len(s))
		//		panic("Error")
		return nil
	}

	// Now, begin converting the string into a byte array.
	frame := make([]byte, UPLINK_FRAME_DATA_BYTES)
	hex.Decode(frame, []byte(s))

	return frame
}

func main() {
	crcInit() // Initialize CRC16 table.

	// Open UDP port to send out the messages.
	addr, err := net.ResolveUDPAddr("udp", ipadAddr)
	if err != nil {
		panic(err)
	}
	outConn, err = net.DialUDP("udp", nil, addr)

	// Start the heartbeat message loop in the background, once per second.
	go heartBeatSender()

	reader := bufio.NewReader(os.Stdin)

	for {
		buf, _ := reader.ReadString('\n')
		o := parseInput(buf)
		if o != nil {
			relayUplinkMessage(o)
		}
	}

}
<commit_msg>Relay downlink frames using "pass-through reports".<commit_after>package main

import (
	"bufio"
	"encoding/hex"
	"fmt"
	"net"
	"os"
	"strings"
	"time"
)

// http://www.faa.gov/nextgen/programs/adsb/wsa/media/GDL90_Public_ICD_RevA.PDF

const (
	ipadAddr                = "192.168.1.255:4000" // Port 4000 for FreeFlight RANGR.
	maxDatagramSize         = 8192
	UPLINK_BLOCK_DATA_BITS  = 576
	UPLINK_BLOCK_BITS       = (UPLINK_BLOCK_DATA_BITS + 160)
	UPLINK_BLOCK_DATA_BYTES = (UPLINK_BLOCK_DATA_BITS / 8)
	UPLINK_BLOCK_BYTES      = (UPLINK_BLOCK_BITS / 8)

	UPLINK_FRAME_BLOCKS     = 6
	UPLINK_FRAME_DATA_BITS  = (UPLINK_FRAME_BLOCKS * UPLINK_BLOCK_DATA_BITS)
	UPLINK_FRAME_BITS       = (UPLINK_FRAME_BLOCKS * UPLINK_BLOCK_BITS)
	UPLINK_FRAME_DATA_BYTES = (UPLINK_FRAME_DATA_BITS / 8)
	UPLINK_FRAME_BYTES      = (UPLINK_FRAME_BITS / 8)

	// assume 6 byte frames: 2 header bytes, 4 byte payload
	// (TIS-B heartbeat with one address, or empty FIS-B APDU)
	UPLINK_MAX_INFO_FRAMES = (424 / 6)

	MSGTYPE_UPLINK			= 0x07
	MSGTYPE_BASIC_REPORT	= 0x1E
	MSGTYPE_LONG_REPORT		= 0x1F
)

var Crc16Table [256]uint16
var outConn *net.UDPConn

// Construct the CRC table. Adapted from FAA ref above.
func crcInit() {
	var i uint16
	var bitctr uint16
	var crc uint16
	for i = 0; i < 256; i++ {
		crc = (i << 8)
		for bitctr = 0; bitctr < 8; bitctr++ {
			z := uint16(0)
			if (crc & 0x8000) != 0 {
				z = 0x1021
			}
			crc = (crc << 1) ^ z
		}
		Crc16Table[i] = crc
	}
}

// Compute CRC. Adapted from FAA ref above.
func crcCompute(data []byte) uint16 {
	ret := uint16(0)
	for i := 0; i < len(data); i++ {
		ret = Crc16Table[ret>>8] ^ (ret << 8) ^ uint16(data[i])
	}
	return ret
}

func prepareMessage(data []byte) []byte {
	tmp := []byte{0x7E} // Flag start.
	// Compute CRC before modifying the message.
	crc := crcCompute(data)

	// Copy the message over, escaping 0x7E (Flag Byte) and 0x7D (Control-Escape).
	for i := 0; i < len(data); i++ {
		mv := data[i]
		if (mv == 0x7E) || (mv == 0x7D) {
			mv = mv ^ 0x20
			tmp = append(tmp, 0x7D)
		}
		tmp = append(tmp, mv)
	}

	// Add the two CRC16 bytes.
	tmp = append(tmp, byte(crc&0xFF))
	tmp = append(tmp, byte(crc>>8))

	tmp = append(tmp, 0x7E) // Flag end.

	return tmp
}

func makeHeartbeat() []byte {
	msg := make([]byte, 7)
	// See p.10.
	msg[0] = 0x00 // Message type "Heartbeat".
	msg[1] = 0x01 // "UAT Initialized".
	nowUTC := time.Now().UTC()
	// Seconds since 0000Z.
	midnightUTC := time.Date(nowUTC.Year(), nowUTC.Month(), nowUTC.Day(), 0, 0, 0, 0, time.UTC)
	secondsSinceMidnightUTC := uint32(nowUTC.Sub(midnightUTC).Seconds())

	msg[2] = byte((secondsSinceMidnightUTC >> 16) << 7)
	msg[3] = byte((secondsSinceMidnightUTC & 0xFF))
	msg[4] = byte((secondsSinceMidnightUTC & 0xFFFF) >> 8)

	// TODO. Number of uplink messages. See p.12.
	// msg[5]
	// msg[6]

	return prepareMessage(msg)
}

func relayMessage(msgtype uint16, msg []byte) {
	ret := make([]byte, len(msg)+4)
	// See p.15.
	ret[0] = byte(msgtype) // Uplink message ID.
	ret[1] = 0x00 //TODO: Time.
	ret[2] = 0x00 //TODO: Time.
	ret[3] = 0x00 //TODO: Time.

	for i := 0; i < len(msg); i++ {
		ret[i+4] = msg[i]
	}

	outConn.Write(prepareMessage(ret))
}

func heartBeatSender() {
	for {
		outConn.Write(makeHeartbeat())
		time.Sleep(1 * time.Second)
	}
}

func parseInput(buf string) ([]byte, uint16) {
	buf = strings.Trim(buf, "\r\n") // Remove newlines.
	x := strings.Split(buf, ";")    // We want to discard everything before the first ';'.
	if len(x) == 0 {
		return nil, 0
	}
	s := x[0]
	if len(s) == 0 {
		return nil, 0
	}
	msgtype := uint16(0)

	s = s[1:]
	msglen := len(s)/2

	if len(s)%2 != 0 { // Bad format.
		return nil, 0
	}

	if msglen == UPLINK_FRAME_DATA_BYTES {
		msgtype = MSGTYPE_UPLINK
	} else if msglen == 34 {
		msgtype = MSGTYPE_LONG_REPORT
	} else if msglen == 18 {
		msgtype = MSGTYPE_BASIC_REPORT
	} else {
		msgtype = 0
	}

	if msgtype == 0 {
		fmt.Printf("UNKNOWN MESSAGE TYPE: %s - msglen=%d\n", s, msglen)
	}

	// Now, begin converting the string into a byte array.
	frame := make([]byte, UPLINK_FRAME_DATA_BYTES)
	hex.Decode(frame, []byte(s))

	return frame, msgtype
}

func main() {
	crcInit() // Initialize CRC16 table.

	// Open UDP port to send out the messages.
	addr, err := net.ResolveUDPAddr("udp", ipadAddr)
	if err != nil {
		panic(err)
	}
	outConn, err = net.DialUDP("udp", nil, addr)

	// Start the heartbeat message loop in the background, once per second.
	go heartBeatSender()

	reader := bufio.NewReader(os.Stdin)

	for {
		buf, _ := reader.ReadString('\n')
		o, msgtype := parseInput(buf)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"os"
	"strings"

	plugin "github.com/davyxu/pbmeta/proto/compiler"
)

type Generator struct {
	*bytes.Buffer

	Request  *plugin.CodeGeneratorRequest  // The input.
	Response *plugin.CodeGeneratorResponse // The output.
	indent   string
}

func New() *Generator {
	self := new(Generator)
	self.Buffer = new(bytes.Buffer)
	self.Request = new(plugin.CodeGeneratorRequest)
	self.Response = new(plugin.CodeGeneratorResponse)
	return self
}

// Error reports a problem, including an error, and exits the program.
func (self *Generator) Error(err error, msgs ...string) {
	s := strings.Join(msgs, " ") + ":" + err.Error()
	log.Errorln("protoc-gen-sharpnet, error:", s)
	os.Exit(1)
}

// Fail reports a problem and exits the program.
func (self *Generator) Fail(msgs ...string) {
	s := strings.Join(msgs, " ")
	log.Errorln("protoc-gen-sharpnet, error:", s)
	os.Exit(1)
}

func (self *Generator) Print(str ...interface{}) {

	for _, v := range str {
		switch s := v.(type) {
		case string:
			self.WriteString(s)
		case *string:
			self.WriteString(*s)
		case bool:
			fmt.Fprintf(self, "%t", s)
		case *bool:
			fmt.Fprintf(self, "%t", *s)
		case int, int32:
			fmt.Fprintf(self, "%d", s)
		case *int32:
			fmt.Fprintf(self, "%d", *s)
		case *int64:
			fmt.Fprintf(self, "%d", *s)
		case float64:
			fmt.Fprintf(self, "%g", s)
		case *float64:
			fmt.Fprintf(self, "%g", *s)
		default:
			panic("here")
			self.Fail(fmt.Sprintf("unknown type in printer: %T", v))

		}
	}

}

func (self *Generator) Println(str ...interface{}) {
	self.BeginLine()
	self.Print(str...)
	self.EndLine()
}

func (self *Generator) BeginLine() {
	self.WriteString(self.indent)
}

func (self *Generator) EndLine() {
	self.WriteByte('\n')
}

// In Indents the output one tab stop.
func (self *Generator) In() { self.indent += "\t" }

// Out unindents the output one tab stop.
func (self *Generator) Out() {
	if len(self.indent) > 0 {
		self.indent = self.indent[1:]
	}
}
<commit_msg>修改生成器可能的类型支持缺失<commit_after>package main

import (
	"bytes"
	"fmt"
	"os"
	"strings"

	plugin "github.com/davyxu/pbmeta/proto/compiler"
)

type Generator struct {
	*bytes.Buffer

	Request  *plugin.CodeGeneratorRequest  // The input.
	Response *plugin.CodeGeneratorResponse // The output.
	indent   string
}

func New() *Generator {
	self := new(Generator)
	self.Buffer = new(bytes.Buffer)
	self.Request = new(plugin.CodeGeneratorRequest)
	self.Response = new(plugin.CodeGeneratorResponse)
	return self
}

// Error reports a problem, including an error, and exits the program.
func (self *Generator) Error(err error, msgs ...string) {
	s := strings.Join(msgs, " ") + ":" + err.Error()
	log.Errorln("protoc-gen-sharpnet, error:", s)
	os.Exit(1)
}

// Fail reports a problem and exits the program.
func (self *Generator) Fail(msgs ...string) {
	s := strings.Join(msgs, " ")
	log.Errorln("protoc-gen-sharpnet, error:", s)
	os.Exit(1)
}

func (self *Generator) Print(str ...interface{}) {

	for _, v := range str {
		switch s := v.(type) {
		case string:
			self.WriteString(s)
		case *string:
			self.WriteString(*s)
		case bool:
			fmt.Fprintf(self, "%t", s)
		case *bool:
			fmt.Fprintf(self, "%t", *s)
		case int, int32, uint, uint32:
			fmt.Fprintf(self, "%d", s)
		case *int32:
			fmt.Fprintf(self, "%d", *s)
		case *int64:
			fmt.Fprintf(self, "%d", *s)
		case float64:
			fmt.Fprintf(self, "%g", s)
		case *float64:
			fmt.Fprintf(self, "%g", *s)
		default:
			self.Fail(fmt.Sprintf("unknown type in printer: %T", v))
			panic("here")

		}
	}

}

func (self *Generator) Println(str ...interface{}) {
	self.BeginLine()
	self.Print(str...)
	self.EndLine()
}

func (self *Generator) BeginLine() {
	self.WriteString(self.indent)
}

func (self *Generator) EndLine() {
	self.WriteByte('\n')
}

// In Indents the output one tab stop.
func (self *Generator) In() { self.indent += "\t" }

// Out unindents the output one tab stop.
func (self *Generator) Out() {
	if len(self.indent) > 0 {
		self.indent = self.indent[1:]
	}
}
<|endoftext|>


<commit_before>package jsval

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strconv"
	"strings"
)

type Generator struct{}

func NewGenerator() *Generator {
	return &Generator{}
}

func (g *Generator) Process(out io.Writer, v *JSVal, name string) error {
	ctx := genctx{
		pkgname: "jsval",
		vname:   "V",
	}

	fmt.Fprintf(out, "func JSVal%s() *%s.JSVal {\n", name, ctx.pkgname)
	g1 := ctx.Indent()
	defer g1()
	generateCode(&ctx, out, v)
	fmt.Fprintf(out, "\n\treturn %s\n}\n", ctx.vname)

	return nil
}

type genctx struct {
	prefix  []byte
	pkgname string
	vname   string
}

func (ctx *genctx) Prefix() []byte {
	return ctx.prefix
}

func (ctx *genctx) Indent() func() {
	ctx.prefix = append(ctx.prefix, '\t')
	return func() {
		l := len(ctx.prefix)
		if l == 0 {
			return
		}
		ctx.prefix = ctx.prefix[:l-1]
	}
}

func generateNilCode(ctx *genctx, out io.Writer, c emptyConstraint) error {
	fmt.Fprintf(out, "%s%s.EmptyConstraint", ctx.Prefix(), ctx.pkgname)
	return nil
}
func generateValidatorCode(ctx *genctx, out io.Writer, v *JSVal) error {
	vname := ctx.vname
	p := ctx.Prefix()

	fmt.Fprintf(out, "%s%s := %s.New()", p, vname, ctx.pkgname)
	fmt.Fprintf(out, "\n%s%s.SetRoot(\n", p, vname)
	g := ctx.Indent()
	if err := generateCode(ctx, out, v.root); err != nil {
		g()
		return err
	}
	g()
	fmt.Fprintf(out, ",\n%s)\n", p)

	refs := make([]string, 0, len(v.refs))
	for ref := range v.refs {
		refs = append(refs, ref)
	}
	sort.Strings(refs)

	for _, ref := range refs {
		c := v.refs[ref]
		fmt.Fprintf(out, "\n%s%s.SetReference(\n%s\t`%s`,\n", p, vname, p, ref)
		g1 := ctx.Indent()
		if ref == "#" {
			fmt.Fprintf(out, "%s%s.Root()", ctx.Prefix(), ctx.vname)
		} else {
			if err := generateCode(ctx, out, c); err != nil {
				g1()
				return err
			}
		}
		fmt.Fprintf(out, ",\n%s)", p)
		g1()
	}

	return nil
}

func generateCode(ctx *genctx, out io.Writer, c Validator) error {
	buf := &bytes.Buffer{}

	switch c.(type) {
	case emptyConstraint:
		if err := generateNilCode(ctx, buf, c.(emptyConstraint)); err != nil {
			return err
		}
	case *JSVal:
		if err := generateValidatorCode(ctx, buf, c.(*JSVal)); err != nil {
			return err
		}
	case *AnyConstraint:
		if err := generateAnyCode(ctx, buf, c.(*AnyConstraint)); err != nil {
			return err
		}
	case *AllConstraint:
		if err := generateAllCode(ctx, buf, c.(*AllConstraint)); err != nil {
			return err
		}
	case *ArrayConstraint:
		if err := generateArrayCode(ctx, buf, c.(*ArrayConstraint)); err != nil {
			return err
		}
	case *BooleanConstraint:
		if err := generateBooleanCode(ctx, buf, c.(*BooleanConstraint)); err != nil {
			return err
		}
	case *IntegerConstraint:
		if err := generateIntegerCode(ctx, buf, c.(*IntegerConstraint)); err != nil {
			return err
		}
	case *NotConstraint:
		if err := generateNotCode(ctx, buf, c.(*NotConstraint)); err != nil {
			return err
		}
	case *NumberConstraint:
		if err := generateNumberCode(ctx, buf, c.(*NumberConstraint)); err != nil {
			return err
		}
	case *ObjectConstraint:
		if err := generateObjectCode(ctx, buf, c.(*ObjectConstraint)); err != nil {
			return err
		}
	case *ReferenceConstraint:
		if err := generateReferenceCode(ctx, buf, c.(*ReferenceConstraint)); err != nil {
			return err
		}
	case *StringConstraint:
		if err := generateStringCode(ctx, buf, c.(*StringConstraint)); err !=nil {
			return err
		}
	}

	s := buf.String()
	s = strings.TrimSuffix(s, ".\n")
	fmt.Fprintf(out, s)

	return nil
}

func generateReferenceCode(ctx *genctx, out io.Writer, c *ReferenceConstraint) error {
	fmt.Fprintf(out, "%s%s.Reference(%s).RefersTo(`%s`)", ctx.Prefix(), ctx.pkgname, ctx.vname, c.reference)

	return nil
}

func generateAnyCode(ctx *genctx, out io.Writer, c *AnyConstraint) error {
	p := ctx.Prefix()
	fmt.Fprintf(out, "%s%s.Any()", p, ctx.pkgname)
	for _, c1 := range c.constraints {
		g1 := ctx.Indent()
		fmt.Fprintf(out, ".\n%sAdd(\n", ctx.Prefix())
		g2 := ctx.Indent()
		if err := generateCode(ctx, out, c1); err != nil {
			g2()
			g1()
			return err
		}
		g2()
		fmt.Fprintf(out, ",\n%s)", ctx.Prefix())
		g1()
	}
	return nil
}

func generateAllCode(ctx *genctx, out io.Writer, c *AllConstraint) error {
	if len(c.constraints) == 0 {
		return generateNilCode(ctx, out, EmptyConstraint)
	}

	p := ctx.Prefix()
	fmt.Fprintf(out, "%s%s.All()", p, ctx.pkgname)
	for _, c1 := range c.constraints {
		g1 := ctx.Indent()
		fmt.Fprintf(out, ".\n%sAdd(\n", ctx.Prefix())
		g2 := ctx.Indent()
		if err := generateCode(ctx, out, c1); err != nil {
			g2()
			g1()
			return err
		}
		g2()
		fmt.Fprintf(out, ",\n%s)", ctx.Prefix())
		g1()
	}
	return nil
}

func generateIntegerCode(ctx *genctx, out io.Writer, c *IntegerConstraint) error {
	fmt.Fprintf(out, "%s%s.Integer()", ctx.Prefix(), ctx.pkgname)

	if c.applyMinimum {
		fmt.Fprintf(out, ".Minimum(%d)", int(c.minimum))
	}

	if c.applyMaximum {
		fmt.Fprintf(out, ".Maximum(%d)", int(c.maximum))
	}

	return nil
}

func generateNumberCode(ctx *genctx, out io.Writer, c *NumberConstraint) error {
	fmt.Fprintf(out, "%s%s.Number()", ctx.Prefix(), ctx.pkgname)

	if c.applyMinimum {
		fmt.Fprintf(out, ".Minimum(%f)", c.minimum)
	}

	if c.exclusiveMinimum {
		fmt.Fprintf(out, ".ExclusiveMinimum(true)")
	}

	if c.applyMaximum {
		fmt.Fprintf(out, ".Maximum(%f)", c.maximum)
	}

	if c.exclusiveMaximum {
		fmt.Fprintf(out, ".ExclusiveMaximum(true)")
	}

	if c.HasDefault() {
		fmt.Fprintf(out, ".Default(%f)", c.DefaultValue())
	}

	return nil
}

func generateEnumCode(ctx *genctx, out io.Writer, c *EnumConstraint) error {
	fmt.Fprintf(out, "[]interface{}{")
	l := len(c.enums)
	for i, v := range c.enums {
		rv := reflect.ValueOf(v)
		switch rv.Kind() {
		case reflect.String:
			fmt.Fprintf(out, "%s", strconv.Quote(rv.String()))
		}
		if i < l-1 {
			fmt.Fprintf(out, ", ")
		}
	}
	fmt.Fprintf(out, "}")

	return nil
}

func generateStringCode(ctx *genctx, out io.Writer, c *StringConstraint) error {
	fmt.Fprintf(out, "%s%s.String()", ctx.Prefix(), ctx.pkgname)

	if c.maxLength > -1 {
		fmt.Fprintf(out, ".MaxLength(%d)", c.maxLength)
	}

	if c.minLength > 0 {
		fmt.Fprintf(out, ".MinLength(%d)", c.minLength)
	}

	if f := c.format; f != "" {
		fmt.Fprintf(out, ".Format(%s)", strconv.Quote(string(f)))
	}

	if rx := c.regexp; rx != nil {
		fmt.Fprintf(out, ".Regexp(`%s`)", rx.String())
	}

	if enum := c.enums; enum != nil {
		fmt.Fprintf(out, ".Enum(")
		if err := generateEnumCode(ctx, out, enum); err != nil {
			return err
		}
		fmt.Fprintf(out, ",)")
	}

	return nil
}

func generateObjectCode(ctx *genctx, out io.Writer, c *ObjectConstraint) error {
	fmt.Fprintf(out, "%s%s.Object()", ctx.Prefix(), ctx.pkgname)

	// object code usually becomes quite nested, so we indent one level
	// to begin with
	g1 := ctx.Indent()
	defer g1()
	p := ctx.Prefix()

	if c.HasDefault() {
		fmt.Fprintf(out, ".\n%sDefault(%s)", p, c.DefaultValue())
	}

	if len(c.required) > 0 {
		fmt.Fprintf(out, ".\n%sRequired([]string{", p)
		l := len(c.required)
		pnames := make([]string, 0, l)
		for pname := range c.required {
			pnames = append(pnames, pname)
		}
		sort.Strings(pnames)
		for i, pname := range pnames {
			fmt.Fprint(out, strconv.Quote(pname))
			if i < l - 1 {
				fmt.Fprint(out, ", ")
			}
		}
		fmt.Fprint(out, "})")
	}

	if aprop := c.additionalProperties; aprop != nil {
		fmt.Fprintf(out, ".\n%sAdditionalProperties(\n", p)
		g := ctx.Indent()
		if err := generateCode(ctx, out, aprop); err != nil {
			g()
			return err
		}
		fmt.Fprintf(out, ",\n%s)", p)
		g()
	}

	pnames := make([]string, 0, len(c.properties))
	for pname := range c.properties {
		pnames = append(pnames, pname)
	}
	sort.Strings(pnames)

	for _, pname := range pnames {
		pdef := c.properties[pname]

		g := ctx.Indent()
		fmt.Fprintf(out, ".\n%sAddProp(\n%s\t`%s`,\n", p, p, pname)
		if err := generateCode(ctx, out, pdef); err != nil {
			g()
			return err
		}
		fmt.Fprintf(out, ",\n%s)", p)
		g()
	}

	if m := c.propdeps; len(m) > 0 {
		for from, deplist := range m {
			for _, to := range deplist {
				fmt.Fprintf(out, ".\n%sPropDependency(%s, %s)", ctx.Prefix(), strconv.Quote(from), strconv.Quote(to))
			}
		}
	}

	return nil
}

func generateArrayCode(ctx *genctx, out io.Writer, c *ArrayConstraint) error {
	fmt.Fprintf(out, "%s%s.Array()", ctx.Prefix(), ctx.pkgname)
	if c.minItems > -1 {
		fmt.Fprintf(out, ".MinItems(%d)", c.minItems)
	}
	if c.maxItems > -1 {
		fmt.Fprintf(out, ".MaxItems(%d)", c.maxItems)
	}
	if c.uniqueItems {
		fmt.Fprintf(out, ".UniqueItems(true)")
	}
	return nil
}

func generateBooleanCode(ctx *genctx, out io.Writer, c *BooleanConstraint) error {
	fmt.Fprintf(out, "%s%s.Boolean()", ctx.Prefix(), ctx.pkgname)
	if c.HasDefault() {
		fmt.Fprintf(out, ".Default(%t)", c.DefaultValue())
	}
	return nil
}

func generateNotCode(ctx *genctx, out io.Writer, c *NotConstraint) error {
	fmt.Fprintf(out, "%s%s.Not(\n", ctx.Prefix(), ctx.pkgname)
	g := ctx.Indent()
	if err := generateCode(ctx, out, c.child); err != nil {
		g()
		return err
	}
	g()
	fmt.Fprintf(out, "\n%s)", ctx.Prefix())
	return nil
}
<commit_msg>Implement OneOf generator<commit_after>package jsval

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strconv"
	"strings"
)

type Generator struct{}

func NewGenerator() *Generator {
	return &Generator{}
}

func (g *Generator) Process(out io.Writer, v *JSVal, name string) error {
	ctx := genctx{
		pkgname: "jsval",
		vname:   "V",
	}

	fmt.Fprintf(out, "func JSVal%s() *%s.JSVal {\n", name, ctx.pkgname)
	g1 := ctx.Indent()
	defer g1()
	generateCode(&ctx, out, v)
	fmt.Fprintf(out, "\n\treturn %s\n}\n", ctx.vname)

	return nil
}

type genctx struct {
	prefix  []byte
	pkgname string
	vname   string
}

func (ctx *genctx) Prefix() []byte {
	return ctx.prefix
}

func (ctx *genctx) Indent() func() {
	ctx.prefix = append(ctx.prefix, '\t')
	return func() {
		l := len(ctx.prefix)
		if l == 0 {
			return
		}
		ctx.prefix = ctx.prefix[:l-1]
	}
}

func generateNilCode(ctx *genctx, out io.Writer, c emptyConstraint) error {
	fmt.Fprintf(out, "%s%s.EmptyConstraint", ctx.Prefix(), ctx.pkgname)
	return nil
}
func generateValidatorCode(ctx *genctx, out io.Writer, v *JSVal) error {
	vname := ctx.vname
	p := ctx.Prefix()

	fmt.Fprintf(out, "%s%s := %s.New()", p, vname, ctx.pkgname)
	fmt.Fprintf(out, "\n%s%s.SetRoot(\n", p, vname)
	g := ctx.Indent()
	if err := generateCode(ctx, out, v.root); err != nil {
		g()
		return err
	}
	g()
	fmt.Fprintf(out, ",\n%s)\n", p)

	refs := make([]string, 0, len(v.refs))
	for ref := range v.refs {
		refs = append(refs, ref)
	}
	sort.Strings(refs)

	for _, ref := range refs {
		c := v.refs[ref]
		fmt.Fprintf(out, "\n%s%s.SetReference(\n%s\t`%s`,\n", p, vname, p, ref)
		g1 := ctx.Indent()
		if ref == "#" {
			fmt.Fprintf(out, "%s%s.Root()", ctx.Prefix(), ctx.vname)
		} else {
			if err := generateCode(ctx, out, c); err != nil {
				g1()
				return err
			}
		}
		fmt.Fprintf(out, ",\n%s)", p)
		g1()
	}

	return nil
}

func generateCode(ctx *genctx, out io.Writer, c Validator) error {
	buf := &bytes.Buffer{}

	switch c.(type) {
	case emptyConstraint:
		if err := generateNilCode(ctx, buf, c.(emptyConstraint)); err != nil {
			return err
		}
	case *JSVal:
		if err := generateValidatorCode(ctx, buf, c.(*JSVal)); err != nil {
			return err
		}
	case *AnyConstraint:
		if err := generateAnyCode(ctx, buf, c.(*AnyConstraint)); err != nil {
			return err
		}
	case *AllConstraint:
		if err := generateAllCode(ctx, buf, c.(*AllConstraint)); err != nil {
			return err
		}
	case *ArrayConstraint:
		if err := generateArrayCode(ctx, buf, c.(*ArrayConstraint)); err != nil {
			return err
		}
	case *BooleanConstraint:
		if err := generateBooleanCode(ctx, buf, c.(*BooleanConstraint)); err != nil {
			return err
		}
	case *IntegerConstraint:
		if err := generateIntegerCode(ctx, buf, c.(*IntegerConstraint)); err != nil {
			return err
		}
	case *NotConstraint:
		if err := generateNotCode(ctx, buf, c.(*NotConstraint)); err != nil {
			return err
		}
	case *NumberConstraint:
		if err := generateNumberCode(ctx, buf, c.(*NumberConstraint)); err != nil {
			return err
		}
	case *ObjectConstraint:
		if err := generateObjectCode(ctx, buf, c.(*ObjectConstraint)); err != nil {
			return err
		}
	case *OneOfConstraint:
		if err := generateOneOfCode(ctx, buf, c.(*OneOfConstraint)); err != nil {
			return err
		}
	case *ReferenceConstraint:
		if err := generateReferenceCode(ctx, buf, c.(*ReferenceConstraint)); err != nil {
			return err
		}
	case *StringConstraint:
		if err := generateStringCode(ctx, buf, c.(*StringConstraint)); err !=nil {
			return err
		}
	}

	s := buf.String()
	s = strings.TrimSuffix(s, ".\n")
	fmt.Fprintf(out, s)

	return nil
}

func generateReferenceCode(ctx *genctx, out io.Writer, c *ReferenceConstraint) error {
	fmt.Fprintf(out, "%s%s.Reference(%s).RefersTo(`%s`)", ctx.Prefix(), ctx.pkgname, ctx.vname, c.reference)

	return nil
}

func generateComboCode(ctx *genctx, out io.Writer, name string, clist []Constraint) error {
	if len(clist) == 0 {
		return generateNilCode(ctx, out, EmptyConstraint)
	}
	p := ctx.Prefix()
	fmt.Fprintf(out, "%s%s.%s()", p, ctx.pkgname, name)
	for _, c1 := range clist {
		g1 := ctx.Indent()
		fmt.Fprintf(out, ".\n%sAdd(\n", ctx.Prefix())
		g2 := ctx.Indent()
		if err := generateCode(ctx, out, c1); err != nil {
			g2()
			g1()
			return err
		}
		g2()
		fmt.Fprintf(out, ",\n%s)", ctx.Prefix())
		g1()
	}
	return nil
}

func generateAnyCode(ctx *genctx, out io.Writer, c *AnyConstraint) error {
	return generateComboCode(ctx, out, "Any", c.constraints)
}

func generateAllCode(ctx *genctx, out io.Writer, c *AllConstraint) error {
	return generateComboCode(ctx, out, "All", c.constraints)
}

func generateOneOfCode(ctx *genctx, out io.Writer, c *OneOfConstraint) error {
	return generateComboCode(ctx, out, "OneOf", c.constraints)
}

func generateIntegerCode(ctx *genctx, out io.Writer, c *IntegerConstraint) error {
	fmt.Fprintf(out, "%s%s.Integer()", ctx.Prefix(), ctx.pkgname)

	if c.applyMinimum {
		fmt.Fprintf(out, ".Minimum(%d)", int(c.minimum))
	}

	if c.applyMaximum {
		fmt.Fprintf(out, ".Maximum(%d)", int(c.maximum))
	}

	return nil
}

func generateNumberCode(ctx *genctx, out io.Writer, c *NumberConstraint) error {
	fmt.Fprintf(out, "%s%s.Number()", ctx.Prefix(), ctx.pkgname)

	if c.applyMinimum {
		fmt.Fprintf(out, ".Minimum(%f)", c.minimum)
	}

	if c.exclusiveMinimum {
		fmt.Fprintf(out, ".ExclusiveMinimum(true)")
	}

	if c.applyMaximum {
		fmt.Fprintf(out, ".Maximum(%f)", c.maximum)
	}

	if c.exclusiveMaximum {
		fmt.Fprintf(out, ".ExclusiveMaximum(true)")
	}

	if c.HasDefault() {
		fmt.Fprintf(out, ".Default(%f)", c.DefaultValue())
	}

	return nil
}

func generateEnumCode(ctx *genctx, out io.Writer, c *EnumConstraint) error {
	fmt.Fprintf(out, "[]interface{}{")
	l := len(c.enums)
	for i, v := range c.enums {
		rv := reflect.ValueOf(v)
		switch rv.Kind() {
		case reflect.String:
			fmt.Fprintf(out, "%s", strconv.Quote(rv.String()))
		}
		if i < l-1 {
			fmt.Fprintf(out, ", ")
		}
	}
	fmt.Fprintf(out, "}")

	return nil
}

func generateStringCode(ctx *genctx, out io.Writer, c *StringConstraint) error {
	fmt.Fprintf(out, "%s%s.String()", ctx.Prefix(), ctx.pkgname)

	if c.maxLength > -1 {
		fmt.Fprintf(out, ".MaxLength(%d)", c.maxLength)
	}

	if c.minLength > 0 {
		fmt.Fprintf(out, ".MinLength(%d)", c.minLength)
	}

	if f := c.format; f != "" {
		fmt.Fprintf(out, ".Format(%s)", strconv.Quote(string(f)))
	}

	if rx := c.regexp; rx != nil {
		fmt.Fprintf(out, ".Regexp(`%s`)", rx.String())
	}

	if enum := c.enums; enum != nil {
		fmt.Fprintf(out, ".Enum(")
		if err := generateEnumCode(ctx, out, enum); err != nil {
			return err
		}
		fmt.Fprintf(out, ",)")
	}

	return nil
}

func generateObjectCode(ctx *genctx, out io.Writer, c *ObjectConstraint) error {
	fmt.Fprintf(out, "%s%s.Object()", ctx.Prefix(), ctx.pkgname)

	// object code usually becomes quite nested, so we indent one level
	// to begin with
	g1 := ctx.Indent()
	defer g1()
	p := ctx.Prefix()

	if c.HasDefault() {
		fmt.Fprintf(out, ".\n%sDefault(%s)", p, c.DefaultValue())
	}

	if len(c.required) > 0 {
		fmt.Fprintf(out, ".\n%sRequired([]string{", p)
		l := len(c.required)
		pnames := make([]string, 0, l)
		for pname := range c.required {
			pnames = append(pnames, pname)
		}
		sort.Strings(pnames)
		for i, pname := range pnames {
			fmt.Fprint(out, strconv.Quote(pname))
			if i < l - 1 {
				fmt.Fprint(out, ", ")
			}
		}
		fmt.Fprint(out, "})")
	}

	if aprop := c.additionalProperties; aprop != nil {
		fmt.Fprintf(out, ".\n%sAdditionalProperties(\n", p)
		g := ctx.Indent()
		if err := generateCode(ctx, out, aprop); err != nil {
			g()
			return err
		}
		fmt.Fprintf(out, ",\n%s)", p)
		g()
	}

	pnames := make([]string, 0, len(c.properties))
	for pname := range c.properties {
		pnames = append(pnames, pname)
	}
	sort.Strings(pnames)

	for _, pname := range pnames {
		pdef := c.properties[pname]

		g := ctx.Indent()
		fmt.Fprintf(out, ".\n%sAddProp(\n%s\t`%s`,\n", p, p, pname)
		if err := generateCode(ctx, out, pdef); err != nil {
			g()
			return err
		}
		fmt.Fprintf(out, ",\n%s)", p)
		g()
	}

	if m := c.propdeps; len(m) > 0 {
		for from, deplist := range m {
			for _, to := range deplist {
				fmt.Fprintf(out, ".\n%sPropDependency(%s, %s)", ctx.Prefix(), strconv.Quote(from), strconv.Quote(to))
			}
		}
	}

	return nil
}

func generateArrayCode(ctx *genctx, out io.Writer, c *ArrayConstraint) error {
	fmt.Fprintf(out, "%s%s.Array()", ctx.Prefix(), ctx.pkgname)
	if c.minItems > -1 {
		fmt.Fprintf(out, ".MinItems(%d)", c.minItems)
	}
	if c.maxItems > -1 {
		fmt.Fprintf(out, ".MaxItems(%d)", c.maxItems)
	}
	if c.uniqueItems {
		fmt.Fprintf(out, ".UniqueItems(true)")
	}
	return nil
}

func generateBooleanCode(ctx *genctx, out io.Writer, c *BooleanConstraint) error {
	fmt.Fprintf(out, "%s%s.Boolean()", ctx.Prefix(), ctx.pkgname)
	if c.HasDefault() {
		fmt.Fprintf(out, ".Default(%t)", c.DefaultValue())
	}
	return nil
}

func generateNotCode(ctx *genctx, out io.Writer, c *NotConstraint) error {
	fmt.Fprintf(out, "%s%s.Not(\n", ctx.Prefix(), ctx.pkgname)
	g := ctx.Indent()
	if err := generateCode(ctx, out, c.child); err != nil {
		g()
		return err
	}
	g()
	fmt.Fprintf(out, "\n%s)", ctx.Prefix())
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

// More information about Google Distance Matrix API is available on
// https://developers.google.com/maps/documentation/distancematrix/

package maps

import (
	"errors"
	"net/url"
	"strings"

	"golang.org/x/net/context"
)

var geocodingAPI = &apiConfig{
	host:            "https://maps.googleapis.com",
	path:            "/maps/api/geocode/json",
	acceptsClientID: true,
}

// Geocode makes a Geocoding API request
func (c *Client) Geocode(ctx context.Context, r *GeocodingRequest) ([]GeocodingResult, error) {
	if r.Address == "" && len(r.Components) == 0 && r.LatLng == nil {
		return nil, errors.New("maps: address, components and LatLng are all missing")
	}

	var response struct {
		Results []GeocodingResult `json:"results"`
		commonResponse
	}

	if err := c.getJSON(ctx, geocodingAPI, r, &response); err != nil {
		return nil, err
	}

	if err := response.StatusError(); err != nil {
		return nil, err
	}

	return response.Results, nil
}

// ReverseGeocode makes a Reverse Geocoding API request
func (c *Client) ReverseGeocode(ctx context.Context, r *GeocodingRequest) ([]GeocodingResult, error) {
	// Since Geocode() does not allow a nil LatLng, whereas it is allowed here
	if r.LatLng == nil && r.PlaceID == "" {
		return nil, errors.New("maps: LatLng and PlaceID are both missing")
	}

	var response struct {
		Results []GeocodingResult `json:"results"`
		commonResponse
	}

	if err := c.getJSON(ctx, geocodingAPI, r, &response); err != nil {
		return nil, err
	}

	if err := response.StatusError(); err != nil {
		return nil, err
	}

	return response.Results, nil

}

func (r *GeocodingRequest) params() url.Values {
	q := make(url.Values)

	for k, v := range r.Custom {
		q[k] = v
	}

	if r.Address != "" {
		q.Set("address", r.Address)
	}
	var cf []string
	for c, f := range r.Components {
		cf = append(cf, string(c)+":"+f)
	}
	if len(cf) > 0 {
		q.Set("components", strings.Join(cf, "|"))
	}
	if r.Bounds != nil {
		q.Set("bounds", r.Bounds.String())
	}
	if r.Region != "" {
		q.Set("region", r.Region)
	}
	if r.LatLng != nil {
		q.Set("latlng", r.LatLng.String())
	}
	if len(r.ResultType) > 0 {
		q.Set("result_type", strings.Join(r.ResultType, "|"))
	}
	if len(r.LocationType) > 0 {
		var lt []string
		for _, l := range r.LocationType {
			lt = append(lt, string(l))
		}
		q.Set("location_type", strings.Join(lt, "|"))
	}
	if r.PlaceID != "" {
		q.Set("place_id", r.PlaceID)
	}
	if r.Language != "" {
		q.Set("language", r.Language)
	}

	return q
}

// GeocodeAccuracy is the type of a location result from the Geocoding API.
type GeocodeAccuracy string

const (
	// GeocodeAccuracyRooftop restricts the results to addresses for which Google has location information accurate down to street address precision
	GeocodeAccuracyRooftop = GeocodeAccuracy("ROOFTOP")
	// GeocodeAccuracyRangeInterpolated restricts the results to those that reflect an approximation interpolated between two precise points.
	GeocodeAccuracyRangeInterpolated = GeocodeAccuracy("RANGE_INTERPOLATED")
	// GeocodeAccuracyGeometricCenter restricts the results to geometric centers of a location such as a polyline or polygon.
	GeocodeAccuracyGeometricCenter = GeocodeAccuracy("GEOMETRIC_CENTER")
	// GeocodeAccuracyApproximate restricts the results to those that are characterized as approximate.
	GeocodeAccuracyApproximate = GeocodeAccuracy("APPROXIMATE")
)

// GeocodingRequest is the request structure for Geocoding API
type GeocodingRequest struct {
	// Geocoding fields

	// Address is the street address that you want to geocode, in the format used by the national postal service of the country concerned.
	Address string
	// Components is a component filter for which you wish to obtain a geocode. Either Address or Components is required in a geocoding request.
	// For more detail on Component Filtering please see
	// https://developers.google.com/maps/documentation/geocoding/intro#ComponentFiltering
	Components map[Component]string
	// Bounds is the bounding box of the viewport within which to bias geocode results more prominently. Optional.
	Bounds *LatLngBounds
	// Region is the region code, specified as a ccTLD two-character value. Optional.
	Region string

	// Reverse geocoding fields

	// LatLng is the textual latitude/longitude value for which you wish to obtain the closest, human-readable address. Either LatLng or PlaceID is required for Reverse Geocoding.
	LatLng *LatLng
	// ResultType is an array of one or more address types. Optional.
	ResultType []string
	// LocationType is an array of one or more geocoding accuracy types. Optional.
	LocationType []GeocodeAccuracy
	// PlaceID is a string which contains the place_id, which can be used for reverse geocoding requests. Either LatLng or PlaceID is required for Reverse Geocoding.
	PlaceID string

	// Language is the language in which to return results. Optional.
	Language string

	// Custom allows passing through custom parameters to the Geocoding back end. Use with caution.
	// For more detail on why this is required, please see
	// https://googlegeodevelopers.blogspot.com/2016/11/address-geocoding-in-google-maps-apis.html
	Custom url.Values
}

// GeocodingResult is a single geocoded address
type GeocodingResult struct {
	AddressComponents []AddressComponent `json:"address_components"`
	FormattedAddress  string             `json:"formatted_address"`
	Geometry          AddressGeometry    `json:"geometry"`
	Types             []string           `json:"types"`
	PlaceID           string             `json:"place_id"`
}

// AddressComponent is a part of an address
type AddressComponent struct {
	LongName  string   `json:"long_name"`
	ShortName string   `json:"short_name"`
	Types     []string `json:"types"`
}

// AddressGeometry is the location of a an address
type AddressGeometry struct {
	Location     LatLng       `json:"location"`
	LocationType string       `json:"location_type"`
	Viewport     LatLngBounds `json:"viewport"`
	Types        []string     `json:"types"`
}
<commit_msg>Include Bounds on Geocodin Response<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

// More information about Google Distance Matrix API is available on
// https://developers.google.com/maps/documentation/distancematrix/

package maps

import (
	"errors"
	"net/url"
	"strings"

	"golang.org/x/net/context"
)

var geocodingAPI = &apiConfig{
	host:            "https://maps.googleapis.com",
	path:            "/maps/api/geocode/json",
	acceptsClientID: true,
}

// Geocode makes a Geocoding API request
func (c *Client) Geocode(ctx context.Context, r *GeocodingRequest) ([]GeocodingResult, error) {
	if r.Address == "" && len(r.Components) == 0 && r.LatLng == nil {
		return nil, errors.New("maps: address, components and LatLng are all missing")
	}

	var response struct {
		Results []GeocodingResult `json:"results"`
		commonResponse
	}

	if err := c.getJSON(ctx, geocodingAPI, r, &response); err != nil {
		return nil, err
	}

	if err := response.StatusError(); err != nil {
		return nil, err
	}

	return response.Results, nil
}

// ReverseGeocode makes a Reverse Geocoding API request
func (c *Client) ReverseGeocode(ctx context.Context, r *GeocodingRequest) ([]GeocodingResult, error) {
	// Since Geocode() does not allow a nil LatLng, whereas it is allowed here
	if r.LatLng == nil && r.PlaceID == "" {
		return nil, errors.New("maps: LatLng and PlaceID are both missing")
	}

	var response struct {
		Results []GeocodingResult `json:"results"`
		commonResponse
	}

	if err := c.getJSON(ctx, geocodingAPI, r, &response); err != nil {
		return nil, err
	}

	if err := response.StatusError(); err != nil {
		return nil, err
	}

	return response.Results, nil

}

func (r *GeocodingRequest) params() url.Values {
	q := make(url.Values)

	for k, v := range r.Custom {
		q[k] = v
	}

	if r.Address != "" {
		q.Set("address", r.Address)
	}
	var cf []string
	for c, f := range r.Components {
		cf = append(cf, string(c)+":"+f)
	}
	if len(cf) > 0 {
		q.Set("components", strings.Join(cf, "|"))
	}
	if r.Bounds != nil {
		q.Set("bounds", r.Bounds.String())
	}
	if r.Region != "" {
		q.Set("region", r.Region)
	}
	if r.LatLng != nil {
		q.Set("latlng", r.LatLng.String())
	}
	if len(r.ResultType) > 0 {
		q.Set("result_type", strings.Join(r.ResultType, "|"))
	}
	if len(r.LocationType) > 0 {
		var lt []string
		for _, l := range r.LocationType {
			lt = append(lt, string(l))
		}
		q.Set("location_type", strings.Join(lt, "|"))
	}
	if r.PlaceID != "" {
		q.Set("place_id", r.PlaceID)
	}
	if r.Language != "" {
		q.Set("language", r.Language)
	}

	return q
}

// GeocodeAccuracy is the type of a location result from the Geocoding API.
type GeocodeAccuracy string

const (
	// GeocodeAccuracyRooftop restricts the results to addresses for which Google has location information accurate down to street address precision
	GeocodeAccuracyRooftop = GeocodeAccuracy("ROOFTOP")
	// GeocodeAccuracyRangeInterpolated restricts the results to those that reflect an approximation interpolated between two precise points.
	GeocodeAccuracyRangeInterpolated = GeocodeAccuracy("RANGE_INTERPOLATED")
	// GeocodeAccuracyGeometricCenter restricts the results to geometric centers of a location such as a polyline or polygon.
	GeocodeAccuracyGeometricCenter = GeocodeAccuracy("GEOMETRIC_CENTER")
	// GeocodeAccuracyApproximate restricts the results to those that are characterized as approximate.
	GeocodeAccuracyApproximate = GeocodeAccuracy("APPROXIMATE")
)

// GeocodingRequest is the request structure for Geocoding API
type GeocodingRequest struct {
	// Geocoding fields

	// Address is the street address that you want to geocode, in the format used by the national postal service of the country concerned.
	Address string
	// Components is a component filter for which you wish to obtain a geocode. Either Address or Components is required in a geocoding request.
	// For more detail on Component Filtering please see
	// https://developers.google.com/maps/documentation/geocoding/intro#ComponentFiltering
	Components map[Component]string
	// Bounds is the bounding box of the viewport within which to bias geocode results more prominently. Optional.
	Bounds *LatLngBounds
	// Region is the region code, specified as a ccTLD two-character value. Optional.
	Region string

	// Reverse geocoding fields

	// LatLng is the textual latitude/longitude value for which you wish to obtain the closest, human-readable address. Either LatLng or PlaceID is required for Reverse Geocoding.
	LatLng *LatLng
	// ResultType is an array of one or more address types. Optional.
	ResultType []string
	// LocationType is an array of one or more geocoding accuracy types. Optional.
	LocationType []GeocodeAccuracy
	// PlaceID is a string which contains the place_id, which can be used for reverse geocoding requests. Either LatLng or PlaceID is required for Reverse Geocoding.
	PlaceID string

	// Language is the language in which to return results. Optional.
	Language string

	// Custom allows passing through custom parameters to the Geocoding back end. Use with caution.
	// For more detail on why this is required, please see
	// https://googlegeodevelopers.blogspot.com/2016/11/address-geocoding-in-google-maps-apis.html
	Custom url.Values
}

// GeocodingResult is a single geocoded address
type GeocodingResult struct {
	AddressComponents []AddressComponent `json:"address_components"`
	FormattedAddress  string             `json:"formatted_address"`
	Geometry          AddressGeometry    `json:"geometry"`
	Types             []string           `json:"types"`
	PlaceID           string             `json:"place_id"`
}

// AddressComponent is a part of an address
type AddressComponent struct {
	LongName  string   `json:"long_name"`
	ShortName string   `json:"short_name"`
	Types     []string `json:"types"`
}

// AddressGeometry is the location of a an address
type AddressGeometry struct {
	Location     LatLng       `json:"location"`
	LocationType string       `json:"location_type"`
	Bounds       LatLngBounds `json:"bounds"`
	Viewport     LatLngBounds `json:"viewport"`
	Types        []string     `json:"types"`
}
<|endoftext|>


<commit_before>package endpoints

import (
	"../config"
	"../models"

	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/gorilla/mux"
)

// RegisterProjectHandlers attaches the closures generated by each function defined below
// to handle incoming requests to the appropriate endpoint using a subrouter with an
// appropriate prefix, specified in main.
func RegisterProjectHandlers(r *mux.Router, db *sql.DB, cfg *config.Config) {
	r.HandleFunc("/", listProjects(db, cfg)).Methods("GET")
	r.HandleFunc("/", createProject(db, cfg)).Methods("POST")
	r.HandleFunc("/{projectId}", getProject(db, cfg)).Methods("GET")
	r.HandleFunc("/{projectId}", updateProject(db, cfg)).Methods("PUT")
	r.HandleFunc("/{projectId}", deleteProject(db, cfg)).Methods("DELETE")
}

// GET /projects

type listProjectsRequest struct {
	Ordering string
}

type listProjectsResponse struct {
	Error    *string          `json:"error"`
	Projects []models.Project `json:"projects"`
}

// listProjects produces a list of all projects. It accepts an "ordering"
// parameter, which can be either "newest" or "oldest" to specify which should
// come first.
func listProjects(db *sql.DB, cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		request := listProjectsRequest{"newest"}
		orderings, found := r.URL.Query()["ordering"]
		if found {
			request.Ordering = orderings[0]
		}

		encoder := json.NewEncoder(w)
		projects, listErr := models.ListProjects(request.Ordering, db)
		if listErr != nil {
			fmt.Println("[---] Listing error:", listErr)
			w.WriteHeader(http.StatusInternalServerError)
			errMsg := "Could not obtain a list of projects. Please try again later."
			encoder.Encode(listProjectsResponse{&errMsg, []models.Project{}})
			return
		}
		encoder.Encode(listProjectsResponse{nil, projects})
	}
}

// POST /projects

type createProjectRequest struct {
	Name        string               `json:"name"`
	ProjectName string               `json:"projectName"`
	Description string               `json:"description"`
	Status      models.ProjectStatus `json:"status"`
}

type createProjectResponse struct {
	Error   *string `json:"error"`
	Success bool    `json:"success"`
	Id      int     `json:"id"`
}

// createProject creates a new project.
func createProject(db *sql.DB, cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		request := createProjectRequest{}
		decoder := json.NewDecoder(r.Body)
		defer r.Body.Close()
		decodeErr := decoder.Decode(&request)

		encoder := json.NewEncoder(w)
		if decodeErr != nil {
			fmt.Println("[---] Decode error:", decodeErr)
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "JSON format error or missing field detected."
			encoder.Encode(createProjectResponse{&errMsg, false, -1})
			return
		}
		project := models.NewProject(request.Name, request.ProjectName, request.Description)
		project.Status = request.Status
		insertErr := project.Save(db)
		if insertErr != nil {
			fmt.Println("[---] Insert error:", insertErr)
			w.WriteHeader(http.StatusInternalServerError)
			errMsg := "Could not create project. Try again later, or with a different projectName."
			encoder.Encode(createProjectResponse{&errMsg, false, -1})
			return
		}
		encoder.Encode(createProjectResponse{nil, true, project.Id})
	}
}

// GET /projects/{projectId}

type getProjectRequest struct {
	Id int
}

type getProjectResponse struct {
	Error       *string              `json:"error"`
	Name        string               `json:"name"`
	ProjectName string               `json:"projectName"`
	Status      models.ProjectStatus `json:"status"`
	Description string               `json:"description"`
	CreatedAt   time.Time            `json:"createdAt"`
}

// getProject obtains information about a specific project.
func getProject(db *sql.DB, cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		request := getProjectRequest{}
		projectId, parseErr := strconv.Atoi(mux.Vars(r)["projectId"])

		encoder := json.NewEncoder(w)
		if parseErr != nil {
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "projectId must be an integer ID."
			encoder.Encode(getProjectResponse{&errMsg, "", "", "", "", time.Now()})
			return
		}
		request.Id = projectId
		project, findErr := models.FindProject(request.Id, db)
		if findErr != nil {
			fmt.Println("[---] Find error:", findErr)
			w.WriteHeader(http.StatusInternalServerError)
			errMsg := "Could not find the requested project."
			encoder.Encode(getProjectResponse{&errMsg, "", "", "", "", time.Now()})
			return
		}
		encoder.Encode(getProjectResponse{
			nil,
			project.Name,
			project.Shorthand,
			project.Status,
			project.Description,
			project.CreatedAt,
		})
	}
}

// PUT /projects/{projectId}

type updateProjectRequest struct {
	Id          int                  // Provided from a URL path parameter
	Name        string               `json:"name"`
	ProjectName string               `json:"projectName"`
	Status      models.ProjectStatus `json:"status"`
	Description string               `json:"description"`
}

type updateProjectResponse struct {
	Error   *string `json:"error"`
	Success bool    `json:"success"`
}

// updateProject updates every field of an existing project with some supplied data.
func updateProject(db *sql.DB, cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		request := updateProjectRequest{}
		projectId, parseErr := strconv.Atoi(mux.Vars(r)["projectId"])
		decoder := json.NewDecoder(r.Body)
		defer r.Body.Close()
		decodeErr := decoder.Decode(&request)

		encoder := json.NewEncoder(w)
		if parseErr != nil {
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "projectId must be an integer ID."
			encoder.Encode(updateProjectResponse{&errMsg, false})
			return
		}
		request.Id = projectId
		if decodeErr != nil {
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "JSON format error or missing field detected."
			encoder.Encode(updateProjectResponse{&errMsg, false})
			return
		}
		// We could pull the existing project from the DB and update the fields, but there
		// isn't really point in doing that when we know the ID we want to set and the query
		// will filter for us anyway.
		project := models.NewProject(request.Name, request.ProjectName, request.Description)
		project.Id = request.Id
		project.Status = request.Status
		updateErr := project.Update(db)
		if updateErr != nil {
			fmt.Println("[---] Update error:", updateErr)
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "Could not update specified project. Please ensure the ID and status are correct."
			encoder.Encode(updateProjectResponse{&errMsg, false})
			return
		}
		encoder.Encode(updateProjectResponse{nil, true})
	}
}

// DELETE /projects/{projectId}

type deleteProjectRequest struct {
	Id int
}

type deleteProjectResponse struct {
	Error   *string `json:"error"`
	Success bool    `json:"success"`
}

// deleteProject removes an entire project from the database, along with
// all of the releases under that project.
func deleteProject(db *sql.DB, cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		request := deleteProjectRequest{}
		projectId, parseErr := strconv.Atoi(mux.Vars(r)["projectId"])
		request.Id = request.Id // Shutting the linter up

		encoder := json.NewEncoder(w)
		if parseErr != nil {
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "projectId must be an integer ID."
			encoder.Encode(deleteProjectResponse{&errMsg, false})
			return
		}
		request.Id = projectId
		// TODO - Delete the project in the DB.
		encoder.Encode(deleteProjectResponse{nil, true})
	}
}
<commit_msg>Finished implementing the delete project endpoint<commit_after>package endpoints

import (
	"../config"
	"../models"

	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/gorilla/mux"
)

// RegisterProjectHandlers attaches the closures generated by each function defined below
// to handle incoming requests to the appropriate endpoint using a subrouter with an
// appropriate prefix, specified in main.
func RegisterProjectHandlers(r *mux.Router, db *sql.DB, cfg *config.Config) {
	r.HandleFunc("/", listProjects(db, cfg)).Methods("GET")
	r.HandleFunc("/", createProject(db, cfg)).Methods("POST")
	r.HandleFunc("/{projectId}", getProject(db, cfg)).Methods("GET")
	r.HandleFunc("/{projectId}", updateProject(db, cfg)).Methods("PUT")
	r.HandleFunc("/{projectId}", deleteProject(db, cfg)).Methods("DELETE")
}

// GET /projects

type listProjectsRequest struct {
	Ordering string
}

type listProjectsResponse struct {
	Error    *string          `json:"error"`
	Projects []models.Project `json:"projects"`
}

// listProjects produces a list of all projects. It accepts an "ordering"
// parameter, which can be either "newest" or "oldest" to specify which should
// come first.
func listProjects(db *sql.DB, cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		request := listProjectsRequest{"newest"}
		orderings, found := r.URL.Query()["ordering"]
		if found {
			request.Ordering = orderings[0]
		}

		encoder := json.NewEncoder(w)
		projects, listErr := models.ListProjects(request.Ordering, db)
		if listErr != nil {
			fmt.Println("[---] Listing error:", listErr)
			w.WriteHeader(http.StatusInternalServerError)
			errMsg := "Could not obtain a list of projects. Please try again later."
			encoder.Encode(listProjectsResponse{&errMsg, []models.Project{}})
			return
		}
		encoder.Encode(listProjectsResponse{nil, projects})
	}
}

// POST /projects

type createProjectRequest struct {
	Name        string               `json:"name"`
	ProjectName string               `json:"projectName"`
	Description string               `json:"description"`
	Status      models.ProjectStatus `json:"status"`
}

type createProjectResponse struct {
	Error   *string `json:"error"`
	Success bool    `json:"success"`
	Id      int     `json:"id"`
}

// createProject creates a new project.
func createProject(db *sql.DB, cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		request := createProjectRequest{}
		decoder := json.NewDecoder(r.Body)
		defer r.Body.Close()
		decodeErr := decoder.Decode(&request)

		encoder := json.NewEncoder(w)
		if decodeErr != nil {
			fmt.Println("[---] Decode error:", decodeErr)
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "JSON format error or missing field detected."
			encoder.Encode(createProjectResponse{&errMsg, false, -1})
			return
		}
		project := models.NewProject(request.Name, request.ProjectName, request.Description)
		project.Status = request.Status
		insertErr := project.Save(db)
		if insertErr != nil {
			fmt.Println("[---] Insert error:", insertErr)
			w.WriteHeader(http.StatusInternalServerError)
			errMsg := "Could not create project. Try again later, or with a different projectName."
			encoder.Encode(createProjectResponse{&errMsg, false, -1})
			return
		}
		encoder.Encode(createProjectResponse{nil, true, project.Id})
	}
}

// GET /projects/{projectId}

type getProjectRequest struct {
	Id int
}

type getProjectResponse struct {
	Error       *string              `json:"error"`
	Name        string               `json:"name"`
	ProjectName string               `json:"projectName"`
	Status      models.ProjectStatus `json:"status"`
	Description string               `json:"description"`
	CreatedAt   time.Time            `json:"createdAt"`
}

// getProject obtains information about a specific project.
func getProject(db *sql.DB, cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		request := getProjectRequest{}
		projectId, parseErr := strconv.Atoi(mux.Vars(r)["projectId"])

		encoder := json.NewEncoder(w)
		if parseErr != nil {
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "projectId must be an integer ID."
			encoder.Encode(getProjectResponse{&errMsg, "", "", "", "", time.Now()})
			return
		}
		request.Id = projectId
		project, findErr := models.FindProject(request.Id, db)
		if findErr != nil {
			fmt.Println("[---] Find error:", findErr)
			w.WriteHeader(http.StatusInternalServerError)
			errMsg := "Could not find the requested project."
			encoder.Encode(getProjectResponse{&errMsg, "", "", "", "", time.Now()})
			return
		}
		encoder.Encode(getProjectResponse{
			nil,
			project.Name,
			project.Shorthand,
			project.Status,
			project.Description,
			project.CreatedAt,
		})
	}
}

// PUT /projects/{projectId}

type updateProjectRequest struct {
	Id          int                  // Provided from a URL path parameter
	Name        string               `json:"name"`
	ProjectName string               `json:"projectName"`
	Status      models.ProjectStatus `json:"status"`
	Description string               `json:"description"`
}

type updateProjectResponse struct {
	Error   *string `json:"error"`
	Success bool    `json:"success"`
}

// updateProject updates every field of an existing project with some supplied data.
func updateProject(db *sql.DB, cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		request := updateProjectRequest{}
		projectId, parseErr := strconv.Atoi(mux.Vars(r)["projectId"])
		decoder := json.NewDecoder(r.Body)
		defer r.Body.Close()
		decodeErr := decoder.Decode(&request)

		encoder := json.NewEncoder(w)
		if parseErr != nil {
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "projectId must be an integer ID."
			encoder.Encode(updateProjectResponse{&errMsg, false})
			return
		}
		request.Id = projectId
		if decodeErr != nil {
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "JSON format error or missing field detected."
			encoder.Encode(updateProjectResponse{&errMsg, false})
			return
		}
		// We could pull the existing project from the DB and update the fields, but there
		// isn't really point in doing that when we know the ID we want to set and the query
		// will filter for us anyway.
		project := models.NewProject(request.Name, request.ProjectName, request.Description)
		project.Id = request.Id
		project.Status = request.Status
		updateErr := project.Update(db)
		if updateErr != nil {
			fmt.Println("[---] Update error:", updateErr)
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "Could not update specified project. Please ensure the ID and status are correct."
			encoder.Encode(updateProjectResponse{&errMsg, false})
			return
		}
		encoder.Encode(updateProjectResponse{nil, true})
	}
}

// DELETE /projects/{projectId}

type deleteProjectRequest struct {
	Id int
}

type deleteProjectResponse struct {
	Error   *string `json:"error"`
	Success bool    `json:"success"`
}

// deleteProject removes an entire project from the database, along with
// all of the releases under that project.
func deleteProject(db *sql.DB, cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		request := deleteProjectRequest{}
		projectId, parseErr := strconv.Atoi(mux.Vars(r)["projectId"])
		request.Id = request.Id // Shutting the linter up

		encoder := json.NewEncoder(w)
		if parseErr != nil {
			w.WriteHeader(http.StatusBadRequest)
			errMsg := "projectId must be an integer ID."
			encoder.Encode(deleteProjectResponse{&errMsg, false})
			return
		}
		request.Id = projectId
		// We could lookup the project before deleting it but we might as well
		// leave that work to the database.
		project := models.NewProject("", "", "")
		project.Id = request.Id
		deleteErr := project.Delete(db)
		if deleteErr != nil {
			fmt.Println("[---] Delete error:", deleteErr)
			w.WriteHeader(http.StatusInternalServerError)
			errMsg := "Could not delete the specified project. Please check that the ID is valid."
			encoder.Encode(deleteProjectResponse{&errMsg, false})
			return
		}
		encoder.Encode(deleteProjectResponse{nil, true})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/mitchellh/go-homedir"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

// The options that the user can set
var settings Settings

// All the possible settings
var possibleSettings = []string{"colorscheme", "tabsize", "autoindent", "syntax"}

// The Settings struct contains the settings for micro
type Settings struct {
	Colorscheme string `json:"colorscheme"`
	TabSize     int    `json:"tabsize"`
	AutoIndent  bool   `json:"autoindent"`
	Syntax      bool   `json:"syntax"`
}

// InitSettings initializes the options map and sets all options to their default values
func InitSettings() {
	home, err := homedir.Dir()
	if err != nil {
		TermMessage("Error finding your home directory\nCan't load settings file")
		return
	}

	filename := home + "/.micro/settings.json"
	if _, e := os.Stat(filename); e == nil {
		input, err := ioutil.ReadFile(filename)
		if err != nil {
			TermMessage("Error reading settings.json file: " + err.Error())
			return
		}

		json.Unmarshal(input, &settings)
	} else {
		settings = DefaultSettings()
		err := WriteSettings(filename)
		if err != nil {
			TermMessage("Error writing settings.json file: " + err.Error())
		}
	}
}

// WriteSettings writes the settings to the specified filename as JSON
func WriteSettings(filename string) error {
	txt, _ := json.MarshalIndent(settings, "", "    ")
	err := ioutil.WriteFile(filename, txt, 0644)
	return err
}

// DefaultSettings returns the default settings for micro
func DefaultSettings() Settings {
	return Settings{
		Colorscheme: "default",
		TabSize:     4,
		AutoIndent:  true,
		Syntax:      true,
	}
}

// SetOption prompts the user to set an option and checks that the response is valid
func SetOption(view *View, args []string) {
	home, err := homedir.Dir()
	if err != nil {
		messenger.Error("Error finding your home directory\nCan't load settings file")
	}

	filename := home + "/.micro/settings.json"
	if len(args) == 2 {
		option := strings.TrimSpace(args[0])
		value := strings.TrimSpace(args[1])

		if Contains(possibleSettings, option) {
			if option == "tabsize" {
				tsize, err := strconv.Atoi(value)
				if err != nil {
					messenger.Error("Invalid value for " + option)
					return
				}
				settings.TabSize = tsize
			} else if option == "colorscheme" {
				settings.Colorscheme = value
				LoadSyntaxFiles()
				view.buf.UpdateRules()
			} else if option == "syntax" {
				if value == "on" {
					settings.Syntax = true
				} else if value == "off" {
					settings.Syntax = false
				} else {
					messenger.Error("Invalid value for " + option)
					return
				}
				LoadSyntaxFiles()
				view.buf.UpdateRules()
			}
			err := WriteSettings(filename)
			if err != nil {
				messenger.Error("Error writing to settings.json: " + err.Error())
				return
			}
		} else {
			messenger.Error("Option " + option + " does not exist")
		}
	} else {
		messenger.Error("Invalid option, please use option value")
	}
}
<commit_msg>Only use settings.json if ~/.micro exists<commit_after>package main

import (
	"encoding/json"
	"github.com/mitchellh/go-homedir"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

// The options that the user can set
var settings Settings

// All the possible settings
var possibleSettings = []string{"colorscheme", "tabsize", "autoindent", "syntax"}

// The Settings struct contains the settings for micro
type Settings struct {
	Colorscheme string `json:"colorscheme"`
	TabSize     int    `json:"tabsize"`
	AutoIndent  bool   `json:"autoindent"`
	Syntax      bool   `json:"syntax"`
}

// InitSettings initializes the options map and sets all options to their default values
func InitSettings() {
	home, err := homedir.Dir()
	if err != nil {
		TermMessage("Error finding your home directory\nCan't load settings file")
		return
	}

	filename := home + "/.micro/settings.json"
	if _, e := os.Stat(filename); e == nil {
		input, err := ioutil.ReadFile(filename)
		if err != nil {
			TermMessage("Error reading settings.json file: " + err.Error())
			return
		}

		json.Unmarshal(input, &settings)
	} else {
		settings = DefaultSettings()
		err := WriteSettings(filename)
		if err != nil {
			TermMessage("Error writing settings.json file: " + err.Error())
		}
	}
}

// WriteSettings writes the settings to the specified filename as JSON
func WriteSettings(filename string) error {
	var err error
	home, err := homedir.Dir()
	if err != nil {
		return err
	}
	if _, e := os.Stat(home + "/.micro"); e == nil {
		txt, _ := json.MarshalIndent(settings, "", "    ")
		err = ioutil.WriteFile(filename, txt, 0644)
	}
	return err
}

// DefaultSettings returns the default settings for micro
func DefaultSettings() Settings {
	return Settings{
		Colorscheme: "default",
		TabSize:     4,
		AutoIndent:  true,
		Syntax:      true,
	}
}

// SetOption prompts the user to set an option and checks that the response is valid
func SetOption(view *View, args []string) {
	home, err := homedir.Dir()
	if err != nil {
		messenger.Error("Error finding your home directory\nCan't load settings file")
	}

	filename := home + "/.micro/settings.json"
	if len(args) == 2 {
		option := strings.TrimSpace(args[0])
		value := strings.TrimSpace(args[1])

		if Contains(possibleSettings, option) {
			if option == "tabsize" {
				tsize, err := strconv.Atoi(value)
				if err != nil {
					messenger.Error("Invalid value for " + option)
					return
				}
				settings.TabSize = tsize
			} else if option == "colorscheme" {
				settings.Colorscheme = value
				LoadSyntaxFiles()
				view.buf.UpdateRules()
			} else if option == "syntax" {
				if value == "on" {
					settings.Syntax = true
				} else if value == "off" {
					settings.Syntax = false
				} else {
					messenger.Error("Invalid value for " + option)
					return
				}
				LoadSyntaxFiles()
				view.buf.UpdateRules()
			}
			err := WriteSettings(filename)
			if err != nil {
				messenger.Error("Error writing to settings.json: " + err.Error())
				return
			}
		} else {
			messenger.Error("Option " + option + " does not exist")
		}
	} else {
		messenger.Error("Invalid option, please use option value")
	}
}
<|endoftext|>