<commit_before>package editor

import (
	"log"

	"github.com/atotto/clipboard"
	"github.com/gdamore/tcell"
	"github.com/jantb/olive/go_plugin"
	"github.com/jantb/olive/rpc"
	"github.com/jantb/olive/xi"
	"github.com/rivo/tview"
)

// View implements the view editor view.
type View struct {
	dataView map[string]*Dataview
	Lines    [][]Block
	*tview.Box
	*Editor
	offy, offx, height, width int
	findstatus                *rpc.FindStatus
}

type Block struct {
	Rune  rune
	Style tcell.Style
}

// NewView returns a new view view primitive.
func NewView() *View {
	view := View{
		Box:   tview.NewBox().SetBorder(false),
		Lines: [][]Block{},
	}
	return &view
}

// Draw draws this primitive onto the screen.
func (v *View) Draw(screen tcell.Screen) {
	_, bg, _ := defaultStyle.Decompose()
	v.Box.SetBackgroundColor(bg).Draw(screen)
	_, _, width, height := v.Box.GetInnerRect()
	v.height = height
	v.width = width
	v.Editor.mutex.Lock()
	defer v.Editor.mutex.Unlock()
	dataview := v.dataView[v.curViewID]
	if dataview == nil {
		return
	}

	lines := dataview.Lines()
	blocksy := [][]Block{}
	offy := v.offy
	offx := v.offx
	blocksy = getBlocks(lines, offy, height, blocksy, offx, width, v)

	v.Lines = blocksy
	v.drawBlocks(screen)
	v.drawCursors(lines, height, screen)
}

func getBlocks(lines []*xi.Line, offy int, height int, blocksy [][]Block, offx int, width int, m *View) [][]Block {

	for y, line := range lines[offy : offy+height] {
		if line == nil {
			continue
		}
		var blocks []Block
		blocksy = append(blocksy, blocks)
		offx := Max(0, Min(offx, len(line.Text)))
		for x, r := range line.Text[offx:Max(0, Min(offx+width, len(line.Text)))] {
			var style = defaultStyle
			if line.StyleIds[x+offx] != nil {
				for _, value := range line.StyleIds[x+offx] {
					s := styles[value]
					if value == 0 {
						s = s.Background(tcell.NewRGBColor(m.Editor.theme.Selection.ToRGB()))
					}

					fg, bg, _ := s.Decompose()

					if fg != tcell.ColorDefault {
						style = style.Foreground(fg)
					}
					if bg != tcell.ColorDefault {
						style = style.Background(bg)
					}
				}
			}
			blocksy[y] = append(blocksy[y], Block{Rune: r, Style: style})
		}
	}
	return blocksy
}

func (v *View) drawBlocks(screen tcell.Screen) {
	for y, line := range v.Lines {
		offx := 0
		for x, block := range line {
			if block.Rune == '\t' {
				v.draw(screen, x, y, block)
				v.draw(screen, x+1, y, block)
				v.draw(screen, x+2, y, block)
				v.draw(screen, x+3, y, block)
				offx += 3
				continue
			}
			v.draw(screen, x+offx, y, block)
		}
	}
}

func (v *View) drawCursors(lines []*xi.Line, h int, screen tcell.Screen) {
	for y, line := range lines[v.offy : v.offy+h] {
		if line == nil {
			continue
		}
		for _, cursor := range line.Cursors {
			x := GetCursorVisualX(cursor-v.offx, line.Text[Max(0, Min(v.offx, len(line.Text))):Max(0, Min(v.offx+v.width, len(line.Text)))])
			content := v.getContent(screen, x, y)
			content.Style = content.Style.Reverse(true)
			v.draw(screen, x, y, content)
		}
	}
}

func (v *View) draw(screen tcell.Screen, x int, y int, b Block) {

	xMin, yMin, width, height := v.Box.GetInnerRect()
	x = xMin + x
	y = yMin + y

	if x < xMin || y < yMin || x >= width+xMin || y >= height+yMin {
		return
	}
	screen.SetContent(x, y, b.Rune, nil, b.Style)
}

func (v *View) getContent(screen tcell.Screen, x int, y int) Block {

	xMin, yMin, width, height := v.Box.GetInnerRect()
	x = xMin + x
	y = yMin + y

	if x < xMin || y < yMin || x >= width+xMin || y >= height+yMin {
		return Block{}
	}
	mainc, _, style, _ := screen.GetContent(x, y)
	return Block{Rune: mainc, Style: style}
}

func (v *View) MakeVisible(x, y int) {
	lines := v.dataView[v.curViewID].Lines()
	y -= v.dataView[v.curViewID].LineCache.InvalidBefore()
	x = GetCursorVisualX(x, lines[y].Text)
	_, _, width, height := v.Box.GetInnerRect()

	if y >= v.offy+height {
		v.offy = y - (height - 1)
	}

	if y >= 0 && y < v.offy {
		v.offy = y
	}

	if x >= v.offx+width {
		v.offx = x - (width - 1)
	}
	if x >= 0 && x < v.offx {
		v.offx = x
	}
}

// InputHandler returns the handler for this primitive.
func (v *View) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
	return v.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
		dataview := v.dataView[v.curViewID]
		ctrl := event.Modifiers()&tcell.ModCtrl != 0
		alt := event.Modifiers()&tcell.ModAlt != 0
		shift := event.Modifiers()&tcell.ModShift != 0
		if !ctrl && !alt && !shift {
			switch event.Key() {
			case tcell.KeyEsc:
				v.findstatus = nil
				dataview.CancelOperation()
			case tcell.KeyUp:
				dataview.MoveUp()
			case tcell.KeyDown:
				dataview.MoveDown()
			case tcell.KeyLeft:
				dataview.MoveLeft()
			case tcell.KeyEnter:
				dataview.Newline()
			case tcell.KeyRight:
				dataview.MoveRight()
			case tcell.KeyRune:
				dataview.Insert(string(event.Rune()))
			case tcell.KeyHome:
				dataview.MoveToBeginningOfLine()
			case tcell.KeyEnd:
				dataview.MoveToEndOfLine()
			case tcell.KeyTab:
				dataview.Tab()
			case tcell.KeyBS:
				dataview.DeleteForward()
			case tcell.KeyDelete:
				dataview.DeleteForward()
			case tcell.KeyBackspace2:
				dataview.DeleteBackward()
			case tcell.KeyPgUp:
				dataview.ScrollPageUp()
			case tcell.KeyPgDn:
				dataview.ScrollPageDown()
			default:
				log.Println(event.Name())
			}
		}
		if !ctrl && !alt && shift {
			switch event.Key() {
			case tcell.KeyRune:
				dataview.Insert(string(event.Rune()))
			case tcell.KeyPgUp:
				dataview.ScrollPageUpAndModifySelection()
			case tcell.KeyPgDn:
				dataview.ScrollPageDownAndModifySelection()
			case tcell.KeyHome:
				dataview.MoveToBeginningOfLineAndModifySelection()
			case tcell.KeyEnd:
				dataview.MoveToEndOfLineAndModifySelection()
			}
			switch event.Name() {
			case "Shift+Right":
				dataview.MoveRightAndModifySelection()
			case "Shift+Left":
				dataview.MoveLeftAndModifySelection()
			case "Shift+Up":
				dataview.MoveUpAndModifySelection()
			case "Shift+Down":
				dataview.MoveDownAndModifySelection()
			default:
				log.Println(event.Name())
			}
		}
		if ctrl && alt {
			switch event.Name() {
			case "Alt+Ctrl+Z":
				dataview.Redo()
			case "Alt+Ctrl+L":
				if v.footer.language == "Go" {
					dataview.CancelOperation()
					dataview.SelectAll()
					src := dataview.Copy()
					dataview.Insert(go_plugin.Format(src))
					dataview.CancelOperation()
				} else if v.footer.language == "XML" {
					dataview.CancelOperation()
					dataview.SelectAll()
					src := dataview.Copy()
					dataview.Insert(go_plugin.FormatXml(src))
					dataview.CancelOperation()
				} else if v.footer.language == "JSON" {
					dataview.CancelOperation()
					dataview.SelectAll()
					src := dataview.Copy()
					dataview.Insert(go_plugin.FormatJson(src))
					dataview.CancelOperation()
				}

			}
		}
		if ctrl && !alt && !shift {
			switch event.Key() {
			case tcell.KeyCtrlG:
				v.pages.ShowPage("gotoLine")
				v.pages.SendToBack("editor")
				v.pages.SendToFront("gotoLine")
			case tcell.KeyBS:
				dataview.DeleteWordForward()
			case tcell.KeyHome:
				dataview.MoveToBeginningOfDocument()
			case tcell.KeyEnd:
				dataview.MoveToEndOfDocument()
			case tcell.KeyDelete:
				dataview.DeleteWordForward()
			case tcell.KeyBackspace2:
				dataview.DeleteBackward()
			case tcell.KeyLeft:
				dataview.MoveWordLeft()
			case tcell.KeyRight:
				dataview.MoveWordRight()
			case tcell.KeyUp:
				dataview.MoveLineUp()
			case tcell.KeyDown:
				dataview.MoveLineDown()
			case tcell.KeyCtrlS:
				dataview.Save()
			case tcell.KeyCtrlC:
				data := dataview.Copy()
				if data == "" {
					dataview.SelectLine()
					data = dataview.Copy()
				}
				clipboard.WriteAll(data)
			case tcell.KeyCtrlX:
				clipboard.WriteAll(dataview.Cut())
			case tcell.KeyCtrlA:
				dataview.SelectAll()
			case tcell.KeyCtrlZ:
				dataview.Undo()
			case tcell.KeyCtrlV:
				s, e := clipboard.ReadAll()
				if e != nil {
					log.Println(e)
					return
				}
				dataview.Insert(s)
			case tcell.KeyCtrlQ:
				dataview.Close()
				v.header.path = ""
				v.curViewID = ""
				v.footer.totalLines = 0
				v.footer.cursorX = 0
				v.footer.cursorY = 0
				v.focusFileselector()
			case tcell.KeyCtrlD:
				dataview.DuplicateLine()
			default:
				log.Println(event.Name())
			}
		}
		if !ctrl && alt {
			switch event.Name() {
			case "Alt+Up":
				dataview.AddSelectionAbove()
			case "Alt+Rune[N]":
				log.Println("open file")
			case "Alt+Rune[j]":
				if v.findstatus == nil {
					s := dataview.Copy()
					if s == "" {
						dataview.MoveWordLeft()
						dataview.MoveWordRightAndModifySelection()
						s = dataview.Copy()
					}
					dataview.Find(s, false, false, false)
				}
				dataview.FindNext(true, true, "add")
			case "Alt+Down":
				dataview.AddSelectionBelow()
			case "Alt+Rune[0]":
				v.focusFileselector()
			default:
				log.Println(event.Name())
			}
		}
		log.Println(event.Name())
	})
}
<commit_msg>Minor fix for coloring offset<commit_after>package editor

import (
	"log"

	"github.com/atotto/clipboard"
	"github.com/gdamore/tcell"
	"github.com/jantb/olive/go_plugin"
	"github.com/jantb/olive/rpc"
	"github.com/jantb/olive/xi"
	"github.com/rivo/tview"
)

// View implements the view editor view.
type View struct {
	dataView map[string]*Dataview
	Lines    [][]Block
	*tview.Box
	*Editor
	offy, offx, height, width int
	findstatus                *rpc.FindStatus
}

type Block struct {
	Rune  rune
	Style tcell.Style
}

// NewView returns a new view view primitive.
func NewView() *View {
	view := View{
		Box:   tview.NewBox().SetBorder(false),
		Lines: [][]Block{},
	}
	return &view
}

// Draw draws this primitive onto the screen.
func (v *View) Draw(screen tcell.Screen) {
	_, bg, _ := defaultStyle.Decompose()
	v.Box.SetBackgroundColor(bg).Draw(screen)
	_, _, width, height := v.Box.GetInnerRect()
	v.height = height
	v.width = width
	v.Editor.mutex.Lock()
	defer v.Editor.mutex.Unlock()
	dataview := v.dataView[v.curViewID]
	if dataview == nil {
		return
	}

	lines := dataview.Lines()
	blocksy := [][]Block{}
	offy := v.offy
	offx := v.offx
	blocksy = getBlocks(lines, offy, height, blocksy, offx, width, v)

	v.Lines = blocksy
	v.drawBlocks(screen)
	v.drawCursors(lines, height, screen)
}

func getBlocks(lines []*xi.Line, offy int, height int, blocksy [][]Block, offx int, width int, m *View) [][]Block {

	for y, line := range lines[offy : offy+height] {
		if line == nil {
			continue
		}
		var blocks []Block
		blocksy = append(blocksy, blocks)
		offxStart := Max(0, Min(offx, len(line.Text)))
		for x, r := range line.Text[offxStart:Max(0, Min(offx+width, len(line.Text)))] {
			var style = defaultStyle
			if line.StyleIds[x+offxStart] != nil {
				for _, value := range line.StyleIds[x+offxStart] {
					s := styles[value]
					if value == 0 {
						s = s.Background(tcell.NewRGBColor(m.Editor.theme.Selection.ToRGB()))
					}

					fg, bg, _ := s.Decompose()

					if fg != tcell.ColorDefault {
						style = style.Foreground(fg)
					}
					if bg != tcell.ColorDefault {
						style = style.Background(bg)
					}
				}
			}
			blocksy[y] = append(blocksy[y], Block{Rune: r, Style: style})
		}
	}
	return blocksy
}

func (v *View) drawBlocks(screen tcell.Screen) {
	for y, line := range v.Lines {
		offx := 0
		for x, block := range line {
			if block.Rune == '\t' {
				v.draw(screen, x, y, block)
				v.draw(screen, x+1, y, block)
				v.draw(screen, x+2, y, block)
				v.draw(screen, x+3, y, block)
				offx += 3
				continue
			}
			v.draw(screen, x+offx, y, block)
		}
	}
}

func (v *View) drawCursors(lines []*xi.Line, h int, screen tcell.Screen) {
	for y, line := range lines[v.offy : v.offy+h] {
		if line == nil {
			continue
		}
		for _, cursor := range line.Cursors {
			x := GetCursorVisualX(cursor-v.offx, line.Text[Max(0, Min(v.offx, len(line.Text))):Max(0, Min(v.offx+v.width, len(line.Text)))])
			content := v.getContent(screen, x, y)
			content.Style = content.Style.Reverse(true)
			v.draw(screen, x, y, content)
		}
	}
}

func (v *View) draw(screen tcell.Screen, x int, y int, b Block) {

	xMin, yMin, width, height := v.Box.GetInnerRect()
	x = xMin + x
	y = yMin + y

	if x < xMin || y < yMin || x >= width+xMin || y >= height+yMin {
		return
	}
	screen.SetContent(x, y, b.Rune, nil, b.Style)
}

func (v *View) getContent(screen tcell.Screen, x int, y int) Block {

	xMin, yMin, width, height := v.Box.GetInnerRect()
	x = xMin + x
	y = yMin + y

	if x < xMin || y < yMin || x >= width+xMin || y >= height+yMin {
		return Block{}
	}
	mainc, _, style, _ := screen.GetContent(x, y)
	return Block{Rune: mainc, Style: style}
}

func (v *View) MakeVisible(x, y int) {
	lines := v.dataView[v.curViewID].Lines()
	y -= v.dataView[v.curViewID].LineCache.InvalidBefore()
	x = GetCursorVisualX(x, lines[y].Text)
	_, _, width, height := v.Box.GetInnerRect()

	if y >= v.offy+height {
		v.offy = y - (height - 1)
	}

	if y >= 0 && y < v.offy {
		v.offy = y
	}

	if x >= v.offx+width {
		v.offx = x - (width - 1)
	}
	if x >= 0 && x < v.offx {
		v.offx = x
	}
}

// InputHandler returns the handler for this primitive.
func (v *View) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
	return v.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
		dataview := v.dataView[v.curViewID]
		ctrl := event.Modifiers()&tcell.ModCtrl != 0
		alt := event.Modifiers()&tcell.ModAlt != 0
		shift := event.Modifiers()&tcell.ModShift != 0
		if !ctrl && !alt && !shift {
			switch event.Key() {
			case tcell.KeyEsc:
				v.findstatus = nil
				dataview.CancelOperation()
			case tcell.KeyUp:
				dataview.MoveUp()
			case tcell.KeyDown:
				dataview.MoveDown()
			case tcell.KeyLeft:
				dataview.MoveLeft()
			case tcell.KeyEnter:
				dataview.Newline()
			case tcell.KeyRight:
				dataview.MoveRight()
			case tcell.KeyRune:
				dataview.Insert(string(event.Rune()))
			case tcell.KeyHome:
				dataview.MoveToBeginningOfLine()
			case tcell.KeyEnd:
				dataview.MoveToEndOfLine()
			case tcell.KeyTab:
				dataview.Tab()
			case tcell.KeyBS:
				dataview.DeleteForward()
			case tcell.KeyDelete:
				dataview.DeleteForward()
			case tcell.KeyBackspace2:
				dataview.DeleteBackward()
			case tcell.KeyPgUp:
				dataview.ScrollPageUp()
			case tcell.KeyPgDn:
				dataview.ScrollPageDown()
			default:
				log.Println(event.Name())
			}
		}
		if !ctrl && !alt && shift {
			switch event.Key() {
			case tcell.KeyRune:
				dataview.Insert(string(event.Rune()))
			case tcell.KeyPgUp:
				dataview.ScrollPageUpAndModifySelection()
			case tcell.KeyPgDn:
				dataview.ScrollPageDownAndModifySelection()
			case tcell.KeyHome:
				dataview.MoveToBeginningOfLineAndModifySelection()
			case tcell.KeyEnd:
				dataview.MoveToEndOfLineAndModifySelection()
			}
			switch event.Name() {
			case "Shift+Right":
				dataview.MoveRightAndModifySelection()
			case "Shift+Left":
				dataview.MoveLeftAndModifySelection()
			case "Shift+Up":
				dataview.MoveUpAndModifySelection()
			case "Shift+Down":
				dataview.MoveDownAndModifySelection()
			default:
				log.Println(event.Name())
			}
		}
		if ctrl && alt {
			switch event.Name() {
			case "Alt+Ctrl+Z":
				dataview.Redo()
			case "Alt+Ctrl+L":
				if v.footer.language == "Go" {
					dataview.CancelOperation()
					dataview.SelectAll()
					src := dataview.Copy()
					dataview.Insert(go_plugin.Format(src))
					dataview.CancelOperation()
				} else if v.footer.language == "XML" {
					dataview.CancelOperation()
					dataview.SelectAll()
					src := dataview.Copy()
					dataview.Insert(go_plugin.FormatXml(src))
					dataview.CancelOperation()
				} else if v.footer.language == "JSON" {
					dataview.CancelOperation()
					dataview.SelectAll()
					src := dataview.Copy()
					dataview.Insert(go_plugin.FormatJson(src))
					dataview.CancelOperation()
				}

			}
		}
		if ctrl && !alt && !shift {
			switch event.Key() {
			case tcell.KeyCtrlG:
				v.pages.ShowPage("gotoLine")
				v.pages.SendToBack("editor")
				v.pages.SendToFront("gotoLine")
			case tcell.KeyBS:
				dataview.DeleteWordForward()
			case tcell.KeyHome:
				dataview.MoveToBeginningOfDocument()
			case tcell.KeyEnd:
				dataview.MoveToEndOfDocument()
			case tcell.KeyDelete:
				dataview.DeleteWordForward()
			case tcell.KeyBackspace2:
				dataview.DeleteBackward()
			case tcell.KeyLeft:
				dataview.MoveWordLeft()
			case tcell.KeyRight:
				dataview.MoveWordRight()
			case tcell.KeyUp:
				dataview.MoveLineUp()
			case tcell.KeyDown:
				dataview.MoveLineDown()
			case tcell.KeyCtrlS:
				dataview.Save()
			case tcell.KeyCtrlC:
				data := dataview.Copy()
				if data == "" {
					dataview.SelectLine()
					data = dataview.Copy()
				}
				clipboard.WriteAll(data)
			case tcell.KeyCtrlX:
				clipboard.WriteAll(dataview.Cut())
			case tcell.KeyCtrlA:
				dataview.SelectAll()
			case tcell.KeyCtrlZ:
				dataview.Undo()
			case tcell.KeyCtrlV:
				s, e := clipboard.ReadAll()
				if e != nil {
					log.Println(e)
					return
				}
				dataview.Insert(s)
			case tcell.KeyCtrlQ:
				dataview.Close()
				v.header.path = ""
				v.curViewID = ""
				v.footer.totalLines = 0
				v.footer.cursorX = 0
				v.footer.cursorY = 0
				v.focusFileselector()
			case tcell.KeyCtrlD:
				dataview.DuplicateLine()
			default:
				log.Println(event.Name())
			}
		}
		if !ctrl && alt {
			switch event.Name() {
			case "Alt+Up":
				dataview.AddSelectionAbove()
			case "Alt+Rune[N]":
				log.Println("open file")
			case "Alt+Rune[j]":
				if v.findstatus == nil {
					s := dataview.Copy()
					if s == "" {
						dataview.MoveWordLeft()
						dataview.MoveWordRightAndModifySelection()
						s = dataview.Copy()
					}
					dataview.Find(s, false, false, false)
				}
				dataview.FindNext(true, true, "add")
			case "Alt+Down":
				dataview.AddSelectionBelow()
			case "Alt+Rune[0]":
				v.focusFileselector()
			default:
				log.Println(event.Name())
			}
		}
		log.Println(event.Name())
	})
}
<|endoftext|>


<commit_before><commit_msg>Add NoSync field to Options<commit_after><|endoftext|>


<commit_before><commit_msg>Don't take address when marshaling<commit_after><|endoftext|>


<commit_before><commit_msg>Add more JS sub opts<commit_after><|endoftext|>


<commit_before>/*
Copyright 2016, RadiantBlue Technologies, 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.
*/

package handlers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"strconv"
)

// VoOptions defines options for the VO function.
type VoOptions struct {
	Filename    *string `json:"filename"` // list of input file paths
	AGL         float64 `json:"agl"`
	MaxSize     uint16  `json:"max_size"`
	MinSize     uint16  `json:"min_size"`
	Resolution  float64 `json:"resolution"`
	Tolerance   float64 `json:"tolerance"`
	Z0Tolerance float64 `json:"z0_tolerance"`
	Denoise     bool    `json:"denoise"`
}

// NewVoOptions constructs VoOptions with default values.
func NewVoOptions() *VoOptions {
	return &VoOptions{AGL: 20.0, MaxSize: 65535, MinSize: 1, Resolution: 10, Tolerance: 3, Z0Tolerance: 6.0}
}

func getFloatAsString(name string, val float64) string {
	return name + "=" + strconv.FormatFloat(val, 'f', -1, 64)
}

func getUintAsString(name string, val uint16) string {
	return name + "=" + strconv.FormatUint(uint64(val), 10)
}

// VoHandler handles PDAL jobs.
func VoHandler(w http.ResponseWriter, r *http.Request) *AppError {
	if r.Body == nil {
		return &AppError{nil, "No JSON", http.StatusBadRequest}
	}

	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}

	opts := NewVoOptions()
	if b != nil {
		if err := json.Unmarshal(b, &opts); err != nil {
			return &AppError{err, err.Error(), http.StatusInternalServerError}
		}
	}

	if opts.Filename == nil {
		return &AppError{err, "No filename", http.StatusInternalServerError}
	}

	s3url, err := url.Parse(*opts.Filename)
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}

	name, _, err := inferAndDownload(s3url)
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}

	outFile := "out.json"
	os.Remove(outFile)

	args := []string{
		"translate", name, outFile,
		"-w", "writers.vo", "-v", "3", "--debug",
		getFloatAsString("--writers.vo.agl", opts.AGL),
		getUintAsString("--writers.vo.max_size", opts.MaxSize),
		getUintAsString("--writers.vo.min_size", opts.MinSize),
		getFloatAsString("--writers.vo.resolution", opts.Resolution),
		getFloatAsString("--writers.vo.tolerance", opts.Tolerance),
		getFloatAsString("--writers.vo.z0_tolerance", opts.Z0Tolerance),
	}
	if opts.Denoise {
		args = append(args, "-f", "filters.statisticaloutlier", "--filters.statisticaloutlier.extract=true")
	}
	log.Println("PDAL CLI called with args", args)
	out, err := exec.Command("pdal", args...).CombinedOutput()
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}
	log.Println("PDAL CLI responded with")
	log.Println(string(out))

	fileOut, err := os.Open(outFile)
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}
	defer fileOut.Close()

	src, err := ioutil.ReadAll(fileOut)
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}

	buffer := new(bytes.Buffer)
	if err := json.Compact(buffer, src); err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, buffer.String())

	os.Remove(name)

	return nil
}
<commit_msg>First attempt at assigning an SRS<commit_after>/*
Copyright 2016, RadiantBlue Technologies, 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.
*/

package handlers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"strconv"
)

// VoOptions defines options for the VO function.
type VoOptions struct {
	Filename    *string `json:"filename"` // list of input file paths
	AGL         float64 `json:"agl"`
	MaxSize     uint16  `json:"max_size"`
	MinSize     uint16  `json:"min_size"`
	Resolution  float64 `json:"resolution"`
	Tolerance   float64 `json:"tolerance"`
	Z0Tolerance float64 `json:"z0_tolerance"`
	Denoise     bool    `json:"denoise"`
	AssignSRS   *string `json:"a_srs"`
}

// NewVoOptions constructs VoOptions with default values.
func NewVoOptions() *VoOptions {
	return &VoOptions{AGL: 20.0, MaxSize: 65535, MinSize: 1, Resolution: 10, Tolerance: 3, Z0Tolerance: 6.0}
}

func getFloatAsString(name string, val float64) string {
	return name + "=" + strconv.FormatFloat(val, 'f', -1, 64)
}

func getUintAsString(name string, val uint16) string {
	return name + "=" + strconv.FormatUint(uint64(val), 10)
}

// VoHandler handles PDAL jobs.
func VoHandler(w http.ResponseWriter, r *http.Request) *AppError {
	if r.Body == nil {
		return &AppError{nil, "No JSON", http.StatusBadRequest}
	}

	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}

	opts := NewVoOptions()
	if b != nil {
		if err := json.Unmarshal(b, &opts); err != nil {
			return &AppError{err, err.Error(), http.StatusInternalServerError}
		}
	}

	if opts.Filename == nil {
		return &AppError{err, "No filename", http.StatusInternalServerError}
	}

	s3url, err := url.Parse(*opts.Filename)
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}

	name, _, err := inferAndDownload(s3url)
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}

	outFile := "out.json"
	os.Remove(outFile)

	if opts.AssignSRS != nil {
		projected := name + "-projected.laz"

		projStr := "--writers.las.a_srs=" + *opts.AssignSRS

		srsArgs := []string{
			"translate", name, projected, projStr, "-v", "3", "--debug",
		}
		log.Println("Assigning SRS with args", srsArgs)
		srsOut, srsErr := exec.Command("pdal", srsArgs...).CombinedOutput()
		if err != nil {
			return &AppError{srsErr, srsErr.Error(), http.StatusInternalServerError}
		}
		log.Println("PDAL CLI responded with")
		log.Println(string(srsOut))

		name = projected
	}

	args := []string{
		"translate", name, outFile,
		"-w", "writers.vo", "-v", "3", "--debug",
		getFloatAsString("--writers.vo.agl", opts.AGL),
		getUintAsString("--writers.vo.max_size", opts.MaxSize),
		getUintAsString("--writers.vo.min_size", opts.MinSize),
		getFloatAsString("--writers.vo.resolution", opts.Resolution),
		getFloatAsString("--writers.vo.tolerance", opts.Tolerance),
		getFloatAsString("--writers.vo.z0_tolerance", opts.Z0Tolerance),
	}
	if opts.Denoise {
		args = append(args, "-f", "filters.statisticaloutlier", "--filters.statisticaloutlier.extract=true")
	}
	log.Println("PDAL CLI called with args", args)
	out, err := exec.Command("pdal", args...).CombinedOutput()
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}
	log.Println("PDAL CLI responded with")
	log.Println(string(out))

	fileOut, err := os.Open(outFile)
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}
	defer fileOut.Close()

	src, err := ioutil.ReadAll(fileOut)
	if err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}

	buffer := new(bytes.Buffer)
	if err := json.Compact(buffer, src); err != nil {
		return &AppError{err, err.Error(), http.StatusInternalServerError}
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, buffer.String())

	// TODO(chambbj): there is a case where we have assigned a projected, which
	// created another file that needs to be cleaned up...may be better in the
	// future to create/use a temp dir that just gets cleared, wiping everything
	os.Remove(name)

	return nil
}
<|endoftext|>


<commit_before>package health

import (
	"errors"
	"github.com/c9s/goprocinfo/linux"
	"runtime"
)

const (
	// General memory stats
	CurrentMemoryUtilizationAlloc   Stat = "CurrentMemoryUtilizationAlloc"
	CurrentMemoryUtilizationHeapSys Stat = "CurrentMemoryUtilizationHeapSys"
	CurrentMemoryUtilizationActive  Stat = "CurrentMemoryUtilizationActive"
	MaxMemoryUtilizationAlloc       Stat = "MaxMemoryUtilizationAlloc"
	MaxMemoryUtilizationHeapSys     Stat = "MaxMemoryUtilizationHeapSys"
	MaxMemoryUtilizationActive      Stat = "MaxMemoryUtilizationActive"
)

var (
	// commonStats is the Stats used to seed the initial set of stats
	// the request-specific stats are not included
	commonStats = Stats{
		CurrentMemoryUtilizationAlloc:   0,
		CurrentMemoryUtilizationHeapSys: 0,
		CurrentMemoryUtilizationActive:  0,
		MaxMemoryUtilizationAlloc:       0,
		MaxMemoryUtilizationHeapSys:     0,
		MaxMemoryUtilizationActive:      0,
	}

	// Invalid stat option error
	ErrorInvalidOption = errors.New("Invalid stat option")
)

// Option describes an option that can be set on a Stats map.
// Various types implement this interface.
type Option interface {
	Set(Stats)
}

// Stat is a named piece of data to be tracked
type Stat string

// Create/Set the stat initially
func (s Stat) Set(stats Stats) {
	if _, ok := stats[s]; !ok {
		stats[s] = 0
	}
}

// HealthFunc functions are allowed to modify the passed-in stats.
type HealthFunc func(Stats)

func (f HealthFunc) Set(stats Stats) {
	f(stats)
}

// Ensure makes certain the given stat is defined.  If it does not exist,
// it is initialized to 0.  Otherwise, the existing stat value is left intact.
func Ensure(stat Stat) HealthFunc {
	return func(stats Stats) {
		if _, ok := stats[stat]; !ok {
			stats[stat] = 0
		}
	}
}

// Inc increments the given stat by a certain amount
func Inc(stat Stat, value int) HealthFunc {
	return func(stats Stats) {
		stats[stat] += value
	}
}

// Set changes (or, initializes) the stat to the given value
func Set(stat Stat, value int) HealthFunc {
	return func(stats Stats) {
		stats[stat] = value
	}
}

// Stats is mapping of Stat to value
type Stats map[Stat]int

func (s Stats) Set(stats Stats) {
	for key, value := range s {
		stats[key] = value
	}
}

// Clone returns a distinct copy of this Stats object
func (s Stats) Clone() Stats {
	clone := make(Stats, len(s))
	for key, value := range s {
		clone[key] = value
	}

	return clone
}

// Apply invokes each Option.Set() on this stats map.
func (s Stats) Apply(options ...Option) {
	for _, option := range options {
		option.Set(s)
	}
}

// UpdateMemInfo takes memory information from a linux environment and
// sets the appropriate stats.
func (s Stats) UpdateMemInfo(memInfo *linux.MemInfo) {
	active := int(memInfo.Active * 1024)
	s[CurrentMemoryUtilizationActive] = active
	if active > s[MaxMemoryUtilizationActive] {
		s[MaxMemoryUtilizationActive] = active
	}
}

// UpdateMemStats takes a MemStats from the golang runtime and sets the
// appropriate stats.
func (s Stats) UpdateMemStats(memStats *runtime.MemStats) {
	alloc := int(memStats.Alloc)
	heapsys := int(memStats.HeapSys)

	// set current
	s[CurrentMemoryUtilizationAlloc] = alloc
	s[CurrentMemoryUtilizationHeapSys] = heapsys

	// set max
	if alloc > s[MaxMemoryUtilizationAlloc] {
		s[MaxMemoryUtilizationAlloc] = alloc
	}

	if heapsys > s[MaxMemoryUtilizationHeapSys] {
		s[MaxMemoryUtilizationHeapSys] = heapsys
	}
}

// UpdateMemory updates all the memory statistics
func (s Stats) UpdateMemory(memInfoReader *MemInfoReader) {
	memInfo, err := memInfoReader.Read()
	if err == nil {
		s.UpdateMemInfo(memInfo)
	}

	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)
	s.UpdateMemStats(&memStats)
}
<commit_msg>Added an Options constructor, to replace Bundle<commit_after>package health

import (
	"errors"
	"github.com/c9s/goprocinfo/linux"
	"runtime"
)

const (
	// General memory stats
	CurrentMemoryUtilizationAlloc   Stat = "CurrentMemoryUtilizationAlloc"
	CurrentMemoryUtilizationHeapSys Stat = "CurrentMemoryUtilizationHeapSys"
	CurrentMemoryUtilizationActive  Stat = "CurrentMemoryUtilizationActive"
	MaxMemoryUtilizationAlloc       Stat = "MaxMemoryUtilizationAlloc"
	MaxMemoryUtilizationHeapSys     Stat = "MaxMemoryUtilizationHeapSys"
	MaxMemoryUtilizationActive      Stat = "MaxMemoryUtilizationActive"
)

var (
	// commonStats is the Stats used to seed the initial set of stats
	// the request-specific stats are not included
	commonStats = Stats{
		CurrentMemoryUtilizationAlloc:   0,
		CurrentMemoryUtilizationHeapSys: 0,
		CurrentMemoryUtilizationActive:  0,
		MaxMemoryUtilizationAlloc:       0,
		MaxMemoryUtilizationHeapSys:     0,
		MaxMemoryUtilizationActive:      0,
	}

	// Invalid stat option error
	ErrorInvalidOption = errors.New("Invalid stat option")
)

// Option describes an option that can be set on a Stats map.
// Various types implement this interface.
type Option interface {
	Set(Stats)
}

// Stat is a named piece of data to be tracked
type Stat string

// Create/Set the stat initially
func (s Stat) Set(stats Stats) {
	if _, ok := stats[s]; !ok {
		stats[s] = 0
	}
}

// HealthFunc functions are allowed to modify the passed-in stats.
type HealthFunc func(Stats)

func (f HealthFunc) Set(stats Stats) {
	f(stats)
}

// Options aggregates a sequence of options into a single Option.
// This constructor allows multiple options to be set atomically as a group.
func Options(options ...Option) Option {
	return HealthFunc(func(stats Stats) {
		for _, option := range options {
			option.Set(stats)
		}
	})
}

// Ensure makes certain the given stat is defined.  If it does not exist,
// it is initialized to 0.  Otherwise, the existing stat value is left intact.
func Ensure(stat Stat) HealthFunc {
	return func(stats Stats) {
		if _, ok := stats[stat]; !ok {
			stats[stat] = 0
		}
	}
}

// Inc increments the given stat by a certain amount
func Inc(stat Stat, value int) HealthFunc {
	return func(stats Stats) {
		stats[stat] += value
	}
}

// Set changes (or, initializes) the stat to the given value
func Set(stat Stat, value int) HealthFunc {
	return func(stats Stats) {
		stats[stat] = value
	}
}

// Stats is mapping of Stat to value
type Stats map[Stat]int

func (s Stats) Set(stats Stats) {
	for key, value := range s {
		stats[key] = value
	}
}

// Clone returns a distinct copy of this Stats object
func (s Stats) Clone() Stats {
	clone := make(Stats, len(s))
	for key, value := range s {
		clone[key] = value
	}

	return clone
}

// Apply invokes each Option.Set() on this stats map.
func (s Stats) Apply(options ...Option) {
	for _, option := range options {
		option.Set(s)
	}
}

// UpdateMemInfo takes memory information from a linux environment and
// sets the appropriate stats.
func (s Stats) UpdateMemInfo(memInfo *linux.MemInfo) {
	active := int(memInfo.Active * 1024)
	s[CurrentMemoryUtilizationActive] = active
	if active > s[MaxMemoryUtilizationActive] {
		s[MaxMemoryUtilizationActive] = active
	}
}

// UpdateMemStats takes a MemStats from the golang runtime and sets the
// appropriate stats.
func (s Stats) UpdateMemStats(memStats *runtime.MemStats) {
	alloc := int(memStats.Alloc)
	heapsys := int(memStats.HeapSys)

	// set current
	s[CurrentMemoryUtilizationAlloc] = alloc
	s[CurrentMemoryUtilizationHeapSys] = heapsys

	// set max
	if alloc > s[MaxMemoryUtilizationAlloc] {
		s[MaxMemoryUtilizationAlloc] = alloc
	}

	if heapsys > s[MaxMemoryUtilizationHeapSys] {
		s[MaxMemoryUtilizationHeapSys] = heapsys
	}
}

// UpdateMemory updates all the memory statistics
func (s Stats) UpdateMemory(memInfoReader *MemInfoReader) {
	memInfo, err := memInfoReader.Read()
	if err == nil {
		s.UpdateMemInfo(memInfo)
	}

	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)
	s.UpdateMemStats(&memStats)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Chris Hanks
//
// MIT License
//
// 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 que

// Thanks to RhodiumToad in #postgresql for help with the job lock CTE.
const (
	sqlLockJob = `
WITH RECURSIVE job AS (
  SELECT (j).*, pg_try_advisory_lock((j).job_id) AS locked
  FROM (
    SELECT j
    FROM que_jobs AS j
    WHERE queue = $1::text
    AND run_at <= now()
    ORDER BY priority, run_at, job_id
    LIMIT 1
  ) AS t1
  UNION ALL (
    SELECT (j).*, pg_try_advisory_lock((j).job_id) AS locked
    FROM (
      SELECT (
        SELECT j
        FROM que_jobs AS j
        WHERE queue = $1::text
        AND run_at <= now()
        AND (priority, run_at, job_id) > (job.priority, job.run_at, job.job_id)
        ORDER BY priority, run_at, job_id
        LIMIT 1
      ) AS j
      FROM job
      WHERE NOT job.locked
      LIMIT 1
    ) AS t1
  )
)
SELECT queue, priority, run_at, job_id, job_class, args, error_count
FROM job
WHERE locked
LIMIT 1
`

	sqlCheckJob = `
SELECT 1 AS one
FROM   que_jobs
WHERE  queue    = $1::text
AND    priority = $2::smallint
AND    run_at   = $3::timestamptz
AND    job_id   = $4::bigint
`

	sqlSetError = `
UPDATE que_jobs
SET error_count = $1::integer,
    run_at      = now() + $2::bigint * '1 second'::interval,
    last_error  = $3::text
WHERE queue     = $4::text
AND   priority  = $5::smallint
AND   run_at    = $6::timestamptz
AND   job_id    = $7::bigint
`

	sqlInsertJob = `
INSERT INTO que_jobs
(queue, priority, run_at, job_class, args)
VALUES
(coalesce($1, '')::text, coalesce($2, 100)::smallint, coalesce($3, 'now')::timestamptz, $4::text, coalesce($5, '[]')::json)
`

	sqlInsertJobAndReturn = `
INSERT INTO que_jobs
(queue, priority, run_at, job_class, args)
VALUES
(coalesce($1, '')::text, coalesce($2, 100)::smallint, coalesce($3, 'now')::timestamptz, $4::text, coalesce($5, '[]')::json)
RETURNING *
`

	sqlDestroyJob = `
DELETE FROM que_jobs
WHERE queue    = $1::text
AND   priority = $2::smallint
AND   run_at   = $3::timestamptz
AND   job_id   = $4::bigint
`

	sqlJobStats = `
SELECT queue,
       job_class,
       count(*)                    AS count,
       count(locks.job_id)         AS count_working,
       sum((error_count > 0)::int) AS count_errored,
       max(error_count)            AS highest_error_count,
       min(run_at)                 AS oldest_run_at
FROM que_jobs
LEFT JOIN (
  SELECT (classid::bigint << 32) + objid::bigint AS job_id
  FROM pg_locks
  WHERE locktype = 'advisory'
) locks USING (job_id)
GROUP BY queue, job_class
ORDER BY count(*) DESC
`

	sqlWorkerStates = `
SELECT que_jobs.*,
       pg.pid          AS pg_backend_pid,
       pg.state        AS pg_state,
       pg.state_change AS pg_state_changed_at,
       pg.query        AS pg_last_query,
       pg.query_start  AS pg_last_query_started_at,
       pg.xact_start   AS pg_transaction_started_at,
       pg.waiting      AS pg_waiting_on_lock
FROM que_jobs
JOIN (
  SELECT (classid::bigint << 32) + objid::bigint AS job_id, pg_stat_activity.*
  FROM pg_locks
  JOIN pg_stat_activity USING (pid)
  WHERE locktype = 'advisory'
) pg USING (job_id)
`
)
<commit_msg>don't need to return values on job insert<commit_after>// Copyright (c) 2013 Chris Hanks
//
// MIT License
//
// 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 que

// Thanks to RhodiumToad in #postgresql for help with the job lock CTE.
const (
	sqlLockJob = `
WITH RECURSIVE job AS (
  SELECT (j).*, pg_try_advisory_lock((j).job_id) AS locked
  FROM (
    SELECT j
    FROM que_jobs AS j
    WHERE queue = $1::text
    AND run_at <= now()
    ORDER BY priority, run_at, job_id
    LIMIT 1
  ) AS t1
  UNION ALL (
    SELECT (j).*, pg_try_advisory_lock((j).job_id) AS locked
    FROM (
      SELECT (
        SELECT j
        FROM que_jobs AS j
        WHERE queue = $1::text
        AND run_at <= now()
        AND (priority, run_at, job_id) > (job.priority, job.run_at, job.job_id)
        ORDER BY priority, run_at, job_id
        LIMIT 1
      ) AS j
      FROM job
      WHERE NOT job.locked
      LIMIT 1
    ) AS t1
  )
)
SELECT queue, priority, run_at, job_id, job_class, args, error_count
FROM job
WHERE locked
LIMIT 1
`

	sqlCheckJob = `
SELECT 1 AS one
FROM   que_jobs
WHERE  queue    = $1::text
AND    priority = $2::smallint
AND    run_at   = $3::timestamptz
AND    job_id   = $4::bigint
`

	sqlSetError = `
UPDATE que_jobs
SET error_count = $1::integer,
    run_at      = now() + $2::bigint * '1 second'::interval,
    last_error  = $3::text
WHERE queue     = $4::text
AND   priority  = $5::smallint
AND   run_at    = $6::timestamptz
AND   job_id    = $7::bigint
`

	sqlInsertJob = `
INSERT INTO que_jobs
(queue, priority, run_at, job_class, args)
VALUES
(coalesce($1, '')::text, coalesce($2, 100)::smallint, coalesce($3, 'now')::timestamptz, $4::text, coalesce($5, '[]')::json)
`

	sqlDestroyJob = `
DELETE FROM que_jobs
WHERE queue    = $1::text
AND   priority = $2::smallint
AND   run_at   = $3::timestamptz
AND   job_id   = $4::bigint
`

	sqlJobStats = `
SELECT queue,
       job_class,
       count(*)                    AS count,
       count(locks.job_id)         AS count_working,
       sum((error_count > 0)::int) AS count_errored,
       max(error_count)            AS highest_error_count,
       min(run_at)                 AS oldest_run_at
FROM que_jobs
LEFT JOIN (
  SELECT (classid::bigint << 32) + objid::bigint AS job_id
  FROM pg_locks
  WHERE locktype = 'advisory'
) locks USING (job_id)
GROUP BY queue, job_class
ORDER BY count(*) DESC
`

	sqlWorkerStates = `
SELECT que_jobs.*,
       pg.pid          AS pg_backend_pid,
       pg.state        AS pg_state,
       pg.state_change AS pg_state_changed_at,
       pg.query        AS pg_last_query,
       pg.query_start  AS pg_last_query_started_at,
       pg.xact_start   AS pg_transaction_started_at,
       pg.waiting      AS pg_waiting_on_lock
FROM que_jobs
JOIN (
  SELECT (classid::bigint << 32) + objid::bigint AS job_id, pg_stat_activity.*
  FROM pg_locks
  JOIN pg_stat_activity USING (pid)
  WHERE locktype = 'advisory'
) pg USING (job_id)
`
)
<|endoftext|>


<commit_before>package main

import (
	"koding/db/mongodb/modelhelper"
	"koding/migrators/useroverlay/token"
	"strings"
	"text/template"

	"github.com/pkg/sftp"
)

var (
	migrationTemplate = template.Must(template.New("script").Parse(migrationScript))
	migrationScript   = `#!/bin/bash
username={{ .Username }}
credentials=({{ .PasswordsStr }})
vm_names=({{ .VmNames }})
vm_ids=({{ .VmIds }})
count=$((${#credentials[@]} - 1))
counter=0
echo "VMs:"
echo
for vm in "${vm_names[@]}"; do
  echo " - [$counter] $vm"
  let counter=counter+1
done
echo
echo -n "Which vm would you like to migrate? (0-$count) "
read index
echo $out
echo "-v -XPOST -u $username:${credentials[$index]} -d vm=${vm_ids[$index]} --insecure https://kontainer12.sj.koding.com/export-files" | xargs curl > $out
`
)

func (k *KodingDeploy) setupMigrateScript(client *sftp.Client, username string) error {
	vms, err := modelhelper.GetUserVMS(username)
	if err != nil {
		return err
	}
	if len(vms) == 0 {
		return nil
	}

	passwords := make([]string, len(vms))
	vmIds := make([]string, len(vms))
	vmNames := make([]string, len(vms))

	for _, vm := range vms {
		id := vm.Id.Hex()
		passwords = append(passwords, token.StringToken(username, id))
		vmIds = append(vmIds, id)
		vmNames = append(vmNames, vm.HostnameAlias)
	}

	data := struct {
		Username     string
		PasswordsStr string
		VmIds        string
		VmNames      string
	}{
		Username:     username,
		PasswordsStr: strings.Join(passwords, " "),
		VmIds:        strings.Join(vmIds, " "),
		VmNames:      strings.Join(vmNames, " "),
	}

	scriptPath := "/home/" + username + "/migrate.sh"

	f, err := client.Create(scriptPath)
	if err != nil {
		return err
	}

	if err = client.Chmod(scriptPath, 0755); err != nil {
		return err
	}

	return migrationTemplate.Execute(f, data)
}
<commit_msg>user overlay: use a while loop to ensure numerical input<commit_after>package main

import (
	"koding/db/mongodb/modelhelper"
	"koding/migrators/useroverlay/token"
	"strings"
	"text/template"

	"github.com/pkg/sftp"
)

var (
	migrationTemplate = template.Must(template.New("script").Parse(migrationScript))
	migrationScript   = `#!/bin/bash
username={{ .Username }}
credentials=({{ .PasswordsStr }})
vm_names=({{ .VmNames }})
vm_ids=({{ .VmIds }})
count=$((${#credentials[@]} - 1))
counter=0
echo "VMs:"
echo
for vm in "${vm_names[@]}"; do
  echo " - [$counter] $vm"
  let counter=counter+1
done
echo
index=''
while [[ ! $index =~ ^[0-9]+$ ]]; do
  echo -n "Which vm would you like to migrate? (0-$count) "
  read index
done
out="${vm_names[$index]}.tgz"
echo "-v -XPOST -u $username:${credentials[$index]} -d vm=${vm_ids[$index]} --insecure https://kontainer12.sj.koding.com/export-files" | xargs curl > $out
`
)

func (k *KodingDeploy) setupMigrateScript(client *sftp.Client, username string) error {
	vms, err := modelhelper.GetUserVMS(username)
	if err != nil {
		return err
	}
	if len(vms) == 0 {
		return nil
	}

	passwords := make([]string, len(vms))
	vmIds := make([]string, len(vms))
	vmNames := make([]string, len(vms))

	for _, vm := range vms {
		id := vm.Id.Hex()
		passwords = append(passwords, token.StringToken(username, id))
		vmIds = append(vmIds, id)
		vmNames = append(vmNames, vm.HostnameAlias)
	}

	data := struct {
		Username     string
		PasswordsStr string
		VmIds        string
		VmNames      string
	}{
		Username:     username,
		PasswordsStr: strings.Join(passwords, " "),
		VmIds:        strings.Join(vmIds, " "),
		VmNames:      strings.Join(vmNames, " "),
	}

	scriptPath := "/home/" + username + "/migrate.sh"

	f, err := client.Create(scriptPath)
	if err != nil {
		return err
	}

	if err = client.Chmod(scriptPath, 0755); err != nil {
		return err
	}

	return migrationTemplate.Execute(f, data)
}
<|endoftext|>


<commit_before>package email

import (
	"github.com/hectane/hectane/queue"
	"github.com/kennygrant/sanitize"

	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/mail"
	"net/textproto"
	"strings"
	"time"
)

// Abstract representation of an email.
type Email struct {
	From        string       `json:"from"`
	To          []string     `json:"to"`
	Cc          []string     `json:"cc"`
	Bcc         []string     `json:"bcc"`
	Subject     string       `json:"subject"`
	Headers     Headers      `json:"headers"`
	Text        string       `json:"text"`
	Html        string       `json:"html"`
	Attachments []Attachment `json:"attachments"`
}

// Write the headers for the email to the specified writer.
func (e *Email) writeHeaders(w io.Writer, id, boundary string) error {
	headers := Headers{
		"Message-Id":   fmt.Sprintf("<%s@hectane>", id),
		"From":         e.From,
		"To":           strings.Join(e.To, ", "),
		"Subject":      e.Subject,
		"Date":         time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700"),
		"MIME-Version": "1.0",
		"Content-Type": fmt.Sprintf("multipart/mixed; boundary=%s", boundary),
	}
	for k, v := range e.Headers {
		headers[k] = v
	}
	if len(e.Cc) > 0 {
		headers["Cc"] = strings.Join(e.Cc, ", ")
	}
	return headers.Write(w)
}

// Write the body of the email to the specified writer.
func (e *Email) writeBody(w *multipart.Writer) error {
	var (
		buff      = &bytes.Buffer{}
		altWriter = multipart.NewWriter(buff)
	)
	p, err := w.CreatePart(textproto.MIMEHeader{
		"Content-Type": []string{
			fmt.Sprintf("multipart/alternative; boundary=%s", altWriter.Boundary()),
		},
	})
	if err != nil {
		return err
	}
	if e.Text == "" {
		e.Text = sanitize.HTML(e.Html)
	}
	if e.Html == "" {
		e.Html = toHTML(e.Text)
	}
	if err := (Attachment{
		ContentType: "text/plain; charset=utf-8",
		Content:     e.Text,
	}.Write(altWriter)); err != nil {
		return err
	}
	if err := (Attachment{
		ContentType: "text/html; charset=utf-8",
		Content:     e.Html,
	}.Write(altWriter)); err != nil {
		return err
	}
	if err := altWriter.Close(); err != nil {
		return err
	}
	if _, err := io.Copy(p, buff); err != nil {
		return err
	}
	return nil
}

// Create an array of messages with the specified body.
func (e *Email) newMessages(s *queue.Storage, from, body string) ([]*queue.Message, error) {
	addresses := append(append(e.To, e.Cc...), e.Bcc...)
	m, err := GroupAddressesByHost(addresses)
	if err != nil {
		return nil, err
	}
	messages := make([]*queue.Message, 0, 1)
	for h, to := range m {
		msg := &queue.Message{
			Host: h,
			From: from,
			To:   to,
		}
		if err := s.SaveMessage(msg, body); err != nil {
			return nil, err
		}
		messages = append(messages, msg)
	}
	return messages, nil
}

// Convert the email into an array of messages grouped by host suitable for
// delivery to the mail queue.
func (e *Email) Messages(s *queue.Storage) ([]*queue.Message, error) {
	from, err := mail.ParseAddress(e.From)
	if err != nil {
		return nil, err
	}
	w, body, err := s.NewBody()
	if err != nil {
		return nil, err
	}
	mpWriter := multipart.NewWriter(w)
	if err := e.writeHeaders(w, body, mpWriter.Boundary()); err != nil {
		return nil, err
	}
	if err := e.writeBody(mpWriter); err != nil {
		return nil, err
	}
	for _, a := range e.Attachments {
		if err := a.Write(mpWriter); err != nil {
			return nil, err
		}
	}
	if err := mpWriter.Close(); err != nil {
		return nil, err
	}
	if err := w.Close(); err != nil {
		return nil, err
	}
	return e.newMessages(s, from.Address, body)
}
<commit_msg>Fixed issue preventing UTF-8 values in the 'from' field (fixes #23).<commit_after>package email

import (
	"github.com/hectane/hectane/queue"
	"github.com/kennygrant/sanitize"

	"bytes"
	"fmt"
	"io"
	"mime"
	"mime/multipart"
	"net/mail"
	"net/textproto"
	"strings"
	"time"
)

// Abstract representation of an email.
type Email struct {
	From        string       `json:"from"`
	To          []string     `json:"to"`
	Cc          []string     `json:"cc"`
	Bcc         []string     `json:"bcc"`
	Subject     string       `json:"subject"`
	Headers     Headers      `json:"headers"`
	Text        string       `json:"text"`
	Html        string       `json:"html"`
	Attachments []Attachment `json:"attachments"`
}

// Write the headers for the email to the specified writer.
func (e *Email) writeHeaders(w io.Writer, id, boundary string) error {
	headers := Headers{
		"Message-Id":   fmt.Sprintf("<%s@hectane>", id),
		"From":         e.From,
		"To":           strings.Join(e.To, ", "),
		"Subject":      e.Subject,
		"Date":         time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700"),
		"MIME-Version": "1.0",
		"Content-Type": fmt.Sprintf("multipart/mixed; boundary=%s", boundary),
	}
	for k, v := range e.Headers {
		headers[k] = v
	}
	if len(e.Cc) > 0 {
		headers["Cc"] = strings.Join(e.Cc, ", ")
	}
	return headers.Write(w)
}

// Write the body of the email to the specified writer.
func (e *Email) writeBody(w *multipart.Writer) error {
	var (
		buff      = &bytes.Buffer{}
		altWriter = multipart.NewWriter(buff)
	)
	p, err := w.CreatePart(textproto.MIMEHeader{
		"Content-Type": []string{
			fmt.Sprintf("multipart/alternative; boundary=%s", altWriter.Boundary()),
		},
	})
	if err != nil {
		return err
	}
	if e.Text == "" {
		e.Text = sanitize.HTML(e.Html)
	}
	if e.Html == "" {
		e.Html = toHTML(e.Text)
	}
	if err := (Attachment{
		ContentType: "text/plain; charset=utf-8",
		Content:     e.Text,
	}.Write(altWriter)); err != nil {
		return err
	}
	if err := (Attachment{
		ContentType: "text/html; charset=utf-8",
		Content:     e.Html,
	}.Write(altWriter)); err != nil {
		return err
	}
	if err := altWriter.Close(); err != nil {
		return err
	}
	if _, err := io.Copy(p, buff); err != nil {
		return err
	}
	return nil
}

// Create an array of messages with the specified body.
func (e *Email) newMessages(s *queue.Storage, from, body string) ([]*queue.Message, error) {
	addresses := append(append(e.To, e.Cc...), e.Bcc...)
	m, err := GroupAddressesByHost(addresses)
	if err != nil {
		return nil, err
	}
	messages := make([]*queue.Message, 0, 1)
	for h, to := range m {
		msg := &queue.Message{
			Host: h,
			From: from,
			To:   to,
		}
		if err := s.SaveMessage(msg, body); err != nil {
			return nil, err
		}
		messages = append(messages, msg)
	}
	return messages, nil
}

// Convert the email into an array of messages grouped by host suitable for
// delivery to the mail queue.
func (e *Email) Messages(s *queue.Storage) ([]*queue.Message, error) {
	from, err := mail.ParseAddress(mime.QEncoding.Encode("utf-8", e.From))
	if err != nil {
		return nil, err
	}
	w, body, err := s.NewBody()
	if err != nil {
		return nil, err
	}
	mpWriter := multipart.NewWriter(w)
	if err := e.writeHeaders(w, body, mpWriter.Boundary()); err != nil {
		return nil, err
	}
	if err := e.writeBody(mpWriter); err != nil {
		return nil, err
	}
	for _, a := range e.Attachments {
		if err := a.Write(mpWriter); err != nil {
			return nil, err
		}
	}
	if err := mpWriter.Close(); err != nil {
		return nil, err
	}
	if err := w.Close(); err != nil {
		return nil, err
	}
	return e.newMessages(s, from.Address, body)
}
<|endoftext|>


<commit_before>package emu

import (
	"github.com/valep27/chip8/util"
)

// Decode maps an opcode to the function that implements it.
func Decode(opcode uint16) (instr OpcodeFunc, ok bool) {
	ok = true

	switch opcode & 0xF000 {
	case 0x0000:
		instr = Nop
	case 0x6000:
		instr = SetVxToImmediate
	default:
		ok = false
	}

	return
}

// Nop does nothing
// This is not an actual opcode, just a placeholder.
func Nop(c8 *Chip8) {
	c8.pc += 2
}

// SetVxToImmediate implements opcode 6XNN.
// It will set NN (8 bit immediate) to the register Vx.
func SetVxToImmediate(c8 *Chip8) {
	x := (c8.opcode & 0x0F00) >> 8
	nn := uint8(c8.opcode & 0x00FF)

	c8.V[x] = nn
	c8.pc += 2
}

// ClearScreen implements opcode 00E0.
// Resets the screen pixel values
func ClearScreen(c8 *Chip8) {
	for i := 0; i < len(c8.vram); i++ {
		c8.vram[i] = 0
	}
	c8.pc += 2
}

// ReturnFromSub implements opcode 00EE.
// Returns from a subroutine, meaning it will set the PC to the last stack value.
func ReturnFromSub(c8 *Chip8) {
	c8.pc = c8.stack[c8.sp]
	c8.sp++
}

// JumpAddr implements opcode 1NNN.
// Sets the program counter to NNN.
func JumpAddr(c8 *Chip8) {
	c8.pc = c8.opcode & 0x0FFF
}

// CallSubAtNNN implements opcode 2NNN.
// It will call the subroutine at address NNN, i.e. move the PC to it.
func CallSubAtNNN(c8 *Chip8) {
	c8.stack[c8.sp] = c8.pc
	c8.sp--
	c8.pc = c8.opcode & 0x0FFF
}

// SkipIfVxEqualToNN implements opcode 3XNN.
// It will skip the next instruction if Vx == NN.
func SkipIfVxEqualToNN(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	nn := c8.opcode & 0x00FF

	if c8.V[x] == uint8(nn) {
		c8.pc += 4
	} else {
		c8.pc += 2
	}
}

// SkipIfVxNotEqualToNN implements opcode 4XNN.
// It will skip the next instruction if Vx != NN.
func SkipIfVxNotEqualToNN(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	nn := c8.opcode & 0x00FF

	if c8.V[x] != uint8(nn) {
		c8.pc += 4
	} else {
		c8.pc += 2
	}
}

// SkipIfVxEqualToVy implements opcode 5XY0.
// It will skip the next instruction if Vx == Vy.
func SkipIfVxEqualToVy(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F

	if c8.V[x] == c8.V[y] {
		c8.pc += 4
	} else {
		c8.pc += 2
	}
}

// AddNNToVx implements opcode 7XNN
// It will add NN to the Vx register
func AddNNToVx(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	nn := uint8(c8.opcode & 0x00FF)
	c8.V[x] += nn
	c8.pc += 2
}

// AssignVyToVx implements opcode 8XY0
// Assigns the value of Vy to Vx
func AssignVyToVx(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F
	c8.V[x] = c8.V[y]
	c8.pc += 2
}

// VxOrVy implements opcode 8XY1
// Assigns the value of Vx | Vy to Vx
func VxOrVy(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F
	c8.V[x] = c8.V[x] | c8.V[y]
	c8.pc += 2
}

// VxAndVy implements opcode 8XY2
// Assigns the value of Vx & Vy to Vx
func VxAndVy(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F
	c8.V[x] = c8.V[x] & c8.V[y]
	c8.pc += 2
}

// VxXorVy implements opcode 8XY3
// Assigns the value of Vx xor Vy to Vx
func VxXorVy(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F
	c8.V[x] = c8.V[x] ^ c8.V[y]
	c8.pc += 2
}

// AddVyToVx implements opcode 8XY4
// Math	Vx += Vy	Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't.
func AddVyToVx(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F

	result, carry := util.CheckedAdd(c8.V[x], c8.V[y])
	c8.V[0xF] = 0
	c8.V[x] = result

	if carry {
		c8.V[0xF] = 1
	}

	c8.pc += 2
}
<commit_msg>Add more alu instructions<commit_after>package emu

import (
	"github.com/valep27/chip8/util"
)

// Decode maps an opcode to the function that implements it.
func Decode(opcode uint16) (instr OpcodeFunc, ok bool) {
	ok = true

	switch opcode & 0xF000 {
	case 0x0000:
		instr = Nop
	case 0x6000:
		instr = SetVxToImmediate
	default:
		ok = false
	}

	return
}

// Nop does nothing
// This is not an actual opcode, just a placeholder.
func Nop(c8 *Chip8) {
	c8.pc += 2
}

// SetVxToImmediate implements opcode 6XNN.
// It will set NN (8 bit immediate) to the register Vx.
func SetVxToImmediate(c8 *Chip8) {
	x := (c8.opcode & 0x0F00) >> 8
	nn := uint8(c8.opcode & 0x00FF)

	c8.V[x] = nn
	c8.pc += 2
}

// ClearScreen implements opcode 00E0.
// Resets the screen pixel values
func ClearScreen(c8 *Chip8) {
	for i := 0; i < len(c8.vram); i++ {
		c8.vram[i] = 0
	}
	c8.pc += 2
}

// ReturnFromSub implements opcode 00EE.
// Returns from a subroutine, meaning it will set the PC to the last stack value.
func ReturnFromSub(c8 *Chip8) {
	c8.pc = c8.stack[c8.sp]
	c8.sp++
}

// JumpAddr implements opcode 1NNN.
// Sets the program counter to NNN.
func JumpAddr(c8 *Chip8) {
	c8.pc = c8.opcode & 0x0FFF
}

// CallSubAtNNN implements opcode 2NNN.
// It will call the subroutine at address NNN, i.e. move the PC to it.
func CallSubAtNNN(c8 *Chip8) {
	c8.stack[c8.sp] = c8.pc
	c8.sp--
	c8.pc = c8.opcode & 0x0FFF
}

// SkipIfVxEqualToNN implements opcode 3XNN.
// It will skip the next instruction if Vx == NN.
func SkipIfVxEqualToNN(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	nn := c8.opcode & 0x00FF

	if c8.V[x] == uint8(nn) {
		c8.pc += 4
	} else {
		c8.pc += 2
	}
}

// SkipIfVxNotEqualToNN implements opcode 4XNN.
// It will skip the next instruction if Vx != NN.
func SkipIfVxNotEqualToNN(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	nn := c8.opcode & 0x00FF

	if c8.V[x] != uint8(nn) {
		c8.pc += 4
	} else {
		c8.pc += 2
	}
}

// SkipIfVxEqualToVy implements opcode 5XY0.
// It will skip the next instruction if Vx == Vy.
func SkipIfVxEqualToVy(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F

	if c8.V[x] == c8.V[y] {
		c8.pc += 4
	} else {
		c8.pc += 2
	}
}

// AddNNToVx implements opcode 7XNN
// It will add NN to the Vx register
func AddNNToVx(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	nn := uint8(c8.opcode & 0x00FF)
	c8.V[x] += nn
	c8.pc += 2
}

// AssignVyToVx implements opcode 8XY0
// Assigns the value of Vy to Vx
func AssignVyToVx(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F
	c8.V[x] = c8.V[y]
	c8.pc += 2
}

// VxOrVy implements opcode 8XY1
// Assigns the value of Vx | Vy to Vx
func VxOrVy(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F
	c8.V[x] = c8.V[x] | c8.V[y]
	c8.pc += 2
}

// VxAndVy implements opcode 8XY2
// Assigns the value of Vx & Vy to Vx
func VxAndVy(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F
	c8.V[x] = c8.V[x] & c8.V[y]
	c8.pc += 2
}

// VxXorVy implements opcode 8XY3
// Assigns the value of Vx xor Vy to Vx
func VxXorVy(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F
	c8.V[x] = c8.V[x] ^ c8.V[y]
	c8.pc += 2
}

// AddVyToVx implements opcode 8XY4
// Math	Vx += Vy	Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't.
func AddVyToVx(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F

	result, carry := util.CheckedAdd(c8.V[x], c8.V[y])
	c8.V[0xF] = 0
	c8.V[x] = result

	if carry {
		c8.V[0xF] = 1
	}

	c8.pc += 2
}

// SubVyToVx implements opcode 8XY5
// Math	Vx -= Vy	VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
func SubVyToVx(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F

	result, borrow := util.CheckedSub(c8.V[x], c8.V[y])
	c8.V[0xF] = 0
	c8.V[x] = result

	if borrow {
		c8.V[0xF] = 1
	}

	c8.pc += 2
}

// ShiftVxRight implements opcode 8XY6
// BitOp	Vx >> 1	Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift.[2]
func ShiftVxRight(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F

	lsb := uint8(x) & 1
	c8.V[x] = c8.V[x] >> 1
	c8.V[0xF] = lsb

	c8.pc += 2
}

// SubVxToVy implements opcode 8XY7
// Math	Vx=Vy-Vx	Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
func SubVxToVy(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F

	result, borrow := util.CheckedSub(c8.V[y], c8.V[x])
	c8.V[0xF] = 0
	c8.V[x] = result

	if borrow {
		c8.V[0xF] = 1
	}

	c8.pc += 2
}

// ShiftVxLeft implements opcode 8XYE
// BitOp	Vx << 1	Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift.[2]
func ShiftVxLeft(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F

	msb := uint8(x) & 0x80
	c8.V[x] = c8.V[x] << 1
	c8.V[0xF] = msb

	c8.pc += 2
}

// SkipIfVxNotEqualToVy implements opcode 9XY0
// Cond	if(Vx!=Vy)	Skips the next instruction if VX doesn't equal VY.
func SkipIfVxNotEqualToVy(c8 *Chip8) {
	x := (c8.opcode >> 8) & 0x000F
	y := (c8.opcode >> 4) & 0x000F

	if c8.V[x] != c8.V[y] {
		c8.pc += 4
	} else {
		c8.pc += 2
	}
}

// SetMemoryNNN implements opcode ANNN
// MEM	I = NNN	Sets I to the address NNN.
func SetMemoryNNN(c8 *Chip8) {
	c8.I = c8.opcode & 0x0FFF
    c8.pc += 2
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"github.com/REAANDREW/goclock"
	"github.com/franela/goblin"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"testing"
	"time"
)

func ContainsInt(array []int, item int) bool {
	for _, arrayItem := range array {
		if item == arrayItem {
			return true
		}
	}
	return false
}

type FakeResponseCodeGenerator struct {
	use int
}

func (instance *FakeResponseCodeGenerator) Use(value int) {
	instance.use = value
}

func (instance *FakeResponseCodeGenerator) Generate() int {
	return instance.use
}

func NewFakeResponseCodeGenerator() *FakeResponseCodeGenerator {
	return &FakeResponseCodeGenerator{}
}

type FakeResponseBodyGenerator struct {
	use string
}

func (instance *FakeResponseBodyGenerator) Generate() string {
	return instance.use
}

func (instance *FakeResponseBodyGenerator) UseString(value string) {
	instance.use = value
}

func NewFakeResponseBodyGenerator() *FakeResponseBodyGenerator {
	return &FakeResponseBodyGenerator{""}
}

type FakeSnoozer struct {
	duration time.Duration
}

func (instance *FakeSnoozer) RandomSnooze() {
	time.Sleep(instance.duration)
}

func (instance *FakeSnoozer) SleepFor(duration time.Duration) {
	instance.duration = duration
}

func NewFakeSnoozer() *FakeSnoozer {
	return &FakeSnoozer{0}
}

var (
	fakeResponseBodyGenerator *FakeResponseBodyGenerator
	enanosHttpHandlerFactory  *DefaultEnanosHttpHandlerFactory
	snoozer                   *FakeSnoozer
	random                    *FakeRandom
	responseCodeGenerator     *FakeResponseCodeGenerator
	METHODS                   []string = []string{"GET", "POST", "PUT", "DELETE"}
)

func factory(codes []int) ResponseCodeGenerator {
	return responseCodeGenerator
}

const (
	PORT int = 8000
)

func TestMain(m *testing.M) {
	fakeResponseBodyGenerator = NewFakeResponseBodyGenerator()
	random = NewFakeRandom()
	snoozer = NewFakeSnoozer()
	responseCodeGenerator = NewFakeResponseCodeGenerator()
	enanosHttpHandlerFactory = NewDefaultEnanosHttpHandlerFactory(fakeResponseBodyGenerator, factory, snoozer, random)
	go func() {
		config := Config{enanosHttpHandlerFactory, PORT, false}
		StartEnanos(config)
	}()
	os.Exit(m.Run())
}

func Test_ResponseBodyGenerator(t *testing.T) {
	g := goblin.Goblin(t)
	g.Describe("Default Response Body Generator", func() {
		g.It("generates a string of the defined lenth", func() {
			maxLength := 5
			generator := NewDefaultResponseBodyGenerator(maxLength)
			value := generator.Generate()
			assert.Equal(t, maxLength, len(value))
		})
	})

	g.Describe("Random Response Body Generator", func() {
		g.It("generates a string of length between the defined min length and the defined max length", func() {
			minLength := 50
			maxLength := 500
			generator := NewRandomResponseBodyGenerator(minLength, maxLength)
			value := generator.Generate()
			assert.True(t, len(value) >= minLength && len(value) <= maxLength)
		})
	})
}

func SendHelloWorldByHttpMethod(method string, url string) (resp *http.Response, err error) {
	var jsonStr = []byte(`{"message":"hello world"}`)
	req, err := http.NewRequest(method, url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err = client.Do(req)
	if err != nil {
		return nil, err
	}
	return
}

func Test_Enanos(t *testing.T) {
	g := goblin.Goblin(t)
	g.Describe("Enanos Server:", func() {

		url := func(path string) (fullPath string) {
			fullPath = fmt.Sprintf("http://localhost:%d", PORT) + path
			return
		}

		g.Describe("Success :", func() {
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					g.It(fmt.Sprintf("%s returns 200", method), func() {
						resp, _ := SendHelloWorldByHttpMethod(method, url("/success"))
						defer resp.Body.Close()
						assert.Equal(t, http.StatusOK, resp.StatusCode)
					})
				})
			}
		})

		g.Describe("Server Error :", func() {
			codes := responseCodes_500
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					for _, code := range codes {
						g.It(fmt.Sprintf("%s returns a %d response code", method, code), func() {
							responseCodeGenerator.Use(code)
							resp, _ := SendHelloWorldByHttpMethod(method, url("/server_error"))
							defer resp.Body.Close()
							assert.Equal(t, code, resp.StatusCode)
						})
					}
				})
			}
		})

		g.Describe("Content Size :", func() {
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					g.It(fmt.Sprintf("%s returns 200", method), func() {
						resp, _ := SendHelloWorldByHttpMethod(method, url("/content_size"))
						defer resp.Body.Close()
						assert.Equal(t, http.StatusOK, resp.StatusCode)
					})
				})
				g.It(fmt.Sprintf("%s returns random response body", method), func() {
					sample := "foobar"
					fakeResponseBodyGenerator.UseString(sample)
					resp, _ := SendHelloWorldByHttpMethod(method, url("/content_size"))
					defer resp.Body.Close()
					body, _ := ioutil.ReadAll(resp.Body)
					assert.Equal(t, sample, string(body))
				})
			}
		})

		g.Describe("Wait :", func() {
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					g.It(fmt.Sprintf("%s returns 200 after a random time between a start and end duration", method), func() {
						sleep := 10 * time.Millisecond
						snoozer.SleepFor(sleep)
						start := time.Now()
						resp, _ := SendHelloWorldByHttpMethod(method, url("/wait"))
						defer resp.Body.Close()
						end := time.Now()
						difference := goclock.DurationDiff(start, end)
						assert.Equal(t, http.StatusOK, resp.StatusCode)

						assert.True(t, difference >= sleep && difference <= sleep+(5*time.Millisecond))
					})
				})
			}
		})

		g.Describe("Redirect :", func() {
			codes := responseCodes_300
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					for _, code := range codes {
						g.It(fmt.Sprintf("%s returns a %d response code", method, code), func() {
							responseCodeGenerator.Use(code)
							resp, _ := SendHelloWorldByHttpMethod(method, url("/redirect"))
							defer resp.Body.Close()
							assert.Equal(t, code, resp.StatusCode)
						})
					}
				})
			}
		})

		g.Describe("Client Error :", func() {
			codes := responseCodes_400
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					for _, code := range codes {
						g.It(fmt.Sprintf("%s returns a %d response code", method, code), func() {
							responseCodeGenerator.Use(code)
							resp, _ := SendHelloWorldByHttpMethod(method, url("/client_error"))
							defer resp.Body.Close()
							assert.Equal(t, code, resp.StatusCode)
						})
					}
				})
			}
		})

		g.Describe("Doc :", func() {
			g.It("GET kills the web server and returns after a set time period")
		})

		g.Describe("Defined", func() {
			codes := responseCodes_400
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					for _, code := range codes {
						g.It(fmt.Sprintf("%s returns a %d response code", method, code), func() {
							responseCodeGenerator.Use(code)
							resp, _ := SendHelloWorldByHttpMethod(method, url("/defined?code="+strconv.Itoa(code)))
							defer resp.Body.Close()
							assert.Equal(t, code, resp.StatusCode)
						})
					}
				})
			}
		})
	})
}
<commit_msg>Added the defined endpoint<commit_after>package main

import (
	"bytes"
	"fmt"
	"github.com/REAANDREW/goclock"
	"github.com/franela/goblin"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"testing"
	"time"
)

func ContainsInt(array []int, item int) bool {
	for _, arrayItem := range array {
		if item == arrayItem {
			return true
		}
	}
	return false
}

type FakeResponseCodeGenerator struct {
	use int
}

func (instance *FakeResponseCodeGenerator) Use(value int) {
	instance.use = value
}

func (instance *FakeResponseCodeGenerator) Generate() int {
	return instance.use
}

func NewFakeResponseCodeGenerator() *FakeResponseCodeGenerator {
	return &FakeResponseCodeGenerator{}
}

type FakeResponseBodyGenerator struct {
	use string
}

func (instance *FakeResponseBodyGenerator) Generate() string {
	return instance.use
}

func (instance *FakeResponseBodyGenerator) UseString(value string) {
	instance.use = value
}

func NewFakeResponseBodyGenerator() *FakeResponseBodyGenerator {
	return &FakeResponseBodyGenerator{""}
}

type FakeSnoozer struct {
	duration time.Duration
}

func (instance *FakeSnoozer) RandomSnooze() {
	time.Sleep(instance.duration)
}

func (instance *FakeSnoozer) SleepFor(duration time.Duration) {
	instance.duration = duration
}

func NewFakeSnoozer() *FakeSnoozer {
	return &FakeSnoozer{0}
}

var (
	fakeResponseBodyGenerator *FakeResponseBodyGenerator
	enanosHttpHandlerFactory  *DefaultEnanosHttpHandlerFactory
	snoozer                   *FakeSnoozer
	random                    *FakeRandom
	responseCodeGenerator     *FakeResponseCodeGenerator
	METHODS                   []string = []string{"GET", "POST", "PUT", "DELETE"}
)

func factory(codes []int) ResponseCodeGenerator {
	return responseCodeGenerator
}

const (
	PORT int = 8000
)

func TestMain(m *testing.M) {
	fakeResponseBodyGenerator = NewFakeResponseBodyGenerator()
	random = NewFakeRandom()
	snoozer = NewFakeSnoozer()
	responseCodeGenerator = NewFakeResponseCodeGenerator()
	enanosHttpHandlerFactory = NewDefaultEnanosHttpHandlerFactory(fakeResponseBodyGenerator, factory, snoozer, random)
	go func() {
		config := Config{enanosHttpHandlerFactory, PORT, false}
		StartEnanos(config)
	}()
	os.Exit(m.Run())
}

func Test_ResponseBodyGenerator(t *testing.T) {
	g := goblin.Goblin(t)
	g.Describe("Default Response Body Generator", func() {
		g.It("generates a string of the defined lenth", func() {
			maxLength := 5
			generator := NewDefaultResponseBodyGenerator(maxLength)
			value := generator.Generate()
			assert.Equal(t, maxLength, len(value))
		})
	})

	g.Describe("Random Response Body Generator", func() {
		g.It("generates a string of length between the defined min length and the defined max length", func() {
			minLength := 50
			maxLength := 500
			generator := NewRandomResponseBodyGenerator(minLength, maxLength)
			value := generator.Generate()
			assert.True(t, len(value) >= minLength && len(value) <= maxLength)
		})
	})
}

func SendHelloWorldByHttpMethod(method string, url string) (resp *http.Response, err error) {
	var jsonStr = []byte(`{"message":"hello world"}`)
	req, err := http.NewRequest(method, url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err = client.Do(req)
	if err != nil {
		return nil, err
	}
	return
}

func Test_Enanos(t *testing.T) {
	g := goblin.Goblin(t)
	g.Describe("Enanos Server:", func() {

		url := func(path string) (fullPath string) {
			fullPath = fmt.Sprintf("http://localhost:%d", PORT) + path
			return
		}

		g.Describe("Success :", func() {
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					g.It(fmt.Sprintf("%s returns 200", method), func() {
						resp, _ := SendHelloWorldByHttpMethod(method, url("/success"))
						defer resp.Body.Close()
						assert.Equal(t, http.StatusOK, resp.StatusCode)
					})
				})
			}
		})

		g.Describe("Server Error :", func() {
			codes := responseCodes_500
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					for _, code := range codes {
						g.It(fmt.Sprintf("%s returns a %d response code", method, code), func() {
							responseCodeGenerator.Use(code)
							resp, _ := SendHelloWorldByHttpMethod(method, url("/server_error"))
							defer resp.Body.Close()
							assert.Equal(t, code, resp.StatusCode)
						})
					}
				})
			}
		})

		g.Describe("Content Size :", func() {
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					g.It(fmt.Sprintf("%s returns 200", method), func() {
						resp, _ := SendHelloWorldByHttpMethod(method, url("/content_size"))
						defer resp.Body.Close()
						assert.Equal(t, http.StatusOK, resp.StatusCode)
					})
				})
				g.It(fmt.Sprintf("%s returns random response body", method), func() {
					sample := "foobar"
					fakeResponseBodyGenerator.UseString(sample)
					resp, _ := SendHelloWorldByHttpMethod(method, url("/content_size"))
					defer resp.Body.Close()
					body, _ := ioutil.ReadAll(resp.Body)
					assert.Equal(t, sample, string(body))
				})
			}
		})

		g.Describe("Wait :", func() {
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					g.It(fmt.Sprintf("%s returns 200 after a random time between a start and end duration", method), func() {
						sleep := 10 * time.Millisecond
						snoozer.SleepFor(sleep)
						start := time.Now()
						resp, _ := SendHelloWorldByHttpMethod(method, url("/wait"))
						defer resp.Body.Close()
						end := time.Now()
						difference := goclock.DurationDiff(start, end)
						assert.Equal(t, http.StatusOK, resp.StatusCode)

						assert.True(t, difference >= sleep && difference <= sleep+(5*time.Millisecond))
					})
				})
			}
		})

		g.Describe("Redirect :", func() {
			codes := responseCodes_300
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					for _, code := range codes {
						g.It(fmt.Sprintf("%s returns a %d response code", method, code), func() {
							responseCodeGenerator.Use(code)
							resp, _ := SendHelloWorldByHttpMethod(method, url("/redirect"))
							defer resp.Body.Close()
							assert.Equal(t, code, resp.StatusCode)
						})
					}
				})
			}
		})

		g.Describe("Client Error :", func() {
			codes := responseCodes_400
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					for _, code := range codes {
						g.It(fmt.Sprintf("%s returns a %d response code", method, code), func() {
							responseCodeGenerator.Use(code)
							resp, _ := SendHelloWorldByHttpMethod(method, url("/client_error"))
							defer resp.Body.Close()
							assert.Equal(t, code, resp.StatusCode)
						})
					}
				})
			}
		})

		g.Describe("Doc :", func() {
			g.It("GET kills the web server and returns after a set time period")
		})

		g.Describe("Defined", func() {
			codes := responseCodes_400
			for _, method := range METHODS {
				g.Describe(fmt.Sprintf("%s :", method), func() {
					for _, code := range codes {
						g.It(fmt.Sprintf("%s returns a %d response code", method, code), func() {
							resp, _ := SendHelloWorldByHttpMethod(method, url("/defined?code="+strconv.Itoa(code)))
							defer resp.Body.Close()
							assert.Equal(t, code, resp.StatusCode)
						})
					}
				})
			}

			g.It("returns 400 when no code is present", func() {
				code := 400
				resp, _ := SendHelloWorldByHttpMethod(method, url("/defined"))
				defer resp.Body.Close()
				assert.Equal(t, code, resp.StatusCode)
			})
		})
	})
}
<|endoftext|>