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

package ast

import (
	"datafmt";
	"go/ast";
	"go/token";
	"io";
	"os";
)

// Format is a customized datafmt.Format for printing of ASTs.
type Format datafmt.Format;

// ----------------------------------------------------------------------------
// Custom formatters

// The AST-specific formatting state is maintained by a state variable.
type state struct {
	// for now we have very little state
	// TODO maintain list of unassociated comments
	optSemi *bool
}

func (s *state) Copy() datafmt.Environment {
	optSemi := *s.optSemi;
	return &state{&optSemi};
}

func isValidPos(s *datafmt.State, value interface{}, ruleName string) bool {
	pos := value.(token.Position);
	return pos.IsValid();
}

func isSend(s *datafmt.State, value interface{}, ruleName string) bool {
	return value.(ast.ChanDir) & ast.SEND != 0;
}

func isRecv(s *datafmt.State, value interface{}, ruleName string) bool {
	return value.(ast.ChanDir) & ast.RECV != 0;
}

func isMultiLineComment(s *datafmt.State, value interface{}, ruleName string) bool {
	return value.([]byte)[1] == '*';
}

func clearOptSemi(s *datafmt.State, value interface{}, ruleName string) bool {
	*s.Env().(*state).optSemi = false;
	return true;
}

func setOptSemi(s *datafmt.State, value interface{}, ruleName string) bool {
	*s.Env().(*state).optSemi = true;
	return true;
}

func optSemi(s *datafmt.State, value interface{}, ruleName string) bool {
	if !*s.Env().(*state).optSemi {
		s.Write([]byte{';'});
	}
	return true;
}

var fmap = datafmt.FormatterMap {
	"isValidPos": isValidPos,
	"isSend": isSend,
	"isRecv": isRecv,
	"isMultiLineComment": isMultiLineComment,
	"/": clearOptSemi,
	"clearOptSemi": clearOptSemi,
	"setOptSemi": setOptSemi,
	"optSemi": optSemi,
}

// ----------------------------------------------------------------------------
// Printing

// NewFormat parses a datafmt format specification from a file
// and adds AST-specific custom formatter rules. The result is
// the customized format or an os.Error, if any.
//
func NewFormat(filename string) (Format, os.Error) {
	src, err := io.ReadFile(filename);
	if err != nil {
		return nil, err;
	}
	f, err := datafmt.Parse(src, fmap);
	return Format(f), err;
}

// Fprint formats each AST node provided as argument according to the
// format f and writes to standard output. The result is the total number
// of bytes written and an os.Error, if any.
//
func (f Format) Fprint(w io.Writer, nodes ...) (int, os.Error) {
	s := state{new(bool)};
	return datafmt.Format(f).Fprint(w, &s, nodes);
}

// Fprint formats each AST node provided as argument according to the
// format f and writes to w. The result is the total number of bytes
// written and an os.Error, if any.
//
func (f Format) Print(nodes ...) (int, os.Error) {
	return f.Fprint(os.Stdout, nodes);
}
<commit_msg>remove superfluous indirection<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ast

import (
	"datafmt";
	"go/ast";
	"go/token";
	"io";
	"os";
)

// Format is a customized datafmt.Format for printing of ASTs.
type Format datafmt.Format;

// ----------------------------------------------------------------------------
// Custom formatters

// The AST-specific formatting state is maintained by a state variable.
type state struct {
	// for now we have very little state
	// TODO maintain list of unassociated comments
	optSemi bool
}

func (s *state) Copy() datafmt.Environment {
	copy := *s;
	return ©
}

func isValidPos(s *datafmt.State, value interface{}, ruleName string) bool {
	pos := value.(token.Position);
	return pos.IsValid();
}

func isSend(s *datafmt.State, value interface{}, ruleName string) bool {
	return value.(ast.ChanDir) & ast.SEND != 0;
}

func isRecv(s *datafmt.State, value interface{}, ruleName string) bool {
	return value.(ast.ChanDir) & ast.RECV != 0;
}

func isMultiLineComment(s *datafmt.State, value interface{}, ruleName string) bool {
	return value.([]byte)[1] == '*';
}

func clearOptSemi(s *datafmt.State, value interface{}, ruleName string) bool {
	s.Env().(*state).optSemi = false;
	return true;
}

func setOptSemi(s *datafmt.State, value interface{}, ruleName string) bool {
	s.Env().(*state).optSemi = true;
	return true;
}

func optSemi(s *datafmt.State, value interface{}, ruleName string) bool {
	if !s.Env().(*state).optSemi {
		s.Write([]byte{';'});
	}
	return true;
}

var fmap = datafmt.FormatterMap {
	"isValidPos": isValidPos,
	"isSend": isSend,
	"isRecv": isRecv,
	"isMultiLineComment": isMultiLineComment,
	"/": clearOptSemi,
	"clearOptSemi": clearOptSemi,
	"setOptSemi": setOptSemi,
	"optSemi": optSemi,
}

// ----------------------------------------------------------------------------
// Printing

// NewFormat parses a datafmt format specification from a file
// and adds AST-specific custom formatter rules. The result is
// the customized format or an os.Error, if any.
//
func NewFormat(filename string) (Format, os.Error) {
	src, err := io.ReadFile(filename);
	if err != nil {
		return nil, err;
	}
	f, err := datafmt.Parse(src, fmap);
	return Format(f), err;
}

// Fprint formats each AST node provided as argument according to the
// format f and writes to standard output. The result is the total number
// of bytes written and an os.Error, if any.
//
func (f Format) Fprint(w io.Writer, nodes ...) (int, os.Error) {
	var s state;
	return datafmt.Format(f).Fprint(w, &s, nodes);
}

// Fprint formats each AST node provided as argument according to the
// format f and writes to w. The result is the total number of bytes
// written and an os.Error, if any.
//
func (f Format) Print(nodes ...) (int, os.Error) {
	return f.Fprint(os.Stdout, nodes);
}
<|endoftext|>


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

package io

// Byte buffer for marshaling nested messages.

import (
	"io";
	"os";
)

// A simple implementation of the io.Read and io.Write interfaces.
// A newly allocated ByteBuffer is ready to use.

// TODO(r): Do better memory management.

func bytecopy(dst []byte, doff int, src []byte, soff int, count int) {
	for i := 0; i < count; i++ {
		dst[doff] = src[soff];
		doff++;
		soff++;
	}
}

export type ByteBuffer struct {
	buf	[]byte;
	off	int;	// Read from here
	len	int;	// Write to here
	cap	int;
}

func (b *ByteBuffer) Reset() {
	b.off = 0;
	b.len = 0;
}

func (b *ByteBuffer) Write(p []byte) (n int, err *os.Error) {
	plen := len(p);
	if len(b.buf) == 0 {
		b.cap = plen + 1024;
		b.buf = make([]byte, b.cap);
		b.len = 0;
	}
	if b.len + len(p) > b.cap {
		b.cap = 2*(b.cap + plen);
		nb := make([]byte, b.cap);
		bytecopy(nb, 0, b.buf, 0, b.len);
		b.buf = nb;
	}
	bytecopy(b.buf, b.len, p, 0, plen);
	b.len += plen;
	return plen, nil;
}

func (b *ByteBuffer) Read(p []byte) (n int, err *os.Error) {
	plen := len(p);
	if len(b.buf) == 0 {
		return 0, nil
	}
	if b.off == b.len {	// empty buffer
		b.Reset();
		return 0, nil
	}
	if plen > b.len - b.off {
		plen = b.len - b.off
	}
	bytecopy(p, 0, b.buf, b.off, plen);
	b.off += plen;
	return plen, nil;
}

func (b *ByteBuffer) Len() int {
	return b.len
}

func (b *ByteBuffer) Data() []byte {
	return b.buf[b.off:b.len]
}

export func NewByteBufferFromArray(buf []byte) *ByteBuffer {
	b := new(ByteBuffer);
	b.buf = buf;
	b.off = 0;
	b.len = len(buf);
	b.cap = len(buf);
	return b;
}
<commit_msg>add a couple of helper methods to io.ByteBuffer<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package io

// Byte buffer for marshaling nested messages.

import (
	"io";
	"os";
)

// A simple implementation of the io.Read and io.Write interfaces.
// A newly allocated ByteBuffer is ready to use.

// TODO(r): Do better memory management.

func bytecopy(dst []byte, doff int, src []byte, soff int, count int) {
	for i := 0; i < count; i++ {
		dst[doff] = src[soff];
		doff++;
		soff++;
	}
}

export type ByteBuffer struct {
	buf	[]byte;
	off	int;	// Read from here
	len	int;	// Write to here
	cap	int;
}

func (b *ByteBuffer) Reset() {
	b.off = 0;
	b.len = 0;
}

func (b *ByteBuffer) Write(p []byte) (n int, err *os.Error) {
	plen := len(p);
	if len(b.buf) == 0 {
		b.cap = plen + 1024;
		b.buf = make([]byte, b.cap);
		b.len = 0;
	}
	if b.len + len(p) > b.cap {
		b.cap = 2*(b.cap + plen);
		nb := make([]byte, b.cap);
		bytecopy(nb, 0, b.buf, 0, b.len);
		b.buf = nb;
	}
	bytecopy(b.buf, b.len, p, 0, plen);
	b.len += plen;
	return plen, nil;
}

func (b *ByteBuffer) Read(p []byte) (n int, err *os.Error) {
	plen := len(p);
	if len(b.buf) == 0 {
		return 0, nil
	}
	if b.off == b.len {	// empty buffer
		b.Reset();
		return 0, nil
	}
	if plen > b.len - b.off {
		plen = b.len - b.off
	}
	bytecopy(p, 0, b.buf, b.off, plen);
	b.off += plen;
	return plen, nil;
}

func (b *ByteBuffer) Len() int {
	return b.len
}

func (b *ByteBuffer) Off() int {
	return b.off
}

func (b *ByteBuffer) Data() []byte {
	return b.buf[b.off:b.len]
}

func (b *ByteBuffer) AllData() []byte {
	return b.buf[0:b.len]
}

export func NewByteBufferFromArray(buf []byte) *ByteBuffer {
	b := new(ByteBuffer);
	b.buf = buf;
	b.off = 0;
	b.len = len(buf);
	b.cap = len(buf);
	return b;
}
<|endoftext|>


<commit_before>package class

import (
    "sync"
    . "jvmgo/any"
)

type Monitor struct {
    owner       Any // *rtda.Thread
    ownerLock   sync.Locker
    lock        sync.Locker
    entryCount  int
    cond        *sync.Cond
}

func newMonitor() (*Monitor) {
    m := &Monitor{}
    m.ownerLock = &sync.Mutex{}
    m.lock = &sync.Mutex{}
    m.cond = sync.NewCond(m.lock)
    return m
}

func (self *Monitor) Cond() (*sync.Cond) {
    return self.cond
}

func (self *Monitor) Enter(thread Any) {
    self.ownerLock.Lock()
    if self.owner == thread {
        self.entryCount++
        self.ownerLock.Unlock()
        return
    } else {
        self.ownerLock.Unlock()
    }

    self.lock.Lock()

    self.ownerLock.Lock()
    self.owner = thread
    self.entryCount = 1
    self.ownerLock.Unlock()
}

func (self *Monitor) Exit(thread Any) {
    self.ownerLock.Lock()
    var _unlock bool
    if self.owner == thread {
        self.entryCount--
        if self.entryCount == 0 {
            self.owner = nil
            _unlock = true
        }
    }
    self.ownerLock.Unlock()

    if _unlock {
        self.lock.Unlock()
    }
}

func (self *Monitor) HasOwner(thread Any) bool {
    self.ownerLock.Lock()
    ok := self.owner == thread
    self.ownerLock.Unlock()

    return ok
}

func (self *Monitor) Wait() {
    self.ownerLock.Lock()
    oldEntryCount := self.entryCount
    oldOwner := self.owner
    self.entryCount = 0
    self.owner = nil
    self.ownerLock.Unlock()

    self.cond.Wait()

    self.ownerLock.Lock()
    self.entryCount = oldEntryCount
    self.owner = oldOwner
    self.ownerLock.Unlock()
}
<commit_msg>code refactor<commit_after>package class

import (
    "sync"
    . "jvmgo/any"
)

type Monitor struct {
    owner       Any // *rtda.Thread
    ownerLock   sync.Locker
    lock        sync.Locker
    entryCount  int
    cond        *sync.Cond
}

func newMonitor() (*Monitor) {
    m := &Monitor{}
    m.ownerLock = &sync.Mutex{}
    m.lock = &sync.Mutex{}
    m.cond = sync.NewCond(m.lock)
    return m
}

func (self *Monitor) Enter(thread Any) {
    self.ownerLock.Lock()
    if self.owner == thread {
        self.entryCount++
        self.ownerLock.Unlock()
        return
    } else {
        self.ownerLock.Unlock()
    }

    self.lock.Lock()

    self.ownerLock.Lock()
    self.owner = thread
    self.entryCount = 1
    self.ownerLock.Unlock()
}

func (self *Monitor) Exit(thread Any) {
    self.ownerLock.Lock()
    var _unlock bool
    if self.owner == thread {
        self.entryCount--
        if self.entryCount == 0 {
            self.owner = nil
            _unlock = true
        }
    }
    self.ownerLock.Unlock()

    if _unlock {
        self.lock.Unlock()
    }
}

func (self *Monitor) HasOwner(thread Any) bool {
    self.ownerLock.Lock()
    isOwner := self.owner == thread
    self.ownerLock.Unlock()

    return isOwner
}

func (self *Monitor) Wait() {
    self.ownerLock.Lock()
    oldEntryCount := self.entryCount
    oldOwner := self.owner
    self.entryCount = 0
    self.owner = nil
    self.ownerLock.Unlock()

    self.cond.Wait()

    self.ownerLock.Lock()
    self.entryCount = oldEntryCount
    self.owner = oldOwner
    self.ownerLock.Unlock()
}
<|endoftext|>


<commit_before>package lang

import (
    . "jvmgo/any"
    "jvmgo/rtda"
    rtc "jvmgo/rtda/class"
)

func init() {
    _class("desiredAssertionStatus0",   "(Ljava/lang/Class;)Z",         desiredAssertionStatus0)
    _class("getClassLoader0",           "()Ljava/lang/ClassLoader;",    getClassLoader0)
    _class("getName0",                  "()Ljava/lang/String;",         getName0)
}

func _class(name, desc string, method Any) {
    rtc.RegisterNativeMethod("java/lang/Class", name, desc, method)
}
//java/lang/Class~getPrimitiveClass~(Ljava/lang/String;)Ljava/lang/Class;

func desiredAssertionStatus0(frame *rtda.Frame) {
    // todo
    stack := frame.OperandStack()
    _ = stack.PopRef() // this
    stack.PushBoolean(false)
}

func getClassLoader0(frame *rtda.Frame) {
    // todo
    stack := frame.OperandStack()
    _ = stack.PopRef() // this
    stack.PushRef(nil)
}

func getName0(frame *rtda.Frame) {
    panic("getName0")
}
<commit_msg>native: java.lang.Class.getPrimitiveClass()<commit_after>package lang

import (
    . "jvmgo/any"
    "jvmgo/rtda"
    rtc "jvmgo/rtda/class"
)

func init() {
    _class("desiredAssertionStatus0",   "(Ljava/lang/Class;)Z",                     desiredAssertionStatus0)
    _class("getClassLoader0",           "()Ljava/lang/ClassLoader;",                getClassLoader0)
    _class("getName0",                  "()Ljava/lang/String;",                     getName0)
    _class("getPrimitiveClass",         "(Ljava/lang/String;)Ljava/lang/Class;",    getPrimitiveClass)
}

func _class(name, desc string, method Any) {
    rtc.RegisterNativeMethod("java/lang/Class", name, desc, method)
}

func desiredAssertionStatus0(frame *rtda.Frame) {
    // todo
    stack := frame.OperandStack()
    _ = stack.PopRef() // this
    stack.PushBoolean(false)
}

func getClassLoader0(frame *rtda.Frame) {
    // todo
    stack := frame.OperandStack()
    _ = stack.PopRef() // this
    stack.PushRef(nil)
}

func getName0(frame *rtda.Frame) {
    panic("getName0")
}

//static native Class<?> getPrimitiveClass(String name);
//getPrimitiveClass(Ljava/lang/String;)Ljava/lang/Class;
func getPrimitiveClass(frame *rtda.Frame) {
    // todo
    panic("getPrimitiveClass")
}
<|endoftext|>


<commit_before>package desugar

import (
	"fmt"

	"github.com/tisp-lang/tisp/src/lib/ast"
	"github.com/tisp-lang/tisp/src/lib/debug"
	"github.com/tisp-lang/tisp/src/lib/gensym"
)

func desugarMutualRecursionStatement(s interface{}) []interface{} {
	switch s := s.(type) {
	case ast.MutualRecursion:
		return desugarMutualRecursion(s)
	default:
		return []interface{}{s}
	}
}

func desugarMutualRecursion(mr ast.MutualRecursion) []interface{} {
	fs := mr.LetFunctions()
	unrecs := make([]interface{}, 0, len(fs))

	for _, f := range fs {
		arg := gensym.GenSym("mr", "functions", "argument")
		n2i := indexLetFunctions(fs...)

		unrecs = append(
			unrecs,
			ast.NewLetFunction(
				gensym.GenSym("mr", "unrec", f.Name()),
				prependPosReqsToSig([]string{arg}, f.Signature()),
				replaceNames(arg, n2i, f.Lets(), mr.DebugInfo()).([]interface{}),
				replaceNames(arg, deleteNamesDefinedByLets(n2i, f.Lets()), f.Body(), mr.DebugInfo()),
				f.DebugInfo()))
	}

	recsList := gensym.GenSym("ys", "mr", "functions")
	recs := make([]interface{}, 0, len(fs))

	for i, f := range fs {
		recs = append(
			recs,
			ast.NewLetVar(
				f.Name(),
				ast.NewPApp(recsList, []interface{}{fmt.Sprint(i)}, f.DebugInfo())))
	}

	return append(
		unrecs,
		append(
			[]interface{}{ast.NewLetVar(
				recsList,
				ast.NewPApp("$ys", stringsToAnys(letStatementsToNames(unrecs)), mr.DebugInfo()))},
			recs...)...)
}

func indexLetFunctions(fs ...ast.LetFunction) map[string]int {
	n2i := make(map[string]int)

	for i, f := range fs {
		n2i[f.Name()] = i
	}

	if len(n2i) != len(fs) {
		panic(fmt.Errorf("Duplicate names were found among mutually-recursive functions"))
	}

	return n2i
}

func replaceNames(funcList string, n2i map[string]int, x interface{}, di debug.Info) interface{} {
	replaceWithNameToIndex := func(n2i map[string]int) func(x interface{}) interface{} {
		return func(x interface{}) interface{} {
			return replaceNames(funcList, n2i, x, di)
		}
	}

	replace := replaceWithNameToIndex(n2i)

	switch x := x.(type) {
	case []interface{}:
		ys := make([]interface{}, 0, len(x))

		for _, x := range x {
			ys = append(ys, replace(x))
		}

		return ys
	case ast.LetFunction:
		n2i := copyNameToIndex(n2i)

		delete(n2i, x.Name())
		for n := range signatureToNames(x.Signature()) {
			delete(n2i, n)
		}

		return ast.NewLetFunction(
			x.Name(),
			x.Signature(),
			replaceWithNameToIndex(n2i)(x.Lets()).([]interface{}),
			replaceWithNameToIndex(deleteNamesDefinedByLets(n2i, x.Lets()))(x.Body()),
			x.DebugInfo())
	case ast.LetVar:
		n2i := copyNameToIndex(n2i)
		delete(n2i, x.Name())
		return ast.NewLetVar(x.Name(), replaceWithNameToIndex(n2i)(x.Expr()))
	case ast.App:
		return ast.NewApp(replace(x.Function()), replace(x.Arguments()).(ast.Arguments), x.DebugInfo())
	case ast.Arguments:
		ps := make([]ast.PositionalArgument, 0, len(x.Positionals()))

		for _, p := range x.Positionals() {
			ps = append(ps, ast.NewPositionalArgument(replace(p.Value()), p.Expanded()))
		}

		ks := make([]ast.KeywordArgument, 0, len(x.Keywords()))

		for _, k := range x.Keywords() {
			ks = append(ks, ast.NewKeywordArgument(k.Name(), replace(k.Value())))
		}

		ds := make([]interface{}, 0, len(x.ExpandedDicts()))

		for _, d := range x.ExpandedDicts() {
			ds = append(ds, replace(d))
		}

		return ast.NewArguments(ps, ks, ds)
	case string:
		if i, ok := n2i[x]; ok {
			return ast.NewPApp(funcList, []interface{}{fmt.Sprint(i)}, di)
		}

		return x
	}

	panic(fmt.Errorf("Invalid value: %#v", x))
}

func copyNameToIndex(ni map[string]int) map[string]int {
	new := make(map[string]int)

	for k, v := range ni {
		new[k] = v
	}

	return new
}

func deleteNamesDefinedByLets(ni map[string]int, ls []interface{}) map[string]int {
	ni = copyNameToIndex(ni)

	for _, n := range letStatementsToNames(ls) {
		delete(ni, n)
	}

	return ni
}

func letStatementsToNames(ls []interface{}) []string {
	ns := make([]string, 0, len(ls))

	for _, l := range ls {
		switch l := l.(type) {
		case ast.LetFunction:
			ns = append(ns, l.Name())
		case ast.LetVar:
			ns = append(ns, l.Name())
		default:
			panic("Unreachable")
		}
	}

	return ns
}

func stringsToAnys(ss []string) []interface{} {
	xs := make([]interface{}, 0, len(ss))

	for _, s := range ss {
		xs = append(xs, s)
	}

	return xs
}
<commit_msg>s/ni/n2i/g<commit_after>package desugar

import (
	"fmt"

	"github.com/tisp-lang/tisp/src/lib/ast"
	"github.com/tisp-lang/tisp/src/lib/debug"
	"github.com/tisp-lang/tisp/src/lib/gensym"
)

func desugarMutualRecursionStatement(s interface{}) []interface{} {
	switch s := s.(type) {
	case ast.MutualRecursion:
		return desugarMutualRecursion(s)
	default:
		return []interface{}{s}
	}
}

func desugarMutualRecursion(mr ast.MutualRecursion) []interface{} {
	fs := mr.LetFunctions()
	unrecs := make([]interface{}, 0, len(fs))

	for _, f := range fs {
		arg := gensym.GenSym("mr", "functions", "argument")
		n2i := indexLetFunctions(fs...)

		unrecs = append(
			unrecs,
			ast.NewLetFunction(
				gensym.GenSym("mr", "unrec", f.Name()),
				prependPosReqsToSig([]string{arg}, f.Signature()),
				replaceNames(arg, n2i, f.Lets(), mr.DebugInfo()).([]interface{}),
				replaceNames(arg, deleteNamesDefinedByLets(n2i, f.Lets()), f.Body(), mr.DebugInfo()),
				f.DebugInfo()))
	}

	recsList := gensym.GenSym("ys", "mr", "functions")
	recs := make([]interface{}, 0, len(fs))

	for i, f := range fs {
		recs = append(
			recs,
			ast.NewLetVar(
				f.Name(),
				ast.NewPApp(recsList, []interface{}{fmt.Sprint(i)}, f.DebugInfo())))
	}

	return append(
		unrecs,
		append(
			[]interface{}{ast.NewLetVar(
				recsList,
				ast.NewPApp("$ys", stringsToAnys(letStatementsToNames(unrecs)), mr.DebugInfo()))},
			recs...)...)
}

func indexLetFunctions(fs ...ast.LetFunction) map[string]int {
	n2i := make(map[string]int)

	for i, f := range fs {
		n2i[f.Name()] = i
	}

	if len(n2i) != len(fs) {
		panic(fmt.Errorf("Duplicate names were found among mutually-recursive functions"))
	}

	return n2i
}

func replaceNames(funcList string, n2i map[string]int, x interface{}, di debug.Info) interface{} {
	replaceWithNameToIndex := func(n2i map[string]int) func(x interface{}) interface{} {
		return func(x interface{}) interface{} {
			return replaceNames(funcList, n2i, x, di)
		}
	}

	replace := replaceWithNameToIndex(n2i)

	switch x := x.(type) {
	case []interface{}:
		ys := make([]interface{}, 0, len(x))

		for _, x := range x {
			ys = append(ys, replace(x))
		}

		return ys
	case ast.LetFunction:
		n2i := copyNameToIndex(n2i)

		delete(n2i, x.Name())
		for n := range signatureToNames(x.Signature()) {
			delete(n2i, n)
		}

		return ast.NewLetFunction(
			x.Name(),
			x.Signature(),
			replaceWithNameToIndex(n2i)(x.Lets()).([]interface{}),
			replaceWithNameToIndex(deleteNamesDefinedByLets(n2i, x.Lets()))(x.Body()),
			x.DebugInfo())
	case ast.LetVar:
		n2i := copyNameToIndex(n2i)
		delete(n2i, x.Name())
		return ast.NewLetVar(x.Name(), replaceWithNameToIndex(n2i)(x.Expr()))
	case ast.App:
		return ast.NewApp(replace(x.Function()), replace(x.Arguments()).(ast.Arguments), x.DebugInfo())
	case ast.Arguments:
		ps := make([]ast.PositionalArgument, 0, len(x.Positionals()))

		for _, p := range x.Positionals() {
			ps = append(ps, ast.NewPositionalArgument(replace(p.Value()), p.Expanded()))
		}

		ks := make([]ast.KeywordArgument, 0, len(x.Keywords()))

		for _, k := range x.Keywords() {
			ks = append(ks, ast.NewKeywordArgument(k.Name(), replace(k.Value())))
		}

		ds := make([]interface{}, 0, len(x.ExpandedDicts()))

		for _, d := range x.ExpandedDicts() {
			ds = append(ds, replace(d))
		}

		return ast.NewArguments(ps, ks, ds)
	case string:
		if i, ok := n2i[x]; ok {
			return ast.NewPApp(funcList, []interface{}{fmt.Sprint(i)}, di)
		}

		return x
	}

	panic(fmt.Errorf("Invalid value: %#v", x))
}

func copyNameToIndex(n2i map[string]int) map[string]int {
	new := make(map[string]int)

	for k, v := range n2i {
		new[k] = v
	}

	return new
}

func deleteNamesDefinedByLets(n2i map[string]int, ls []interface{}) map[string]int {
	n2i = copyNameToIndex(n2i)

	for _, n := range letStatementsToNames(ls) {
		delete(n2i, n)
	}

	return n2i
}

func letStatementsToNames(ls []interface{}) []string {
	ns := make([]string, 0, len(ls))

	for _, l := range ls {
		switch l := l.(type) {
		case ast.LetFunction:
			ns = append(ns, l.Name())
		case ast.LetVar:
			ns = append(ns, l.Name())
		default:
			panic("Unreachable")
		}
	}

	return ns
}

func stringsToAnys(ss []string) []interface{} {
	xs := make([]interface{}, 0, len(ss))

	for _, s := range ss {
		xs = append(xs, s)
	}

	return xs
}
<|endoftext|>


<commit_before>// package wfilter provides facilities for adding filtering to io.Writer.
package wfilter

import (
	"bytes"
	"io"
)

type Prepend func(w io.Writer) (int, error)

// LinePrepender creates an io.Writer that prepends to each line by calling the
// given prepend function. Perepend can write whatever it wants. It should
// return the bytes written and any error encountered.
func LinePrepender(w io.Writer, prepend Prepend) io.Writer {
	return &lp{w, prepend, true}
}

type lp struct {
	io.Writer
	prepend       Prepend
	prependNeeded bool
}

func (w *lp) Write(buf []byte) (int, error) {
	if w.prependNeeded {
		_, err := w.prepend(w.Writer)
		if err != nil {
			return 0, err
		}
		w.prependNeeded = false
	}

	// Prepend before every newline in the buffer
	totalN := 0

	for {
		i := bytes.IndexRune(buf, '\n') + 1
		newlineFound := i > 0
		newlineAtEnd := newlineFound && i == len(buf)

		if !newlineFound {
			break
		} else if newlineAtEnd {
			// Prepend will be needed at beginning of next write
			w.prependNeeded = true
			break
		} else {
			// Newline is somewhere before end
			n, err := w.Writer.Write(buf[:i])
			totalN += n
			if err != nil {
				return totalN, err
			}
			// Add prepend
			_, err = w.prepend(w.Writer)
			if err != nil {
				return totalN, err
			}
			// Remove processed portion of buffer
			buf = buf[i:]
		}
	}

	// Write what's left of buf
	n, err := w.Writer.Write(buf)
	totalN += n
	return totalN, err
}
<commit_msg>Implement SimplePrepender Writer<commit_after>// package wfilter provides facilities for adding filtering to io.Writer.
package wfilter

import (
	"bytes"
	"io"
)

type Prepend func(w io.Writer) (int, error)

// LinePrepender creates an io.Writer that prepends to each line by calling the
// given prepend function. Prepend can write whatever it wants. It should
// return the bytes written and any error encountered.
func LinePrepender(w io.Writer, prepend Prepend) io.Writer {
	return &linePrepender{w, prepend, true}
}

type linePrepender struct {
	io.Writer
	prepend       Prepend
	prependNeeded bool
}

func (w *linePrepender) Write(buf []byte) (int, error) {
	if w.prependNeeded {
		_, err := w.prepend(w.Writer)
		if err != nil {
			return 0, err
		}
		w.prependNeeded = false
	}

	// Prepend before every newline in the buffer
	totalN := 0

	for {
		i := bytes.IndexRune(buf, '\n') + 1
		newlineFound := i > 0
		newlineAtEnd := newlineFound && i == len(buf)

		if !newlineFound {
			break
		} else if newlineAtEnd {
			// Prepend will be needed at beginning of next write
			w.prependNeeded = true
			break
		} else {
			// Newline is somewhere before end
			n, err := w.Writer.Write(buf[:i])
			totalN += n
			if err != nil {
				return totalN, err
			}
			// Add prepend
			_, err = w.prepend(w.Writer)
			if err != nil {
				return totalN, err
			}
			// Remove processed portion of buffer
			buf = buf[i:]
		}
	}

	// Write what's left of buf
	n, err := w.Writer.Write(buf)
	totalN += n
	return totalN, err
}

// SimplePrepender creates an io.Writer that prepends to each line by calling the
// given prepend function. Prepend can write whatever it wants. It should
// return the bytes written and any error encountered.
func SimplePrepender(w io.Writer, prepend Prepend) io.Writer {
	return &simplePrepender{w, prepend}
}

type simplePrepender struct {
	io.Writer
	prepend Prepend
}

func (w *simplePrepender) Write(buf []byte) (int, error) {
	written := 0

	n, err := w.prepend(w.Writer)
	written = written + n
	if err != nil {
		return written, err
	}

	n, err = w.Writer.Write(buf)
	written = written + n
	return written, err
}
<|endoftext|>


<commit_before>/* Mozilla InvestiGator API: Compliance parsing functions

Version: MPL 1.1/GPL 2.0/LGPL 2.1

The contents of this file are subject to the Mozilla Public License Version
1.1 (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.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.

The Initial Developer of the Original Code is
Mozilla Corporation
Portions created by the Initial Developer are Copyright (C) 2013
the Initial Developer. All Rights Reserved.

Contributor(s):
Julien Vehent jvehent@mozilla.com [:ulfr]

Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
*/

package main

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

	"github.com/mozilla/mig/src/mig/modules/filechecker"
)

type ComplianceItem struct {
	Timestamp  time.Time        `json:"timestamp"`
	Target     string           `json:"target"`
	Policy     CompliancePolicy `json:"policy"`
	Check      ComplianceCheck  `json:"check"`
	Compliance bool             `json:"compliance"`
	Link       string           `json:"link"`
}

type CompliancePolicy struct {
	Name  string `json:"name"`
	URL   string `json:"url"`
	Level string `json:"level"`
}

type ComplianceCheck struct {
	Description string         `json:"description"`
	Name        string         `json:"name"`
	Location    string         `json:"location"`
	Test        ComplianceTest `json:"test"`
}

type ComplianceTest struct {
	Type  string `json:"type"`
	Value string `json:"value"`
}

func commandsToComplianceItems(commands []mig.Command) (items []ComplianceItem, err error) {
	for _, cmd := range commands {
		var bitem ComplianceItem
		bitem.Timestamp = cmd.FinishTime
		bitem.Target = cmd.Agent.Name
		bitem.Policy.Name = cmd.Action.Threat.Type
		bitem.Policy.URL = cmd.Action.Description.URL
		bitem.Policy.Level = cmd.Action.Threat.Level
		bitem.Check.Description = cmd.Action.Name
		bitem.Link = fmt.Sprintf("%s/command?commandid=%d", ctx.Server.BaseURL, cmd.ID)
		for i, result := range cmd.Results {
			buf, err := json.Marshal(result)
			if err != nil {
				return items, err
			}
			switch cmd.Action.Operations[i].Module {
			case "filechecker":
				var r filechecker.Results
				err = json.Unmarshal(buf, &r)
				if err != nil {
					return items, err
				}
				for path, _ := range r.Elements {
					bitem.Check.Location = path
					for method, _ := range r.Elements[path] {
						bitem.Check.Test.Type = method
						for id, _ := range r.Elements[path][method] {
							bitem.Check.Name = id
							for value, _ := range r.Elements[path][method][id] {
								bitem.Check.Test.Value = value
								if r.Elements[path][method][id][value].Matchcount > 0 {
									bitem.Compliance = true
								} else {
									bitem.Compliance = false
								}
								item := bitem
								items = append(items, item)
							}
						}
					}
				}
			}
		}
	}
	return
}
<commit_msg>[minor] compliance: change timestamp to utctimestamp with mozdef format<commit_after>/* Mozilla InvestiGator API: Compliance parsing functions

Version: MPL 1.1/GPL 2.0/LGPL 2.1

The contents of this file are subject to the Mozilla Public License Version
1.1 (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.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.

The Initial Developer of the Original Code is
Mozilla Corporation
Portions created by the Initial Developer are Copyright (C) 2013
the Initial Developer. All Rights Reserved.

Contributor(s):
Julien Vehent jvehent@mozilla.com [:ulfr]

Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
*/

package main

import (
	"encoding/json"
	"fmt"
	"mig"

	"github.com/mozilla/mig/src/mig/modules/filechecker"
)

type ComplianceItem struct {
	Utctimestamp  string           `json:"utctimestamp"`
	Target        string           `json:"target"`
	Policy        CompliancePolicy `json:"policy"`
	Check         ComplianceCheck  `json:"check"`
	Compliance    bool             `json:"compliance"`
	Link          string           `json:"link"`
}

type CompliancePolicy struct {
	Name  string `json:"name"`
	URL   string `json:"url"`
	Level string `json:"level"`
}

type ComplianceCheck struct {
	Description string         `json:"description"`
	Name        string         `json:"name"`
	Location    string         `json:"location"`
	Test        ComplianceTest `json:"test"`
}

type ComplianceTest struct {
	Type  string `json:"type"`
	Value string `json:"value"`
}

const RFC3339Nano = "2006-01-02T15:04:05.999999999+07:00"

func commandsToComplianceItems(commands []mig.Command) (items []ComplianceItem, err error) {
	for _, cmd := range commands {
		var bitem ComplianceItem
		bitem.Utctimestamp = cmd.FinishTime.Format(RFC3339Nano)
		bitem.Target = cmd.Agent.Name
		bitem.Policy.Name = cmd.Action.Threat.Type
		bitem.Policy.URL = cmd.Action.Description.URL
		bitem.Policy.Level = cmd.Action.Threat.Level
		bitem.Check.Description = cmd.Action.Name
		bitem.Link = fmt.Sprintf("%s/command?commandid=%d", ctx.Server.BaseURL, cmd.ID)
		for i, result := range cmd.Results {
			buf, err := json.Marshal(result)
			if err != nil {
				return items, err
			}
			switch cmd.Action.Operations[i].Module {
			case "filechecker":
				var r filechecker.Results
				err = json.Unmarshal(buf, &r)
				if err != nil {
					return items, err
				}
				for path, _ := range r.Elements {
					bitem.Check.Location = path
					for method, _ := range r.Elements[path] {
						bitem.Check.Test.Type = method
						for id, _ := range r.Elements[path][method] {
							bitem.Check.Name = id
							for value, _ := range r.Elements[path][method][id] {
								bitem.Check.Test.Value = value
								if r.Elements[path][method][id][value].Matchcount > 0 {
									bitem.Compliance = true
								} else {
									bitem.Compliance = false
								}
								item := bitem
								items = append(items, item)
							}
						}
					}
				}
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package tests

import (
    "testing"
    "github.com/zubairhamed/lwm2m/core"
    "time"
)

func TestGetValueLength(t *testing.T) {
    core.GetValueLength(-128)
    core.GetValueLength(127)
    core.GetValueLength(-32768)
    core.GetValueLength(32767)
    core.GetValueLength(-2147483648)
    core.GetValueLength(2147483647)
    core.GetValueLength(-9223372036854775808)
    core.GetValueLength(9223372036854775807)

    core.GetValueLength(-3.4E+38)
    core.GetValueLength(+3.4E+38)

    core.GetValueLength(-1.7E+308)
    core.GetValueLength(+1.7E+308)

    core.GetValueLength("this is a string")

    core.GetValueLength(true)
    core.GetValueLength(false)

    core.GetValueLength(time.Now())

    core.GetValueLength([]byte{})
}

/*
if _, ok := val.(float32); ok {
log.Println("float32")
}

if _, ok := val.(float64); ok {
log.Println("float64")
}

if _, ok := val.(time.Time); ok {
log.Println("time")
}
*/<commit_msg>Test Fixes<commit_after>package tests

import (
    "testing"
    "github.com/zubairhamed/lwm2m/core"
    "time"
)

func TestGetValueByteLength(t *testing.T) {
    core.GetValueByteLength(-128)
    core.GetValueByteLength(127)
    core.GetValueByteLength(-32768)
    core.GetValueByteLength(32767)
    core.GetValueByteLength(-2147483648)
    core.GetValueByteLength(2147483647)
    core.GetValueByteLength(-9223372036854775808)
    core.GetValueByteLength(9223372036854775807)

    core.GetValueByteLength(-3.4E+38)
    core.GetValueByteLength(+3.4E+38)

    core.GetValueByteLength(-1.7E+308)
    core.GetValueByteLength(+1.7E+308)

    core.GetValueByteLength("this is a string")

    core.GetValueByteLength(true)
    core.GetValueByteLength(false)

    core.GetValueByteLength(time.Now())

    core.GetValueByteLength([]byte{})

    core.GetValueByteLength(uint(1))
    core.GetValueByteLength(uint16(1))
    core.GetValueByteLength(uint32(1))
    core.GetValueByteLength(uint64(1))

}

/*
if _, ok := val.(float32); ok {
log.Println("float32")
}

if _, ok := val.(float64); ok {
log.Println("float64")
}

if _, ok := val.(time.Time); ok {
log.Println("time")
}
*/<|endoftext|>


<commit_before>package test

import (
	"log"
	"net/http"

	x "github.com/javinc/puto"
	"github.com/javinc/puto/test/resource"
	"github.com/javinc/puto/test/service"
)

var (
	// Model for import use
	Model = resource.Model{}
)

// Handler catches /test endpoint
func Handler(w http.ResponseWriter, r *http.Request) {
	log.Println("test handler")

	var single bool
	o := new(resource.Options)
	p := new(resource.Model)

	// extracting resource id
	if id, e := x.GetID(r); e == nil {
		// assign id on Filters
		single = true
		o.Filters.ID = id
	}

	// extract field from get params
	x.ParseOption(r, o)
	log.Println("id", o.Filters.ID)
	log.Println("options", o)

	// extract field from json post
	x.ParsePayload(r, p)
	log.Println("payload", p)

	// lets base on the request type then use the service
	var err error
	var model interface{}
	// var err error
	switch r.Method {
	case "GET":
		// check if singles
		if single {
			model, err = service.Get(o)
		} else {
			model, err = service.Find(o)
		}
	case "POST":
		model, err = service.Create(p)
	case "DELETE":
		model, err = service.Remove(o)
	case "PUT":
		model, err = service.Update(p, o)
	}

	if err != nil {
		x.ErrorOutput(w, err, 400)

		return
	}

	x.Output(w, model)
}
<commit_msg>fix comments<commit_after>package test

import (
	"log"
	"net/http"

	x "github.com/javinc/puto"
	"github.com/javinc/puto/test/resource"
	"github.com/javinc/puto/test/service"
)

var (
	// Model for import use
	Model = resource.Model{}
)

// Handler catches /test endpoint
func Handler(w http.ResponseWriter, r *http.Request) {
	log.Println("test handler")

	var err error
	var single bool
	var model interface{}

	// inits objects
	o := new(resource.Options)
	p := new(resource.Model)

	// extracting resource id
	if id, e := x.GetID(r); e == nil {
		// assign id on Filters
		single = true
		o.Filters.ID = id
	}

	// extract field from get params
	x.ParseOption(r, o)
	log.Println("id", o.Filters.ID)
	log.Println("options", o)

	// extract field from json post
	x.ParsePayload(r, p)
	log.Println("payload", p)

	// lets base on the request type then use the service
	switch r.Method {
	case "GET":
		// check if singles
		if single {
			model, err = service.Get(o)
		} else {
			model, err = service.Find(o)
		}
	case "POST":
		model, err = service.Create(p)
	case "DELETE":
		model, err = service.Remove(o)
	case "PUT":
		model, err = service.Update(p, o)
	}

	// response error
	if err != nil {
		x.ErrorOutput(w, err, 400)

		return
	}

	x.Output(w, model)
}
<|endoftext|>


<commit_before>/*
(BSD 2-clause license)

Copyright (c) 2014, Shawn Webb
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package jail

/*
 * The jail.Jail object implements the VirtualMachine interface
 */

import (
    /* "fmt" */
    "github.com/nu7hatch/gouuid"
    "github.com/coopernurse/gorp"
    "github.com/virtbsd/network"
    "github.com/virtbsd/VirtualMachine"
    "github.com/virtbsd/zfs"
)

type MountPoint struct {
    JailUUID string
    Source string
    Destination string
    Options string
    MountOrder int
}

type JailOption struct {
    JailUUID string
    OptionKey string
    OptionValue string
}

type Jail struct {
    UUID string
    Name string
    HostName string
    CreateDate int
    ModificationDate int
    ZFSDataset string

    NetworkDevices []*network.NetworkDevice `db:"-"`
    Mounts []*MountPoint `db:"-"`
    Options []*JailOption `db:"-"`
    BootEnvironments map[string]bool `db:"-"`
    Snapshots []string `db:"-"`
    ZFSDatasetObj *zfs.Dataset `db:"-"`

    Path string `db:"-"`
    Dirty bool `db:"-"`
}

func (jail *Jail) PostGet(s gorp.SqlExecutor) error {
    jail.NetworkDevices = network.GetNetworkDevices(map[string]interface{}{"sqlexecutor": s}, jail)

    s.Select(&jail.Mounts, "select * from MountPoint where JailUUID = ?", jail.UUID)
    s.Select(&jail.Options, "select * from JailOption where JailUUID = ?", jail.UUID)
    if len(jail.HostName) == 0 {
        jail.HostName = jail.Name
    }

    jail.ZFSDatasetObj = zfs.GetDataset(jail.ZFSDataset)

    return nil
}

func (jail *Jail) GetUUID() string {
    return jail.UUID
}

func LookupUUID(db *gorp.DbMap, field map[string]interface{}) string {
    fields := []string{ "name", "hostname" }

    if uuid, ok := field["uuid"]; ok == true {
        return uuid.(string)
    }

    for i := 0; i < len(fields); i++ {
        if val, ok := field[fields[i]]; ok == true {
            myuuid, err := db.SelectStr("select UUID from jail where " + fields[i] + " = ?", val)
            if err == nil {
                return myuuid
            }
        }
    }

    return ""
}

func GetJail(db *gorp.DbMap, field map[string]interface{}) *Jail {
    uuid := LookupUUID(db, field)
    if len(uuid) == 0 {
        return nil
    }

    obj, err := db.Get(Jail{}, uuid)
    if err != nil {
        panic(err)
        return nil
    }

    if obj == nil {
        /* Jail not found */
        return nil
    }

    return obj.(*Jail)
}

func (jail *Jail) Start() error {
    if jail.IsOnline() == false {
        return nil
    }

    return nil
}

func (jail *Jail) Stop() error {
    return nil
}

func (jail *Jail) Status() string {
    if jail.IsOnline() {
        return "Online"
    } else {
        return "Offline"
    }
}

func (jail *Jail) CreateSnapshot(snapname string) error {
    return nil
}

func (jail *Jail) RestoreSnapshot(snapname string) error {
    return nil
}

func (jail *Jail) DeleteSnapshot(snapname string) error {
    return nil
}

func (jail *Jail) PrepareHostNetworking() error {
    return nil
}

func (jail *Jail) PrepareGuestNetworking() error {
    return nil
}

func (jail *Jail) NetworkingStatus() string {
    return ""
}

func (jail *Jail) GetPath() string {
    if len(jail.Path) > 0 {
        return jail.Path
    }

    path, err := zfs.GetDatasetPath(jail.ZFSDataset)
    if err != nil {
        panic(err)
        return ""
    }

    jail.Path = path

    return path
}

func (jail *Jail) IsOnline() bool {
    return false
}

func (jail *Jail) Validate() error {
    if len(jail.UUID) == 0 {
        /* If we haven't been persisted (this is a new jail), then we don't have a UUID */
        myuuid, _ := uuid.NewV4()
        jail.UUID = myuuid.String()
    }

    if _, err := uuid.ParseHex(jail.UUID); err != nil {
        return VirtualMachine.VirtualMachineError{"Invalid UUID", jail}
    }

    if len(jail.GetPath()) == 0 {
        return VirtualMachine.VirtualMachineError{"Invalid Path, ZFS Dataset: " + jail.ZFSDataset, jail}
    }

    return nil
}

func (jail *Jail) Persist(db *gorp.DbMap) error {
    if err := jail.Validate(); err != nil {
        return err
    }

    return nil
}

func (jail *Jail) Delete(db *gorp.DbMap) error {
    return nil
}

func (jail *Jail) Archive(archivename string) error {
    return nil
}
<commit_msg>Add basic logic for starting a jail<commit_after>/*
(BSD 2-clause license)

Copyright (c) 2014, Shawn Webb
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package jail

/*
 * The jail.Jail object implements the VirtualMachine interface
 */

import (
    /* "fmt" */
    "os/exec"
    "github.com/nu7hatch/gouuid"
    "github.com/coopernurse/gorp"
    "github.com/virtbsd/network"
    "github.com/virtbsd/VirtualMachine"
    "github.com/virtbsd/zfs"
)

type MountPoint struct {
    JailUUID string
    Source string
    Destination string
    Options string
    Driver string
    MountOrder int
}

type JailOption struct {
    JailUUID string
    OptionKey string
    OptionValue string
}

type Jail struct {
    UUID string
    Name string
    HostName string
    CreateDate int
    ModificationDate int
    ZFSDataset string

    NetworkDevices []*network.NetworkDevice `db:"-"`
    Mounts []*MountPoint `db:"-"`
    Options []*JailOption `db:"-"`
    BootEnvironments map[string]bool `db:"-"`
    Snapshots []string `db:"-"`
    ZFSDatasetObj *zfs.Dataset `db:"-"`
    Routes []*network.Route `db:"-"`

    Path string `db:"-"`
    Dirty bool `db:"-"`
}

func (jail *Jail) PostGet(s gorp.SqlExecutor) error {
    jail.NetworkDevices = network.GetNetworkDevices(map[string]interface{}{"sqlexecutor": s}, jail)

    s.Select(&jail.Mounts, "select * from MountPoint where JailUUID = ? order by MountOrder", jail.UUID)
    s.Select(&jail.Options, "select * from JailOption where JailUUID = ?", jail.UUID)
    s.Select(&jail.Routes, "select * from Route WHERE VmUUID = ?", jail.UUID)
    if len(jail.HostName) == 0 {
        jail.HostName = jail.Name
    }

    jail.ZFSDatasetObj = zfs.GetDataset(jail.ZFSDataset)

    return nil
}

func (jail *Jail) GetUUID() string {
    return jail.UUID
}

func LookupUUID(db *gorp.DbMap, field map[string]interface{}) string {
    fields := []string{ "name", "hostname" }

    if uuid, ok := field["uuid"]; ok == true {
        return uuid.(string)
    }

    for i := 0; i < len(fields); i++ {
        if val, ok := field[fields[i]]; ok == true {
            myuuid, err := db.SelectStr("select UUID from jail where " + fields[i] + " = ?", val)
            if err == nil {
                return myuuid
            }
        }
    }

    return ""
}

func GetJail(db *gorp.DbMap, field map[string]interface{}) *Jail {
    uuid := LookupUUID(db, field)
    if len(uuid) == 0 {
        return nil
    }

    obj, err := db.Get(Jail{}, uuid)
    if err != nil {
        panic(err)
        return nil
    }

    if obj == nil {
        /* Jail not found */
        return nil
    }

    return obj.(*Jail)
}

func (jail *Jail) Start() error {
    path := jail.GetPath()

    if jail.IsOnline() == true {
        return nil
    }

    cmd := exec.Command("/sbin/mount", "-t", "devfs", "devfs", path + "/dev")
    if err := cmd.Run(); err != nil {
        return err
    }

    cmd = exec.Command("/usr/sbin/jail", "-c", "vnet", "name=" + jail.UUID, "host.hostname=" + jail.HostName, "path=" + path, "persist")
    if err := cmd.Run(); err != nil {
        return err
    }

    for i := range jail.Mounts {
        cmd = exec.Command("/usr/sbin/jexec", jail.UUID, "/sbin/mount")
        if len(jail.Mounts[i].Driver) > 0 {
            cmd.Args = append(cmd.Args, "-t")
            cmd.Args = append(cmd.Args, jail.Mounts[i].Driver)
        }

        if len(jail.Mounts[i].Options) > 0 {
            cmd.Args = append(cmd.Args, "-o")
            cmd.Args = append(cmd.Args, jail.Mounts[i].Options)
        }

        cmd.Args = append(cmd.Args, jail.Mounts[i].Source)
        cmd.Args = append(cmd.Args, path + "/" + jail.Mounts[i].Destination)

        if err := cmd.Run(); err != nil {
            return err
        }
    }

    return nil
}

func (jail *Jail) Stop() error {
    return nil
}

func (jail *Jail) Status() string {
    if jail.IsOnline() {
        return "Online"
    } else {
        return "Offline"
    }
}

func (jail *Jail) CreateSnapshot(snapname string) error {
    return nil
}

func (jail *Jail) RestoreSnapshot(snapname string) error {
    return nil
}

func (jail *Jail) DeleteSnapshot(snapname string) error {
    return nil
}

func (jail *Jail) PrepareHostNetworking() error {
    for i := range jail.NetworkDevices {
        if err := jail.NetworkDevices[i].BringHostOnline(); err != nil {
            return err
        }
    }

    return nil
}

func (jail *Jail) PrepareGuestNetworking() error {
    for i := range jail.NetworkDevices {
        if err := jail.NetworkDevices[i].BringGuestOnline(jail); err != nil {
            return err
        }
    }

    cmd := exec.Command("/usr/sbin/jexec", jail.UUID, "/sbin/ifconfig", "lo0", "inet", "127.0.0.1", "up")
    if err := cmd.Run(); err != nil {
        return err
    }

    return nil
}

func (jail *Jail) NetworkingStatus() string {
    return ""
}

func (jail *Jail) GetPath() string {
    if len(jail.Path) > 0 {
        return jail.Path
    }

    path, err := zfs.GetDatasetPath(jail.ZFSDataset)
    if err != nil {
        panic(err)
        return ""
    }

    jail.Path = path

    return path
}

func (jail *Jail) IsOnline() bool {
    cmd := exec.Command("/usr/sbin/jls", "-j", jail.UUID)
    err := cmd.Run()
    if err == nil {
        return true
    }

    return false
}

func (jail *Jail) Validate() error {
    if len(jail.UUID) == 0 {
        /* If we haven't been persisted (this is a new jail), then we don't have a UUID */
        myuuid, _ := uuid.NewV4()
        jail.UUID = myuuid.String()
    }

    if _, err := uuid.ParseHex(jail.UUID); err != nil {
        return VirtualMachine.VirtualMachineError{"Invalid UUID", jail}
    }

    if len(jail.GetPath()) == 0 {
        return VirtualMachine.VirtualMachineError{"Invalid Path, ZFS Dataset: " + jail.ZFSDataset, jail}
    }

    return nil
}

func (jail *Jail) Persist(db *gorp.DbMap) error {
    if err := jail.Validate(); err != nil {
        return err
    }

    return nil
}

func (jail *Jail) Delete(db *gorp.DbMap) error {
    return nil
}

func (jail *Jail) Archive(archivename string) error {
    return nil
}
<|endoftext|>


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

package e2e

import (
	"path"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/golang/glog"
	"github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/config"
	"github.com/onsi/ginkgo/reporters"
	"github.com/onsi/gomega"
)

type testResult bool

func (t *testResult) Fail() { *t = false }

// Run each Go end-to-end-test. This function assumes the
// creation of a test cluster.
func RunE2ETests(authConfig, certDir, host, repoRoot, provider string, orderseed int64, times int, reportDir string, testList []string) {
	testContext = testContextType{authConfig, certDir, host, repoRoot, provider}
	util.ReallyCrash = true
	util.InitLogs()
	defer util.FlushLogs()

	// TODO: Associate a timeout with each test individually.
	go func() {
		defer util.FlushLogs()
		// TODO: We should modify testSpec to include an estimated running time
		//       for each test and use that information to estimate a timeout
		//       value. Until then, as we add more tests (and before we move to
		//       parallel testing) we need to adjust this value as we add more tests.
		time.Sleep(15 * time.Minute)
		glog.Fatalf("This test has timed out. Cleanup not guaranteed.")
	}()

	// TODO: Make -t TestName work again.
	// TODO: Make "times" work again.
	// TODO: Make orderseed work again.

	var passed testResult = true
	gomega.RegisterFailHandler(ginkgo.Fail)
	// Turn of colors for now to make it easier to collect console output in Jenkins
	config.DefaultReporterConfig.NoColor = true
	var r []ginkgo.Reporter
	if reportDir != "" {
		// TODO: When we start using parallel tests we need to change this to "junit_%d.xml",
		// see ginkgo docs for more details.
		r = append(r, reporters.NewJUnitReporter(path.Join(reportDir, "junit.xml")))
	}
	// Run the existing tests with output to console + JUnit for Jenkins
	ginkgo.RunSpecsWithDefaultAndCustomReporters(&passed, "Kubernetes e2e Suite", r)

	if !passed {
		glog.Fatalf("At least one test failed")
	} else {
		glog.Infof("All tests pass")
	}
}
<commit_msg>Make it possible to re-enable color output in Ginkgo e2e tests<commit_after>/*
Copyright 2014 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.
*/

package e2e

import (
	"path"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/golang/glog"
	"github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/config"
	"github.com/onsi/ginkgo/reporters"
	"github.com/onsi/gomega"
)

type testResult bool

func init() {
	// Turn off colors by default to make it easier to collect console output in Jenkins
	// Override colors off with --ginkgo.noColor=false in the command-line
	config.DefaultReporterConfig.NoColor = true
}

func (t *testResult) Fail() { *t = false }

// Run each Go end-to-end-test. This function assumes the
// creation of a test cluster.
func RunE2ETests(authConfig, certDir, host, repoRoot, provider string, orderseed int64, times int, reportDir string, testList []string) {
	testContext = testContextType{authConfig, certDir, host, repoRoot, provider}
	util.ReallyCrash = true
	util.InitLogs()
	defer util.FlushLogs()

	// TODO: Associate a timeout with each test individually.
	go func() {
		defer util.FlushLogs()
		// TODO: We should modify testSpec to include an estimated running time
		//       for each test and use that information to estimate a timeout
		//       value. Until then, as we add more tests (and before we move to
		//       parallel testing) we need to adjust this value as we add more tests.
		time.Sleep(15 * time.Minute)
		glog.Fatalf("This test has timed out. Cleanup not guaranteed.")
	}()

	// TODO: Make -t TestName work again.
	// TODO: Make "times" work again.
	// TODO: Make orderseed work again.

	var passed testResult = true
	gomega.RegisterFailHandler(ginkgo.Fail)
	var r []ginkgo.Reporter
	if reportDir != "" {
		// TODO: When we start using parallel tests we need to change this to "junit_%d.xml",
		// see ginkgo docs for more details.
		r = append(r, reporters.NewJUnitReporter(path.Join(reportDir, "junit.xml")))
	}
	// Run the existing tests with output to console + JUnit for Jenkins
	ginkgo.RunSpecsWithDefaultAndCustomReporters(&passed, "Kubernetes e2e Suite", r)

	if !passed {
		glog.Fatalf("At least one test failed")
	} else {
		glog.Infof("All tests pass")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"math"
	"math/big"
	"net/http"
	"os"
	"path"
	"strconv"

	"github.com/gorilla/handlers"
	_ "github.com/mattn/go-sqlite3"
)

const (
	listenAddr     = "127.0.0.1:9292"
	bigThumbSize   = 1000
	smallThumbSize = 200
)

var (
	db            *sql.DB
	getSetStmt    *sql.Stmt
	getSetsStmt   *sql.Stmt
	getPhotoStmt  *sql.Stmt
	getPhotosStmt *sql.Stmt
)

type Set struct {
	Id             int
	Name           string
	PhotosCount    int
	TakenAt        sql.NullString
	ThumbPhotoId   int
	ThumbPhotoPath string
}

type Photo struct {
	Aperture      sql.NullFloat64
	Camera        sql.NullString
	ExposureComp  sql.NullInt64
	ExposureTime  sql.NullFloat64
	Flash         sql.NullString
	FocalLength   sql.NullFloat64
	FocalLength35 sql.NullInt64
	Height        int64
	ISO           sql.NullInt64
	Id            int
	Lat           sql.NullFloat64
	Lens          sql.NullString
	Lng           sql.NullFloat64
	NextPhotoId   sql.NullInt64
	Path          string
	PrevPhotoId   sql.NullInt64
	SetId         int
	Size          int
	TakenAt       sql.NullString
	Width         int64
}

// used by scanSet and scanPhoto to accept row(s)
type RowScanner interface {
	Scan(dest ...interface{}) error
}

func thumbURL(photoPath, suffix string) string {
	identifier := fmt.Sprintf("%x", md5.Sum([]byte(photoPath)))
	return fmt.Sprintf("/thumbs/%s_%s.jpg", identifier, suffix)
}

func (s *Set) ThumbURL() string {
	return thumbURL(s.ThumbPhotoPath, "small")
}

func (s *Set) MarshalJSON() ([]byte, error) { // implements Marshaler
	setMap := map[string]interface{}{
		"id":             s.Id,
		"name":           s.Name,
		"photos_count":   s.PhotosCount,
		"thumb_photo_id": s.ThumbPhotoId,
		"thumb_url":      s.ThumbURL(),
	}
	setMap["taken_at"], _ = s.TakenAt.Value()
	return json.Marshal(setMap)
}

func (p *Photo) AspectRatio() [2]int64 {
	gcd := new(big.Int).GCD(nil, nil, big.NewInt(p.Width), big.NewInt(p.Height)).Int64()
	return [2]int64{p.Width / gcd, p.Height / gcd}
}

func (p *Photo) BigThumbHeight() int64 {
	if p.Orientation() == "portrait" {
		if p.Height < bigThumbSize {
			return p.Height
		}

		return bigThumbSize
	}

	aspectRatio := p.AspectRatio()
	return int64(math.Floor((float64(aspectRatio[1])/float64(aspectRatio[0]))*float64(p.BigThumbWidth()) + .5))
}

func (p *Photo) BigThumbWidth() int64 {
	if p.Orientation() == "portrait" {
		aspectRatio := p.AspectRatio()
		return int64(math.Floor((float64(aspectRatio[0])/float64(aspectRatio[1]))*float64(p.BigThumbHeight()) + .5))
	}

	if p.Width < bigThumbSize {
		return p.Width
	}

	return bigThumbSize
}

func (p *Photo) Filename() string {
	return path.Base(p.Path)
}

func (p *Photo) Orientation() string {
	if p.Height > p.Width {
		return "portrait"
	}
	return "landscape"
}

func (p *Photo) ThumbURL(suffix string) string {
	return thumbURL(p.Path, suffix)
}

func (p *Photo) MarshalJSON() ([]byte, error) { // implements Marshaler
	photoMap := map[string]interface{}{
		"aspect_ratio":     p.AspectRatio(),
		"big_thumb_height": p.BigThumbHeight(),
		"big_thumb_url":    p.ThumbURL("big"),
		"big_thumb_width":  p.BigThumbWidth(),
		"filename":         p.Filename(),
		"height":           p.Height,
		"id":               p.Id,
		"orientation":      p.Orientation(),
		"path":             p.Path,
		"set_id":           p.SetId,
		"size":             p.Size,
		"small_thumb_url":  p.ThumbURL("small"),
		"width":            p.Width,
	}

	photoMap["aperture"], _ = p.Aperture.Value()
	photoMap["camera"], _ = p.Camera.Value()
	photoMap["exposure_comp"], _ = p.ExposureComp.Value()
	photoMap["exposure_time"], _ = p.ExposureTime.Value()
	photoMap["flash"], _ = p.Flash.Value()
	photoMap["focal_length"], _ = p.FocalLength.Value()
	photoMap["focal_length_35"], _ = p.FocalLength35.Value()
	photoMap["iso"], _ = p.ISO.Value()
	photoMap["lat"], _ = p.Lat.Value()
	photoMap["lens"], _ = p.Lens.Value()
	photoMap["lng"], _ = p.Lng.Value()
	photoMap["next_photo_id"], _ = p.NextPhotoId.Value()
	photoMap["prev_photo_id"], _ = p.PrevPhotoId.Value()
	photoMap["taken_at"], _ = p.TakenAt.Value()

	return json.Marshal(photoMap)
}

func badRequest(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusBadRequest)
	fmt.Fprintln(w, http.StatusBadRequest, "Bad Request")
}

func internalServerError(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprintln(w, http.StatusInternalServerError, "Internal Server Error")
}

func requireParam(param string, w http.ResponseWriter, r *http.Request) error {
	if len(r.URL.Query()[param]) == 0 {
		badRequest(w, r)
		return errors.New(fmt.Sprintf("missing %s parameter", param))
	}
	return nil
}

func scanSet(row RowScanner, set *Set) error {
	return row.Scan(
		&set.Id,
		&set.Name,
		&set.PhotosCount,
		&set.TakenAt,
		&set.ThumbPhotoId,
		&set.ThumbPhotoPath,
	)
}

func getSetById(setId int) (set *Set, err error) {
	set = &Set{}
	row := getSetStmt.QueryRow(setId)
	err = scanSet(row, set)
	return
}

func getSets() (sets []*Set, err error) {
	rows, err := getSetsStmt.Query()
	if err != nil {
		return
	}
	defer rows.Close()

	for rows.Next() {
		set := Set{}
		if err = scanSet(rows, &set); err != nil {
			return
		}
		sets = append(sets, &set)
	}

	err = rows.Err()

	return
}

func scanPhoto(row RowScanner, photo *Photo) error {
	return row.Scan(
		&photo.Aperture,
		&photo.Camera,
		&photo.ExposureComp,
		&photo.ExposureTime,
		&photo.Flash,
		&photo.FocalLength,
		&photo.FocalLength35,
		&photo.Height,
		&photo.Id,
		&photo.ISO,
		&photo.Lat,
		&photo.Lens,
		&photo.Lng,
		&photo.NextPhotoId,
		&photo.Path,
		&photo.PrevPhotoId,
		&photo.SetId,
		&photo.Size,
		&photo.TakenAt,
		&photo.Width,
	)
}

func getPhotoById(photoId int) (photo *Photo, err error) {
	photo = &Photo{}
	row := getPhotoStmt.QueryRow(photoId)
	err = scanPhoto(row, photo)
	return
}

func getPhotosBySetId(setId int) (photos []*Photo, err error) {
	rows, err := getPhotosStmt.Query(setId)
	if err != nil {
		return
	}
	defer rows.Close()

	for rows.Next() {
		photo := Photo{}
		if err = scanPhoto(rows, &photo); err != nil {
			return
		}
		photos = append(photos, &photo)
	}

	err = rows.Err()

	return
}

func getSetHandler(w http.ResponseWriter, r *http.Request) {
	if requireParam("id", w, r) != nil {
		return
	}

	setId, err := strconv.Atoi(r.URL.Query()["id"][0])
	if err != nil {
		log.Fatalln("Failed to convert id to integer:", err)
	}

	set, err := getSetById(setId)
	if err == sql.ErrNoRows { // set does not exist
		http.NotFound(w, r)
		return
	}
	if err != nil {
		internalServerError(w, r)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(set)
}

func getSetsHandler(w http.ResponseWriter, r *http.Request) {
	sets, err := getSets()
	if err != nil {
		internalServerError(w, r)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(sets)
}

func getPhotoHandler(w http.ResponseWriter, r *http.Request) {
	if requireParam("id", w, r) != nil {
		return
	}

	photoId, err := strconv.Atoi(r.URL.Query()["id"][0])
	if err != nil {
		log.Fatalln("Failed to convert id to integer:", err)
	}

	photo, err := getPhotoById(photoId)
	if err == sql.ErrNoRows { // photo does not exist
		http.NotFound(w, r)
		return
	}
	if err != nil {
		internalServerError(w, r)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(photo)
}

func getPhotosHandler(w http.ResponseWriter, r *http.Request) {
	if requireParam("set_id", w, r) != nil {
		return
	}

	setId, err := strconv.Atoi(r.URL.Query()["set_id"][0])
	if err != nil {
		log.Fatalln("Failed to convert id to integer:", err)
	}

	photos, err := getPhotosBySetId(setId)
	if err != nil {
		internalServerError(w, r)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(photos)
}

func setupDatabase() {
	db, err := sql.Open("sqlite3", "thyme.db")
	if err != nil {
		log.Fatalln("Failed to open database:", err)
	}

	setAttrs := `sets.id, name, photos_count, sets.taken_at, thumb_photo_id,
	photos.path`

	getSetStmt, err = db.Prepare(fmt.Sprintf(`
	SELECT %s
	FROM sets
	JOIN photos ON sets.thumb_photo_id = photos.id
	WHERE sets.id = ?
	`, setAttrs))
	if err != nil {
		log.Fatalln("Failed to access table:", err)
	}

	getSetsStmt, err = db.Prepare(fmt.Sprintf(`
	SELECT %s
	FROM sets
	JOIN photos ON sets.thumb_photo_id = photos.id
	ORDER BY sets.taken_at DESC
	`, setAttrs))
	if err != nil {
		log.Fatalln("Failed to access table:", err)
	}

	photoAttrs := `aperture, camera, exposure_comp, exposure_time, flash,
	focal_length, focal_length_35, height, id, iso, lat, lens, lng,
	next_photo_id, path, prev_photo_id, set_id, size, taken_at, width`

	getPhotoStmt, err = db.Prepare(fmt.Sprintf(`
	SELECT %s
	FROM photos
	WHERE id = ?
	`, photoAttrs))
	if err != nil {
		log.Fatalln("Failed to access table:", err)
	}

	getPhotosStmt, err = db.Prepare(fmt.Sprintf(`
	SELECT %s
	FROM photos
	WHERE set_id = ?
	`, photoAttrs))
	if err != nil {
		log.Fatalln("Failed to access table:", err)
	}
}

func main() {
	setupDatabase()
	defer db.Close()
	defer getSetStmt.Close()
	defer getSetsStmt.Close()
	defer getPhotoStmt.Close()
	defer getPhotosStmt.Close()

	http.Handle("/", http.FileServer(http.Dir("public"))) // static
	http.HandleFunc("/set", getSetHandler)
	http.HandleFunc("/sets", getSetsHandler)
	http.HandleFunc("/photo", getPhotoHandler)
	http.HandleFunc("/photos", getPhotosHandler)

	fmt.Printf("Listening on http://%s\n", listenAddr)
	fmt.Println("Press Ctrl-C to exit")

	log.Fatal(http.ListenAndServe(listenAddr, handlers.LoggingHandler(os.Stdout, http.DefaultServeMux)))
}
<commit_msg>Reduce number of lines for short SQL queries<commit_after>package main

import (
	"crypto/md5"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"math"
	"math/big"
	"net/http"
	"os"
	"path"
	"strconv"

	"github.com/gorilla/handlers"
	_ "github.com/mattn/go-sqlite3"
)

const (
	listenAddr     = "127.0.0.1:9292"
	bigThumbSize   = 1000
	smallThumbSize = 200
)

var (
	db            *sql.DB
	getSetStmt    *sql.Stmt
	getSetsStmt   *sql.Stmt
	getPhotoStmt  *sql.Stmt
	getPhotosStmt *sql.Stmt
)

type Set struct {
	Id             int
	Name           string
	PhotosCount    int
	TakenAt        sql.NullString
	ThumbPhotoId   int
	ThumbPhotoPath string
}

type Photo struct {
	Aperture      sql.NullFloat64
	Camera        sql.NullString
	ExposureComp  sql.NullInt64
	ExposureTime  sql.NullFloat64
	Flash         sql.NullString
	FocalLength   sql.NullFloat64
	FocalLength35 sql.NullInt64
	Height        int64
	ISO           sql.NullInt64
	Id            int
	Lat           sql.NullFloat64
	Lens          sql.NullString
	Lng           sql.NullFloat64
	NextPhotoId   sql.NullInt64
	Path          string
	PrevPhotoId   sql.NullInt64
	SetId         int
	Size          int
	TakenAt       sql.NullString
	Width         int64
}

// used by scanSet and scanPhoto to accept row(s)
type RowScanner interface {
	Scan(dest ...interface{}) error
}

func thumbURL(photoPath, suffix string) string {
	identifier := fmt.Sprintf("%x", md5.Sum([]byte(photoPath)))
	return fmt.Sprintf("/thumbs/%s_%s.jpg", identifier, suffix)
}

func (s *Set) ThumbURL() string {
	return thumbURL(s.ThumbPhotoPath, "small")
}

func (s *Set) MarshalJSON() ([]byte, error) { // implements Marshaler
	setMap := map[string]interface{}{
		"id":             s.Id,
		"name":           s.Name,
		"photos_count":   s.PhotosCount,
		"thumb_photo_id": s.ThumbPhotoId,
		"thumb_url":      s.ThumbURL(),
	}
	setMap["taken_at"], _ = s.TakenAt.Value()
	return json.Marshal(setMap)
}

func (p *Photo) AspectRatio() [2]int64 {
	gcd := new(big.Int).GCD(nil, nil, big.NewInt(p.Width), big.NewInt(p.Height)).Int64()
	return [2]int64{p.Width / gcd, p.Height / gcd}
}

func (p *Photo) BigThumbHeight() int64 {
	if p.Orientation() == "portrait" {
		if p.Height < bigThumbSize {
			return p.Height
		}

		return bigThumbSize
	}

	aspectRatio := p.AspectRatio()
	return int64(math.Floor((float64(aspectRatio[1])/float64(aspectRatio[0]))*float64(p.BigThumbWidth()) + .5))
}

func (p *Photo) BigThumbWidth() int64 {
	if p.Orientation() == "portrait" {
		aspectRatio := p.AspectRatio()
		return int64(math.Floor((float64(aspectRatio[0])/float64(aspectRatio[1]))*float64(p.BigThumbHeight()) + .5))
	}

	if p.Width < bigThumbSize {
		return p.Width
	}

	return bigThumbSize
}

func (p *Photo) Filename() string {
	return path.Base(p.Path)
}

func (p *Photo) Orientation() string {
	if p.Height > p.Width {
		return "portrait"
	}
	return "landscape"
}

func (p *Photo) ThumbURL(suffix string) string {
	return thumbURL(p.Path, suffix)
}

func (p *Photo) MarshalJSON() ([]byte, error) { // implements Marshaler
	photoMap := map[string]interface{}{
		"aspect_ratio":     p.AspectRatio(),
		"big_thumb_height": p.BigThumbHeight(),
		"big_thumb_url":    p.ThumbURL("big"),
		"big_thumb_width":  p.BigThumbWidth(),
		"filename":         p.Filename(),
		"height":           p.Height,
		"id":               p.Id,
		"orientation":      p.Orientation(),
		"path":             p.Path,
		"set_id":           p.SetId,
		"size":             p.Size,
		"small_thumb_url":  p.ThumbURL("small"),
		"width":            p.Width,
	}

	photoMap["aperture"], _ = p.Aperture.Value()
	photoMap["camera"], _ = p.Camera.Value()
	photoMap["exposure_comp"], _ = p.ExposureComp.Value()
	photoMap["exposure_time"], _ = p.ExposureTime.Value()
	photoMap["flash"], _ = p.Flash.Value()
	photoMap["focal_length"], _ = p.FocalLength.Value()
	photoMap["focal_length_35"], _ = p.FocalLength35.Value()
	photoMap["iso"], _ = p.ISO.Value()
	photoMap["lat"], _ = p.Lat.Value()
	photoMap["lens"], _ = p.Lens.Value()
	photoMap["lng"], _ = p.Lng.Value()
	photoMap["next_photo_id"], _ = p.NextPhotoId.Value()
	photoMap["prev_photo_id"], _ = p.PrevPhotoId.Value()
	photoMap["taken_at"], _ = p.TakenAt.Value()

	return json.Marshal(photoMap)
}

func badRequest(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusBadRequest)
	fmt.Fprintln(w, http.StatusBadRequest, "Bad Request")
}

func internalServerError(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprintln(w, http.StatusInternalServerError, "Internal Server Error")
}

func requireParam(param string, w http.ResponseWriter, r *http.Request) error {
	if len(r.URL.Query()[param]) == 0 {
		badRequest(w, r)
		return errors.New(fmt.Sprintf("missing %s parameter", param))
	}
	return nil
}

func scanSet(row RowScanner, set *Set) error {
	return row.Scan(
		&set.Id,
		&set.Name,
		&set.PhotosCount,
		&set.TakenAt,
		&set.ThumbPhotoId,
		&set.ThumbPhotoPath,
	)
}

func getSetById(setId int) (set *Set, err error) {
	set = &Set{}
	row := getSetStmt.QueryRow(setId)
	err = scanSet(row, set)
	return
}

func getSets() (sets []*Set, err error) {
	rows, err := getSetsStmt.Query()
	if err != nil {
		return
	}
	defer rows.Close()

	for rows.Next() {
		set := Set{}
		if err = scanSet(rows, &set); err != nil {
			return
		}
		sets = append(sets, &set)
	}

	err = rows.Err()

	return
}

func scanPhoto(row RowScanner, photo *Photo) error {
	return row.Scan(
		&photo.Aperture,
		&photo.Camera,
		&photo.ExposureComp,
		&photo.ExposureTime,
		&photo.Flash,
		&photo.FocalLength,
		&photo.FocalLength35,
		&photo.Height,
		&photo.Id,
		&photo.ISO,
		&photo.Lat,
		&photo.Lens,
		&photo.Lng,
		&photo.NextPhotoId,
		&photo.Path,
		&photo.PrevPhotoId,
		&photo.SetId,
		&photo.Size,
		&photo.TakenAt,
		&photo.Width,
	)
}

func getPhotoById(photoId int) (photo *Photo, err error) {
	photo = &Photo{}
	row := getPhotoStmt.QueryRow(photoId)
	err = scanPhoto(row, photo)
	return
}

func getPhotosBySetId(setId int) (photos []*Photo, err error) {
	rows, err := getPhotosStmt.Query(setId)
	if err != nil {
		return
	}
	defer rows.Close()

	for rows.Next() {
		photo := Photo{}
		if err = scanPhoto(rows, &photo); err != nil {
			return
		}
		photos = append(photos, &photo)
	}

	err = rows.Err()

	return
}

func getSetHandler(w http.ResponseWriter, r *http.Request) {
	if requireParam("id", w, r) != nil {
		return
	}

	setId, err := strconv.Atoi(r.URL.Query()["id"][0])
	if err != nil {
		log.Fatalln("Failed to convert id to integer:", err)
	}

	set, err := getSetById(setId)
	if err == sql.ErrNoRows { // set does not exist
		http.NotFound(w, r)
		return
	}
	if err != nil {
		internalServerError(w, r)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(set)
}

func getSetsHandler(w http.ResponseWriter, r *http.Request) {
	sets, err := getSets()
	if err != nil {
		internalServerError(w, r)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(sets)
}

func getPhotoHandler(w http.ResponseWriter, r *http.Request) {
	if requireParam("id", w, r) != nil {
		return
	}

	photoId, err := strconv.Atoi(r.URL.Query()["id"][0])
	if err != nil {
		log.Fatalln("Failed to convert id to integer:", err)
	}

	photo, err := getPhotoById(photoId)
	if err == sql.ErrNoRows { // photo does not exist
		http.NotFound(w, r)
		return
	}
	if err != nil {
		internalServerError(w, r)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(photo)
}

func getPhotosHandler(w http.ResponseWriter, r *http.Request) {
	if requireParam("set_id", w, r) != nil {
		return
	}

	setId, err := strconv.Atoi(r.URL.Query()["set_id"][0])
	if err != nil {
		log.Fatalln("Failed to convert id to integer:", err)
	}

	photos, err := getPhotosBySetId(setId)
	if err != nil {
		internalServerError(w, r)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(photos)
}

func setupDatabase() {
	db, err := sql.Open("sqlite3", "thyme.db")
	if err != nil {
		log.Fatalln("Failed to open database:", err)
	}

	setAttrs := `sets.id, name, photos_count, sets.taken_at, thumb_photo_id,
	photos.path`

	getSetStmt, err = db.Prepare(fmt.Sprintf(`
	SELECT %s FROM sets
	JOIN photos ON sets.thumb_photo_id = photos.id
	WHERE sets.id = ?
	`, setAttrs))
	if err != nil {
		log.Fatalln("Failed to access table:", err)
	}

	getSetsStmt, err = db.Prepare(fmt.Sprintf(`
	SELECT %s FROM sets
	JOIN photos ON sets.thumb_photo_id = photos.id
	ORDER BY sets.taken_at DESC
	`, setAttrs))
	if err != nil {
		log.Fatalln("Failed to access table:", err)
	}

	photoAttrs := `aperture, camera, exposure_comp, exposure_time, flash,
	focal_length, focal_length_35, height, id, iso, lat, lens, lng,
	next_photo_id, path, prev_photo_id, set_id, size, taken_at, width`

	getPhotoStmt, err = db.Prepare(fmt.Sprintf(`
	SELECT %s FROM photos WHERE id = ?
	`, photoAttrs))
	if err != nil {
		log.Fatalln("Failed to access table:", err)
	}

	getPhotosStmt, err = db.Prepare(fmt.Sprintf(`
	SELECT %s FROM photos WHERE set_id = ?
	`, photoAttrs))
	if err != nil {
		log.Fatalln("Failed to access table:", err)
	}
}

func main() {
	setupDatabase()
	defer db.Close()
	defer getSetStmt.Close()
	defer getSetsStmt.Close()
	defer getPhotoStmt.Close()
	defer getPhotosStmt.Close()

	http.Handle("/", http.FileServer(http.Dir("public"))) // static
	http.HandleFunc("/set", getSetHandler)
	http.HandleFunc("/sets", getSetsHandler)
	http.HandleFunc("/photo", getPhotoHandler)
	http.HandleFunc("/photos", getPhotosHandler)

	fmt.Printf("Listening on http://%s\n", listenAddr)
	fmt.Println("Press Ctrl-C to exit")

	log.Fatal(http.ListenAndServe(listenAddr, handlers.LoggingHandler(os.Stdout, http.DefaultServeMux)))
}
<|endoftext|>


<commit_before>package config

const (
	// Special env name for vagrant
	VagrantEnvName = "vagrant"
)

type (
	// Config holds all the configuration variables of socialapi
	Config struct {
		// Postres holds connection credentials for postgresql
		Postgres Postgres

		// Mq holds connction credentials for rabbitmq
		Mq Mq

		// Redis holds connection string for redis
		Redis Redis

		// Mongo holds full connection string
		Mongo string `env:"key=KONFIG_SOCIALAPI_MONGO                                 required"`

		// Environment holds the environment of the the running application
		Environment string `env:"key=KONFIG_SOCIALAPI_ENVIRONMENT                     required"`

		// Region holds the region of the the running application
		Region string `env:"key=KONFIG_SOCIALAPI_REGION                               required"`

		// Hostname is the web end point the app
		Hostname string `env:"key=KONFIG_SOCIALAPI_HOSTNAME                           required"`

		// Protocol holds used protocol information
		Protocol string `env:"key=KONFIG_SOCIALAPI_PROTOCOL                           required"`

		// Email holds the required configuration data for email related workers
		Email Email

		// Sitemap holds configuration for Sitemap workers
		Sitemap Sitemap

		// Algolia holds configuration parameters for Aloglia search engine
		Algolia Algolia

		// Mixpanel holds configuration parameters for mixpanel
		Mixpanel Mixpanel

		// Limits holds limits for various cases
		Limits Limits

		Stripe Stripe

		// random access configs
		EventExchangeName string `env:"key=KONFIG_SOCIALAPI_EVENTEXCHANGENAME               required  default=BrokerMessageBus"`
		DisableCaching    bool   `env:"key=KONFIG_SOCIALAPI_DISABLECACHING                  required  default=false"`
		Debug             bool   `env:"key=KONFIG_SOCIALAPI_DEBUG 					       		      default=false"`

		// just a temp hack
		Host string
		Port string
	}

	// Postgres holds Postgresql database related configuration
	Postgres struct {
		Host     string `env:"key=KONFIG_SOCIALAPI_POSTGRES_HOST                            required"`
		Port     int    `env:"key=KONFIG_SOCIALAPI_POSTGRES_PORT                            required  default=5432"`
		Username string `env:"key=KONFIG_SOCIALAPI_POSTGRES_USERNAME                        required  default=socialapplication"`
		Password string `env:"key=KONFIG_SOCIALAPI_POSTGRES_PASSWORD                        required  default=socialapplication"`
		DBName   string `env:"key=KONFIG_SOCIALAPI_POSTGRES_DBNAME                          required  default=social"`
	}

	// Mq holds Rabbitmq related configuration
	Mq struct {
		Host     string `env:"key=KONFIG_SOCIALAPI_MQ_HOST                                  required"`
		Port     int    `env:"key=KONFIG_SOCIALAPI_MQ_PORT                                  required"`
		Login    string `env:"key=KONFIG_SOCIALAPI_MQ_LOGIN                                 required"`
		Password string `env:"key=KONFIG_SOCIALAPI_MQ_PASSWORD                              required"`
		Vhost    string `env:"key=KONFIG_SOCIALAPI_MQ_VHOST                                 required"`
	}

	// Redis holds Redis related config
	Redis struct {
		URL string `env:"key=KONFIG_SOCIALAPI_REDIS_URL                                    required"`
		DB  int    `env:"key=KONFIG_SOCIALAPI_REDIS_DB                                                  default=0"`
	}

	// Email holds Email Workers' config
	Email struct {
		Host            string `env:"key=KONFIG_SOCIALAPI_EMAIL_HOST                     required"`
		Protocol        string `env:"key=KONFIG_SOCIALAPI_EMAIL_PROTOCOL                 required"`
		DefaultFromMail string `env:"key=KONFIG_SOCIALAPI_EMAIL_DEFAULTFROMMAIL          required"`
		DefaultFromName string `env:"key=KONFIG_SOCIALAPI_EMAIL_DEFAULTFROMNAME          required"`
		ForcedRecipient string `env:"key=KONFIG_SOCIALAPI_EMAIL_FORCEDRECIPIENT"`
		Username        string `env:"key=KONFIG_SOCIALAPI_EMAIL_USERNAME                 required"`
		Password        string `env:"key=KONFIG_SOCIALAPI_EMAIL_PASSWORD                 required"`
		TemplateRoot    string `env:"key=KONFIG_SOCIALAPI_EMAIL_TEMPLATEROOT 	        default=workers/sitemap/files/"`
	}

	// Sitemap holds Sitemap Workers' config
	Sitemap struct {
		RedisDB int `env:"key=KONFIG_SOCIALAPI_SITEMAP_REDISDB"`
	}

	// Algolia holds Algolia service credentials
	Algolia struct {
		AppId        string `env:"key=KONFIG_SOCIALAPI_ALGOLIA_APPID                        required"`
		ApiKey       string `env:"key=KONFIG_SOCIALAPI_ALGOLIA_APIKEY                       required"`
		ApiSecretKey string `env:"key=KONFIG_SOCIALAPI_ALGOLIA_APISECRETKEY                 required"`
		IndexSuffix  string `env:"key=KONFIG_SOCIALAPI_ALGOLIA_INDEXSUFFIX                  required"`
	}

	// Mixpanel holds mixpanel credentials
	Mixpanel struct {
		Token   string `env:"key=KONFIG_SOCIALAPI_MIXPANEL_TOKEN                            required"`
		Enabled bool   `env:"key=KONFIG_SOCIALAPI_MIXPANEL_ENABLED"`
	}

	// Limits holds application's various limits
	Limits struct {
		MessageBodyMinLen    int    `env:"key=KONFIG_SOCIALAPI_LIMITS_MESSAGEBODYMINLEN     required default=1"`
		PostThrottleDuration string `env:"key=KONFIG_SOCIALAPI_LIMITS_POSTTHROTTLEDURATION  required default=5s"`
		PostThrottleCount    int    `env:"key=KONFIG_SOCIALAPI_LIMITS_POSTTHROTTLECOUNT     required default=20"`
	}

	Stripe struct {
		SecretToken string `env:"key=KONFIG_SOCIALAPI_STRIPE_SECRETTOKEN"`
	}
)
<commit_msg>Social: we don't need vagrant env now<commit_after>package config

type (
	// Config holds all the configuration variables of socialapi
	Config struct {
		// Postres holds connection credentials for postgresql
		Postgres Postgres

		// Mq holds connction credentials for rabbitmq
		Mq Mq

		// Redis holds connection string for redis
		Redis Redis

		// Mongo holds full connection string
		Mongo string `env:"key=KONFIG_SOCIALAPI_MONGO                                 required"`

		// Environment holds the environment of the the running application
		Environment string `env:"key=KONFIG_SOCIALAPI_ENVIRONMENT                     required"`

		// Region holds the region of the the running application
		Region string `env:"key=KONFIG_SOCIALAPI_REGION                               required"`

		// Hostname is the web end point the app
		Hostname string `env:"key=KONFIG_SOCIALAPI_HOSTNAME                           required"`

		// Protocol holds used protocol information
		Protocol string `env:"key=KONFIG_SOCIALAPI_PROTOCOL                           required"`

		// Email holds the required configuration data for email related workers
		Email Email

		// Sitemap holds configuration for Sitemap workers
		Sitemap Sitemap

		// Algolia holds configuration parameters for Aloglia search engine
		Algolia Algolia

		// Mixpanel holds configuration parameters for mixpanel
		Mixpanel Mixpanel

		// Limits holds limits for various cases
		Limits Limits

		Stripe Stripe

		// random access configs
		EventExchangeName string `env:"key=KONFIG_SOCIALAPI_EVENTEXCHANGENAME               required  default=BrokerMessageBus"`
		DisableCaching    bool   `env:"key=KONFIG_SOCIALAPI_DISABLECACHING                  required  default=false"`
		Debug             bool   `env:"key=KONFIG_SOCIALAPI_DEBUG 					       		      default=false"`

		// just a temp hack
		Host string
		Port string
	}

	// Postgres holds Postgresql database related configuration
	Postgres struct {
		Host     string `env:"key=KONFIG_SOCIALAPI_POSTGRES_HOST                            required"`
		Port     int    `env:"key=KONFIG_SOCIALAPI_POSTGRES_PORT                            required  default=5432"`
		Username string `env:"key=KONFIG_SOCIALAPI_POSTGRES_USERNAME                        required  default=socialapplication"`
		Password string `env:"key=KONFIG_SOCIALAPI_POSTGRES_PASSWORD                        required  default=socialapplication"`
		DBName   string `env:"key=KONFIG_SOCIALAPI_POSTGRES_DBNAME                          required  default=social"`
	}

	// Mq holds Rabbitmq related configuration
	Mq struct {
		Host     string `env:"key=KONFIG_SOCIALAPI_MQ_HOST                                  required"`
		Port     int    `env:"key=KONFIG_SOCIALAPI_MQ_PORT                                  required"`
		Login    string `env:"key=KONFIG_SOCIALAPI_MQ_LOGIN                                 required"`
		Password string `env:"key=KONFIG_SOCIALAPI_MQ_PASSWORD                              required"`
		Vhost    string `env:"key=KONFIG_SOCIALAPI_MQ_VHOST                                 required"`
	}

	// Redis holds Redis related config
	Redis struct {
		URL string `env:"key=KONFIG_SOCIALAPI_REDIS_URL                                    required"`
		DB  int    `env:"key=KONFIG_SOCIALAPI_REDIS_DB                                                  default=0"`
	}

	// Email holds Email Workers' config
	Email struct {
		Host            string `env:"key=KONFIG_SOCIALAPI_EMAIL_HOST                     required"`
		Protocol        string `env:"key=KONFIG_SOCIALAPI_EMAIL_PROTOCOL                 required"`
		DefaultFromMail string `env:"key=KONFIG_SOCIALAPI_EMAIL_DEFAULTFROMMAIL          required"`
		DefaultFromName string `env:"key=KONFIG_SOCIALAPI_EMAIL_DEFAULTFROMNAME          required"`
		ForcedRecipient string `env:"key=KONFIG_SOCIALAPI_EMAIL_FORCEDRECIPIENT"`
		Username        string `env:"key=KONFIG_SOCIALAPI_EMAIL_USERNAME                 required"`
		Password        string `env:"key=KONFIG_SOCIALAPI_EMAIL_PASSWORD                 required"`
		TemplateRoot    string `env:"key=KONFIG_SOCIALAPI_EMAIL_TEMPLATEROOT 	        default=workers/sitemap/files/"`
	}

	// Sitemap holds Sitemap Workers' config
	Sitemap struct {
		RedisDB int `env:"key=KONFIG_SOCIALAPI_SITEMAP_REDISDB"`
	}

	// Algolia holds Algolia service credentials
	Algolia struct {
		AppId        string `env:"key=KONFIG_SOCIALAPI_ALGOLIA_APPID                        required"`
		ApiKey       string `env:"key=KONFIG_SOCIALAPI_ALGOLIA_APIKEY                       required"`
		ApiSecretKey string `env:"key=KONFIG_SOCIALAPI_ALGOLIA_APISECRETKEY                 required"`
		IndexSuffix  string `env:"key=KONFIG_SOCIALAPI_ALGOLIA_INDEXSUFFIX                  required"`
	}

	// Mixpanel holds mixpanel credentials
	Mixpanel struct {
		Token   string `env:"key=KONFIG_SOCIALAPI_MIXPANEL_TOKEN                            required"`
		Enabled bool   `env:"key=KONFIG_SOCIALAPI_MIXPANEL_ENABLED"`
	}

	// Limits holds application's various limits
	Limits struct {
		MessageBodyMinLen    int    `env:"key=KONFIG_SOCIALAPI_LIMITS_MESSAGEBODYMINLEN     required default=1"`
		PostThrottleDuration string `env:"key=KONFIG_SOCIALAPI_LIMITS_POSTTHROTTLEDURATION  required default=5s"`
		PostThrottleCount    int    `env:"key=KONFIG_SOCIALAPI_LIMITS_POSTTHROTTLECOUNT     required default=20"`
	}

	Stripe struct {
		SecretToken string `env:"key=KONFIG_SOCIALAPI_STRIPE_SECRETTOKEN"`
	}
)
<|endoftext|>