<commit_before>package common

import (
	"github.com/EngoEngine/ecs"
	"github.com/EngoEngine/engo"
	"github.com/EngoEngine/gl"
	"image/color"
	"sort"
	"sync"
	"unsafe"
)

const (
	// RenderSystemPriority is the priority of the RenderSystem
	RenderSystemPriority = -1000
)

type renderChangeMessage struct{}

func (renderChangeMessage) Type() string {
	return "renderChangeMessage"
}

// Drawable is that which can be rendered to OpenGL.
type Drawable interface {
	Texture() *gl.Texture
	Width() float32
	Height() float32
	View() (float32, float32, float32, float32)
	Close()
}

// TextureRepeating is the method used to repeat a texture in OpenGL.
type TextureRepeating uint8

const (
	// NoRepeat does not repeat the texture.
	NoRepeat TextureRepeating = iota
	// ClampToEdge stretches the texture to the edge of the viewport.
	ClampToEdge
	// ClampToBorder stretches the texture to the border of the viewpport.
	ClampToBorder
	// Repeat repeats the texture until the border of the viewport.
	Repeat
	// MirroredRepeat repeats a mirror image of the texture until the border of the viewport.
	MirroredRepeat
)

// ZoomFilter is a filter used when zooming in or out of a texture.
type ZoomFilter uint8

const (
	// FilterNearest is a simple nearest neighbor algorithm
	FilterNearest ZoomFilter = iota
	// FilterLinear is a bilinear interpolation algorithm
	FilterLinear
)

// RenderComponent is the component needed to render an entity.
type RenderComponent struct {
	// Hidden is used to prevent drawing by OpenGL
	Hidden bool
	// Scale is the scale at which to render, in the X and Y axis. Not defining Scale, will default to engo.Point{1, 1}
	Scale engo.Point
	// Color defines how much of the color-components of the texture get used
	Color color.Color
	// Drawable refers to the Texture that should be drawn
	Drawable Drawable
	// Repeat defines how to repeat the Texture if the SpaceComponent of the entity
	// is larger than the texture itself, after applying scale. Defaults to NoRepeat
	// which allows the texture to draw entirely without regard to th SpaceComponent
	// Do not set to anything other than NoRepeat for textures in a sprite sheet.
	// This does not yet work with sprite sheets.
	Repeat TextureRepeating
	// Buffer represents the buffer object itself
	// Avoid using it unless your are writing a custom shader
	Buffer *gl.Buffer
	// BufferContent contains the buffer data
	// Avoid using it unless your are writing a custom shader
	BufferContent []float32
	// StartZIndex defines the initial Z-Index. Z-Index defines the order which the content is drawn to the
	// screen. Higher z-indices are drawn on top of lower ones. Beware that you must use `SetZIndex` function to change
	// the Z-Index.
	StartZIndex float32

	magFilter, minFilter ZoomFilter

	shader Shader
	zIndex float32
}

// SetShader sets the shader used by the RenderComponent.
func (r *RenderComponent) SetShader(s Shader) {
	r.shader = s
	engo.Mailbox.Dispatch(&renderChangeMessage{})
}

func (r *RenderComponent) ensureShader() {
	// Setting default shader
	if r.shader == nil {
		switch r.Drawable.(type) {
		case Triangle:
			r.shader = LegacyShader
		case Circle:
			r.shader = LegacyShader
		case Rectangle:
			r.shader = LegacyShader
		case ComplexTriangles:
			r.shader = LegacyShader
		case Text:
			r.shader = TextShader
		case Blendmap:
			r.shader = BlendmapShader
		default:
			r.shader = DefaultShader
		}
	}
}

func (r *RenderComponent) Shader() Shader {
	r.ensureShader()
	return r.shader
}

// SetZIndex sets the order that the RenderComponent is drawn to the screen. Higher z-indices are drawn on top of
// lower ones if they overlap.
func (r *RenderComponent) SetZIndex(index float32) {
	r.zIndex = index
	engo.Mailbox.Dispatch(&renderChangeMessage{})
}

// SetMinFilter sets the ZoomFilter used for minimizing the RenderComponent
func (r *RenderComponent) SetMinFilter(z ZoomFilter) {
	r.minFilter = z
	engo.Mailbox.Dispatch(renderChangeMessage{})
}

// SetMagFilter sets the ZoomFilter used for magnifying the RenderComponent
func (r *RenderComponent) SetMagFilter(z ZoomFilter) {
	r.magFilter = z
	engo.Mailbox.Dispatch(renderChangeMessage{})
}

type renderEntity struct {
	*ecs.BasicEntity
	*RenderComponent
	*SpaceComponent
}

type renderEntityList []renderEntity

func (r renderEntityList) Len() int {
	return len(r)
}

func (r renderEntityList) Less(i, j int) bool {
	// Sort by shader-pointer if they have the same zIndex
	if r[i].RenderComponent.zIndex != r[j].RenderComponent.zIndex {
		return r[i].RenderComponent.zIndex < r[j].RenderComponent.zIndex
	}

	p1, p2 := getShadersPtr(r[i].RenderComponent.shader, r[j].RenderComponent.shader)
	if p1 != p2 {
		return p1 < p2
	}

	switch r[i].RenderComponent.Drawable.(type) {
	// Tiles can either be as a spriteSheet or as separate image
	// if we sort them by texture and they're saved as separate images,
	// sorting by texture messes up rendering.
	case *Tile:
		// NO-OP
	default:
		t1, t2 := uintptr(unsafe.Pointer(r[i].RenderComponent.Drawable.Texture())), uintptr(unsafe.Pointer(r[j].RenderComponent.Drawable.Texture()))
		if t1 != t2 {
			return t1 < t2
		}
	}

	// Sort by minFilter if they're the same magFilter
	mag1, mag2 := r[i].RenderComponent.magFilter, r[j].RenderComponent.magFilter
	if mag1 != mag2 {
		return mag1 < mag2
	}

	// Sort by position if they're the same minFilter
	min1, min2 := r[i].RenderComponent.minFilter, r[j].RenderComponent.minFilter
	if min1 != min2 {
		return min1 < min2
	}

	if r[i].Position.Y != r[j].Position.Y {
		return r[i].Position.Y < r[j].Position.Y
	}

	return r[i].Position.X < r[j].Position.X
}

func (r renderEntityList) Swap(i, j int) {
	r[i], r[j] = r[j], r[i]
}

// RenderSystem is the system that draws entities on the OpenGL surface. It requires
// a CameraSystem to work. If a CameraSystem is not in the World when you add RenderSystem
// one is automatically added to the world.
type RenderSystem struct {
	entities renderEntityList
	ids      map[uint64]struct{}
	world    *ecs.World

	sortingNeeded, newCamera bool
}

// Priority implements the ecs.Prioritizer interface.
func (*RenderSystem) Priority() int { return RenderSystemPriority }

// New initializes the RenderSystem
func (rs *RenderSystem) New(w *ecs.World) {
	rs.world = w
	rs.ids = make(map[uint64]struct{})

	engo.Mailbox.Listen("NewCameraMessage", func(engo.Message) {
		rs.newCamera = true
	})

	addCameraSystemOnce(w)

	if !engo.Headless() {
		if err := initShaders(w); err != nil {
			panic(err)
		}
		engo.Gl.Enable(engo.Gl.MULTISAMPLE)
	}

	engo.Mailbox.Listen("renderChangeMessage", func(engo.Message) {
		rs.sortingNeeded = true
	})
}

var cameraInitMutex sync.Mutex

func addCameraSystemOnce(w *ecs.World) {
	cameraInitMutex.Lock()
	defer cameraInitMutex.Unlock()

	camSystemAlreadyAdded := false
	for _, system := range w.Systems() {
		switch system.(type) {
		case *CameraSystem:
			camSystemAlreadyAdded = true
		}
	}
	if !camSystemAlreadyAdded {
		w.AddSystem(&CameraSystem{})
	}
}

// Add adds an entity to the RenderSystem. The entity needs a basic, render, and space component to be added to the system.
func (rs *RenderSystem) Add(basic *ecs.BasicEntity, render *RenderComponent, space *SpaceComponent) {
	// Do nothing if entity already exists
	if _, ok := rs.ids[basic.ID()]; ok {
		return
	}

	rs.ids[basic.ID()] = struct{}{}

	render.ensureShader()

	// This is to prevent users from using the wrong one
	if render.shader == HUDShader {
		switch render.Drawable.(type) {
		case Triangle:
			render.shader = LegacyHUDShader
		case Circle:
			render.shader = LegacyHUDShader
		case Rectangle:
			render.shader = LegacyHUDShader
		case ComplexTriangles:
			render.shader = LegacyHUDShader
		case Text:
			render.shader = TextHUDShader
		default:
			render.shader = HUDShader
		}
	}

	// If the scale is zero, set it to one.
	if render.Scale.X == 0 {
		render.Scale.X = 1
	}
	if render.Scale.Y == 0 {
		render.Scale.Y = 1
	}

	render.zIndex = render.StartZIndex

	rs.entities = append(rs.entities, renderEntity{basic, render, space})
	rs.sortingNeeded = true
}

// EntityExists looks if the entity is already into the System's entities. It will return the index >= 0 of the object into de rs.entities or -1 if it could not be found.
func (rs *RenderSystem) EntityExists(basic *ecs.BasicEntity) int {
	for index, entity := range rs.entities {
		if entity.ID() == basic.ID() {
			return index
		}
	}

	return -1
}

// AddByInterface adds any Renderable to the render system. Any Entity containing a BasicEntity,RenderComponent, and SpaceComponent anonymously does this automatically
func (rs *RenderSystem) AddByInterface(i ecs.Identifier) {
	o, _ := i.(Renderable)
	rs.Add(o.GetBasicEntity(), o.GetRenderComponent(), o.GetSpaceComponent())
}

// Remove removes an entity from the RenderSystem
func (rs *RenderSystem) Remove(basic ecs.BasicEntity) {
	var d = rs.EntityExists(&basic)
	if d >= 0 {
		rs.entities = append(rs.entities[:d], rs.entities[d+1:]...)
		rs.sortingNeeded = true
	}
	delete(rs.ids, basic.ID())
}

// Update draws the entities in the RenderSystem to the OpenGL Surface.
func (rs *RenderSystem) Update(dt float32) {
	if engo.Headless() {
		return
	}

	if rs.sortingNeeded {
		sort.Sort(rs.entities)
		rs.sortingNeeded = false
	}

	if rs.newCamera {
		newCamera(rs.world)
		rs.newCamera = false
	}

	engo.Gl.Clear(engo.Gl.COLOR_BUFFER_BIT)

	preparedCullingShaders := make(map[CullingShader]struct{})
	var cullingShader CullingShader // current culling shader
	var prevShader Shader           // shader of the previous entity
	var currentShader Shader        // currently "active" shader

	// TODO: it's linear for now, but that might very well be a bad idea
	for _, e := range rs.entities {
		if e.RenderComponent.Hidden {
			continue // with other entities
		}

		// Retrieve a shader, may be the default one -- then use it if we aren't already using it
		shader := e.RenderComponent.shader

		if !compareShaders(shader, prevShader) {
			// to increase performance avoid the type assertions when possible
			prevShader = shader
			if cs, ok := shader.(CullingShader); ok {
				cullingShader = cs
				if _, isPrepared := preparedCullingShaders[cullingShader]; !isPrepared {
					cullingShader.PrepareCulling()
					preparedCullingShaders[cullingShader] = struct{}{}
				}
			} else {
				cullingShader = nil
			}
		}

		if cullingShader != nil && !cullingShader.ShouldDraw(e.RenderComponent, e.SpaceComponent) {
			continue
		}

		// Change Shader if we have to
		if !compareShaders(shader, currentShader) {
			if currentShader != nil {
				currentShader.Post()
			}
			shader.Pre()
			currentShader = shader
		}

		// Setting default scale to 1
		if e.RenderComponent.Scale.X == 0 && e.RenderComponent.Scale.Y == 0 {
			e.RenderComponent.Scale = engo.Point{X: 1, Y: 1}
		}

		// Setting default to white
		if e.RenderComponent.Color == nil {
			e.RenderComponent.Color = color.White
		}

		currentShader.Draw(e.RenderComponent, e.SpaceComponent)
	}

	if currentShader != nil {
		currentShader.Post()
	}
}

// SetBackground sets the OpenGL ClearColor to the provided color.
func SetBackground(c color.Color) {
	if !engo.Headless() {
		r, g, b, a := c.RGBA()

		engo.Gl.ClearColor(float32(r)/0xffff, float32(g)/0xffff, float32(b)/0xffff, float32(a)/0xffff)
	}
}
<commit_msg>fix z-index<commit_after>package common

import (
	"github.com/EngoEngine/ecs"
	"github.com/EngoEngine/engo"
	"github.com/EngoEngine/gl"
	"image/color"
	"sort"
	"sync"
	"unsafe"
)

const (
	// RenderSystemPriority is the priority of the RenderSystem
	RenderSystemPriority = -1000
)

type renderChangeMessage struct{}

func (renderChangeMessage) Type() string {
	return "renderChangeMessage"
}

// Drawable is that which can be rendered to OpenGL.
type Drawable interface {
	Texture() *gl.Texture
	Width() float32
	Height() float32
	View() (float32, float32, float32, float32)
	Close()
}

// TextureRepeating is the method used to repeat a texture in OpenGL.
type TextureRepeating uint8

const (
	// NoRepeat does not repeat the texture.
	NoRepeat TextureRepeating = iota
	// ClampToEdge stretches the texture to the edge of the viewport.
	ClampToEdge
	// ClampToBorder stretches the texture to the border of the viewpport.
	ClampToBorder
	// Repeat repeats the texture until the border of the viewport.
	Repeat
	// MirroredRepeat repeats a mirror image of the texture until the border of the viewport.
	MirroredRepeat
)

// ZoomFilter is a filter used when zooming in or out of a texture.
type ZoomFilter uint8

const (
	// FilterNearest is a simple nearest neighbor algorithm
	FilterNearest ZoomFilter = iota
	// FilterLinear is a bilinear interpolation algorithm
	FilterLinear
)

// RenderComponent is the component needed to render an entity.
type RenderComponent struct {
	// Hidden is used to prevent drawing by OpenGL
	Hidden bool
	// Scale is the scale at which to render, in the X and Y axis. Not defining Scale, will default to engo.Point{1, 1}
	Scale engo.Point
	// Color defines how much of the color-components of the texture get used
	Color color.Color
	// Drawable refers to the Texture that should be drawn
	Drawable Drawable
	// Repeat defines how to repeat the Texture if the SpaceComponent of the entity
	// is larger than the texture itself, after applying scale. Defaults to NoRepeat
	// which allows the texture to draw entirely without regard to th SpaceComponent
	// Do not set to anything other than NoRepeat for textures in a sprite sheet.
	// This does not yet work with sprite sheets.
	Repeat TextureRepeating
	// Buffer represents the buffer object itself
	// Avoid using it unless your are writing a custom shader
	Buffer *gl.Buffer
	// BufferContent contains the buffer data
	// Avoid using it unless your are writing a custom shader
	BufferContent []float32
	// StartZIndex defines the initial Z-Index. Z-Index defines the order which the content is drawn to the
	// screen. Higher z-indices are drawn on top of lower ones. Beware that you must use `SetZIndex` function to change
	// the Z-Index.
	StartZIndex float32

	magFilter, minFilter ZoomFilter

	shader Shader
	zIndex float32
}

// SetShader sets the shader used by the RenderComponent.
func (r *RenderComponent) SetShader(s Shader) {
	r.shader = s
	engo.Mailbox.Dispatch(&renderChangeMessage{})
}

func (r *RenderComponent) ensureShader() {
	// Setting default shader
	if r.shader == nil {
		switch r.Drawable.(type) {
		case Triangle:
			r.shader = LegacyShader
		case Circle:
			r.shader = LegacyShader
		case Rectangle:
			r.shader = LegacyShader
		case ComplexTriangles:
			r.shader = LegacyShader
		case Text:
			r.shader = TextShader
		case Blendmap:
			r.shader = BlendmapShader
		default:
			r.shader = DefaultShader
		}
	}
}

func (r *RenderComponent) Shader() Shader {
	r.ensureShader()
	return r.shader
}

// SetZIndex sets the order that the RenderComponent is drawn to the screen. Higher z-indices are drawn on top of
// lower ones if they overlap.
func (r *RenderComponent) SetZIndex(index float32) {
	r.zIndex = index
	engo.Mailbox.Dispatch(&renderChangeMessage{})
}

// SetMinFilter sets the ZoomFilter used for minimizing the RenderComponent
func (r *RenderComponent) SetMinFilter(z ZoomFilter) {
	r.minFilter = z
	engo.Mailbox.Dispatch(renderChangeMessage{})
}

// SetMagFilter sets the ZoomFilter used for magnifying the RenderComponent
func (r *RenderComponent) SetMagFilter(z ZoomFilter) {
	r.magFilter = z
	engo.Mailbox.Dispatch(renderChangeMessage{})
}

type renderEntity struct {
	*ecs.BasicEntity
	*RenderComponent
	*SpaceComponent
}

type renderEntityList []renderEntity

func (r renderEntityList) Len() int {
	return len(r)
}

func (r renderEntityList) Less(i, j int) bool {
	// Sort by shader-pointer if they have the same zIndex
	if r[i].RenderComponent.zIndex != r[j].RenderComponent.zIndex {
		return r[i].RenderComponent.zIndex < r[j].RenderComponent.zIndex
	}

	p1, p2 := getShadersPtr(r[i].RenderComponent.shader, r[j].RenderComponent.shader)
	if p1 != p2 {
		return p1 < p2
	}

	switch r[i].RenderComponent.Drawable.(type) {
	// Tiles can either be as a spriteSheet or as separate image
	// if we sort them by texture and they're saved as separate images,
	// sorting by texture messes up rendering.
	case *Tile:
		// NO-OP
	default:
		t1, t2 := uintptr(unsafe.Pointer(r[i].RenderComponent.Drawable.Texture())), uintptr(unsafe.Pointer(r[j].RenderComponent.Drawable.Texture()))
		if t1 != t2 {
			return t1 < t2
		}
	}

	// Sort by minFilter if they're the same magFilter
	mag1, mag2 := r[i].RenderComponent.magFilter, r[j].RenderComponent.magFilter
	if mag1 != mag2 {
		return mag1 < mag2
	}

	// Sort by position if they're the same minFilter
	min1, min2 := r[i].RenderComponent.minFilter, r[j].RenderComponent.minFilter
	if min1 != min2 {
		return min1 < min2
	}

	if r[i].Position.Y != r[j].Position.Y {
		return r[i].Position.Y < r[j].Position.Y
	}

	return r[i].Position.X < r[j].Position.X
}

func (r renderEntityList) Swap(i, j int) {
	r[i], r[j] = r[j], r[i]
}

// RenderSystem is the system that draws entities on the OpenGL surface. It requires
// a CameraSystem to work. If a CameraSystem is not in the World when you add RenderSystem
// one is automatically added to the world.
type RenderSystem struct {
	entities renderEntityList
	ids      map[uint64]struct{}
	world    *ecs.World

	sortingNeeded, newCamera bool
}

// Priority implements the ecs.Prioritizer interface.
func (*RenderSystem) Priority() int { return RenderSystemPriority }

// New initializes the RenderSystem
func (rs *RenderSystem) New(w *ecs.World) {
	rs.world = w
	rs.ids = make(map[uint64]struct{})

	engo.Mailbox.Listen("NewCameraMessage", func(engo.Message) {
		rs.newCamera = true
	})

	addCameraSystemOnce(w)

	if !engo.Headless() {
		if err := initShaders(w); err != nil {
			panic(err)
		}
		engo.Gl.Enable(engo.Gl.MULTISAMPLE)
	}

	engo.Mailbox.Listen("renderChangeMessage", func(engo.Message) {
		rs.sortingNeeded = true
	})
}

var cameraInitMutex sync.Mutex

func addCameraSystemOnce(w *ecs.World) {
	cameraInitMutex.Lock()
	defer cameraInitMutex.Unlock()

	camSystemAlreadyAdded := false
	for _, system := range w.Systems() {
		switch system.(type) {
		case *CameraSystem:
			camSystemAlreadyAdded = true
		}
	}
	if !camSystemAlreadyAdded {
		w.AddSystem(&CameraSystem{})
	}
}

// Add adds an entity to the RenderSystem. The entity needs a basic, render, and space component to be added to the system.
func (rs *RenderSystem) Add(basic *ecs.BasicEntity, render *RenderComponent, space *SpaceComponent) {
	// Do nothing if entity already exists
	if _, ok := rs.ids[basic.ID()]; ok {
		return
	}

	rs.ids[basic.ID()] = struct{}{}

	render.ensureShader()

	// This is to prevent users from using the wrong one
	if render.shader == HUDShader {
		switch render.Drawable.(type) {
		case Triangle:
			render.shader = LegacyHUDShader
		case Circle:
			render.shader = LegacyHUDShader
		case Rectangle:
			render.shader = LegacyHUDShader
		case ComplexTriangles:
			render.shader = LegacyHUDShader
		case Text:
			render.shader = TextHUDShader
		default:
			render.shader = HUDShader
		}
	}

	// If the scale is zero, set it to one.
	if render.Scale.X == 0 {
		render.Scale.X = 1
	}
	if render.Scale.Y == 0 {
		render.Scale.Y = 1
	}

	if render.zIndex == 0 {
		render.zIndex = render.StartZIndex
	}

	rs.entities = append(rs.entities, renderEntity{basic, render, space})
	rs.sortingNeeded = true
}

// EntityExists looks if the entity is already into the System's entities. It will return the index >= 0 of the object into de rs.entities or -1 if it could not be found.
func (rs *RenderSystem) EntityExists(basic *ecs.BasicEntity) int {
	for index, entity := range rs.entities {
		if entity.ID() == basic.ID() {
			return index
		}
	}

	return -1
}

// AddByInterface adds any Renderable to the render system. Any Entity containing a BasicEntity,RenderComponent, and SpaceComponent anonymously does this automatically
func (rs *RenderSystem) AddByInterface(i ecs.Identifier) {
	o, _ := i.(Renderable)
	rs.Add(o.GetBasicEntity(), o.GetRenderComponent(), o.GetSpaceComponent())
}

// Remove removes an entity from the RenderSystem
func (rs *RenderSystem) Remove(basic ecs.BasicEntity) {
	var d = rs.EntityExists(&basic)
	if d >= 0 {
		rs.entities = append(rs.entities[:d], rs.entities[d+1:]...)
		rs.sortingNeeded = true
	}
	delete(rs.ids, basic.ID())
}

// Update draws the entities in the RenderSystem to the OpenGL Surface.
func (rs *RenderSystem) Update(dt float32) {
	if engo.Headless() {
		return
	}

	if rs.sortingNeeded {
		sort.Sort(rs.entities)
		rs.sortingNeeded = false
	}

	if rs.newCamera {
		newCamera(rs.world)
		rs.newCamera = false
	}

	engo.Gl.Clear(engo.Gl.COLOR_BUFFER_BIT)

	preparedCullingShaders := make(map[CullingShader]struct{})
	var cullingShader CullingShader // current culling shader
	var prevShader Shader           // shader of the previous entity
	var currentShader Shader        // currently "active" shader

	// TODO: it's linear for now, but that might very well be a bad idea
	for _, e := range rs.entities {
		if e.RenderComponent.Hidden {
			continue // with other entities
		}

		// Retrieve a shader, may be the default one -- then use it if we aren't already using it
		shader := e.RenderComponent.shader

		if !compareShaders(shader, prevShader) {
			// to increase performance avoid the type assertions when possible
			prevShader = shader
			if cs, ok := shader.(CullingShader); ok {
				cullingShader = cs
				if _, isPrepared := preparedCullingShaders[cullingShader]; !isPrepared {
					cullingShader.PrepareCulling()
					preparedCullingShaders[cullingShader] = struct{}{}
				}
			} else {
				cullingShader = nil
			}
		}

		if cullingShader != nil && !cullingShader.ShouldDraw(e.RenderComponent, e.SpaceComponent) {
			continue
		}

		// Change Shader if we have to
		if !compareShaders(shader, currentShader) {
			if currentShader != nil {
				currentShader.Post()
			}
			shader.Pre()
			currentShader = shader
		}

		// Setting default scale to 1
		if e.RenderComponent.Scale.X == 0 && e.RenderComponent.Scale.Y == 0 {
			e.RenderComponent.Scale = engo.Point{X: 1, Y: 1}
		}

		// Setting default to white
		if e.RenderComponent.Color == nil {
			e.RenderComponent.Color = color.White
		}

		currentShader.Draw(e.RenderComponent, e.SpaceComponent)
	}

	if currentShader != nil {
		currentShader.Post()
	}
}

// SetBackground sets the OpenGL ClearColor to the provided color.
func SetBackground(c color.Color) {
	if !engo.Headless() {
		r, g, b, a := c.RGBA()

		engo.Gl.ClearColor(float32(r)/0xffff, float32(g)/0xffff, float32(b)/0xffff, float32(a)/0xffff)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2011 Google Inc.

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.
*/

// The sigserver is a stand-alone JSON signing and verification server.
//
// TODO(bradfitz): as of 2012-01-10 this is very old and superceded by
// the general server and pkg/serverconfig.  We should just make it
// possible to configure a signing-only server with
// serverconfig/genconfig.go.  I think we basically already can. Then
// we can delete this.
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"

	"camlistore.org/pkg/auth"
	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/httputil"
	"camlistore.org/pkg/webserver"
)

var accessPassword string

var flagPubKeyDir = flag.String("pubkey-dir", "test/pubkey-blobs",
	"Temporary development hack; directory to dig-xxxx.camli public keys.")

// TODO: for now, the only implementation of the blobref.Fetcher
// interface for fetching public keys is the "local, from disk"
// implementation used for testing.  In reality we'd want to be able
// to fetch these from blobservers.
var pubKeyFetcher = blobref.NewSimpleDirectoryFetcher(*flagPubKeyDir)

func handleRoot(conn http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(conn, "camsigd")
}

func handleCamliSig(conn http.ResponseWriter, req *http.Request) {
	handler := func(conn http.ResponseWriter, req *http.Request) {
		httputil.BadRequestError(conn, "Unsupported path or method.")
	}

	switch req.Method {
	case "POST":
		switch req.URL.Path {
		case "/camli/sig/sign":
			handler = auth.RequireAuth(handleSign, auth.OpSign)
		case "/camli/sig/verify":
			handler = handleVerify
		}
	}
	handler(conn, req)
}

func main() {
	flag.Parse()

	mode, err := auth.FromEnv()
	if err != nil {
		log.Fatal(err)
	}
	auth.SetMode(mode)

	ws := webserver.New()
	ws.HandleFunc("/", handleRoot)
	ws.HandleFunc("/camli/sig/", handleCamliSig)
	ws.Serve()
}
<commit_msg>sigserver: fix build<commit_after>/*
Copyright 2011 Google Inc.

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.
*/

// The sigserver is a stand-alone JSON signing and verification server.
//
// TODO(bradfitz): as of 2012-01-10 this is very old and superceded by
// the general server and pkg/serverconfig.  We should just make it
// possible to configure a signing-only server with
// serverconfig/genconfig.go.  I think we basically already can. Then
// we can delete this.
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"

	"camlistore.org/pkg/auth"
	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/httputil"
	"camlistore.org/pkg/webserver"
)

var accessPassword string

var flagPubKeyDir = flag.String("pubkey-dir", "test/pubkey-blobs",
	"Temporary development hack; directory to dig-xxxx.camli public keys.")

// TODO: for now, the only implementation of the blobref.Fetcher
// interface for fetching public keys is the "local, from disk"
// implementation used for testing.  In reality we'd want to be able
// to fetch these from blobservers.
var pubKeyFetcher = blob.NewSimpleDirectoryFetcher(*flagPubKeyDir)

func handleRoot(conn http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(conn, "camsigd")
}

func handleCamliSig(conn http.ResponseWriter, req *http.Request) {
	handler := func(conn http.ResponseWriter, req *http.Request) {
		httputil.BadRequestError(conn, "Unsupported path or method.")
	}

	switch req.Method {
	case "POST":
		switch req.URL.Path {
		case "/camli/sig/sign":
			handler = auth.RequireAuth(handleSign, auth.OpSign)
		case "/camli/sig/verify":
			handler = handleVerify
		}
	}
	handler(conn, req)
}

func main() {
	flag.Parse()

	mode, err := auth.FromEnv()
	if err != nil {
		log.Fatal(err)
	}
	auth.SetMode(mode)

	ws := webserver.New()
	ws.HandleFunc("/", handleRoot)
	ws.HandleFunc("/camli/sig/", handleCamliSig)
	ws.Serve()
}
<|endoftext|>


<commit_before>package common

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

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
)

// Exported error messages
var (
	ErrS3MissingBucketKey = errors.New("missing S3 bucket or object key")
	ErrS3UnknownScheme    = errors.New("unknown URI scheme")
)

// s3Info contains the information needed to connect to an S3
// datastore and create or retrieve objects
type s3Info struct {
	awsConfig *aws.Config
	bucket    string
	key       string
}

// isS3 does a very basic check if the given string *could* be an S3 URI
func isS3(s string) bool {
	return strings.HasPrefix(s, "s3://") || strings.HasPrefix(s, "s3n://")
}

// parseS3URI returns a struct containing all the information needed to connect
// to an S3 endpoing and create or retrieve objects.  The data is collected from
// parsing the passed s3uri and environment variables.
func parseS3URI(s3uri string) (*s3Info, error) {
	var info *s3Info                // parsed info
	var u *url.URL                  // parsed url
	var accessKey, secretKey string // key holders
	var err error                   // general error holder

	// The `net/url` package does not handle '/' in password.
	// Therefore, we strip out and parse the user/password portion manually.
	// See: https://github.com/myENA/consul-backinator/issues/30
	if strings.Contains(s3uri, "@") {
		var keyStart = strings.Index(s3uri, "://") + 3 // get start
		var keyEnd = strings.Index(s3uri, "@")         // get end
		var keyString = s3uri[keyStart:keyEnd]         // pull out key string
		// check key string
		if strings.Contains(keyString, ":") {
			// split the keys
			var keySplit = strings.Split(keyString, ":")
			// check split
			if len(keySplit) == 2 {
				// set keys
				accessKey = keySplit[0]
				secretKey = keySplit[1]
				// rewrite uri - remove credentials
				s3uri = s3uri[:keyStart] + s3uri[keyEnd+1:]
			}
		}
	}

	// parse the s3 path
	if u, err = url.Parse(s3uri); err != nil {
		return nil, err
	}

	// check scheme for giggles
	if u.Scheme != "s3" && u.Scheme != "s3n" {
		return nil, ErrS3UnknownScheme
	}

	// init info
	info = &s3Info{awsConfig: aws.NewConfig()}

	// check access/secret key
	if accessKey != "" && secretKey != "" {
		info.awsConfig.Credentials = credentials.NewStaticCredentials(
			accessKey,
			secretKey,
			"",
		)
	}

	// get region
	if temps := u.Query().Get("region"); temps != "" {
		info.awsConfig.Region = aws.String(temps)
	}

	// get bucket
	if info.bucket = u.Host; info.bucket == "" {
		return nil, ErrS3MissingBucketKey
	}

	// get object key
	if info.key = u.Path; u.Path == "" || u.Path == "/" {
		return nil, ErrS3MissingBucketKey
	}

	// check for endpoint override
	if temps := u.Query().Get("endpoint"); temps != "" {
		info.awsConfig.Endpoint = aws.String(temps)
	}

	// check for ssl override
	if temps := u.Query().Get("secure"); temps != "" {
		var secure bool // local bool
		if secure, err = strconv.ParseBool(temps); err != nil {
			return nil, err
		}
		// update config
		info.awsConfig.DisableSSL = aws.Bool(secure)
	}

	// return populated struct
	return info, nil
}
<commit_msg>style<commit_after>package common

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

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
)

// Exported error messages
var (
	ErrS3MissingBucketKey = errors.New("missing S3 bucket or object key")
	ErrS3UnknownScheme    = errors.New("unknown URI scheme")
)

// s3Info contains the information needed to connect to an S3
// datastore and create or retrieve objects
type s3Info struct {
	awsConfig *aws.Config
	bucket    string
	key       string
}

// isS3 does a very basic check if the given string *could* be an S3 URI
func isS3(s string) bool {
	return strings.HasPrefix(s, "s3://") || strings.HasPrefix(s, "s3n://")
}

// parseS3URI returns a struct containing all the information needed to connect
// to an S3 endpoing and create or retrieve objects.  The data is collected from
// parsing the passed s3uri and environment variables.
func parseS3URI(s3uri string) (*s3Info, error) {
	var info *s3Info                // parsed info
	var u *url.URL                  // parsed url
	var accessKey, secretKey string // key holders
	var err error                   // general error holder

	// The `net/url` package does not handle '/' in password.
	// Therefore, we strip out and parse the user/password portion manually.
	// See: https://github.com/myENA/consul-backinator/issues/30
	if strings.Contains(s3uri, "@") {
		var keyStart = strings.Index(s3uri, "://") + 3 // get start
		var keyEnd = strings.Index(s3uri, "@")         // get end
		var keyString = s3uri[keyStart:keyEnd]         // pull out key string
		// check key string
		if strings.Contains(keyString, ":") {
			// split the keys
			var keySplit = strings.Split(keyString, ":")
			// check split
			if len(keySplit) == 2 {
				// set keys
				accessKey = keySplit[0]
				secretKey = keySplit[1]
				// rewrite uri - remove credentials
				s3uri = s3uri[:keyStart] + s3uri[keyEnd+1:]
			}
		}
	}

	// parse the s3 path
	if u, err = url.Parse(s3uri); err != nil {
		return nil, err
	}

	// check scheme for giggles
	if u.Scheme != "s3" && u.Scheme != "s3n" {
		return nil, ErrS3UnknownScheme
	}

	// init info
	info = &s3Info{awsConfig: aws.NewConfig()}

	// check access/secret key
	if accessKey != "" && secretKey != "" {
		info.awsConfig.Credentials = credentials.NewStaticCredentials(
			accessKey,
			secretKey,
			"",
		)
	}

	// get region
	if temps := u.Query().Get("region"); temps != "" {
		info.awsConfig.Region = aws.String(temps)
	}

	// get bucket
	if info.bucket = u.Host; info.bucket == "" {
		return nil, ErrS3MissingBucketKey
	}

	// get object key
	if info.key = u.Path; info.key == "" || info.key == "/" {
		return nil, ErrS3MissingBucketKey
	}

	// check for endpoint override
	if temps := u.Query().Get("endpoint"); temps != "" {
		info.awsConfig.Endpoint = aws.String(temps)
	}

	// check for ssl override
	if temps := u.Query().Get("secure"); temps != "" {
		var secure bool // local bool
		if secure, err = strconv.ParseBool(temps); err != nil {
			return nil, err
		}
		// update config
		info.awsConfig.DisableSSL = aws.Bool(secure)
	}

	// return populated struct
	return info, nil
}
<|endoftext|>


<commit_before>package next

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"reflect"
	"regexp"
	"runtime"
	"strings"
)

type Mysql struct {
	Db *sql.DB
	Tx *sql.Tx
}

func NewMysql() *Mysql {
	return &Mysql{}
}

func (mysql *Mysql) Open(dsn string) {
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		panic(err.Error())
	}

	mysql.Db = db
	runtime.SetFinalizer(db, nil)
}

func (mysql *Mysql) Ping() error {
	return mysql.Db.Ping()
}

func (mysql *Mysql) Close() {
	mysql.Db.Close()
}

func (mysql *Mysql) Query(args ...interface{}) ([]interface{}, error) {
	// Parse sql
	q, param, err := mysql.parseQuery(args...)
	if err != nil {
		return nil, err
	}

	var stmt *sql.Stmt
	// Prepare
	if mysql.Tx != nil {
		stmt, err = mysql.Tx.Prepare(q)
	} else {
		stmt, err = mysql.Db.Prepare(q)
	}
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	// -------------
	// Scan
	// -------------
	rows, err := stmt.Query(param...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	// Get all col name
	cols, err := rows.Columns()
	if err != nil {
		return nil, err
	}

	// Scan value
	out := make([]interface{}, 0)
	for rows.Next() {
		rbs := make([]sql.RawBytes, len(cols))
		vals := make([]interface{}, len(cols))
		for i := range vals {
			vals[i] = &rbs[i]
		}

		if err = rows.Scan(vals...); err != nil {
			return nil, err
		}

		// Make map
		r := make(map[string]interface{}, len(cols))
		for i, val := range rbs {
			r[cols[i]] = string(val)
		}
		out = append(out, r)
	}

	return out, nil
}

func (mysql *Mysql) Row(args ...interface{}) (interface{}, error) {
	// Parse sql
	q, param, err := mysql.parseQuery(args...)
	if err != nil {
		return nil, err
	}

	var stmt *sql.Stmt
	// Prepare
	if mysql.Tx != nil {
		stmt, err = mysql.Tx.Prepare(q)
	} else {
		stmt, err = mysql.Db.Prepare(q)
	}
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	// -------------
	// Scan
	// -------------
	rows, err := stmt.Query(param...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	// Get all col name
	cols, err := rows.Columns()
	if err != nil {
		return nil, err
	}

	// Scan value
	out := make(map[string]interface{}, len(cols))
	if rows.Next() {
		rbs := make([]sql.RawBytes, len(cols))
		vals := make([]interface{}, len(cols))
		for i := range vals {
			vals[i] = &rbs[i]
		}

		if err = rows.Scan(vals...); err != nil {
			return nil, err
		}

		// Make map
		for i, val := range rbs {
			out[cols[i]] = string(val)
		}
	}

	return out, nil
}

// DML for tabel, insert update delete operation.
// usage:
// mysql.Exec("users", "add", &addData)
// mysql.Exec("users", "up", &upData, &where)
// mysql.Exec("users", "del", &where)
func (mysql *Mysql) Exec(table, dml string, args ...interface{}) (interface{}, error) {
	if len(table) == 0 {
		panic("plase set table for exec method")
	}

	switch strings.ToLower(dml); dml {
	case "add":
		return mysql.insert(table, args...)
	case "up":
		return mysql.update(table, args...)
	case "del":
		return mysql.del(table, args...)
	default:
		panic("mysql exec method <add, up, del> can not support: " + dml)
	}
	return nil, nil
}

func (mysql *Mysql) Begin() {
	tx, err := mysql.Db.Begin()
	if err != nil {
		panic(err.Error())
	}
	mysql.Tx = tx
}

func (mysql *Mysql) Rollback() error {
	if mysql.Tx != nil {
		return mysql.Tx.Rollback()
	}
	return nil
}

func (mysql *Mysql) Commit() error {
	if mysql.Tx != nil {
		return mysql.Tx.Commit()
	}
	return nil
}

func (mysql *Mysql) parseQuery(args ...interface{}) (string, []interface{}, error) {
	// SQL
	q, ok := (args[0]).(string)
	if !ok {
		panic("first param should be a sql string")
	}

	// No param
	if len(args) == 1 {
		return q, nil, nil
	}

	// Parse sql with mapping
	v := reflect.ValueOf(args[1])
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Map {
		panic("param should be a map's pointer")
	}

	param := make([]interface{}, 0)
	re := regexp.MustCompile(":\\w+")
	q = re.ReplaceAllStringFunc(q, func(src string) string {
		param = append(param, v.Elem().MapIndex(reflect.ValueOf(src[1:])).Interface())
		return "?"
	})

	return q, param, nil
}

func (mysql *Mysql) insert(table string, args ...interface{}) (interface{}, error) {
	v := reflect.ValueOf(args[0])
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Map {
		panic("param should be a map's pointer")
	}

	// Parse args
	maps := v.Elem().MapKeys()
	feild := make([]string, len(maps))
	bind := make([]string, len(maps))
	param := make([]interface{}, 0)
	for i, k := range maps {
		f := strings.SplitN(k.String(), ":", 2)
		if len(f) > 1 {
			feild[i] = fmt.Sprintf("`%s`", f[0])
			bind[i] = fmt.Sprintf("%s", v.Elem().MapIndex(k).Interface())
		} else {
			feild[i] = fmt.Sprintf("`%s`", k)
			bind[i] = "?"
			param = append(param, v.Elem().MapIndex(k).Interface())
		}
	}
	q := fmt.Sprintf("INSERT INTO `%s`(%s) VALUES(%s);", table, strings.Join(feild, ","), strings.Join(bind, ","))

	// Sql execute
	var stmt *sql.Stmt
	var err error
	// Prepare
	if mysql.Tx != nil {
		stmt, err = mysql.Tx.Prepare(q)
	} else {
		stmt, err = mysql.Db.Prepare(q)
	}
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	res, err := stmt.Exec(param...)
	if err != nil {
		return nil, err
	}

	return res.LastInsertId()
}

func (mysql *Mysql) update(table string, args ...interface{}) (interface{}, error) {
	if len(args) < 2 {
		panic("mysql update method need the data of update and where")
	}

	u := reflect.ValueOf(args[0])
	if u.Kind() != reflect.Ptr || u.Elem().Kind() != reflect.Map {
		panic("updata args should be a map's pointer")
	}
	w := reflect.ValueOf(args[1])
	if w.Kind() != reflect.Ptr || w.Elem().Kind() != reflect.Map {
		panic("where args should be a map's pointer")
	}

	param := make([]interface{}, 0)
	// Parse upate args
	mu := u.Elem().MapKeys()
	up := make([]string, len(mu))
	for i, k := range mu {
		f := strings.SplitN(k.String(), ":", 2)
		if len(f) > 1 {
			up[i] = fmt.Sprintf("`%s`%s%s", f[0], f[1], u.Elem().MapIndex(k).Interface())
		} else {
			up[i] = fmt.Sprintf("`%s`=?", k)
			param = append(param, u.Elem().MapIndex(k).Interface())
		}
	}
	// Parse upate args
	mw := w.Elem().MapKeys()
	where := make([]string, len(mw))
	for i, k := range mw {
		f := strings.SplitN(k.String(), ":", 2)
		if len(f) > 1 {
			where[i] = fmt.Sprintf("`%s`%s%s", f[0], f[1], w.Elem().MapIndex(k).Interface())
		} else {
			where[i] = fmt.Sprintf("`%s`=?", k)
			param = append(param, w.Elem().MapIndex(k).Interface())
		}
	}
	q := fmt.Sprintf("UPDATE `%s` SET %s WHERE %s;", table, strings.Join(up, ","), strings.Join(where, " AND "))

	// Sql execute
	var stmt *sql.Stmt
	var err error
	// Prepare
	if mysql.Tx != nil {
		stmt, err = mysql.Tx.Prepare(q)
	} else {
		stmt, err = mysql.Db.Prepare(q)
	}
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	res, err := stmt.Exec(param...)
	if err != nil {
		return nil, err
	}

	return res.RowsAffected()
}

func (mysql *Mysql) del(table string, args ...interface{}) (interface{}, error) {
	w := reflect.ValueOf(args[0])
	if w.Kind() != reflect.Ptr || w.Elem().Kind() != reflect.Map {
		panic("where args should be a map's pointer")
	}

	mw := w.Elem().MapKeys()
	param := make([]interface{}, 0)
	// Parse where args
	where := make([]string, len(mw))
	for i, k := range mw {
		f := strings.SplitN(k.String(), ":", 2)
		if len(f) > 1 {
			where[i] = fmt.Sprintf("`%s`%s%s", f[0], f[1], w.Elem().MapIndex(k).Interface())
		} else {
			where[i] = fmt.Sprintf("`%s`=?", k)
			param = append(param, w.Elem().MapIndex(k).Interface())
		}
	}
	q := fmt.Sprintf("DELETE FROM `%s` WHERE %s;", table, strings.Join(where, " AND "))

	// Sql execute
	var stmt *sql.Stmt
	var err error
	// Prepare
	if mysql.Tx != nil {
		stmt, err = mysql.Tx.Prepare(q)
	} else {
		stmt, err = mysql.Db.Prepare(q)
	}
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	res, err := stmt.Exec(param...)
	if err != nil {
		return nil, err
	}

	return res.RowsAffected()
}
<commit_msg>fix commit issue<commit_after>package next

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"reflect"
	"regexp"
	"runtime"
	"strings"
)

type Mysql struct {
	Db *sql.DB
	Tx *sql.Tx
}

func NewMysql() *Mysql {
	return &Mysql{}
}

func (mysql *Mysql) Open(dsn string) {
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		panic(err.Error())
	}

	mysql.Db = db
	runtime.SetFinalizer(db, nil)
}

func (mysql *Mysql) Ping() error {
	return mysql.Db.Ping()
}

func (mysql *Mysql) Close() {
	mysql.Db.Close()
}

func (mysql *Mysql) Query(args ...interface{}) ([]interface{}, error) {
	// Parse sql
	q, param, err := mysql.parseQuery(args...)
	if err != nil {
		return nil, err
	}

	var stmt *sql.Stmt
	// Prepare
	if mysql.Tx != nil {
		stmt, err = mysql.Tx.Prepare(q)
	} else {
		stmt, err = mysql.Db.Prepare(q)
	}
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	// -------------
	// Scan
	// -------------
	rows, err := stmt.Query(param...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	// Get all col name
	cols, err := rows.Columns()
	if err != nil {
		return nil, err
	}

	// Scan value
	out := make([]interface{}, 0)
	for rows.Next() {
		rbs := make([]sql.RawBytes, len(cols))
		vals := make([]interface{}, len(cols))
		for i := range vals {
			vals[i] = &rbs[i]
		}

		if err = rows.Scan(vals...); err != nil {
			return nil, err
		}

		// Make map
		r := make(map[string]interface{}, len(cols))
		for i, val := range rbs {
			r[cols[i]] = string(val)
		}
		out = append(out, r)
	}

	return out, nil
}

func (mysql *Mysql) Row(args ...interface{}) (interface{}, error) {
	// Parse sql
	q, param, err := mysql.parseQuery(args...)
	if err != nil {
		return nil, err
	}

	var stmt *sql.Stmt
	// Prepare
	if mysql.Tx != nil {
		stmt, err = mysql.Tx.Prepare(q)
	} else {
		stmt, err = mysql.Db.Prepare(q)
	}
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	// -------------
	// Scan
	// -------------
	rows, err := stmt.Query(param...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	// Get all col name
	cols, err := rows.Columns()
	if err != nil {
		return nil, err
	}

	// Scan value
	out := make(map[string]interface{}, len(cols))
	if rows.Next() {
		rbs := make([]sql.RawBytes, len(cols))
		vals := make([]interface{}, len(cols))
		for i := range vals {
			vals[i] = &rbs[i]
		}

		if err = rows.Scan(vals...); err != nil {
			return nil, err
		}

		// Make map
		for i, val := range rbs {
			out[cols[i]] = string(val)
		}
	}

	return out, nil
}

// DML for tabel, insert update delete operation.
// usage:
// mysql.Exec("users", "add", &addData)
// mysql.Exec("users", "up", &upData, &where)
// mysql.Exec("users", "del", &where)
func (mysql *Mysql) Exec(table, dml string, args ...interface{}) (interface{}, error) {
	if len(table) == 0 {
		panic("plase set table for exec method")
	}

	switch strings.ToLower(dml); dml {
	case "add":
		return mysql.insert(table, args...)
	case "up":
		return mysql.update(table, args...)
	case "del":
		return mysql.del(table, args...)
	default:
		panic("mysql exec method <add, up, del> can not support: " + dml)
	}
	return nil, nil
}

func (mysql *Mysql) Begin() {
	tx, err := mysql.Db.Begin()
	if err != nil {
		panic(err.Error())
	}
	mysql.Tx = tx
}

func (mysql *Mysql) Rollback() error {
	if mysql.Tx != nil {
		return mysql.Tx.Rollback()
	}
	return nil
}

func (mysql *Mysql) Commit() error {
	if mysql.Tx != nil {
		err := mysql.Tx.Commit()
		mysql.Tx = nil
		return err
	}
	return nil
}

func (mysql *Mysql) parseQuery(args ...interface{}) (string, []interface{}, error) {
	// SQL
	q, ok := (args[0]).(string)
	if !ok {
		panic("first param should be a sql string")
	}

	// No param
	if len(args) == 1 {
		return q, nil, nil
	}

	// Parse sql with mapping
	v := reflect.ValueOf(args[1])
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Map {
		panic("param should be a map's pointer")
	}

	param := make([]interface{}, 0)
	re := regexp.MustCompile(":\\w+")
	q = re.ReplaceAllStringFunc(q, func(src string) string {
		param = append(param, v.Elem().MapIndex(reflect.ValueOf(src[1:])).Interface())
		return "?"
	})

	return q, param, nil
}

func (mysql *Mysql) insert(table string, args ...interface{}) (interface{}, error) {
	v := reflect.ValueOf(args[0])
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Map {
		panic("param should be a map's pointer")
	}

	// Parse args
	maps := v.Elem().MapKeys()
	feild := make([]string, len(maps))
	bind := make([]string, len(maps))
	param := make([]interface{}, 0)
	for i, k := range maps {
		f := strings.SplitN(k.String(), ":", 2)
		if len(f) > 1 {
			feild[i] = fmt.Sprintf("`%s`", f[0])
			bind[i] = fmt.Sprintf("%s", v.Elem().MapIndex(k).Interface())
		} else {
			feild[i] = fmt.Sprintf("`%s`", k)
			bind[i] = "?"
			param = append(param, v.Elem().MapIndex(k).Interface())
		}
	}
	q := fmt.Sprintf("INSERT INTO `%s`(%s) VALUES(%s);", table, strings.Join(feild, ","), strings.Join(bind, ","))

	// Sql execute
	var stmt *sql.Stmt
	var err error
	// Prepare
	if mysql.Tx != nil {
		stmt, err = mysql.Tx.Prepare(q)
	} else {
		stmt, err = mysql.Db.Prepare(q)
	}
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	res, err := stmt.Exec(param...)
	if err != nil {
		return nil, err
	}

	return res.LastInsertId()
}

func (mysql *Mysql) update(table string, args ...interface{}) (interface{}, error) {
	if len(args) < 2 {
		panic("mysql update method need the data of update and where")
	}

	u := reflect.ValueOf(args[0])
	if u.Kind() != reflect.Ptr || u.Elem().Kind() != reflect.Map {
		panic("updata args should be a map's pointer")
	}
	w := reflect.ValueOf(args[1])
	if w.Kind() != reflect.Ptr || w.Elem().Kind() != reflect.Map {
		panic("where args should be a map's pointer")
	}

	param := make([]interface{}, 0)
	// Parse upate args
	mu := u.Elem().MapKeys()
	up := make([]string, len(mu))
	for i, k := range mu {
		f := strings.SplitN(k.String(), ":", 2)
		if len(f) > 1 {
			up[i] = fmt.Sprintf("`%s`%s%s", f[0], f[1], u.Elem().MapIndex(k).Interface())
		} else {
			up[i] = fmt.Sprintf("`%s`=?", k)
			param = append(param, u.Elem().MapIndex(k).Interface())
		}
	}
	// Parse upate args
	mw := w.Elem().MapKeys()
	where := make([]string, len(mw))
	for i, k := range mw {
		f := strings.SplitN(k.String(), ":", 2)
		if len(f) > 1 {
			where[i] = fmt.Sprintf("`%s`%s%s", f[0], f[1], w.Elem().MapIndex(k).Interface())
		} else {
			where[i] = fmt.Sprintf("`%s`=?", k)
			param = append(param, w.Elem().MapIndex(k).Interface())
		}
	}
	q := fmt.Sprintf("UPDATE `%s` SET %s WHERE %s;", table, strings.Join(up, ","), strings.Join(where, " AND "))

	// Sql execute
	var stmt *sql.Stmt
	var err error
	// Prepare
	if mysql.Tx != nil {
		stmt, err = mysql.Tx.Prepare(q)
	} else {
		stmt, err = mysql.Db.Prepare(q)
	}
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	res, err := stmt.Exec(param...)
	if err != nil {
		return nil, err
	}

	return res.RowsAffected()
}

func (mysql *Mysql) del(table string, args ...interface{}) (interface{}, error) {
	w := reflect.ValueOf(args[0])
	if w.Kind() != reflect.Ptr || w.Elem().Kind() != reflect.Map {
		panic("where args should be a map's pointer")
	}

	mw := w.Elem().MapKeys()
	param := make([]interface{}, 0)
	// Parse where args
	where := make([]string, len(mw))
	for i, k := range mw {
		f := strings.SplitN(k.String(), ":", 2)
		if len(f) > 1 {
			where[i] = fmt.Sprintf("`%s`%s%s", f[0], f[1], w.Elem().MapIndex(k).Interface())
		} else {
			where[i] = fmt.Sprintf("`%s`=?", k)
			param = append(param, w.Elem().MapIndex(k).Interface())
		}
	}
	q := fmt.Sprintf("DELETE FROM `%s` WHERE %s;", table, strings.Join(where, " AND "))

	// Sql execute
	var stmt *sql.Stmt
	var err error
	// Prepare
	if mysql.Tx != nil {
		stmt, err = mysql.Tx.Prepare(q)
	} else {
		stmt, err = mysql.Db.Prepare(q)
	}
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	res, err := stmt.Exec(param...)
	if err != nil {
		return nil, err
	}

	return res.RowsAffected()
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Cornelius Buschka.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package config4go

// Config is a config read by ConfigReader.
type Config struct {
	valueMap map[string]string
}

// ToMap returns the config as a new map.
func (this *Config) ToMap() map[string]string {
	newMap := make(map[string]string)
	for key, value := range this.valueMap {
		newMap[key] = value
	}

	return newMap
}
<commit_msg>Replaced this with config.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Cornelius Buschka.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package config4go

// Config is a config read by ConfigReader.
type Config struct {
	valueMap map[string]string
}

// ToMap returns the config as a new map.
func (config *Config) ToMap() map[string]string {
	newMap := make(map[string]string)
	for key, value := range config.valueMap {
		newMap[key] = value
	}

	return newMap
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/base64"

	"gopkg.in/macaron.v1"

	"github.com/emersion/neutron/backend"
)

type UserResp struct {
	Resp
	User *backend.User
}

type CreateUserReq struct {
	Req
	Username string
	Password string
	Domain string
	News bool
	PrivateKey string
	Token string
	TokenType string
}

type DirectUserResp struct {
	Resp
	Direct int
}

type UsernameAvailableResp struct {
	Resp
	Available int
}

type UpdateUserDisplayNameReq struct {
	Req
	DisplayName string
}

func (api *Api) GetCurrentUser(ctx *macaron.Context) {
	userId := api.getUserId(ctx)

	user, err := api.backend.GetUser(userId)
	if err != nil {
		ctx.JSON(200, &ErrorResp{
			Resp: Resp{NotFound},
			Error: "invalid_user",
			ErrorDescription: err.Error(),
		})
		return
	}

	ctx.JSON(200, &UserResp{
		Resp: Resp{Ok},
		User: user,
	})
}

func (api *Api) CreateUser(ctx *macaron.Context, req CreateUserReq) (err error) {
	// TODO: support req.Domain, req.Token, req.TokenType

	user, err := api.backend.InsertUser(&backend.User{
		Name: req.Username,
		EncPrivateKey: req.PrivateKey,
	}, req.Password)
	if err != nil {
		return
	}

	ctx.JSON(200, &UserResp{
		Resp: Resp{Ok},
		User: user,
	})
	return
}

func (api *Api) GetDirectUser(ctx *macaron.Context) {
	ctx.JSON(200, &DirectUserResp{
		Resp: Resp{Ok},
		Direct: 1,
	})
}

func (api *Api) GetUsernameAvailable(ctx *macaron.Context) (err error) {
	username := ctx.Params("username")

	available, err := api.backend.IsUsernameAvailable(username)
	if err != nil {
		return
	}

	value := 0
	if available {
		value = 1
	}

	ctx.JSON(200, &UsernameAvailableResp{
		Resp: Resp{Ok},
		Available: value,
	})
	return
}

func (api *Api) UpdateUserDisplayName(ctx *macaron.Context, req UpdateUserDisplayNameReq) (err error) {
	err = api.backend.UpdateUser(&backend.UserUpdate{
		User: &backend.User{
			DisplayName: req.DisplayName,
		},
		DisplayName: true,
	})
	if err != nil {
		return
	}

	ctx.JSON(200, &Resp{Ok})
	return
}

func (api *Api) GetPublicKey(ctx *macaron.Context) (err error) {
	b, err := base64.URLEncoding.DecodeString(ctx.Params("email"))
	if err != nil {
		return
	}

	email := string(b)

	key, err := api.backend.GetPublicKey(email)
	if err != nil {
		return
	}

	resp := map[string]interface{}{ "Code": Ok }
	resp[email] = key
	ctx.JSON(200, resp)
	return
}
<commit_msg>Minor fixes for account creation<commit_after>package api

import (
	"encoding/base64"

	"gopkg.in/macaron.v1"

	"github.com/emersion/neutron/backend"
)

type UserResp struct {
	Resp
	User *backend.User
}

type CreateUserReq struct {
	Req
	Username string
	Password string
	Domain string
	News bool
	PrivateKey string
	Token string
	TokenType string
}

type DirectUserResp struct {
	Resp
	Direct int
}

type UsernameAvailableResp struct {
	Resp
	Available int
}

type UpdateUserDisplayNameReq struct {
	Req
	DisplayName string
}

func (api *Api) GetCurrentUser(ctx *macaron.Context) {
	userId := api.getUserId(ctx)

	user, err := api.backend.GetUser(userId)
	if err != nil {
		ctx.JSON(200, &ErrorResp{
			Resp: Resp{NotFound},
			Error: "invalid_user",
			ErrorDescription: err.Error(),
		})
		return
	}

	ctx.JSON(200, &UserResp{
		Resp: Resp{Ok},
		User: user,
	})
}

func (api *Api) CreateUser(ctx *macaron.Context, req CreateUserReq) (err error) {
	// TODO: check req.Token & req.TokenType

	user, err := api.backend.InsertUser(&backend.User{
		Name: req.Username,
		EncPrivateKey: req.PrivateKey,
		Addresses: []*backend.Address{
			&backend.Address{
				ID: "address_id", // TODO: insert address
				DomainID: "domain_id", // TODO: check req.Domain
				Email: req.Username + "@" + req.Domain,
				Send: 1,
				Receive: 1,
				Status: 1,
				Type: 1,
			},
		},
	}, req.Password)
	if err != nil {
		return
	}

	ctx.JSON(200, &UserResp{
		Resp: Resp{Ok},
		User: user,
	})
	return
}

func (api *Api) GetDirectUser(ctx *macaron.Context) {
	ctx.JSON(200, &DirectUserResp{
		Resp: Resp{Ok},
		Direct: 1,
	})
}

func (api *Api) GetUsernameAvailable(ctx *macaron.Context) (err error) {
	username := ctx.Params("username")

	available, err := api.backend.IsUsernameAvailable(username)
	if err != nil {
		return
	}

	value := 0
	if available {
		value = 1
	}

	ctx.JSON(200, &UsernameAvailableResp{
		Resp: Resp{Ok},
		Available: value,
	})
	return
}

func (api *Api) UpdateUserDisplayName(ctx *macaron.Context, req UpdateUserDisplayNameReq) (err error) {
	userId := api.getUserId(ctx)

	err = api.backend.UpdateUser(&backend.UserUpdate{
		User: &backend.User{
			ID: userId,
			DisplayName: req.DisplayName,
		},
		DisplayName: true,
	})
	if err != nil {
		return
	}

	ctx.JSON(200, &Resp{Ok})
	return
}

func (api *Api) GetPublicKey(ctx *macaron.Context) (err error) {
	b, err := base64.URLEncoding.DecodeString(ctx.Params("email"))
	if err != nil {
		return
	}

	email := string(b)

	key, err := api.backend.GetPublicKey(email)
	if err != nil {
		return
	}

	resp := map[string]interface{}{ "Code": Ok }
	resp[email] = key
	ctx.JSON(200, resp)
	return
}
<|endoftext|>


<commit_before>package bwmf

import (
	"math"

	pb "github.com/taskgraph/taskgraph/example/bwmf/proto"
	"github.com/taskgraph/taskgraph/op"
)

// `KLDivLoss` is a `Function` that evaluates Kullback-Leibler Divergence and the corresponding gradient at the given `Parameter`.
//
//  XXX(baigang): matrix layout
//    W is vectorized by the mapping W[ I, J ] = W_para[ I * k + J ]
//    H is vectorized by the mapping H[ I, J ] = H_para[ I * k + J ]
//  So actually H is H^T, but it saves code by using identical routine when alternatively optimize over H and W.
//
type KLDivLoss struct {
	V       Matrix
	W       Matrix
	smooth  float32
}

func NewKLDivLoss(v *pb.MatrixShard, w []*pb.MatrixShard, m, n, k uint32, smooth float32) *KLDivLoss {
	wData := &pb.MatrixShard{M: m, N: k, Val: make([]float32, m*k)}
	idx := 0
	for idx = 0; idx < len(w); idx += 1 {
		w_ := w[idx]
		for i := uint32(0); i < w_.M * w_.N; i+=1 {
			wData.Val[idx] = w_.Val[i]
			idx += 1
		}
	}
	return &KLDivLoss{V: Matrix{data: v}, W: Matrix{data: wData}, smooth: smooth}
}

// This function evaluates the Kullback-Leibler Divergence given $\mathbf{V} the matrix to fact and $\mathbf{W}$ the fixed factor.
//  The generalized KL div is:
//
//    $$ D_{KL} = \Sum_{ij} ( V_{ij} log \frac{V_{ij}}{(WH)_{ij}} - V_{ij} + (WH_{ij} )
//
//  After removing the redundant constant factor and adding the smooth factor, it becomes:
//
//    $$ L_{kl} = \Sum{ij} ( -V_{ij} log((WH)_{ij} + smooth) + (WH)_{ij} )
//
//  The gradient is:
//
//  $$ \divsymb \frac{D_{KL}}{H} = -W^T*Z + W^T*\bar{Z} $$
//  , where $Z_{ij} = \frac{V_{ij}}{(WH)_{ij}}$ and \bar{Z}_{ij}=1
//
//  This implementation consists of two pass of visiting the full matrix, each of
//  which goes parallel. One pass is for evaluating W*H and accumulate kl-divergence
//  value and the other is for evalutating the matrix gradient of kl-div.
//
func (l *KLDivLoss) Evaluate(param op.Parameter, gradient op.Parameter) float32 {
	H := param
	op.Fill(gradient, 0.0)
	value := float32(0.0)

	M, N, K := l.W.M(), l.V.M(), l.W.N()
	H_data := H.Data()
	grad_data := gradient.Data()
	w_data := l.W.data.Val

	for i := uint32(0); i < M; i++ {
		for j := uint32(0); j < N; j++ {
			wh := float32(0.0)
			for k := uint32(0); k < K; k += 1 {
				wh += w_data[i*K+k] * H_data[j*K+k]
			}

			// v is zero
			value += wh
			for k := uint32(0); k < K; k += 1 {
				grad_data[j*K+k] += w_data[i*K+k]
			}
		}
	}

	for j := uint32(0); j < N; j++ {
		for p := l.V.data.Jc[j]; p < l.V.data.Jc[j+1]; p++ {
			i, v := l.V.data.Ir[p], l.V.data.Val[p]

			wh := float32(0.0)
			for k := uint32(0); k < K; k += 1 {
				wh += w_data[i*K+k] * H_data[j*K+k]
			}

			// accumulate to grad vec
			value += -v*float32(math.Log(float64(wh+l.smooth)))
			for k := uint32(0); k < K; k += 1 {
				grad_data[j*K+k] += -w_data[i*K+k]*(v+l.smooth)/(wh+l.smooth)
			}
		}
	}

	return value
}
<commit_msg>bwmf: fix bugs in kldiv_loss.go<commit_after>package bwmf

import (
	"math"

	pb "github.com/taskgraph/taskgraph/example/bwmf/proto"
	"github.com/taskgraph/taskgraph/op"
)

// `KLDivLoss` is a `Function` that evaluates Kullback-Leibler Divergence and the corresponding gradient at the given `Parameter`.
//
//  XXX(baigang): matrix layout
//    W is vectorized by the mapping W[ I, J ] = W_para[ I * k + J ]
//    H is vectorized by the mapping H[ I, J ] = H_para[ I * k + J ]
//  So actually H is H^T, but it saves code by using identical routine when alternatively optimize over H and W.
//
type KLDivLoss struct {
	V       Matrix
	W       Matrix
	smooth  float32
}

func NewKLDivLoss(v *pb.MatrixShard, w []*pb.MatrixShard, m, n, k uint32, smooth float32) *KLDivLoss {
	wData := &pb.MatrixShard{M: m, N: k, Val: make([]float32, m*k)}
	idx := 0
	for _, w_ := range w {
		for i := uint32(0); i < w_.M * w_.N; i+=1 {
			wData.Val[idx] = w_.Val[i]
			idx += 1
		}
	}
	return &KLDivLoss{V: Matrix{data: v}, W: Matrix{data: wData}, smooth: smooth}
}

// This function evaluates the Kullback-Leibler Divergence given $\mathbf{V} the matrix to fact and $\mathbf{W}$ the fixed factor.
//  The generalized KL div is:
//
//    $$ D_{KL} = \Sum_{ij} ( V_{ij} log \frac{V_{ij}}{(WH)_{ij}} - V_{ij} + (WH_{ij} )
//
//  After removing the redundant constant factor and adding the smooth factor, it becomes:
//
//    $$ L_{kl} = \Sum{ij} ( -V_{ij} log((WH)_{ij} + smooth) + (WH)_{ij} )
//
//  The gradient is:
//
//  $$ \divsymb \frac{D_{KL}}{H} = -W^T*Z + W^T*\bar{Z} $$
//  , where $Z_{ij} = \frac{V_{ij}}{(WH)_{ij}}$ and \bar{Z}_{ij}=1
//
//  This implementation consists of two pass of visiting the full matrix, each of
//  which goes parallel. One pass is for evaluating W*H and accumulate kl-divergence
//  value and the other is for evalutating the matrix gradient of kl-div.
//
func (l *KLDivLoss) Evaluate(H op.Parameter, gradient op.Parameter) float32 {
	op.Fill(gradient, 0.0)
	value := float32(0.0)

	M, N, K := l.W.M(), l.V.M(), l.W.N()
	H_data := H.Data()
	grad_data := gradient.Data()
	w_data := l.W.data.Val

	for i := uint32(0); i < M; i++ {
		for j := uint32(0); j < N; j++ {
			wh := float32(0.0)
			for k := uint32(0); k < K; k += 1 {
				wh += w_data[i*K+k] * H_data[j*K+k]
			}

			// v is zero
			value += wh
			for k := uint32(0); k < K; k += 1 {
				grad_data[j*K+k] += w_data[i*K+k]
			}
		}
	}

	for i := uint32(0); i < M; i++ {
		for p := l.V.data.Jc[i]; p < l.V.data.Jc[i+1]; p++ {
			j, v := l.V.data.Ir[p], l.V.data.Val[p]

			wh := float32(0.0)
			for k := uint32(0); k < K; k += 1 {
				wh += w_data[i*K+k] * H_data[j*K+k]
			}

			// accumulate to grad vec
			value += -v*float32(math.Log(float64(wh+l.smooth)))
			for k := uint32(0); k < K; k += 1 {
				grad_data[j*K+k] += -w_data[i*K+k]*(v+l.smooth)/(wh+l.smooth)
			}
		}
	}

	return value
}
<|endoftext|>


<commit_before>package core

import "github.com/raviqqe/tisp/src/lib/util"

// Arguments represents a structured set of arguments passed to a predicate.
type Arguments struct {
	positionals   []*Thunk
	expandedList  *Thunk
	keywords      []KeywordArgument
	expandedDicts []*Thunk
}

// NewArguments creates a new Arguments.
func NewArguments(
	ps []PositionalArgument,
	ks []KeywordArgument,
	expandedDicts []*Thunk) Arguments {
	if ks == nil {
		ks = []KeywordArgument{}
	}

	ts := make([]*Thunk, 0, len(ps))

	l := (*Thunk)(nil)

	for i, p := range ps {
		if p.expanded {
			l = mergeRestPositionalArgs(ps[i:]...)
			break
		}

		ts = append(ts, p.value)
	}

	return Arguments{
		positionals:   ts,
		expandedList:  l,
		keywords:      ks,
		expandedDicts: expandedDicts,
	}
}

func mergeRestPositionalArgs(ps ...PositionalArgument) *Thunk {
	if !ps[0].expanded {
		util.Fail("First PositionalArgument must be a list.")
	}

	t := ps[0].value

	for _, p := range ps[1:] {
		if p.expanded {
			t = PApp(Merge, t, p.value)
		} else {
			t = PApp(
				NewLazyFunction(appendFuncSignature, appendFunc), // Avoid initialization loop
				t, p.value)
		}
	}

	return t
}

func (args *Arguments) nextPositional() *Thunk {
	if len(args.positionals) != 0 {
		defer func() { args.positionals = args.positionals[1:] }()
		return args.positionals[0]
	}

	if args.expandedList == nil {
		return nil
	}

	defer func() {
		args.expandedList = PApp(Rest, args.expandedList)
	}()

	return PApp(First, args.expandedList)
}

func (args Arguments) restPositionals() *Thunk {
	if args.expandedList == nil {
		return NewList(args.positionals...)
	}

	if len(args.positionals) == 0 {
		return args.expandedList
	}

	return PApp(Merge, NewList(args.positionals...), args.expandedList)
}

func (args *Arguments) searchKeyword(s string) *Thunk {
	for i, k := range args.keywords {
		if s == k.name {
			args.keywords = append(args.keywords[:i], args.keywords[i+1:]...)
			return k.value
		}
	}

	for i, t := range args.expandedDicts {
		o := t.Eval()
		d, ok := o.(DictionaryType)

		if !ok {
			return NotDictionaryError(o)
		}

		k := StringType(s)

		if v, ok := d.Search(k); ok {
			args.expandedDicts[i] = Normal(d.Remove(k))
			return v.(*Thunk)
		}
	}

	return nil
}

func (args Arguments) restKeywords() *Thunk {
	t := EmptyDictionary

	for _, k := range args.keywords {
		t = PApp(Set, t, NewString(k.name), k.value)
	}

	for _, tt := range args.expandedDicts {
		t = PApp(Merge, t, tt)
	}

	return t
}

func (args Arguments) Merge(merged Arguments) Arguments {
	var new Arguments

	if new.expandedList == nil {
		new.positionals = append(args.positionals, merged.positionals...)
		new.expandedList = merged.expandedList
	} else {
		new.positionals = args.positionals
		new.expandedList = PApp(
			Append,
			append([]*Thunk{args.expandedList}, merged.positionals...)...)

		if merged.expandedList != nil {
			new.expandedList = PApp(Merge, new.expandedList, merged.expandedList)
		}
	}

	new.keywords = append(args.keywords, merged.keywords...)
	new.expandedDicts = append(args.expandedDicts, merged.expandedDicts...)

	return new
}
<commit_msg>Add documentation of core/arguments.go<commit_after>package core

import "github.com/raviqqe/tisp/src/lib/util"

// Arguments represents a structured set of arguments passed to a predicate.
type Arguments struct {
	positionals   []*Thunk
	expandedList  *Thunk
	keywords      []KeywordArgument
	expandedDicts []*Thunk
}

// NewArguments creates a new Arguments.
func NewArguments(
	ps []PositionalArgument,
	ks []KeywordArgument,
	expandedDicts []*Thunk) Arguments {
	if ks == nil {
		ks = []KeywordArgument{}
	}

	ts := make([]*Thunk, 0, len(ps))

	l := (*Thunk)(nil)

	for i, p := range ps {
		if p.expanded {
			l = mergeRestPositionalArgs(ps[i:]...)
			break
		}

		ts = append(ts, p.value)
	}

	return Arguments{
		positionals:   ts,
		expandedList:  l,
		keywords:      ks,
		expandedDicts: expandedDicts,
	}
}

func mergeRestPositionalArgs(ps ...PositionalArgument) *Thunk {
	if !ps[0].expanded {
		util.Fail("First PositionalArgument must be a list.")
	}

	t := ps[0].value

	for _, p := range ps[1:] {
		if p.expanded {
			t = PApp(Merge, t, p.value)
		} else {
			t = PApp(
				NewLazyFunction(appendFuncSignature, appendFunc), // Avoid initialization loop
				t, p.value)
		}
	}

	return t
}

func (args *Arguments) nextPositional() *Thunk {
	if len(args.positionals) != 0 {
		defer func() { args.positionals = args.positionals[1:] }()
		return args.positionals[0]
	}

	if args.expandedList == nil {
		return nil
	}

	defer func() {
		args.expandedList = PApp(Rest, args.expandedList)
	}()

	return PApp(First, args.expandedList)
}

func (args Arguments) restPositionals() *Thunk {
	if args.expandedList == nil {
		return NewList(args.positionals...)
	}

	if len(args.positionals) == 0 {
		return args.expandedList
	}

	return PApp(Merge, NewList(args.positionals...), args.expandedList)
}

func (args *Arguments) searchKeyword(s string) *Thunk {
	for i, k := range args.keywords {
		if s == k.name {
			args.keywords = append(args.keywords[:i], args.keywords[i+1:]...)
			return k.value
		}
	}

	for i, t := range args.expandedDicts {
		o := t.Eval()
		d, ok := o.(DictionaryType)

		if !ok {
			return NotDictionaryError(o)
		}

		k := StringType(s)

		if v, ok := d.Search(k); ok {
			args.expandedDicts[i] = Normal(d.Remove(k))
			return v.(*Thunk)
		}
	}

	return nil
}

func (args Arguments) restKeywords() *Thunk {
	t := EmptyDictionary

	for _, k := range args.keywords {
		t = PApp(Set, t, NewString(k.name), k.value)
	}

	for _, tt := range args.expandedDicts {
		t = PApp(Merge, t, tt)
	}

	return t
}

// Merge merges 2 sets of arguments into one.
func (args Arguments) Merge(merged Arguments) Arguments {
	var new Arguments

	if new.expandedList == nil {
		new.positionals = append(args.positionals, merged.positionals...)
		new.expandedList = merged.expandedList
	} else {
		new.positionals = args.positionals
		new.expandedList = PApp(
			Append,
			append([]*Thunk{args.expandedList}, merged.positionals...)...)

		if merged.expandedList != nil {
			new.expandedList = PApp(Merge, new.expandedList, merged.expandedList)
		}
	}

	new.keywords = append(args.keywords, merged.keywords...)
	new.expandedDicts = append(args.expandedDicts, merged.expandedDicts...)

	return new
}
<|endoftext|>


<commit_before>package node

import (
	"crypto/md5"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/MG-RAST/Shock/shock-server/conf"
	e "github.com/MG-RAST/Shock/shock-server/errors"
	"io/ioutil"
	"github.com/MG-RAST/golib/mgo/bson"
	"os"
	"strconv"
	"strings"
	"time"
)

//Modification functions
func (node *Node) Update(params map[string]string, files FormFiles) (err error) {
	// Exclusive conditions
	// 1. has files[upload] (regular upload)
	// 2. has params[parts] (partial upload support)
	// 3. has params[type] & params[source] (v_node)
	// 4. has params[path] (set from local path)
	//
	// All condition allow setting of attributes

	if _, uploadMisplaced := params["upload"]; uploadMisplaced {
		return errors.New("upload form field must be file encoded.")
	}

	_, isRegularUpload := files["upload"]
	_, isPartialUpload := params["parts"]

	isVirtualNode := false
	if t, hasType := params["type"]; hasType && t == "virtual" {
		isVirtualNode = true
	}
	_, isPathUpload := params["path"]
	_, isCopyUpload := params["copy_data"]

	// Check exclusive conditions
	if (isRegularUpload && isPartialUpload) || (isRegularUpload && isVirtualNode) || (isRegularUpload && isPathUpload) || (isRegularUpload && isCopyUpload) {
		return errors.New("upload parameter incompatible with parts, path, type and/or copy_data parameter(s)")
	} else if (isPartialUpload && isVirtualNode) || (isPartialUpload && isPathUpload) || (isPartialUpload && isCopyUpload) {
		return errors.New("parts parameter incompatible with type, path and/or copy_data parameter(s)")
	} else if (isVirtualNode && isPathUpload) || (isVirtualNode && isCopyUpload) {
		return errors.New("type parameter incompatible with path and/or copy_data parameter")
	} else if isPathUpload && isCopyUpload {
		return errors.New("path parameter incompatible with copy_data parameter")
	}

	// Check if immutable
	if (isRegularUpload || isPartialUpload || isVirtualNode || isPathUpload || isCopyUpload) && node.HasFile() {
		return errors.New(e.FileImut)
	}

	if isRegularUpload {
		if err = node.SetFile(files["upload"]); err != nil {
			return err
		}
		delete(files, "upload")
	} else if isPartialUpload {
		if params["parts"] == "unknown" {
			if err = node.initParts("unknown"); err != nil {
				return err
			}
		} else if params["parts"] == "close" {
			if err = node.closeVarLenPartial(); err != nil {
				return err
			}
		} else if node.isVarLen() || node.partsCount() > 0 {
			return errors.New("parts already set")
		} else {
			n, err := strconv.Atoi(params["parts"])
			if err != nil {
				return errors.New("parts must be an integer or 'unknown'")
			}
			if n < 1 {
				return errors.New("parts cannot be less than 1")
			}
			if err = node.initParts(params["parts"]); err != nil {
				return err
			}
		}
	} else if isVirtualNode {
		if source, hasSource := params["source"]; hasSource {
			ids := strings.Split(source, ",")
			node.addVirtualParts(ids)
		} else {
			return errors.New("type virtual requires source parameter")
		}
	} else if isPathUpload {
		if action, hasAction := params["action"]; !hasAction || (action != "copy_file" && action != "move_file" && action != "keep_file") {
			return errors.New("path upload requires action field equal to copy_file, move_file or keep_file")
		}
		localpaths := strings.Split(conf.Conf["local-paths"], ",")
		if len(localpaths) <= 0 {
			return errors.New("local files path uploads must be configured. Please contact your Shock administrator.")
		}
		var success = false
		for _, p := range localpaths {
			if strings.HasPrefix(params["path"], p) {
				if err = node.SetFileFromPath(params["path"], params["action"]); err != nil {
					return err
				} else {
					success = true
				}
			}
		}
		if !success {
			return errors.New("file not in local files path. Please contact your Shock administrator.")
		}
	} else if isCopyUpload {
		var n *Node
		n, err = LoadUnauth(params["copy_data"])
		if err != nil {
			return err
		}

		if n.File.Virtual {
			return errors.New("copy_data parameter points to a virtual node, invalid operation.")
		}

		// Copy node file information
		node.File.Name = n.File.Name
		node.File.Size = n.File.Size
		node.File.Checksum = n.File.Checksum
		node.File.Format = n.File.Format

		if n.File.Path == "" {
			node.File.Path = fmt.Sprintf("%s/%s.data", getPath(params["copy_data"]), params["copy_data"])
		} else {
			node.File.Path = n.File.Path
		}
	}

	// set attributes from file
	if _, hasAttr := files["attributes"]; hasAttr {
		if err = node.SetAttributes(files["attributes"]); err != nil {
			return err
		}
		os.Remove(files["attributes"].Path)
		delete(files, "attributes")
	}

	// handle part file
	LockMgr.LockPartOp()
	parts_count := node.partsCount()
	if parts_count > 0 || node.isVarLen() {
		for key, file := range files {
			if node.HasFile() {
				LockMgr.UnlockPartOp()
				return errors.New(e.FileImut)
			}
			keyn, errf := strconv.Atoi(key)
			if errf == nil && (keyn <= parts_count || node.isVarLen()) {
				err = node.addPart(keyn-1, &file)
				if err != nil {
					LockMgr.UnlockPartOp()
					return err
				}
			} else {
				LockMgr.UnlockPartOp()
				return errors.New("invalid file parameter")
			}
		}
	} else if node.HasFile() {
		// if node has a file and user is trying to perform parts upload, return error that file is immutable.
		for key, _ := range files {
			if _, errf := strconv.Atoi(key); errf == nil {
				LockMgr.UnlockPartOp()
				return errors.New(e.FileImut)
			}
		}
	} else if parts_count == -1 {
		// if node is not variable length and user is trying to perform parts upload, return error that node is not variable
		for key, _ := range files {
			if _, errf := strconv.Atoi(key); errf == nil {
				LockMgr.UnlockPartOp()
				return errors.New("This is not a variable length node and thus does not support uploading in parts.")
			}
		}
	}

	LockMgr.UnlockPartOp()

	// update relatives
	if _, hasRelation := params["linkage"]; hasRelation {
		ltype := params["linkage"]

		if ltype == "parent" {
			if node.HasParent() {
				return errors.New(e.ProvenanceImut)
			}
		}
		var ids string
		if _, hasIds := params["ids"]; hasIds {
			ids = params["ids"]
		} else {
			return errors.New("missing ids for updating relatives")
		}
		var operation string
		if _, hasOp := params["operation"]; hasOp {
			operation = params["operation"]
		}
		if err = node.UpdateLinkages(ltype, ids, operation); err != nil {
			return err
		}
	}

	//update node tags
	if _, hasDataType := params["tags"]; hasDataType {
		if err = node.UpdateDataTags(params["tags"]); err != nil {
			return err
		}
	}

	//update file format
	if _, hasFormat := params["format"]; hasFormat {
		if node.File.Format != "" {
			return errors.New(fmt.Sprintf("file format already set:%s", node.File.Format))
		}
		if err = node.SetFileFormat(params["format"]); err != nil {
			return err
		}
	}
	return
}

func (node *Node) Save() (err error) {
	node.UpdateVersion()
	if len(node.Revisions) == 0 || node.Revisions[len(node.Revisions)-1].Version != node.Version {
		n := Node{node.Id, node.Version, node.File, node.Attributes, node.Public, node.Indexes, node.Acl, node.VersionParts, node.Tags, nil, node.Linkages, node.CreatedOn, node.LastModified}
		node.Revisions = append(node.Revisions, n)
	}
	if node.CreatedOn == "" {
		node.CreatedOn = time.Now().Format(time.UnixDate)
	} else {
		node.LastModified = time.Now().Format(time.UnixDate)
	}

	bsonPath := fmt.Sprintf("%s/%s.bson", node.Path(), node.Id)
	os.Remove(bsonPath)
	nbson, err := bson.Marshal(node)
	if err != nil {
		return
	}
	err = ioutil.WriteFile(bsonPath, nbson, 0644)
	if err != nil {
		return
	}
	err = dbUpsert(node)
	if err != nil {
		return
	}
	return
}

func (node *Node) UpdateVersion() (err error) {
	parts := make(map[string]string)
	h := md5.New()
	version := node.Id
	for name, value := range map[string]interface{}{"file_ver": node.File, "attributes_ver": node.Attributes, "acl_ver": node.Acl} {
		m, er := json.Marshal(value)
		if er != nil {
			return
		}
		h.Write(m)
		sum := fmt.Sprintf("%x", h.Sum(nil))
		parts[name] = sum
		version = version + ":" + sum
		h.Reset()
	}
	h.Write([]byte(version))
	node.Version = fmt.Sprintf("%x", h.Sum(nil))
	node.VersionParts = parts
	return
}

func (node *Node) UpdateLinkages(ltype string, ids string, operation string) (err error) {
	var link linkage
	link.Type = ltype
	idList := strings.Split(ids, ",")
	for _, id := range idList {
		link.Ids = append(link.Ids, id)
	}
	link.Operation = operation
	node.Linkages = append(node.Linkages, link)
	err = node.Save()
	return
}

func (node *Node) UpdateDataTags(types string) (err error) {
	tagslist := strings.Split(types, ",")
	for _, newtag := range tagslist {
		if contains(node.Tags, newtag) {
			continue
		}
		node.Tags = append(node.Tags, newtag)
	}
	err = node.Save()
	return
}
<commit_msg>added option to copy indices when doing node copy<commit_after>package node

import (
	"crypto/md5"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/MG-RAST/Shock/shock-server/util"
	"github.com/MG-RAST/Shock/shock-server/conf"
	e "github.com/MG-RAST/Shock/shock-server/errors"
	"io/ioutil"
	"github.com/MG-RAST/golib/mgo/bson"
	"os"
	"strconv"
	"strings"
	"time"
	"path/filepath"
)

//Modification functions
func (node *Node) Update(params map[string]string, files FormFiles) (err error) {
	// Exclusive conditions
	// 1. has files[upload] (regular upload)
	// 2. has params[parts] (partial upload support)
	// 3. has params[type] & params[source] (v_node)
	// 4. has params[path] (set from local path)
	//
	// All condition allow setting of attributes

	if _, uploadMisplaced := params["upload"]; uploadMisplaced {
		return errors.New("upload form field must be file encoded.")
	}

	_, isRegularUpload := files["upload"]
	_, isPartialUpload := params["parts"]

	isVirtualNode := false
	if t, hasType := params["type"]; hasType && t == "virtual" {
		isVirtualNode = true
	}
	_, isPathUpload := params["path"]
	_, isCopyUpload := params["copy_data"]

	// Check exclusive conditions
	if (isRegularUpload && isPartialUpload) || (isRegularUpload && isVirtualNode) || (isRegularUpload && isPathUpload) || (isRegularUpload && isCopyUpload) {
		return errors.New("upload parameter incompatible with parts, path, type and/or copy_data parameter(s)")
	} else if (isPartialUpload && isVirtualNode) || (isPartialUpload && isPathUpload) || (isPartialUpload && isCopyUpload) {
		return errors.New("parts parameter incompatible with type, path and/or copy_data parameter(s)")
	} else if (isVirtualNode && isPathUpload) || (isVirtualNode && isCopyUpload) {
		return errors.New("type parameter incompatible with path and/or copy_data parameter")
	} else if isPathUpload && isCopyUpload {
		return errors.New("path parameter incompatible with copy_data parameter")
	}

	// Check if immutable
	if (isRegularUpload || isPartialUpload || isVirtualNode || isPathUpload || isCopyUpload) && node.HasFile() {
		return errors.New(e.FileImut)
	}

	if isRegularUpload {
		if err = node.SetFile(files["upload"]); err != nil {
			return err
		}
		delete(files, "upload")
	} else if isPartialUpload {
		if params["parts"] == "unknown" {
			if err = node.initParts("unknown"); err != nil {
				return err
			}
		} else if params["parts"] == "close" {
			if err = node.closeVarLenPartial(); err != nil {
				return err
			}
		} else if node.isVarLen() || node.partsCount() > 0 {
			return errors.New("parts already set")
		} else {
			n, err := strconv.Atoi(params["parts"])
			if err != nil {
				return errors.New("parts must be an integer or 'unknown'")
			}
			if n < 1 {
				return errors.New("parts cannot be less than 1")
			}
			if err = node.initParts(params["parts"]); err != nil {
				return err
			}
		}
	} else if isVirtualNode {
		if source, hasSource := params["source"]; hasSource {
			ids := strings.Split(source, ",")
			node.addVirtualParts(ids)
		} else {
			return errors.New("type virtual requires source parameter")
		}
	} else if isPathUpload {
		if action, hasAction := params["action"]; !hasAction || (action != "copy_file" && action != "move_file" && action != "keep_file") {
			return errors.New("path upload requires action field equal to copy_file, move_file or keep_file")
		}
		localpaths := strings.Split(conf.Conf["local-paths"], ",")
		if len(localpaths) <= 0 {
			return errors.New("local files path uploads must be configured. Please contact your Shock administrator.")
		}
		var success = false
		for _, p := range localpaths {
			if strings.HasPrefix(params["path"], p) {
				if err = node.SetFileFromPath(params["path"], params["action"]); err != nil {
					return err
				} else {
					success = true
				}
			}
		}
		if !success {
			return errors.New("file not in local files path. Please contact your Shock administrator.")
		}
	} else if isCopyUpload {
		var n *Node
		n, err = LoadUnauth(params["copy_data"])
		if err != nil {
			return err
		}

		if n.File.Virtual {
			return errors.New("copy_data parameter points to a virtual node, invalid operation.")
		}

		// Copy node file information
		node.File.Name = n.File.Name
		node.File.Size = n.File.Size
		node.File.Checksum = n.File.Checksum
		node.File.Format = n.File.Format

		// Copy node indices
		if _, copyIndex := params["copy_index"]; copyIndex {
    		indices, err := filepath.Glob(n.IndexPath()+"/*.idx")
    		if err != nil {
    			return err
    		}
    		for _, indexPath := range indices {
    		    _, indexFile := filepath.Split(indexPath)
    		    if _, cerr := util.CopyFile(indexPath, node.IndexPath()+'/'+indexFile); cerr != nil {
					return cerr
				}
		    }
    	}

		if n.File.Path == "" {
			node.File.Path = fmt.Sprintf("%s/%s.data", getPath(params["copy_data"]), params["copy_data"])
		} else {
			node.File.Path = n.File.Path
		}
	}

	// set attributes from file
	if _, hasAttr := files["attributes"]; hasAttr {
		if err = node.SetAttributes(files["attributes"]); err != nil {
			return err
		}
		os.Remove(files["attributes"].Path)
		delete(files, "attributes")
	}

	// handle part file
	LockMgr.LockPartOp()
	parts_count := node.partsCount()
	if parts_count > 0 || node.isVarLen() {
		for key, file := range files {
			if node.HasFile() {
				LockMgr.UnlockPartOp()
				return errors.New(e.FileImut)
			}
			keyn, errf := strconv.Atoi(key)
			if errf == nil && (keyn <= parts_count || node.isVarLen()) {
				err = node.addPart(keyn-1, &file)
				if err != nil {
					LockMgr.UnlockPartOp()
					return err
				}
			} else {
				LockMgr.UnlockPartOp()
				return errors.New("invalid file parameter")
			}
		}
	} else if node.HasFile() {
		// if node has a file and user is trying to perform parts upload, return error that file is immutable.
		for key, _ := range files {
			if _, errf := strconv.Atoi(key); errf == nil {
				LockMgr.UnlockPartOp()
				return errors.New(e.FileImut)
			}
		}
	} else if parts_count == -1 {
		// if node is not variable length and user is trying to perform parts upload, return error that node is not variable
		for key, _ := range files {
			if _, errf := strconv.Atoi(key); errf == nil {
				LockMgr.UnlockPartOp()
				return errors.New("This is not a variable length node and thus does not support uploading in parts.")
			}
		}
	}

	LockMgr.UnlockPartOp()

	// update relatives
	if _, hasRelation := params["linkage"]; hasRelation {
		ltype := params["linkage"]

		if ltype == "parent" {
			if node.HasParent() {
				return errors.New(e.ProvenanceImut)
			}
		}
		var ids string
		if _, hasIds := params["ids"]; hasIds {
			ids = params["ids"]
		} else {
			return errors.New("missing ids for updating relatives")
		}
		var operation string
		if _, hasOp := params["operation"]; hasOp {
			operation = params["operation"]
		}
		if err = node.UpdateLinkages(ltype, ids, operation); err != nil {
			return err
		}
	}

	//update node tags
	if _, hasDataType := params["tags"]; hasDataType {
		if err = node.UpdateDataTags(params["tags"]); err != nil {
			return err
		}
	}

	//update file format
	if _, hasFormat := params["format"]; hasFormat {
		if node.File.Format != "" {
			return errors.New(fmt.Sprintf("file format already set:%s", node.File.Format))
		}
		if err = node.SetFileFormat(params["format"]); err != nil {
			return err
		}
	}
	return
}

func (node *Node) Save() (err error) {
	node.UpdateVersion()
	if len(node.Revisions) == 0 || node.Revisions[len(node.Revisions)-1].Version != node.Version {
		n := Node{node.Id, node.Version, node.File, node.Attributes, node.Public, node.Indexes, node.Acl, node.VersionParts, node.Tags, nil, node.Linkages, node.CreatedOn, node.LastModified}
		node.Revisions = append(node.Revisions, n)
	}
	if node.CreatedOn == "" {
		node.CreatedOn = time.Now().Format(time.UnixDate)
	} else {
		node.LastModified = time.Now().Format(time.UnixDate)
	}

	bsonPath := fmt.Sprintf("%s/%s.bson", node.Path(), node.Id)
	os.Remove(bsonPath)
	nbson, err := bson.Marshal(node)
	if err != nil {
		return
	}
	err = ioutil.WriteFile(bsonPath, nbson, 0644)
	if err != nil {
		return
	}
	err = dbUpsert(node)
	if err != nil {
		return
	}
	return
}

func (node *Node) UpdateVersion() (err error) {
	parts := make(map[string]string)
	h := md5.New()
	version := node.Id
	for name, value := range map[string]interface{}{"file_ver": node.File, "attributes_ver": node.Attributes, "acl_ver": node.Acl} {
		m, er := json.Marshal(value)
		if er != nil {
			return
		}
		h.Write(m)
		sum := fmt.Sprintf("%x", h.Sum(nil))
		parts[name] = sum
		version = version + ":" + sum
		h.Reset()
	}
	h.Write([]byte(version))
	node.Version = fmt.Sprintf("%x", h.Sum(nil))
	node.VersionParts = parts
	return
}

func (node *Node) UpdateLinkages(ltype string, ids string, operation string) (err error) {
	var link linkage
	link.Type = ltype
	idList := strings.Split(ids, ",")
	for _, id := range idList {
		link.Ids = append(link.Ids, id)
	}
	link.Operation = operation
	node.Linkages = append(node.Linkages, link)
	err = node.Save()
	return
}

func (node *Node) UpdateDataTags(types string) (err error) {
	tagslist := strings.Split(types, ",")
	for _, newtag := range tagslist {
		if contains(node.Tags, newtag) {
			continue
		}
		node.Tags = append(node.Tags, newtag)
	}
	err = node.Save()
	return
}
<|endoftext|>


<commit_before>package version

// VERSION ...
const VERSION = "1.1.32"
<commit_msg>v1.1.33<commit_after>package version

// VERSION ...
const VERSION = "1.1.33"
<|endoftext|>


<commit_before>// Copyright 2016 The etcd-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package version

var (
	Version = "0.8.0"
	GitSHA  = "Not provided (use ./build instead of go build)"
)
<commit_msg>version: bump version to 0.8.0+git (#1827)<commit_after>// Copyright 2016 The etcd-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package version

var (
	Version = "0.8.0+git"
	GitSHA  = "Not provided (use ./build instead of go build)"
)
<|endoftext|>


<commit_before>package version

var (
	// Package is filled at linking time
	Package = "github.com/containerd/containerd"

	// Version holds the complete version number. Filled in at linking time.
	Version = "1.0.0-alpha0+unknown"

	// Revision is filled with the VCS (e.g. git) revision being used to build
	// the program at linking time.
	Revision = ""
)
<commit_msg>containerd: prepare for v1.0.0-alpha1<commit_after>package version

var (
	// Package is filled at linking time
	Package = "github.com/containerd/containerd"

	// Version holds the complete version number. Filled in at linking time.
	Version = "1.0.0-alpha1+unknown"

	// Revision is filled with the VCS (e.g. git) revision being used to build
	// the program at linking time.
	Revision = ""
)
<|endoftext|>


<commit_before>package rpc_test

import (
	"errors"
	"net"
	"testing"

	"google.golang.org/grpc"

	"github.com/asdine/lobby"
	"github.com/asdine/lobby/mock"
	"github.com/asdine/lobby/rpc"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func newBackend(t *testing.T, b lobby.Backend) (*rpc.Backend, func()) {
	l, err := net.Listen("tcp", ":")
	require.NoError(t, err)

	srv := rpc.NewServer(rpc.WithBucketService(b))

	go func() {
		srv.Serve(l)
	}()

	conn, err := grpc.Dial(l.Addr().String(), grpc.WithInsecure())
	require.NoError(t, err)

	backend, err := rpc.NewBackend(conn)
	require.NoError(t, err)

	return backend, func() {
		backend.Close()
		srv.Stop()
	}
}

func TestBucketPut(t *testing.T) {
	t.Run("OK", func(t *testing.T) {
		var b mock.Backend

		b.BucketFn = func(name string) (lobby.Bucket, error) {
			require.Equal(t, "bucket", name)

			return &mock.Bucket{
				PutFn: func(key string, value []byte) (*lobby.Item, error) {
					assert.Equal(t, "key", key)
					assert.Equal(t, []byte(`"Value"`), value)
					return &lobby.Item{
						Key:   key,
						Value: value,
					}, nil
				},
			}, nil
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("bucket")
		require.NoError(t, err)

		item, err := bucket.Put("key", []byte(`"Value"`))
		require.NoError(t, err)
		require.Equal(t, "key", item.Key)
		require.Equal(t, []byte(`"Value"`), item.Value)
	})

	t.Run("BucketNotFound", func(t *testing.T) {
		var b mock.Backend
		b.BucketFn = func(name string) (lobby.Bucket, error) {
			assert.Equal(t, "unknown", name)
			return nil, lobby.ErrBucketNotFound
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("unknown")
		require.NoError(t, err)

		_, err = bucket.Put("key", []byte(`"Value"`))
		require.Error(t, err)
		require.Equal(t, lobby.ErrBucketNotFound, err)
	})

	t.Run("InternalError", func(t *testing.T) {
		var b mock.Backend

		b.BucketFn = func(name string) (lobby.Bucket, error) {
			require.Equal(t, "bucket", name)

			return &mock.Bucket{
				PutFn: func(key string, value []byte) (*lobby.Item, error) {
					assert.Equal(t, "key", key)
					assert.Equal(t, []byte(`"Value"`), value)
					return nil, errors.New("something unexpected happened !")
				},
			}, nil
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("bucket")
		require.NoError(t, err)

		_, err = bucket.Put("key", []byte(`"Value"`))
		require.Error(t, err)
	})

	t.Run("KeyNotFound", func(t *testing.T) {
		var b mock.Backend

		b.BucketFn = func(name string) (lobby.Bucket, error) {
			require.Equal(t, "bucket", name)

			return &mock.Bucket{
				PutFn: func(key string, value []byte) (*lobby.Item, error) {
					assert.Equal(t, "key", key)
					assert.Equal(t, []byte(`"Value"`), value)
					return nil, lobby.ErrKeyNotFound
				},
			}, nil
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("bucket")
		require.NoError(t, err)

		_, err = bucket.Put("key", []byte(`"Value"`))
		require.Error(t, err)
		require.Equal(t, lobby.ErrKeyNotFound, err)
	})
}

func TestBucketGet(t *testing.T) {
	t.Run("OK", func(t *testing.T) {
		var b mock.Backend

		b.BucketFn = func(name string) (lobby.Bucket, error) {
			assert.Equal(t, "bucket", name)

			return &mock.Bucket{
				GetFn: func(key string) (*lobby.Item, error) {
					assert.Equal(t, "key", key)
					return &lobby.Item{
						Key:   key,
						Value: []byte(`"Value"`),
					}, nil
				},
			}, nil
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("bucket")
		require.NoError(t, err)

		item, err := bucket.Get("key")
		require.NoError(t, err)
		require.Equal(t, "key", item.Key)
		require.Equal(t, []byte(`"Value"`), item.Value)
	})
}

func TestBucketDelete(t *testing.T) {
	t.Run("OK", func(t *testing.T) {
		var b mock.Backend

		b.BucketFn = func(name string) (lobby.Bucket, error) {
			assert.Equal(t, "bucket", name)

			return &mock.Bucket{
				DeleteFn: func(key string) error {
					assert.Equal(t, "key", key)
					return nil
				},
			}, nil
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("bucket")
		require.NoError(t, err)

		err = bucket.Delete("key")
		require.NoError(t, err)
	})
}
<commit_msg>Blocking dial on gRPC test<commit_after>package rpc_test

import (
	"errors"
	"net"
	"testing"

	"google.golang.org/grpc"

	"github.com/asdine/lobby"
	"github.com/asdine/lobby/mock"
	"github.com/asdine/lobby/rpc"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func newBackend(t *testing.T, b lobby.Backend) (*rpc.Backend, func()) {
	l, err := net.Listen("tcp", ":")
	require.NoError(t, err)

	srv := rpc.NewServer(rpc.WithBucketService(b))

	go func() {
		srv.Serve(l)
	}()

	conn, err := grpc.Dial(l.Addr().String(), grpc.WithInsecure(), grpc.WithBlock())
	require.NoError(t, err)

	backend, err := rpc.NewBackend(conn)
	require.NoError(t, err)

	return backend, func() {
		backend.Close()
		srv.Stop()
	}
}

func TestBucketPut(t *testing.T) {
	t.Run("OK", func(t *testing.T) {
		var b mock.Backend

		b.BucketFn = func(name string) (lobby.Bucket, error) {
			require.Equal(t, "bucket", name)

			return &mock.Bucket{
				PutFn: func(key string, value []byte) (*lobby.Item, error) {
					assert.Equal(t, "key", key)
					assert.Equal(t, []byte(`"Value"`), value)
					return &lobby.Item{
						Key:   key,
						Value: value,
					}, nil
				},
			}, nil
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("bucket")
		require.NoError(t, err)

		item, err := bucket.Put("key", []byte(`"Value"`))
		require.NoError(t, err)
		require.Equal(t, "key", item.Key)
		require.Equal(t, []byte(`"Value"`), item.Value)
	})

	t.Run("BucketNotFound", func(t *testing.T) {
		var b mock.Backend
		b.BucketFn = func(name string) (lobby.Bucket, error) {
			assert.Equal(t, "unknown", name)
			return nil, lobby.ErrBucketNotFound
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("unknown")
		require.NoError(t, err)

		_, err = bucket.Put("key", []byte(`"Value"`))
		require.Error(t, err)
		require.Equal(t, lobby.ErrBucketNotFound, err)
	})

	t.Run("InternalError", func(t *testing.T) {
		var b mock.Backend

		b.BucketFn = func(name string) (lobby.Bucket, error) {
			require.Equal(t, "bucket", name)

			return &mock.Bucket{
				PutFn: func(key string, value []byte) (*lobby.Item, error) {
					assert.Equal(t, "key", key)
					assert.Equal(t, []byte(`"Value"`), value)
					return nil, errors.New("something unexpected happened !")
				},
			}, nil
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("bucket")
		require.NoError(t, err)

		_, err = bucket.Put("key", []byte(`"Value"`))
		require.Error(t, err)
	})

	t.Run("KeyNotFound", func(t *testing.T) {
		var b mock.Backend

		b.BucketFn = func(name string) (lobby.Bucket, error) {
			require.Equal(t, "bucket", name)

			return &mock.Bucket{
				PutFn: func(key string, value []byte) (*lobby.Item, error) {
					assert.Equal(t, "key", key)
					assert.Equal(t, []byte(`"Value"`), value)
					return nil, lobby.ErrKeyNotFound
				},
			}, nil
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("bucket")
		require.NoError(t, err)

		_, err = bucket.Put("key", []byte(`"Value"`))
		require.Error(t, err)
		require.Equal(t, lobby.ErrKeyNotFound, err)
	})
}

func TestBucketGet(t *testing.T) {
	t.Run("OK", func(t *testing.T) {
		var b mock.Backend

		b.BucketFn = func(name string) (lobby.Bucket, error) {
			assert.Equal(t, "bucket", name)

			return &mock.Bucket{
				GetFn: func(key string) (*lobby.Item, error) {
					assert.Equal(t, "key", key)
					return &lobby.Item{
						Key:   key,
						Value: []byte(`"Value"`),
					}, nil
				},
			}, nil
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("bucket")
		require.NoError(t, err)

		item, err := bucket.Get("key")
		require.NoError(t, err)
		require.Equal(t, "key", item.Key)
		require.Equal(t, []byte(`"Value"`), item.Value)
	})
}

func TestBucketDelete(t *testing.T) {
	t.Run("OK", func(t *testing.T) {
		var b mock.Backend

		b.BucketFn = func(name string) (lobby.Bucket, error) {
			assert.Equal(t, "bucket", name)

			return &mock.Bucket{
				DeleteFn: func(key string) error {
					assert.Equal(t, "key", key)
					return nil
				},
			}, nil
		}

		backend, cleanup := newBackend(t, &b)
		defer cleanup()

		bucket, err := backend.Bucket("bucket")
		require.NoError(t, err)

		err = bucket.Delete("key")
		require.NoError(t, err)
	})
}
<|endoftext|>