<commit_before>package main

import (
	"fmt"
	"github.com/getgauge/gauge/gauge_messages"
)

type simpleConsoleWriter struct{}

func newSimpleConsoleWriter() *simpleConsoleWriter {
	return &simpleConsoleWriter{}
}

func (writer *simpleConsoleWriter) Write(b []byte) (int, error) {
	fmt.Print(string(b))
	return len(b), nil
}

func (writer *simpleConsoleWriter) writeString(value string) {
	writer.Write([]byte(value))
}

func (writer *simpleConsoleWriter) writeError(value string) {
	writer.writeString(value)
}

func (writer *simpleConsoleWriter) writeSpecHeading(heading string) {
	formattedHeading := formatSpecHeading(heading)
	writer.Write([]byte(formattedHeading))
}

func (writer *simpleConsoleWriter) writeItems(items []item) {
	for _, item := range items {
		writer.writeItem(item)
	}
}

func (writer *simpleConsoleWriter) writeSteps(steps []*step) {
	for _, step := range steps {
		writer.writeItem(step)
	}
}

func (writer *simpleConsoleWriter) writeItem(item item) {
	switch item.kind() {
	case commentKind:
		comment := item.(*comment)
		writer.writeComment(comment)
	case stepKind:
		step := item.(*step)
		writer.writeStep(step)
	case tableKind:
		table := item.(*table)
		writer.writeTable(table)
	}
}

func (writer *simpleConsoleWriter) writeComment(comment *comment) {
	writer.writeString(formatComment(comment))
}

func (writer *simpleConsoleWriter) writeScenarioHeading(scenarioHeading string) {
	formattedHeading := formatScenarioHeading(scenarioHeading)
	writer.Write([]byte(fmt.Sprintf("\n%s", formattedHeading)))
}

func (writer *simpleConsoleWriter) writeStep(step *step) {
	writer.writeString(formatStep(step))
}

func (writer *simpleConsoleWriter) writeStepStarting(step *step) {
	writer.writeString(fmt.Sprintf("Executing.. => %s", formatStep(step)))
}

//todo: pass protostep instead
func (writer *simpleConsoleWriter) writeStepFinished(step *step, failed bool) {
	var message string
	if failed {
		message = fmt.Sprintf("Step Failed => %s\n", formatStep(step))
	} else {
		message = fmt.Sprintf("Step Passed => %s\n", formatStep(step))
	}
	writer.writeString(message)
}

func (writer *simpleConsoleWriter) writeTable(table *table) {
	writer.writeString(formatTable(table))
}

func (writer *simpleConsoleWriter) writeConceptStarting(protoConcept *gauge_messages.ProtoConcept) {
	writer.writeString(formatConcept(protoConcept))
}

func (writer *simpleConsoleWriter) writeConceptFinished(protoConcept *gauge_messages.ProtoConcept) {
	writer.writeString(formatConcept(protoConcept))
}
<commit_msg>Printing only step execution sucess or failure on simple console output.<commit_after>package main

import (
	"fmt"
	"github.com/getgauge/gauge/gauge_messages"
)

type simpleConsoleWriter struct{}

func newSimpleConsoleWriter() *simpleConsoleWriter {
	return &simpleConsoleWriter{}
}

func (writer *simpleConsoleWriter) Write(b []byte) (int, error) {
	fmt.Print(string(b))
	return len(b), nil
}

func (writer *simpleConsoleWriter) writeString(value string) {
	writer.Write([]byte(value))
}

func (writer *simpleConsoleWriter) writeError(value string) {
	writer.writeString(value)
}

func (writer *simpleConsoleWriter) writeSpecHeading(heading string) {
	formattedHeading := formatSpecHeading(heading)
	writer.Write([]byte(formattedHeading))
}

func (writer *simpleConsoleWriter) writeItems(items []item) {
	for _, item := range items {
		writer.writeItem(item)
	}
}

func (writer *simpleConsoleWriter) writeSteps(steps []*step) {
	for _, step := range steps {
		writer.writeItem(step)
	}
}

func (writer *simpleConsoleWriter) writeItem(item item) {
	switch item.kind() {
	case commentKind:
		comment := item.(*comment)
		writer.writeComment(comment)
	case stepKind:
		step := item.(*step)
		writer.writeStep(step)
	case tableKind:
		table := item.(*table)
		writer.writeTable(table)
	}
}

func (writer *simpleConsoleWriter) writeComment(comment *comment) {
	writer.writeString(formatComment(comment))
}

func (writer *simpleConsoleWriter) writeScenarioHeading(scenarioHeading string) {
	formattedHeading := formatScenarioHeading(scenarioHeading)
	writer.Write([]byte(fmt.Sprintf("\n%s", formattedHeading)))
}

func (writer *simpleConsoleWriter) writeStep(step *step) {
	writer.writeString(formatStep(step))
}

func (writer *simpleConsoleWriter) writeStepStarting(step *step) {
}

//todo: pass protostep instead
func (writer *simpleConsoleWriter) writeStepFinished(step *step, failed bool) {
	var message string
	if failed {
		message = fmt.Sprintf("Step Failed => %s\n", formatStep(step))
	} else {
		message = fmt.Sprintf("Step Passed => %s\n", formatStep(step))
	}
	writer.writeString(message)
}

func (writer *simpleConsoleWriter) writeTable(table *table) {
	writer.writeString(formatTable(table))
}

func (writer *simpleConsoleWriter) writeConceptStarting(protoConcept *gauge_messages.ProtoConcept) {
	writer.writeString(formatConcept(protoConcept))
}

func (writer *simpleConsoleWriter) writeConceptFinished(protoConcept *gauge_messages.ProtoConcept) {
	writer.writeString(formatConcept(protoConcept))
}
<|endoftext|>


<commit_before>package bittrex

import "github.com/shopspring/decimal"

type Currency struct {
	Currency        string          `json:"Currency"`
	CurrencyLong    string          `json:"CurrencyLong"`
	MinConfirmation int             `json:"MinConfirmation"`
	TxFee           decimal.Decimal `json:"TxFee"`
	IsActive        bool            `json:"IsActive"`
	CoinType        string          `json:"CoinType"`
	BaseAddress     string          `json:"BaseAddress"`
	Notice          string          `json:"Notice"`
}

type CurrencyV3 struct {
	Symbol                   string        `json:"symbol"`
	Name                     string        `json:"name"`
	CoinType                 string        `json:"coinType"`
	Status                   string        `json:"status"`
	MinConfirmations         int           `json:"minConfirmations"`
	Notice                   string        `json:"notice"`
	TxFee                    string        `json:"txFee"`
	LogoURL                  string        `json:"logoUrl,omitempty"`
	ProhibitedIn             []interface{} `json:"prohibitedIn"`
	BaseAddress              string        `json:"baseAddress,omitempty"`
	AssociatedTermsOfService []interface{} `json:"associatedTermsOfService"`
}
<commit_msg>Update model<commit_after>package bittrex

import "github.com/shopspring/decimal"

type Currency struct {
	Currency        string          `json:"Currency"`
	CurrencyLong    string          `json:"CurrencyLong"`
	MinConfirmation int             `json:"MinConfirmation"`
	TxFee           decimal.Decimal `json:"TxFee"`
	IsActive        bool            `json:"IsActive"`
	CoinType        string          `json:"CoinType"`
	BaseAddress     string          `json:"BaseAddress"`
	Notice          string          `json:"Notice"`
}

type CurrencyV3 struct {
	Symbol                   string          `json:"symbol"`
	Name                     string          `json:"name"`
	CoinType                 string          `json:"coinType"`
	Status                   string          `json:"status"`
	MinConfirmations         int             `json:"minConfirmations"`
	Notice                   string          `json:"notice"`
	TxFee                    decimal.Decimal `json:"txFee"`
	LogoURL                  string          `json:"logoUrl,omitempty"`
	ProhibitedIn             []interface{}   `json:"prohibitedIn"`
	BaseAddress              string          `json:"baseAddress,omitempty"`
	AssociatedTermsOfService []interface{}   `json:"associatedTermsOfService"`
}
<|endoftext|>


<commit_before>package couchdb

import (
  "crypto/rand"
  "encoding/json"
  "fmt"
  "io/ioutil"
  "net/http"
  "net/url"
  "os"
  "strconv"
  "strings"
)

const (
  DEFAULT_BASE_URL = "http://localhost:5984"
)

// getDefaultCouchDBURL returns the default CouchDB server url.
func getDefaultCouchDBURL() string {
  var couchdbUrlEnviron string
  for _, couchdbUrlEnviron = range os.Environ() {
    if strings.HasPrefix(couchdbUrlEnviron, "COUCHDB_URL") {
      break
    }
  }
  if len(couchdbUrlEnviron) == 0 {
    couchdbUrlEnviron = DEFAULT_BASE_URL
  } else {
    couchdbUrlEnviron = strings.Split(couchdbUrlEnviron, "=")[1]
  }
  return couchdbUrlEnviron
}

// Database represents a CouchDB database instance.
type Database struct {
  resource *Resource
}

// NewDatabase returns a CouchDB database instance.
func NewDatabase(urlStr string) *Database {
  var dbUrlStr string
  if !strings.HasPrefix(urlStr, "http") {
    base, err := url.Parse(getDefaultCouchDBURL())
    if err != nil {
      return nil
    }
    dbUrl, err := base.Parse(urlStr)
    if err != nil {
      return nil
    }
    dbUrlStr = dbUrl.String()
  } else {
    dbUrlStr = urlStr
  }
  res := NewResource(dbUrlStr, nil)

  if res == nil {
    return nil
  }

  return &Database{
    resource: res,
  }
}

// NewDatabaseWithResource returns a CouchDB database instance with resource obj.
func NewDatabaseWithResource(res *Resource) *Database {
  return &Database{
    resource: res,
  }
}

// Name returns the name of database.
func (d *Database)Name() string {
  info := d.databaseInfo()
  if _, ok := info["db_name"]; !ok {
    return ""
  }

  return info["db_name"].(string)
}

func (d *Database)databaseInfo() map[string]interface{} {
  _, _, jsonData := d.resource.GetJSON("", nil, url.Values{})

  var jsonMap map[string]interface{}

  if jsonData == nil {
    return jsonMap
  }

  json.Unmarshal(*jsonData, &jsonMap)

  return jsonMap
}

// Aavailable returns true if the database is good to go.
func (d *Database)Available() bool {
  status, _, _ := d.resource.Head("", nil, nil)
  return status == OK
}

// Contains returns true if the database contains a document with the specified ID.
func (d *Database)Contains(docid string) bool {
  docRes := docResource(d.resource, docid)
  status, _, _ := docRes.Head("", nil, nil)
  return status == OK
}

// Get returns the document with the specified ID.
func (d *Database)Get(docid string) map[string]interface{} {
  docRes := docResource(d.resource, docid)
  status, _, data := docRes.GetJSON("", nil, nil)
  if status != OK {
    return nil
  }
  var doc map[string]interface{}
  json.Unmarshal(*data, &doc)
  return doc
}

// Delete deletes the document with the specified ID.
func (d *Database)Delete(docid string) bool {
  docRes := docResource(d.resource, docid)
  status, header, _ := docRes.Head("", nil, nil)
  if status != OK {
    return false
  }
  rev := strings.Trim(header.Get("ETag"), `"`)
  params := url.Values{}
  params.Set("rev", rev)
  status, _, _ = docRes.DeleteJSON("", nil, params)
  return status == OK
}

// Set creates or updates a document with the specified ID.
func (d *Database)Set(docid string, doc map[string]interface{}) bool {
  if doc == nil {
    return false
  }

  docRes := docResource(d.resource, docid)
  status, _, data := docRes.PutJSON("", nil, doc, nil)
  if status != Created {
    return false
  }

  var jsonMap map[string]interface{}
  json.Unmarshal(*data, &jsonMap)
  doc["_id"] = jsonMap["id"].(string)
  doc["_rev"] = jsonMap["rev"].(string)
  return true
}

// DocIDs returns the IDs of all documents in database.
func (d *Database)DocIDs() []string {
  docRes := docResource(d.resource, "_all_docs")
  status, _, data := docRes.GetJSON("", nil, nil)
  if status != OK {
    return nil
  }
  var jsonMap map[string]*json.RawMessage
  json.Unmarshal(*data, &jsonMap)
  if _, ok := jsonMap["rows"]; !ok {
    return nil
  }
  var jsonArr []*json.RawMessage
  json.Unmarshal(*jsonMap["rows"], &jsonArr)
  if len(jsonArr) == 0 {
    return nil
  }
  ids := make([]string, len(jsonArr))
  for i, v := range jsonArr {
    var row map[string]interface{}
    json.Unmarshal(*v, &row)
    ids[i] = row["id"].(string)
  }
  return ids
}

// Len returns the number of documents stored in it.
func (d *Database)Len() int {
  info := d.databaseInfo()
  if count, ok := info["doc_count"]; ok {
    return int(count.(float64))
  }
  return -1
}

// Save creates a new document or update an existing document.
// If doc has no _id the server will generate a random UUID and a new document will be created.
// Otherwise the doc's _id will be used to identify the document to create or update.
// Trying to update an existing document with an incorrect _rev will cause failure.
// *NOTE* It is recommended to avoid saving doc without _id and instead generate document ID on client side.
// To avoid such problems you can generate a UUID on the client side.
// GenerateUUID provides a simple, platform-independent implementation.
// You can also use other third-party packages instead.
// doc: the document to create or update.
func (d *Database)Save(doc map[string]interface{}) (string, string) {

  var id, rev string
  if doc == nil {
    return id, rev
  }

  var httpFunc func(string, *http.Header, map[string]interface{}, url.Values) (int, http.Header, *json.RawMessage)
  if v, ok := doc["_id"]; ok {
    httpFunc = docResource(d.resource, v.(string)).PutJSON
  } else {
    httpFunc = d.resource.PostJSON
  }

  _, _, data := httpFunc("", nil, doc, nil)
  var jsonMap map[string]interface{}
  json.Unmarshal(*data, &jsonMap)

  if v, ok := jsonMap["id"]; ok {
    id = v.(string)
    doc["_id"] = id
  }

  if v, ok := jsonMap["rev"]; ok {
    rev = v.(string)
    doc["_rev"] = rev
  }

  return id, rev
}

// docResource returns a Resource instance for docID
func docResource(res *Resource, docID string) *Resource {
  if docID[:1] == "_" {
    paths := strings.SplitN(docID, "/", 2)
    for _, p := range paths {
      res = res.NewResourceWithURL(p)
    }
    return res
  }

  return res.NewResourceWithURL(docID)
}

// GenerateUUID returns a random 128-bit UUID
func GenerateUUID() string {
  b := make([]byte, 16)
  _, err := rand.Read(b)
  if err != nil {
    return ""
  }

  uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
  return uuid
}

// Commit flushes any recent changes to the specified database to disk.
// If the server is configured to delay commits or previous requests use the special
// "X-Couch-Full-Commit: false" header to disable immediate commits, this method
// can be used to ensure that non-commited changes are commited to physical storage.
func (d *Database)Commit() bool {
  status, _, _ := d.resource.PostJSON("_ensure_full_commit", nil, nil, nil)
  return status == Created
}

// GetAttachment returns the file attachment associated with the document.
// The raw data of the associated attachment is returned as a []byte.
func (d *Database)GetAttachment(docid, fileName string) ([]byte, bool) {
  // defensive check
  if len(docid) == 0 || len(fileName) == 0 {
    return nil, false
  }

  docRes := docResource(docResource(d.resource, docid), fileName)
  status, _, data := docRes.Get("", nil, nil)
  return data, status == OK
}

// PutAttachment uploads the supplied *os.File as an attachment to the specified document.
// doc: the document that the attachment belongs to. Must have _id and _rev inside.
func (d *Database)PutAttachment(doc map[string]interface{}, file *os.File, mimeType string) bool {
  // defensive check
  if doc == nil || file == nil || len(mimeType) == 0 {
    return false
  }

  if _, ok := doc["_id"]; !ok {
    return false
  }
  if _, ok := doc["_rev"]; !ok {
    return false
  }

  id, rev := doc["_id"].(string), doc["_rev"].(string)

  if len(id) == 0 || len(rev) == 0 {
    return false
  }

  fileInfo, err := file.Stat()
  if err != nil {
    return false
  }

  contents, err := ioutil.ReadAll(file)
  if err != nil {
    return false
  }

  docRes := docResource(docResource(d.resource, id), fileInfo.Name())
  header := http.Header{}
  header.Set("Content-Type", mimeType)
  params := url.Values{}
  params.Set("rev", rev)

  status, _, data := docRes.Put("", &header, contents, params)
  if status == Created {
    var jsonMap map[string]interface{}
    json.Unmarshal(data, &jsonMap)
    doc["_rev"] = jsonMap["rev"].(string)
  }

  return status == Created
}

// DeleteAttachment deletes the specified attachment
func (d *Database)DeleteAttachment(doc map[string]interface{}, fileName string) bool {
  // defensive check
  if doc == nil || len(fileName) == 0 {
    return false
  }

  if _, ok := doc["_id"]; !ok {
    return false
  }

  if _, ok := doc["_rev"]; !ok {
    return false
  }

  id, rev := doc["_id"].(string), doc["_rev"].(string)

  if len(id) == 0 || len(rev) == 0 {
    return false
  }

  params := url.Values{}
  params.Set("rev", rev)
  docRes := docResource(docResource(d.resource, id), fileName)
  status, _, data := docRes.DeleteJSON("", nil, params)
  if status == OK {
    var jsonMap map[string]interface{}
    json.Unmarshal(*data, &jsonMap)
    doc["_rev"] = jsonMap["rev"]
  }
  return status == OK
}

type IDRev struct {
  Id string
  Rev string
}

// UpdateDocuments performs a bulk update or creation of the given documents in a single HTTP request.
func (d *Database)UpdateDocuments(docs []map[string]interface{}, options map[string]interface{}) ([]IDRev, bool) {
  results := []IDRev{}

  if docs == nil {
    return results, false
  }

  body := map[string]interface{}{}
  if options != nil {
    for k, v := range options {
      body[k] = v
    }
  }
  body["docs"] = docs

  status, _, data := d.resource.PostJSON("_bulk_docs", nil, body, nil)
  if status == Created {
    var jsonArr []map[string]interface{}
    json.Unmarshal(*data, &jsonArr)
    for _, ele := range jsonArr {
      id, rev := ele["id"].(string), ele["rev"].(string)
      results = append(results, IDRev{Id: id, Rev: rev})
    }
  }
  return results, status == Created
}

// GetRevsLimit gets the current revs_limit(revision limit) setting.
func (d *Database)GetRevsLimit() (int, bool) {
  status, _, data := d.resource.Get("_revs_limit", nil, nil)
  limit, err := strconv.Atoi(strings.Trim(string(data), "\n"))
  return limit, status == OK && err == nil
}

// SetRevsLimit sets the maximum number of document revisions that will be
// tracked by CouchDB.
func (d *Database)SetRevsLimit(limit int) bool {
  status, _, _ := d.resource.Put("_revs_limit", nil, []byte(strconv.Itoa(limit)), nil)
  return status == OK
}

// Changes returns a sorted list of changes feed made to documents in the database.
func (d *Database)Changes(options url.Values) (map[string]interface{}, bool) {
  status, _, data := d.resource.GetJSON("_changes", nil, options)
  if status != OK {
    return nil, false
  }
  var changes map[string]interface{}
  json.Unmarshal(*data, &changes)
  return changes, status == OK
}

// Cleanup removes all view index files no longer required by CouchDB.
func (d *Database)Cleanup() bool {
  status, _, _ := d.resource.PostJSON("_view_cleanup", nil, nil, nil)
  return status == Accepted
}

// Compact compacts the database by compressing the disk database file.
func (d *Database)Compact() bool {
  status, _, _ := d.resource.PostJSON("_compact", nil, nil, nil)
  return status == Accepted
}

// Copy copies an existing document to a new or existing document.
func (d *Database)Copy(srcID, destID string) (string, bool) {
  docRes := docResource(d.resource, srcID)
  header := &http.Header{
    "Destination": []string{destID},
  }
  status, _, data := request("COPY", docRes.base, header, nil, nil)
  var rev string
  if status == Created {
    var jsonMap map[string]interface{}
    json.Unmarshal(data, &jsonMap)
    rev = jsonMap["rev"].(string)
  }

  return rev, status == Created
}

// Purge performs complete removing of the given documents.
func (d *Database)Purge(docIDs []string) bool {
  // TODO
  return false
}

func (d *Database)SetSecurity(securityDoc map[string]interface{}) bool {
  status, _, _ := d.resource.PutJSON("_security", nil, securityDoc, nil)
  return status == OK
}

func (d *Database)GetSecurity() (map[string]interface{}, bool) {
  status, _, data := d.resource.GetJSON("_security", nil, nil)
  var secDoc map[string]interface{}
  if status == OK {
    json.Unmarshal(*data, &secDoc)
  }
  return secDoc, status == OK
}
<commit_msg>add todo func<commit_after>package couchdb

import (
  "crypto/rand"
  "encoding/json"
  "fmt"
  "io/ioutil"
  "net/http"
  "net/url"
  "os"
  "strconv"
  "strings"
)

const (
  DEFAULT_BASE_URL = "http://localhost:5984"
)

// getDefaultCouchDBURL returns the default CouchDB server url.
func getDefaultCouchDBURL() string {
  var couchdbUrlEnviron string
  for _, couchdbUrlEnviron = range os.Environ() {
    if strings.HasPrefix(couchdbUrlEnviron, "COUCHDB_URL") {
      break
    }
  }
  if len(couchdbUrlEnviron) == 0 {
    couchdbUrlEnviron = DEFAULT_BASE_URL
  } else {
    couchdbUrlEnviron = strings.Split(couchdbUrlEnviron, "=")[1]
  }
  return couchdbUrlEnviron
}

// Database represents a CouchDB database instance.
type Database struct {
  resource *Resource
}

// NewDatabase returns a CouchDB database instance.
func NewDatabase(urlStr string) *Database {
  var dbUrlStr string
  if !strings.HasPrefix(urlStr, "http") {
    base, err := url.Parse(getDefaultCouchDBURL())
    if err != nil {
      return nil
    }
    dbUrl, err := base.Parse(urlStr)
    if err != nil {
      return nil
    }
    dbUrlStr = dbUrl.String()
  } else {
    dbUrlStr = urlStr
  }
  res := NewResource(dbUrlStr, nil)

  if res == nil {
    return nil
  }

  return &Database{
    resource: res,
  }
}

// NewDatabaseWithResource returns a CouchDB database instance with resource obj.
func NewDatabaseWithResource(res *Resource) *Database {
  return &Database{
    resource: res,
  }
}

// Name returns the name of database.
func (d *Database)Name() string {
  info := d.databaseInfo()
  if _, ok := info["db_name"]; !ok {
    return ""
  }

  return info["db_name"].(string)
}

func (d *Database)databaseInfo() map[string]interface{} {
  _, _, jsonData := d.resource.GetJSON("", nil, url.Values{})

  var jsonMap map[string]interface{}

  if jsonData == nil {
    return jsonMap
  }

  json.Unmarshal(*jsonData, &jsonMap)

  return jsonMap
}

// Aavailable returns true if the database is good to go.
func (d *Database)Available() bool {
  status, _, _ := d.resource.Head("", nil, nil)
  return status == OK
}

// Contains returns true if the database contains a document with the specified ID.
func (d *Database)Contains(docid string) bool {
  docRes := docResource(d.resource, docid)
  status, _, _ := docRes.Head("", nil, nil)
  return status == OK
}

// Get returns the document with the specified ID.
func (d *Database)Get(docid string) map[string]interface{} {
  docRes := docResource(d.resource, docid)
  status, _, data := docRes.GetJSON("", nil, nil)
  if status != OK {
    return nil
  }
  var doc map[string]interface{}
  json.Unmarshal(*data, &doc)
  return doc
}

// Delete deletes the document with the specified ID.
func (d *Database)Delete(docid string) bool {
  docRes := docResource(d.resource, docid)
  status, header, _ := docRes.Head("", nil, nil)
  if status != OK {
    return false
  }
  rev := strings.Trim(header.Get("ETag"), `"`)
  params := url.Values{}
  params.Set("rev", rev)
  status, _, _ = docRes.DeleteJSON("", nil, params)
  return status == OK
}

// Set creates or updates a document with the specified ID.
func (d *Database)Set(docid string, doc map[string]interface{}) bool {
  if doc == nil {
    return false
  }

  docRes := docResource(d.resource, docid)
  status, _, data := docRes.PutJSON("", nil, doc, nil)
  if status != Created {
    return false
  }

  var jsonMap map[string]interface{}
  json.Unmarshal(*data, &jsonMap)
  doc["_id"] = jsonMap["id"].(string)
  doc["_rev"] = jsonMap["rev"].(string)
  return true
}

// DocIDs returns the IDs of all documents in database.
func (d *Database)DocIDs() []string {
  docRes := docResource(d.resource, "_all_docs")
  status, _, data := docRes.GetJSON("", nil, nil)
  if status != OK {
    return nil
  }
  var jsonMap map[string]*json.RawMessage
  json.Unmarshal(*data, &jsonMap)
  if _, ok := jsonMap["rows"]; !ok {
    return nil
  }
  var jsonArr []*json.RawMessage
  json.Unmarshal(*jsonMap["rows"], &jsonArr)
  if len(jsonArr) == 0 {
    return nil
  }
  ids := make([]string, len(jsonArr))
  for i, v := range jsonArr {
    var row map[string]interface{}
    json.Unmarshal(*v, &row)
    ids[i] = row["id"].(string)
  }
  return ids
}

// Len returns the number of documents stored in it.
func (d *Database)Len() int {
  info := d.databaseInfo()
  if count, ok := info["doc_count"]; ok {
    return int(count.(float64))
  }
  return -1
}

// Save creates a new document or update an existing document.
// If doc has no _id the server will generate a random UUID and a new document will be created.
// Otherwise the doc's _id will be used to identify the document to create or update.
// Trying to update an existing document with an incorrect _rev will cause failure.
// *NOTE* It is recommended to avoid saving doc without _id and instead generate document ID on client side.
// To avoid such problems you can generate a UUID on the client side.
// GenerateUUID provides a simple, platform-independent implementation.
// You can also use other third-party packages instead.
// doc: the document to create or update.
func (d *Database)Save(doc map[string]interface{}) (string, string) {

  var id, rev string
  if doc == nil {
    return id, rev
  }

  var httpFunc func(string, *http.Header, map[string]interface{}, url.Values) (int, http.Header, *json.RawMessage)
  if v, ok := doc["_id"]; ok {
    httpFunc = docResource(d.resource, v.(string)).PutJSON
  } else {
    httpFunc = d.resource.PostJSON
  }

  _, _, data := httpFunc("", nil, doc, nil)
  var jsonMap map[string]interface{}
  json.Unmarshal(*data, &jsonMap)

  if v, ok := jsonMap["id"]; ok {
    id = v.(string)
    doc["_id"] = id
  }

  if v, ok := jsonMap["rev"]; ok {
    rev = v.(string)
    doc["_rev"] = rev
  }

  return id, rev
}

// docResource returns a Resource instance for docID
func docResource(res *Resource, docID string) *Resource {
  if docID[:1] == "_" {
    paths := strings.SplitN(docID, "/", 2)
    for _, p := range paths {
      res = res.NewResourceWithURL(p)
    }
    return res
  }

  return res.NewResourceWithURL(docID)
}

// GenerateUUID returns a random 128-bit UUID
func GenerateUUID() string {
  b := make([]byte, 16)
  _, err := rand.Read(b)
  if err != nil {
    return ""
  }

  uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
  return uuid
}

// Commit flushes any recent changes to the specified database to disk.
// If the server is configured to delay commits or previous requests use the special
// "X-Couch-Full-Commit: false" header to disable immediate commits, this method
// can be used to ensure that non-commited changes are commited to physical storage.
func (d *Database)Commit() bool {
  status, _, _ := d.resource.PostJSON("_ensure_full_commit", nil, nil, nil)
  return status == Created
}

// GetAttachment returns the file attachment associated with the document.
// The raw data of the associated attachment is returned as a []byte.
func (d *Database)GetAttachment(docid, fileName string) ([]byte, bool) {
  // defensive check
  if len(docid) == 0 || len(fileName) == 0 {
    return nil, false
  }

  docRes := docResource(docResource(d.resource, docid), fileName)
  status, _, data := docRes.Get("", nil, nil)
  return data, status == OK
}

// PutAttachment uploads the supplied *os.File as an attachment to the specified document.
// doc: the document that the attachment belongs to. Must have _id and _rev inside.
func (d *Database)PutAttachment(doc map[string]interface{}, file *os.File, mimeType string) bool {
  // defensive check
  if doc == nil || file == nil || len(mimeType) == 0 {
    return false
  }

  if _, ok := doc["_id"]; !ok {
    return false
  }
  if _, ok := doc["_rev"]; !ok {
    return false
  }

  id, rev := doc["_id"].(string), doc["_rev"].(string)

  if len(id) == 0 || len(rev) == 0 {
    return false
  }

  fileInfo, err := file.Stat()
  if err != nil {
    return false
  }

  contents, err := ioutil.ReadAll(file)
  if err != nil {
    return false
  }

  docRes := docResource(docResource(d.resource, id), fileInfo.Name())
  header := http.Header{}
  header.Set("Content-Type", mimeType)
  params := url.Values{}
  params.Set("rev", rev)

  status, _, data := docRes.Put("", &header, contents, params)
  if status == Created {
    var jsonMap map[string]interface{}
    json.Unmarshal(data, &jsonMap)
    doc["_rev"] = jsonMap["rev"].(string)
  }

  return status == Created
}

// DeleteAttachment deletes the specified attachment
func (d *Database)DeleteAttachment(doc map[string]interface{}, fileName string) bool {
  // defensive check
  if doc == nil || len(fileName) == 0 {
    return false
  }

  if _, ok := doc["_id"]; !ok {
    return false
  }

  if _, ok := doc["_rev"]; !ok {
    return false
  }

  id, rev := doc["_id"].(string), doc["_rev"].(string)

  if len(id) == 0 || len(rev) == 0 {
    return false
  }

  params := url.Values{}
  params.Set("rev", rev)
  docRes := docResource(docResource(d.resource, id), fileName)
  status, _, data := docRes.DeleteJSON("", nil, params)
  if status == OK {
    var jsonMap map[string]interface{}
    json.Unmarshal(*data, &jsonMap)
    doc["_rev"] = jsonMap["rev"]
  }
  return status == OK
}

type IDRev struct {
  Id string
  Rev string
}

// UpdateDocuments performs a bulk update or creation of the given documents in a single HTTP request.
func (d *Database)UpdateDocuments(docs []map[string]interface{}, options map[string]interface{}) ([]IDRev, bool) {
  results := []IDRev{}

  if docs == nil {
    return results, false
  }

  body := map[string]interface{}{}
  if options != nil {
    for k, v := range options {
      body[k] = v
    }
  }
  body["docs"] = docs

  status, _, data := d.resource.PostJSON("_bulk_docs", nil, body, nil)
  if status == Created {
    var jsonArr []map[string]interface{}
    json.Unmarshal(*data, &jsonArr)
    for _, ele := range jsonArr {
      id, rev := ele["id"].(string), ele["rev"].(string)
      results = append(results, IDRev{Id: id, Rev: rev})
    }
  }
  return results, status == Created
}

// GetRevsLimit gets the current revs_limit(revision limit) setting.
func (d *Database)GetRevsLimit() (int, bool) {
  status, _, data := d.resource.Get("_revs_limit", nil, nil)
  limit, err := strconv.Atoi(strings.Trim(string(data), "\n"))
  return limit, status == OK && err == nil
}

// SetRevsLimit sets the maximum number of document revisions that will be
// tracked by CouchDB.
func (d *Database)SetRevsLimit(limit int) bool {
  status, _, _ := d.resource.Put("_revs_limit", nil, []byte(strconv.Itoa(limit)), nil)
  return status == OK
}

// Changes returns a sorted list of changes feed made to documents in the database.
func (d *Database)Changes(options url.Values) (map[string]interface{}, bool) {
  status, _, data := d.resource.GetJSON("_changes", nil, options)
  if status != OK {
    return nil, false
  }
  var changes map[string]interface{}
  json.Unmarshal(*data, &changes)
  return changes, status == OK
}

// Cleanup removes all view index files no longer required by CouchDB.
func (d *Database)Cleanup() bool {
  status, _, _ := d.resource.PostJSON("_view_cleanup", nil, nil, nil)
  return status == Accepted
}

// Compact compacts the database by compressing the disk database file.
func (d *Database)Compact() bool {
  status, _, _ := d.resource.PostJSON("_compact", nil, nil, nil)
  return status == Accepted
}

// Copy copies an existing document to a new or existing document.
func (d *Database)Copy(srcID, destID string) (string, bool) {
  docRes := docResource(d.resource, srcID)
  header := &http.Header{
    "Destination": []string{destID},
  }
  status, _, data := request("COPY", docRes.base, header, nil, nil)
  var rev string
  if status == Created {
    var jsonMap map[string]interface{}
    json.Unmarshal(data, &jsonMap)
    rev = jsonMap["rev"].(string)
  }

  return rev, status == Created
}

// Purge performs complete removing of the given documents.
func (d *Database)Purge(docIDs []string) bool {
  // TODO
  return false
}

func (d *Database)SetSecurity(securityDoc map[string]interface{}) bool {
  status, _, _ := d.resource.PutJSON("_security", nil, securityDoc, nil)
  return status == OK
}

func (d *Database)GetSecurity() (map[string]interface{}, bool) {
  status, _, data := d.resource.GetJSON("_security", nil, nil)
  var secDoc map[string]interface{}
  if status == OK {
    json.Unmarshal(*data, &secDoc)
  }
  return secDoc, status == OK
}

// GetRevisions returns all available revisions of the given document in reverse
// order, e.g. latest first.TODO
func (d *Database)GetRevisions() {}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"os"
	"strconv"
	"time"

	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/lib/pq"

	"github.com/juju/errors"

	"github.com/literatesnow/go-datapipe/bulk"
)

type Config struct {
	maxRowBufSz    int //Maximum number of rows to buffer at a time
	maxRowTxCommit int //Maximum number of rows to process before committing the database transaction

	srcDbDriver  string //Source database driver name
	srcDbUri     string //Source database driver URI
	srcSelectSql string //Source database select SQL statement

	dstDbDriver string //Destination database driver name
	dstDbUri    string //Destination database driver URI
	dstSchema   string
	dstTable    string //Destination database table name

	showStackTrace bool //Display stack traces on error
}

type Insert interface {
	Append(rows *sql.Rows) (err error)
	Flush() (totalRowCount int, err error)
	Close() (err error)
}

func (c *Config) Init() (err error) {
	if os.Getenv("SHOW_STACK_TRACE") != "" {
		c.showStackTrace = true
	}

	c.maxRowBufSz, _ = c.EnvInt("MAX_ROW_BUF_SZ", 100)
	c.maxRowTxCommit, _ = c.EnvInt("MAX_ROW_TX_COMMIT", 500)

	if c.srcDbDriver, err = c.EnvStr("SRC_DB_DRIVER"); err != nil {
		return errors.Trace(err)
	}
	if c.srcDbUri, err = c.EnvStr("SRC_DB_URI"); err != nil {
		return errors.Trace(err)
	}
	if c.srcSelectSql, err = c.EnvStr("SRC_DB_SELECT_SQL"); err != nil {
		return errors.Trace(err)
	}

	if c.dstDbDriver, err = c.EnvStr("DST_DB_DRIVER"); err != nil {
		return errors.Trace(err)
	}
	if c.dstDbUri, err = c.EnvStr("DST_DB_URI"); err != nil {
		return errors.Trace(err)
	}
	if c.dstSchema, err = c.EnvStr("DST_DB_SCHEMA"); err != nil {
		return errors.Trace(err)
	}
	if c.dstTable, err = c.EnvStr("DST_DB_TABLE"); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (c *Config) EnvStr(envName string) (dst string, err error) {
	dst = os.Getenv(envName)
	if dst == "" {
		err = errors.Errorf("Missing ENV variable: %s", envName)
	}

	return dst, err
}

func (c *Config) EnvInt(envName string, defaultValue int) (dst int, err error) {
	if dst, err = strconv.Atoi(os.Getenv(envName)); err != nil {
		dst = defaultValue
	}

	return dst, nil
}

func main() {
	cfg := &Config{}
	if err := cfg.Init(); err != nil {
		showError(cfg, err)
		return
	}

	if err := run(cfg); err != nil {
		showError(cfg, err)
		return
	}
}

func run(cfg *Config) (err error) {
	var srcDb, dstDb *sql.DB

	if srcDb, err = sql.Open(cfg.srcDbDriver, cfg.srcDbUri); err != nil {
		return errors.Trace(err)
	}

	defer srcDb.Close()

	if dstDb, err = sql.Open(cfg.dstDbDriver, cfg.dstDbUri); err != nil {
		return errors.Trace(err)
	}

	defer dstDb.Close()

	if err = clearTable(dstDb, cfg); err != nil {
		return errors.Trace(err)
	}

	if err = copyTable(srcDb, dstDb, cfg); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func clearTable(dstDb *sql.DB, cfg *Config) (err error) {
	if _, err = dstDb.Exec("TRUNCATE TABLE " + cfg.dstSchema + "." + cfg.dstTable); err != nil {
		return errors.Trace(err)
	}
	return nil
}

func copyTable(srcDb *sql.DB, dstDb *sql.DB, cfg *Config) (err error) {
	var ir Insert
	var rows *sql.Rows
	var rowCount int
	var columns []string

	if rows, err = srcDb.Query(cfg.srcSelectSql); err != nil {
		return errors.Trace(err)
	}

	defer rows.Close()

	if columns, err = rows.Columns(); err != nil {
		return errors.Trace(err)
	}

	startTime := time.Now()

	switch cfg.dstDbDriver {
	case "postgres":
		if ir, err = bulk.NewCopyIn(dstDb, columns, cfg.dstSchema, cfg.dstTable); err != nil {
			return errors.Trace(err)
		}
	default:
		if ir, err = bulk.NewBulk(dstDb, columns,
			cfg.dstSchema, cfg.dstTable,
			cfg.maxRowBufSz, cfg.maxRowTxCommit); err != nil {
			return errors.Trace(err)
		}
	}

	rowCount, err = copyBulkRows(dstDb, rows, ir, cfg)
	if err != nil {
		return errors.Trace(err)
	}

	if err = ir.Close(); err != nil {
		return errors.Trace(err)
	}

	fmt.Printf("%d rows in %s\n", rowCount, time.Since(startTime).String())

	return errors.Trace(rows.Err())
}

func copyBulkRows(dstDb *sql.DB, rows *sql.Rows, ir Insert, cfg *Config) (rowCount int, err error) {
	var totalRowCount int
	const dotLimit = 1000

	i := 1

	for rows.Next() {
		if err = ir.Append(rows); err != nil {
			return 0, errors.Trace(err)
		}

		if i%dotLimit == 0 {
			fmt.Print(".")
			i = 1
		}

		i++
	}

	if totalRowCount, err = ir.Flush(); err != nil {
		return 0, errors.Trace(err)
	}

	if totalRowCount > dotLimit {
		fmt.Println()
	}

	return totalRowCount, errors.Trace(rows.Err())
}

func showError(cfg *Config, err error) {
	if cfg.showStackTrace {
		fmt.Println(errors.ErrorStack(err))
	} else {
		fmt.Println(err)
	}
}
<commit_msg>Return OS exit codes on error.<commit_after>package main

import (
	"database/sql"
	"fmt"
	"os"
	"strconv"
	"time"

	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/lib/pq"

	"github.com/juju/errors"

	"github.com/literatesnow/go-datapipe/bulk"
)

type Config struct {
	maxRowBufSz    int //Maximum number of rows to buffer at a time
	maxRowTxCommit int //Maximum number of rows to process before committing the database transaction

	srcDbDriver  string //Source database driver name
	srcDbUri     string //Source database driver URI
	srcSelectSql string //Source database select SQL statement

	dstDbDriver string //Destination database driver name
	dstDbUri    string //Destination database driver URI
	dstSchema   string
	dstTable    string //Destination database table name

	showStackTrace bool //Display stack traces on error
}

type Insert interface {
	Append(rows *sql.Rows) (err error)
	Flush() (totalRowCount int, err error)
	Close() (err error)
}

func (c *Config) Init() (err error) {
	if os.Getenv("SHOW_STACK_TRACE") != "" {
		c.showStackTrace = true
	}

	c.maxRowBufSz, _ = c.EnvInt("MAX_ROW_BUF_SZ", 100)
	c.maxRowTxCommit, _ = c.EnvInt("MAX_ROW_TX_COMMIT", 500)

	if c.srcDbDriver, err = c.EnvStr("SRC_DB_DRIVER"); err != nil {
		return errors.Trace(err)
	}
	if c.srcDbUri, err = c.EnvStr("SRC_DB_URI"); err != nil {
		return errors.Trace(err)
	}
	if c.srcSelectSql, err = c.EnvStr("SRC_DB_SELECT_SQL"); err != nil {
		return errors.Trace(err)
	}

	if c.dstDbDriver, err = c.EnvStr("DST_DB_DRIVER"); err != nil {
		return errors.Trace(err)
	}
	if c.dstDbUri, err = c.EnvStr("DST_DB_URI"); err != nil {
		return errors.Trace(err)
	}
	if c.dstSchema, err = c.EnvStr("DST_DB_SCHEMA"); err != nil {
		return errors.Trace(err)
	}
	if c.dstTable, err = c.EnvStr("DST_DB_TABLE"); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (c *Config) EnvStr(envName string) (dst string, err error) {
	dst = os.Getenv(envName)
	if dst == "" {
		err = errors.Errorf("Missing ENV variable: %s", envName)
	}

	return dst, err
}

func (c *Config) EnvInt(envName string, defaultValue int) (dst int, err error) {
	if dst, err = strconv.Atoi(os.Getenv(envName)); err != nil {
		dst = defaultValue
	}

	return dst, nil
}

func main() {
	cfg := &Config{}
	if err := cfg.Init(); err != nil {
		showError(cfg, err)
		os.Exit(2)

	} else if err := run(cfg); err != nil {
		showError(cfg, err)
		os.Exit(1)
	}
}

func run(cfg *Config) (err error) {
	var srcDb, dstDb *sql.DB

	if srcDb, err = sql.Open(cfg.srcDbDriver, cfg.srcDbUri); err != nil {
		return errors.Trace(err)
	}

	defer srcDb.Close()

	if dstDb, err = sql.Open(cfg.dstDbDriver, cfg.dstDbUri); err != nil {
		return errors.Trace(err)
	}

	defer dstDb.Close()

	if err = clearTable(dstDb, cfg); err != nil {
		return errors.Trace(err)
	}

	if err = copyTable(srcDb, dstDb, cfg); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func clearTable(dstDb *sql.DB, cfg *Config) (err error) {
	if _, err = dstDb.Exec("TRUNCATE TABLE " + cfg.dstSchema + "." + cfg.dstTable); err != nil {
		return errors.Trace(err)
	}
	return nil
}

func copyTable(srcDb *sql.DB, dstDb *sql.DB, cfg *Config) (err error) {
	var ir Insert
	var rows *sql.Rows
	var rowCount int
	var columns []string

	if rows, err = srcDb.Query(cfg.srcSelectSql); err != nil {
		return errors.Trace(err)
	}

	defer rows.Close()

	if columns, err = rows.Columns(); err != nil {
		return errors.Trace(err)
	}

	startTime := time.Now()

	switch cfg.dstDbDriver {
	case "postgres":
		if ir, err = bulk.NewCopyIn(dstDb, columns, cfg.dstSchema, cfg.dstTable); err != nil {
			return errors.Trace(err)
		}
	default:
		if ir, err = bulk.NewBulk(dstDb, columns,
			cfg.dstSchema, cfg.dstTable,
			cfg.maxRowBufSz, cfg.maxRowTxCommit); err != nil {
			return errors.Trace(err)
		}
	}

	rowCount, err = copyBulkRows(dstDb, rows, ir, cfg)
	if err != nil {
		return errors.Trace(err)
	}

	if err = ir.Close(); err != nil {
		return errors.Trace(err)
	}

	fmt.Printf("%d rows in %s\n", rowCount, time.Since(startTime).String())

	return errors.Trace(rows.Err())
}

func copyBulkRows(dstDb *sql.DB, rows *sql.Rows, ir Insert, cfg *Config) (rowCount int, err error) {
	var totalRowCount int
	const dotLimit = 1000

	i := 1

	for rows.Next() {
		if err = ir.Append(rows); err != nil {
			return 0, errors.Trace(err)
		}

		if i%dotLimit == 0 {
			fmt.Print(".")
			i = 1
		}

		i++
	}

	if totalRowCount, err = ir.Flush(); err != nil {
		return 0, errors.Trace(err)
	}

	if totalRowCount > dotLimit {
		fmt.Println()
	}

	return totalRowCount, errors.Trace(rows.Err())
}

func showError(cfg *Config, err error) {
	if cfg.showStackTrace {
		fmt.Fprintf(os.Stderr, "%s\n", errors.ErrorStack(err))
	} else {
		fmt.Fprintf(os.Stderr, "%s\n", err)
	}
}
<|endoftext|>


<commit_before>package songlist

import (
	"sort"

	"github.com/ambientsound/pms/console"
)

// ManuallySelected returns true if the given song index is selected through manual selection.
func (s *BaseSonglist) ManuallySelected(i int) bool {
	_, ok := s.selection[i]
	return ok
}

// VisuallySelected returns true if the given song index is selected through visual selection.
func (s *BaseSonglist) VisuallySelected(i int) bool {
	return s.visualSelection[0] <= i && i <= s.visualSelection[1]
}

// Selected returns true if the given song index is selected, either through
// visual selection or manual selection. If the song is doubly selected, the
// selection is inversed.
func (s *BaseSonglist) Selected(i int) bool {
	a := s.ManuallySelected(i)
	b := s.VisuallySelected(i)
	return (a || b) && a != b
}

// SelectionIndices returns a slice of ints holding the position of each
// element in the current selection. If no elements are selected, the cursor
// position is returned.
func (s *BaseSonglist) SelectionIndices() []int {
	selection := make([]int, 0, s.Len())
	max := s.Len()
	for i := 0; i < max; i++ {
		if s.Selected(i) {
			selection = append(selection, i)
		}
	}
	if len(selection) == 0 && s.Len() > 0 {
		selection = append(selection, s.Cursor())
	}
	selection = sort.IntSlice(selection)
	return selection
}

// SetSelection sets the selected status of a single song.
func (s *BaseSonglist) SetSelected(i int, selected bool) {
	var x struct{}
	_, ok := s.selection[i]
	if ok == selected {
		return
	}
	if selected {
		s.selection[i] = x
	} else {
		delete(s.selection, i)
	}
}

// CommitVisualSelection converts the visual selection to manual selection.
func (s *BaseSonglist) CommitVisualSelection() {
	if !s.HasVisualSelection() {
		return
	}
	for key := s.visualSelection[0]; key <= s.visualSelection[1]; key++ {
		selected := s.Selected(key)
		s.SetSelected(key, selected)
	}
}

// ClearSelection removes all selection.
func (s *BaseSonglist) ClearSelection() {
	s.selection = make(map[int]struct{}, 0)
	s.visualSelection = [3]int{-1, -1, -1}
	// FIXME
	//PostEventModeSync(w, MultibarModeNormal)
}

// Selection returns the current selection as a new Songlist.
func (s *BaseSonglist) Selection() Songlist {
	indices := s.SelectionIndices()
	dest := New()
	for _, i := range indices {
		if song := s.Song(i); song != nil {
			dest.Add(song)
		} else {
			console.Log("SelectionIndices() returned an integer '%d' that resulted in a nil song, ignoring", i)
		}
	}
	return dest
}

// validateVisualSelection makes sure the visual selection stays in range of
// the songlist size.
func (s *BaseSonglist) validateVisualSelection(ymin, ymax, ystart int) (int, int, int) {
	if s.Len() == 0 || ymin < 0 || ymax < 0 || !s.InRange(ystart) {
		return -1, -1, -1
	}
	if !s.InRange(ymin) {
		ymin = 0
	}
	if !s.InRange(ymax) {
		ymax = s.Len() - 1
	}
	return ymin, ymax, ystart
}

// VisualSelection returns the min, max, and start position of visual select.
func (s *BaseSonglist) VisualSelection() (int, int, int) {
	return s.visualSelection[0], s.visualSelection[1], s.visualSelection[2]
}

// SetVisualSelection sets the range of the visual selection. Use negative
// integers to un-select all visually selected songs.
func (s *BaseSonglist) SetVisualSelection(ymin, ymax, ystart int) {
	s.visualSelection[0] = ymin
	s.visualSelection[1] = ymax
	s.visualSelection[2] = ystart
}

// HasVisualSelection returns true if the songlist is in visual selection mode.
func (s *BaseSonglist) HasVisualSelection() bool {
	return s.visualSelection[0] >= 0 && s.visualSelection[1] >= 0
}

// EnableVisualSelection sets start and stop of the visual selection to the
// cursor position.
func (s *BaseSonglist) EnableVisualSelection() {
	cursor := s.Cursor()
	s.SetVisualSelection(cursor, cursor, cursor)
}

// DisableVisualSelection disables visual selection.
func (s *BaseSonglist) DisableVisualSelection() {
	s.SetVisualSelection(-1, -1, -1)
}

// ToggleVisualSelection toggles visual selection on and off.
func (s *BaseSonglist) ToggleVisualSelection() {
	if !s.HasVisualSelection() {
		s.EnableVisualSelection()
	} else {
		s.DisableVisualSelection()
	}
}

// expandVisualSelection sets the visual selection boundaries from where it
// started to the current cursor position.
func (s *BaseSonglist) expandVisualSelection() {
	if !s.HasVisualSelection() {
		return
	}
	ymin, ymax, ystart := s.VisualSelection()
	switch {
	case s.Cursor() < ystart:
		ymin, ymax = s.Cursor(), ystart
	case s.Cursor() > ystart:
		ymin, ymax = ystart, s.Cursor()
	default:
		ymin, ymax = ystart, ystart
	}
	s.SetVisualSelection(ymin, ymax, ystart)
}
<commit_msg>Remove fixed FIXME<commit_after>package songlist

import (
	"sort"

	"github.com/ambientsound/pms/console"
)

// ManuallySelected returns true if the given song index is selected through manual selection.
func (s *BaseSonglist) ManuallySelected(i int) bool {
	_, ok := s.selection[i]
	return ok
}

// VisuallySelected returns true if the given song index is selected through visual selection.
func (s *BaseSonglist) VisuallySelected(i int) bool {
	return s.visualSelection[0] <= i && i <= s.visualSelection[1]
}

// Selected returns true if the given song index is selected, either through
// visual selection or manual selection. If the song is doubly selected, the
// selection is inversed.
func (s *BaseSonglist) Selected(i int) bool {
	a := s.ManuallySelected(i)
	b := s.VisuallySelected(i)
	return (a || b) && a != b
}

// SelectionIndices returns a slice of ints holding the position of each
// element in the current selection. If no elements are selected, the cursor
// position is returned.
func (s *BaseSonglist) SelectionIndices() []int {
	selection := make([]int, 0, s.Len())
	max := s.Len()
	for i := 0; i < max; i++ {
		if s.Selected(i) {
			selection = append(selection, i)
		}
	}
	if len(selection) == 0 && s.Len() > 0 {
		selection = append(selection, s.Cursor())
	}
	selection = sort.IntSlice(selection)
	return selection
}

// SetSelection sets the selected status of a single song.
func (s *BaseSonglist) SetSelected(i int, selected bool) {
	var x struct{}
	_, ok := s.selection[i]
	if ok == selected {
		return
	}
	if selected {
		s.selection[i] = x
	} else {
		delete(s.selection, i)
	}
}

// CommitVisualSelection converts the visual selection to manual selection.
func (s *BaseSonglist) CommitVisualSelection() {
	if !s.HasVisualSelection() {
		return
	}
	for key := s.visualSelection[0]; key <= s.visualSelection[1]; key++ {
		selected := s.Selected(key)
		s.SetSelected(key, selected)
	}
}

// ClearSelection removes all selection.
func (s *BaseSonglist) ClearSelection() {
	s.selection = make(map[int]struct{}, 0)
	s.visualSelection = [3]int{-1, -1, -1}
}

// Selection returns the current selection as a new Songlist.
func (s *BaseSonglist) Selection() Songlist {
	indices := s.SelectionIndices()
	dest := New()
	for _, i := range indices {
		if song := s.Song(i); song != nil {
			dest.Add(song)
		} else {
			console.Log("SelectionIndices() returned an integer '%d' that resulted in a nil song, ignoring", i)
		}
	}
	return dest
}

// validateVisualSelection makes sure the visual selection stays in range of
// the songlist size.
func (s *BaseSonglist) validateVisualSelection(ymin, ymax, ystart int) (int, int, int) {
	if s.Len() == 0 || ymin < 0 || ymax < 0 || !s.InRange(ystart) {
		return -1, -1, -1
	}
	if !s.InRange(ymin) {
		ymin = 0
	}
	if !s.InRange(ymax) {
		ymax = s.Len() - 1
	}
	return ymin, ymax, ystart
}

// VisualSelection returns the min, max, and start position of visual select.
func (s *BaseSonglist) VisualSelection() (int, int, int) {
	return s.visualSelection[0], s.visualSelection[1], s.visualSelection[2]
}

// SetVisualSelection sets the range of the visual selection. Use negative
// integers to un-select all visually selected songs.
func (s *BaseSonglist) SetVisualSelection(ymin, ymax, ystart int) {
	s.visualSelection[0] = ymin
	s.visualSelection[1] = ymax
	s.visualSelection[2] = ystart
}

// HasVisualSelection returns true if the songlist is in visual selection mode.
func (s *BaseSonglist) HasVisualSelection() bool {
	return s.visualSelection[0] >= 0 && s.visualSelection[1] >= 0
}

// EnableVisualSelection sets start and stop of the visual selection to the
// cursor position.
func (s *BaseSonglist) EnableVisualSelection() {
	cursor := s.Cursor()
	s.SetVisualSelection(cursor, cursor, cursor)
}

// DisableVisualSelection disables visual selection.
func (s *BaseSonglist) DisableVisualSelection() {
	s.SetVisualSelection(-1, -1, -1)
}

// ToggleVisualSelection toggles visual selection on and off.
func (s *BaseSonglist) ToggleVisualSelection() {
	if !s.HasVisualSelection() {
		s.EnableVisualSelection()
	} else {
		s.DisableVisualSelection()
	}
}

// expandVisualSelection sets the visual selection boundaries from where it
// started to the current cursor position.
func (s *BaseSonglist) expandVisualSelection() {
	if !s.HasVisualSelection() {
		return
	}
	ymin, ymax, ystart := s.VisualSelection()
	switch {
	case s.Cursor() < ystart:
		ymin, ymax = s.Cursor(), ystart
	case s.Cursor() > ystart:
		ymin, ymax = ystart, s.Cursor()
	default:
		ymin, ymax = ystart, ystart
	}
	s.SetVisualSelection(ymin, ymax, ystart)
}
<|endoftext|>


<commit_before>// Copyright 2014 The Serviced 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 servicedefinition

import (
	"github.com/control-center/serviced/domain"
	"github.com/control-center/serviced/utils"
	//	"github.com/zenoss/glog"

	"encoding/json"
	"errors"
	"strings"
	"time"
)

//ServiceDefinition is the definition of a service hierarchy.
type ServiceDefinition struct {
	Name              string                 // Name of the defined service
	Title             string                 // Title is a label used when describing this service in the context of a service tree
	Version           string                 // Version of the defined service
	Command           string                 // Command which runs the service
	Description       string                 // Description of the service
	Tags              []string               // Searchable service tags
	ImageID           string                 // Docker image hosting the service
	Instances         domain.MinMax          // Constraints on the number of instances
	ChangeOptions     []string               // Control options for what happens when a running service is changed
	Launch            string                 // Must be "AUTO", the default, or "MANUAL"
	HostPolicy        HostPolicy             // Policy for starting up instances
	Hostname          string                 // Optional hostname which should be set on run
	Privileged        bool                   // Whether to run the container with extended privileges
	ConfigFiles       map[string]ConfigFile  // Config file templates
	Context           map[string]interface{} // Context information for the service
	Endpoints         []EndpointDefinition   // Comms endpoints used by the service
	Services          []ServiceDefinition    // Supporting subservices
	Tasks             []Task                 // Scheduled tasks for celery to find
	LogFilters        map[string]string      // map of log filter name to log filter definitions
	Volumes           []Volume               // list of volumes to bind into containers
	LogConfigs        []LogConfig
	Snapshot          SnapshotCommands              // Snapshot quiesce info for the service: Pause/Resume bash commands
	RAMCommitment     utils.EngNotation             // expected RAM commitment to use for scheduling
	CPUCommitment     uint64                        // expected CPU commitment (#cores) to use for scheduling
	Runs              map[string]string             // Map of commands that can be executed with 'serviced run ...'
	Actions           map[string]string             // Map of commands that can be executed with 'serviced action ...'
	HealthChecks      map[string]domain.HealthCheck // HealthChecks for a service.
	Prereqs           []domain.Prereq               // Optional list of scripts that must be successfully run before kicking off the service command.
	MonitoringProfile domain.MonitorProfile         // An optional list of queryable metrics, graphs, and thresholds
	MemoryLimit       float64
	CPUShares         int64
	PIDFile           string // An optional path or command to generate a path for a PID file to which signals are relayed.
}

// SnapshotCommands commands to be called during and after a snapshot
type SnapshotCommands struct {
	Pause  string // bash command to pause the volume  (quiesce)
	Resume string // bash command to resume the volume (unquiesce)
}

// EndpointDefinition An endpoint that a Service exposes.
type EndpointDefinition struct {
	Name                string // Human readable name of the endpoint. Unique per service definition
	Purpose             string
	Protocol            string
	PortNumber          uint16
	PortTemplate        string // A template which, if specified, is used to calculate the port number
	VirtualAddress      string // An address by which an imported endpoint may be accessed within the container, e.g. "mysqlhost:1234"
	Application         string
	ApplicationTemplate string
	AddressConfig       AddressResourceConfig
	//	VHosts              []string // VHost is used to request named vhost for this endpoint. Should be the name of a
	// subdomain, i.e "myapplication"  not "myapplication.host.com"
	VHostList []VHost // VHost is used to request named vhost(s) for this endpoint.
}

// VHost is the configuration for an application endpoint that wants an http VHost endpoint provided by Control Center
type VHost struct {
	Name    string // name of the vhost subdomain subdomain, i.e "myapplication"  not "myapplication.host.com
	Enabled bool   // whether the vhost should be enabled or disabled.
}

// Task A scheduled task
type Task struct {
	Name          string
	Schedule      string
	Command       string
	LastRunAt     time.Time
	TotalRunCount int
}

// Volume import defines a file system directory underneath an export directory
type Volume struct {
	Owner             string //Resource Path Owner
	Permission        string //Resource Path permissions, eg what you pass to chmod
	ResourcePath      string //Resource Pool Path, shared across all hosts in a resource pool
	ContainerPath     string //Container bind-mount path
	Type              string //Path use, i.e. "dfs" or "tmp"
	InitContainerPath string //Path to initialize the volume from at creation time, optional
}

// ConfigFile config file for a service
type ConfigFile struct {
	Filename    string // complete path of file
	Owner       string // owner of file within the container, root:root or 0:0 for root owned file, what you would pass to chown
	Permissions string // permission of file, eg 0664, what you would pass to chmod
	Content     string // content of config file
}

//AddressResourceConfig defines an external facing port for a service definition
type AddressResourceConfig struct {
	Port     uint16
	Protocol string
}

// LogConfig represents the configuration for a logfile for a service.
type LogConfig struct {
	Path    string   // The location on the container's filesystem of the log, can be a directory
	Type    string   // Arbitrary string that identifies the "types" of logs that come from this source. This will be
	Filters []string // A list of filters that must be contained in either the LogFilters or a parent's LogFilter,
	LogTags []LogTag // Key value pair of tags that are sent to logstash for all entries coming out of this logfile
}

// LogTag  no clue what this is. Maybe someone actually reads this
type LogTag struct {
	Name  string
	Value string
}

// HostPolicy represents the optional policy used to determine which hosts on
// which to run instances of a service. Default is to run on the available
// host with the most uncommitted RAM.
type HostPolicy string

const (
	//DEFAULT policy for scheduling a service instance
	DEFAULT HostPolicy = ""
	//LeastCommitted run on host w/ least committed memory
	LeastCommitted = "LEAST_COMMITTED"
	//PreferSeparate attempt to schedule instances of a service on separate hosts
	PreferSeparate = "PREFER_SEPARATE"
	//RequireSeparate schedule instances of a service on separate hosts
	RequireSeparate = "REQUIRE_SEPARATE"
)

// UnmarshalText implements the encoding/TextUnmarshaler interface
func (p *HostPolicy) UnmarshalText(b []byte) error {
	s := strings.Trim(string(b), `"`)
	switch s {
	case LeastCommitted, PreferSeparate, RequireSeparate:
		*p = HostPolicy(s)
	case "":
		*p = DEFAULT
	default:
		return errors.New("Invalid HostPolicy: " + s)
	}
	return nil
}

// private for dealing with unmarshal recursion
type endpointDefinition EndpointDefinition

// UnmarshalJSON implements the encoding/TextUnmarshaler interface

func (e *EndpointDefinition) UnmarshalJSON(b []byte) error {
	epd := endpointDefinition{}
	if err := json.Unmarshal(b, &epd); err == nil {
		*e = EndpointDefinition(epd)
	} else {
		return err
	}
	//	if len(e.VHostList) > 0{
	//		//VHostList is defined, keep it and unset deprecated field if set
	//		e.VHosts = nil
	//		return nil
	//	}
	//	if len(e.VHosts) > 0{
	//		// no VHostsList but vhosts is defined. Convert to VHostsList
	//		glog.V(0).Warn("EndpointDefinition VHosts field is deprecated, see VHostList")
	//		for _, vhost := range e.VHosts{
	//			e.VHostList = append(e.VHostList, VHost{Name:vhost, Enabled:true})
	//		}
	return nil
}
func (e EndpointDefinition) MarshalJSON() ([]byte, error) {
	//	if len(e.VHosts) > 0 {
	//		glog.V(0).Warn("EndpointDefinition VHosts field is deprecated, value will not be marshalled; see VHostList")
	//		e.Vhosts = nil
	//	}
	// Can' marshal EndpointDefinitio as it would be infinite recursion
	return json.Marshal(endpointDefinition(e))
}

func (s ServiceDefinition) String() string {
	return s.Name
}

//BuildFromPath given a path will create a ServiceDefintion
func BuildFromPath(path string) (*ServiceDefinition, error) {
	sd, err := getServiceDefinition(path)
	if err != nil {
		return nil, err
	}
	return sd, sd.ValidEntity()
}
<commit_msg>don't marshal/unmarshal vhosts<commit_after>// Copyright 2014 The Serviced 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 servicedefinition

import (
	"github.com/control-center/serviced/domain"
	"github.com/control-center/serviced/utils"
	"github.com/zenoss/glog"

	"encoding/json"
	"errors"
	"strings"
	"time"
)

//ServiceDefinition is the definition of a service hierarchy.
type ServiceDefinition struct {
	Name              string                 // Name of the defined service
	Title             string                 // Title is a label used when describing this service in the context of a service tree
	Version           string                 // Version of the defined service
	Command           string                 // Command which runs the service
	Description       string                 // Description of the service
	Tags              []string               // Searchable service tags
	ImageID           string                 // Docker image hosting the service
	Instances         domain.MinMax          // Constraints on the number of instances
	ChangeOptions     []string               // Control options for what happens when a running service is changed
	Launch            string                 // Must be "AUTO", the default, or "MANUAL"
	HostPolicy        HostPolicy             // Policy for starting up instances
	Hostname          string                 // Optional hostname which should be set on run
	Privileged        bool                   // Whether to run the container with extended privileges
	ConfigFiles       map[string]ConfigFile  // Config file templates
	Context           map[string]interface{} // Context information for the service
	Endpoints         []EndpointDefinition   // Comms endpoints used by the service
	Services          []ServiceDefinition    // Supporting subservices
	Tasks             []Task                 // Scheduled tasks for celery to find
	LogFilters        map[string]string      // map of log filter name to log filter definitions
	Volumes           []Volume               // list of volumes to bind into containers
	LogConfigs        []LogConfig
	Snapshot          SnapshotCommands              // Snapshot quiesce info for the service: Pause/Resume bash commands
	RAMCommitment     utils.EngNotation             // expected RAM commitment to use for scheduling
	CPUCommitment     uint64                        // expected CPU commitment (#cores) to use for scheduling
	Runs              map[string]string             // Map of commands that can be executed with 'serviced run ...'
	Actions           map[string]string             // Map of commands that can be executed with 'serviced action ...'
	HealthChecks      map[string]domain.HealthCheck // HealthChecks for a service.
	Prereqs           []domain.Prereq               // Optional list of scripts that must be successfully run before kicking off the service command.
	MonitoringProfile domain.MonitorProfile         // An optional list of queryable metrics, graphs, and thresholds
	MemoryLimit       float64
	CPUShares         int64
	PIDFile           string // An optional path or command to generate a path for a PID file to which signals are relayed.
}

// SnapshotCommands commands to be called during and after a snapshot
type SnapshotCommands struct {
	Pause  string // bash command to pause the volume  (quiesce)
	Resume string // bash command to resume the volume (unquiesce)
}

// EndpointDefinition An endpoint that a Service exposes.
type EndpointDefinition struct {
	Name                string // Human readable name of the endpoint. Unique per service definition
	Purpose             string
	Protocol            string
	PortNumber          uint16
	PortTemplate        string // A template which, if specified, is used to calculate the port number
	VirtualAddress      string // An address by which an imported endpoint may be accessed within the container, e.g. "mysqlhost:1234"
	Application         string
	ApplicationTemplate string
	AddressConfig       AddressResourceConfig
	VHosts              []string // VHost is used to request named vhost for this endpoint. Should be the name of a
	// subdomain, i.e "myapplication"  not "myapplication.host.com"
	VHostList []VHost // VHost is used to request named vhost(s) for this endpoint.
}

// VHost is the configuration for an application endpoint that wants an http VHost endpoint provided by Control Center
type VHost struct {
	Name    string // name of the vhost subdomain subdomain, i.e "myapplication"  not "myapplication.host.com
	Enabled bool   // whether the vhost should be enabled or disabled.
}

// Task A scheduled task
type Task struct {
	Name          string
	Schedule      string
	Command       string
	LastRunAt     time.Time
	TotalRunCount int
}

// Volume import defines a file system directory underneath an export directory
type Volume struct {
	Owner             string //Resource Path Owner
	Permission        string //Resource Path permissions, eg what you pass to chmod
	ResourcePath      string //Resource Pool Path, shared across all hosts in a resource pool
	ContainerPath     string //Container bind-mount path
	Type              string //Path use, i.e. "dfs" or "tmp"
	InitContainerPath string //Path to initialize the volume from at creation time, optional
}

// ConfigFile config file for a service
type ConfigFile struct {
	Filename    string // complete path of file
	Owner       string // owner of file within the container, root:root or 0:0 for root owned file, what you would pass to chown
	Permissions string // permission of file, eg 0664, what you would pass to chmod
	Content     string // content of config file
}

//AddressResourceConfig defines an external facing port for a service definition
type AddressResourceConfig struct {
	Port     uint16
	Protocol string
}

// LogConfig represents the configuration for a logfile for a service.
type LogConfig struct {
	Path    string   // The location on the container's filesystem of the log, can be a directory
	Type    string   // Arbitrary string that identifies the "types" of logs that come from this source. This will be
	Filters []string // A list of filters that must be contained in either the LogFilters or a parent's LogFilter,
	LogTags []LogTag // Key value pair of tags that are sent to logstash for all entries coming out of this logfile
}

// LogTag  no clue what this is. Maybe someone actually reads this
type LogTag struct {
	Name  string
	Value string
}

// HostPolicy represents the optional policy used to determine which hosts on
// which to run instances of a service. Default is to run on the available
// host with the most uncommitted RAM.
type HostPolicy string

const (
	//DEFAULT policy for scheduling a service instance
	DEFAULT HostPolicy = ""
	//LeastCommitted run on host w/ least committed memory
	LeastCommitted = "LEAST_COMMITTED"
	//PreferSeparate attempt to schedule instances of a service on separate hosts
	PreferSeparate = "PREFER_SEPARATE"
	//RequireSeparate schedule instances of a service on separate hosts
	RequireSeparate = "REQUIRE_SEPARATE"
)

// UnmarshalText implements the encoding/TextUnmarshaler interface
func (p *HostPolicy) UnmarshalText(b []byte) error {
	s := strings.Trim(string(b), `"`)
	switch s {
	case LeastCommitted, PreferSeparate, RequireSeparate:
		*p = HostPolicy(s)
	case "":
		*p = DEFAULT
	default:
		return errors.New("Invalid HostPolicy: " + s)
	}
	return nil
}

// private for dealing with unmarshal recursion
type endpointDefinition EndpointDefinition

// UnmarshalJSON implements the encoding/TextUnmarshaler interface

func (e *EndpointDefinition) UnmarshalJSON(b []byte) error {
	epd := endpointDefinition{}
	if err := json.Unmarshal(b, &epd); err == nil {
		*e = EndpointDefinition(epd)
	} else {
		return err
	}
	if len(e.VHostList) > 0 {
		//VHostList is defined, keep it and unset deprecated field if set
		e.VHosts = nil
		return nil
	}
	if len(e.VHosts) > 0 {
		// no VHostsList but vhosts is defined. Convert to VHostsList
		glog.Warning("EndpointDefinition VHosts field is deprecated, see VHostList")
		for _, vhost := range e.VHosts {
			e.VHostList = append(e.VHostList, VHost{Name: vhost, Enabled: true})
		}
	}
	return nil
}
func (e EndpointDefinition) MarshalJSON() ([]byte, error) {
	if len(e.VHosts) > 0 {
		glog.Warning("EndpointDefinition VHosts field is deprecated, value will not be marshalled; see VHostList")
		e.VHosts = nil
	}
	// Can' marshal EndpointDefinitio as it would be infinite recursion
	return json.Marshal(endpointDefinition(e))
}

func (s ServiceDefinition) String() string {
	return s.Name
}

//BuildFromPath given a path will create a ServiceDefintion
func BuildFromPath(path string) (*ServiceDefinition, error) {
	sd, err := getServiceDefinition(path)
	if err != nil {
		return nil, err
	}
	return sd, sd.ValidEntity()
}
<|endoftext|>


<commit_before>package object

import (
	"fmt"
	"math"

	"github.com/Bredgren/gotracer/trace/bvh"
	"github.com/Bredgren/gotracer/trace/options"
	"github.com/Bredgren/gotracer/trace/ray"
	"github.com/Bredgren/gotracer/trace/vec"
	"github.com/go-gl/mathgl/mgl64"
)

type objFn func(*Object) (bvh.IntersectFn, *bvh.AABB)

var objFnMap = map[string]objFn{
	"Plane": plane,
	"Cube":  cube,
	// "Sphere": sphere,
	// "Cylinder": cylinder,
	// "Cone": cone,
	// "Triangle": triangle,
	// "Trimesh": trimesh,
	// "CSG": csg,
}

// Object reprsents an object in the scene and can be intersected with rays.
type Object struct {
	Transform    mgl64.Mat4
	InvTransform mgl64.Mat4
	MaterialName string
	IsectFn      bvh.IntersectFn
	aabb         *bvh.AABB
}

// Intersect implements the bvh.Intersector interface.
func (o *Object) Intersect(r *ray.Ray, res *bvh.IntersectResult) {
	newDir := mgl64.TransformNormal(r.Dir, o.InvTransform)
	localRay := ray.Ray{
		Origin: mgl64.TransformCoordinate(r.Origin, o.InvTransform),
		Dir:    newDir.Normalize(),
	}
	o.IsectFn(&localRay, res)
	if res.Object != nil {
		if !mgl64.FloatEqual(newDir.Len(), 0) {
			res.T /= newDir.Len()
		}
		res.Normal = mgl64.TransformNormal(res.Normal, o.Transform).Normalize()
	}
}

// AABB implements the bvh.Intersector interface.
func (o *Object) AABB() *bvh.AABB {
	return o.aabb
}

// MakeObjects creates new objects from the given options.
func MakeObjects(opts *options.Options) ([]*Object, error) {
	var objs []*Object

	objOpts := make(map[string]*options.Object)
	for _, o := range opts.Objects {
		objOpts[o.Name] = o
	}

	for _, layout := range opts.Layout {
		l, ok := objOpts[layout.Name]
		if !ok {
			return nil, fmt.Errorf("layout specified unknown object: %s", layout.Name)
		}
		os, e := newObjects(l, getTransform(layout.Transform), objOpts, layout.Name, true)
		if e != nil {
			return nil, fmt.Errorf("creating layout for object %s: %v", layout.Name, e)
		}
		objs = append(objs, os...)
	}
	return objs, nil
}

func newObjects(opts *options.Object, transform mgl64.Mat4, objOpts map[string]*options.Object, top string, atTop bool) ([]*Object, error) {
	transform = transform.Mul4(getTransform(opts.Transform))
	if !atTop && opts.Name != "" {
		if opts.Name == top {
			return nil, fmt.Errorf("recursive object not supported: %s", opts.Name)
		}
		o, ok := objOpts[opts.Name]
		if !ok {
			return nil, fmt.Errorf("unknown child object for %s: %s", top, opts.Name)
		}
		objs, e := newObjects(o, transform, objOpts, top, true)
		if e != nil {
			return nil, e
		}
		for _, child := range opts.Children {
			os, e := newObjects(child, transform, objOpts, top, false)
			if e != nil {
				return nil, e
			}
			objs = append(objs, os...)
		}
		return objs, nil
	}

	var objs []*Object
	o := Object{}
	fn, ok := objFnMap[opts.Type]
	if !ok {
		return nil, fmt.Errorf("unknown object type '%s'", opts.Type)
	}
	o.Transform = transform
	o.InvTransform = o.Transform.Inv()
	o.IsectFn, o.aabb = fn(&o)

	objs = append(objs, &o)
	for _, child := range opts.Children {
		os, e := newObjects(child, o.Transform, objOpts, top, false)
		if e != nil {
			return nil, e
		}
		objs = append(objs, os...)
	}
	return objs, nil
}

func getTransform(optsT options.Transform) mgl64.Mat4 {
	if mgl64.FloatEqual(optsT.Scale.X, 0) {
		optsT.Scale.X = 1
	}
	if mgl64.FloatEqual(optsT.Scale.Y, 0) {
		optsT.Scale.Y = 1
	}
	if mgl64.FloatEqual(optsT.Scale.Z, 0) {
		optsT.Scale.Z = 1
	}
	transform := mgl64.Ident4()
	transform = transform.Mul4(mgl64.Translate3D(optsT.Translate.X, optsT.Translate.Y, optsT.Translate.Z))
	transform = transform.Mul4(mgl64.HomogRotate3D(optsT.RotateAngle*math.Pi/180, vec.Normalize(mgl64.Vec3{optsT.RotateAxis.X, optsT.RotateAxis.Y, optsT.RotateAxis.Z}, vec.Y)))
	transform = transform.Mul4(mgl64.Scale3D(optsT.Scale.X, optsT.Scale.Y, optsT.Scale.Z))
	return transform
}

// Plane is a 2D plane object with a width and height of 1 in the XY-plane centered at the origin.
func plane(o *Object) (bvh.IntersectFn, *bvh.AABB) {
	return func(r *ray.Ray, res *bvh.IntersectResult) {
		res.Object = nil

		if mgl64.FloatEqual(r.Dir.Z(), 0) {
			return // Miss when parallel
		}

		t := -r.Origin.Z() / r.Dir.Z()

		if t < ray.Epsilon {
			return // We're too close
		}

		point := r.At(t)

		if point.X() < -0.5 || point.X() > 0.5 || point.Y() < -0.5 || point.Y() > 0.5 {
			return // Out of bounds
		}

		// Successful hit
		res.Object = o
		res.T = t
		if r.Dir.Z() > 0 {
			res.Normal = mgl64.Vec3{0, 0, -1}
		} else {
			res.Normal = mgl64.Vec3{0, 0, 1}
		}

		res.UV = mgl64.Vec2{point.X() + 0.5, 1 - (point.Y() + 0.5)}
	}, makeAABB(1, 1, 0.1, o.Transform)
}

// Cube has dimensinos 1x1x1 and is centered at the origin.
func cube(o *Object) (bvh.IntersectFn, *bvh.AABB) {
	return func(r *ray.Ray, res *bvh.IntersectResult) {
		res.Object = nil

		res.T = math.Inf(1)
		bestSide := -1

		for side := 0; side < 6; side++ {
			axis := side % 3
			if r.Dir[axis] == 0 {
				continue
			}

			t := (float64(side/3) - 0.5 - r.Origin[axis]) / r.Dir[axis]
			if t < ray.Epsilon || t > res.T {
				continue
			}

			x := r.Origin[(side+1)%3] + t*r.Dir[(side+1)%3]
			y := r.Origin[(side+2)%3] + t*r.Dir[(side+2)%3]
			if x <= 0.5 && x >= -0.5 && y <= 0.5 && y >= -0.5 && res.T > t {
				res.T = t
				bestSide = side
			}
		}

		if bestSide < 0 {
			return
		}

		res.Object = o
		res.Normal = mgl64.Vec3{}

		// Calculate UV coords and Normal
		point := r.At(res.T)
		side1 := float64((bestSide + 1) % 3)
		side2 := float64((bestSide + 2) % 3)
		if bestSide < 3 {
			res.UV = mgl64.Vec2{
				0.5 - point[int(math.Min(side1, side2))],
				0.5 + point[int(math.Max(side1, side2))],
			}
			res.Normal[bestSide%3] = -1
		} else {
			res.UV = mgl64.Vec2{
				0.5 + point[int(math.Min(side1, side2))],
				0.5 + point[int(math.Max(side1, side2))],
			}
			res.Normal[bestSide%3] = 1
		}
	}, makeAABB(1, 1, 1, o.Transform)
}

// Sphere has radius 1 centered at the origin.
type Sphere struct {
}

// Cylinder has height and radius 1 centered at the origin.
type Cylinder struct {
}

// Cone has height and base radius 1 centered at the origin.
type Cone struct {
}

// Triangle is made up of the points (0, 0, 0), (1, 0, 0), (0, 1, 0).
type Triangle struct {
}

// Trimesh is a mesh of many triangles.
type Trimesh struct {
}

// CSG (constructive solid geometry) combines other objects using union, intersection and difference.
type CSG struct {
}

func makeAABB(w, h, d float64, transform mgl64.Mat4) *bvh.AABB {
	points := aabbPoints(w, h, d)
	transformPoints(points[:], transform)
	return aabbFromPoints(points)
}

func aabbPoints(w, h, d float64) [8]mgl64.Vec3 {
	hw := w / 2
	hh := h / 2
	hd := d / 2
	return [8]mgl64.Vec3{
		{-hw, -hh, -hd}, {-hw, -hh, hd}, {hw, -hh, -hd}, {hw, -hh, hd},
		{-hw, hh, -hd}, {-hw, hh, hd}, {hw, hh, -hd}, {hw, hh, hd},
	}
}

func transformPoints(points []mgl64.Vec3, transform mgl64.Mat4) {
	for i, p := range points {
		points[i] = mgl64.TransformCoordinate(p, transform)
	}
}

func aabbFromPoints(points [8]mgl64.Vec3) *bvh.AABB {
	aabb := bvh.AABB{
		Min: mgl64.Vec3{math.Inf(1), math.Inf(1), math.Inf(1)},
		Max: mgl64.Vec3{math.Inf(-1), math.Inf(-1), math.Inf(-1)},
	}

	for _, p := range points {
		for axis := 0; axis < 3; axis++ {
			if p[axis] < aabb.Min[axis] {
				aabb.Min[axis] = p[axis]
			}
			if p[axis] > aabb.Max[axis] {
				aabb.Max[axis] = p[axis]
			}
		}
	}

	return &aabb
}
<commit_msg>Handle Transform object type.<commit_after>package object

import (
	"fmt"
	"math"

	"github.com/Bredgren/gotracer/trace/bvh"
	"github.com/Bredgren/gotracer/trace/options"
	"github.com/Bredgren/gotracer/trace/ray"
	"github.com/Bredgren/gotracer/trace/vec"
	"github.com/go-gl/mathgl/mgl64"
)

type objFn func(*Object) (bvh.IntersectFn, *bvh.AABB)

var objFnMap = map[string]objFn{
	"Plane": plane,
	"Cube":  cube,
	// "Sphere": sphere,
	// "Cylinder": cylinder,
	// "Cone": cone,
	// "Triangle": triangle,
	// "Trimesh": trimesh,
	// "CSG": csg,
}

// Object reprsents an object in the scene and can be intersected with rays.
type Object struct {
	Transform    mgl64.Mat4
	InvTransform mgl64.Mat4
	MaterialName string
	IsectFn      bvh.IntersectFn
	aabb         *bvh.AABB
}

// Intersect implements the bvh.Intersector interface.
func (o *Object) Intersect(r *ray.Ray, res *bvh.IntersectResult) {
	newDir := mgl64.TransformNormal(r.Dir, o.InvTransform)
	localRay := ray.Ray{
		Origin: mgl64.TransformCoordinate(r.Origin, o.InvTransform),
		Dir:    newDir.Normalize(),
	}
	o.IsectFn(&localRay, res)
	if res.Object != nil {
		if !mgl64.FloatEqual(newDir.Len(), 0) {
			res.T /= newDir.Len()
		}
		res.Normal = mgl64.TransformNormal(res.Normal, o.Transform).Normalize()
	}
}

// AABB implements the bvh.Intersector interface.
func (o *Object) AABB() *bvh.AABB {
	return o.aabb
}

// MakeObjects creates new objects from the given options.
func MakeObjects(opts *options.Options) ([]*Object, error) {
	var objs []*Object

	objOpts := make(map[string]*options.Object)
	for _, o := range opts.Objects {
		objOpts[o.Name] = o
	}

	for _, layout := range opts.Layout {
		l, ok := objOpts[layout.Name]
		if !ok {
			return nil, fmt.Errorf("layout specified unknown object: %s", layout.Name)
		}
		os, e := newObjects(l, getTransform(layout.Transform), objOpts, layout.Name, true)
		if e != nil {
			return nil, fmt.Errorf("creating layout for object %s: %v", layout.Name, e)
		}
		objs = append(objs, os...)
	}
	return objs, nil
}

func newObjects(opts *options.Object, transform mgl64.Mat4, objOpts map[string]*options.Object, top string, atTop bool) ([]*Object, error) {
	transform = transform.Mul4(getTransform(opts.Transform))
	if !atTop && opts.Name != "" {
		if opts.Name == top {
			return nil, fmt.Errorf("recursive object not supported: %s", opts.Name)
		}
		o, ok := objOpts[opts.Name]
		if !ok {
			return nil, fmt.Errorf("unknown child object for %s: %s", top, opts.Name)
		}
		objs, e := newObjects(o, transform, objOpts, top, true)
		if e != nil {
			return nil, e
		}
		for _, child := range opts.Children {
			os, e := newObjects(child, transform, objOpts, top, false)
			if e != nil {
				return nil, e
			}
			objs = append(objs, os...)
		}
		return objs, nil
	}

	if opts.Type == "Transform" {
		var objs []*Object
		for _, child := range opts.Children {
			os, e := newObjects(child, transform, objOpts, top, false)
			if e != nil {
				return nil, e
			}
			objs = append(objs, os...)
		}
		return objs, nil
	}

	var objs []*Object
	o := Object{}
	fn, ok := objFnMap[opts.Type]
	if !ok {
		return nil, fmt.Errorf("unknown object type '%s'", opts.Type)
	}
	o.Transform = transform
	o.InvTransform = o.Transform.Inv()
	o.IsectFn, o.aabb = fn(&o)

	objs = append(objs, &o)
	for _, child := range opts.Children {
		os, e := newObjects(child, o.Transform, objOpts, top, false)
		if e != nil {
			return nil, e
		}
		objs = append(objs, os...)
	}
	return objs, nil
}

func getTransform(optsT options.Transform) mgl64.Mat4 {
	if mgl64.FloatEqual(optsT.Scale.X, 0) {
		optsT.Scale.X = 1
	}
	if mgl64.FloatEqual(optsT.Scale.Y, 0) {
		optsT.Scale.Y = 1
	}
	if mgl64.FloatEqual(optsT.Scale.Z, 0) {
		optsT.Scale.Z = 1
	}
	transform := mgl64.Ident4()
	transform = transform.Mul4(mgl64.Translate3D(optsT.Translate.X, optsT.Translate.Y, optsT.Translate.Z))
	transform = transform.Mul4(mgl64.HomogRotate3D(optsT.RotateAngle*math.Pi/180, vec.Normalize(mgl64.Vec3{optsT.RotateAxis.X, optsT.RotateAxis.Y, optsT.RotateAxis.Z}, vec.Y)))
	transform = transform.Mul4(mgl64.Scale3D(optsT.Scale.X, optsT.Scale.Y, optsT.Scale.Z))
	return transform
}

// Plane is a 2D plane object with a width and height of 1 in the XY-plane centered at the origin.
func plane(o *Object) (bvh.IntersectFn, *bvh.AABB) {
	return func(r *ray.Ray, res *bvh.IntersectResult) {
		res.Object = nil

		if mgl64.FloatEqual(r.Dir.Z(), 0) {
			return // Miss when parallel
		}

		t := -r.Origin.Z() / r.Dir.Z()

		if t < ray.Epsilon {
			return // We're too close
		}

		point := r.At(t)

		if point.X() < -0.5 || point.X() > 0.5 || point.Y() < -0.5 || point.Y() > 0.5 {
			return // Out of bounds
		}

		// Successful hit
		res.Object = o
		res.T = t
		if r.Dir.Z() > 0 {
			res.Normal = mgl64.Vec3{0, 0, -1}
		} else {
			res.Normal = mgl64.Vec3{0, 0, 1}
		}

		res.UV = mgl64.Vec2{point.X() + 0.5, 1 - (point.Y() + 0.5)}
	}, makeAABB(1, 1, 0.1, o.Transform)
}

// Cube has dimensinos 1x1x1 and is centered at the origin.
func cube(o *Object) (bvh.IntersectFn, *bvh.AABB) {
	return func(r *ray.Ray, res *bvh.IntersectResult) {
		res.Object = nil

		res.T = math.Inf(1)
		bestSide := -1

		for side := 0; side < 6; side++ {
			axis := side % 3
			if r.Dir[axis] == 0 {
				continue
			}

			t := (float64(side/3) - 0.5 - r.Origin[axis]) / r.Dir[axis]
			if t < ray.Epsilon || t > res.T {
				continue
			}

			x := r.Origin[(side+1)%3] + t*r.Dir[(side+1)%3]
			y := r.Origin[(side+2)%3] + t*r.Dir[(side+2)%3]
			if x <= 0.5 && x >= -0.5 && y <= 0.5 && y >= -0.5 && res.T > t {
				res.T = t
				bestSide = side
			}
		}

		if bestSide < 0 {
			return
		}

		res.Object = o
		res.Normal = mgl64.Vec3{}

		// Calculate UV coords and Normal
		point := r.At(res.T)
		side1 := float64((bestSide + 1) % 3)
		side2 := float64((bestSide + 2) % 3)
		if bestSide < 3 {
			res.UV = mgl64.Vec2{
				0.5 - point[int(math.Min(side1, side2))],
				0.5 + point[int(math.Max(side1, side2))],
			}
			res.Normal[bestSide%3] = -1
		} else {
			res.UV = mgl64.Vec2{
				0.5 + point[int(math.Min(side1, side2))],
				0.5 + point[int(math.Max(side1, side2))],
			}
			res.Normal[bestSide%3] = 1
		}
	}, makeAABB(1, 1, 1, o.Transform)
}

// Sphere has radius 1 centered at the origin.
type Sphere struct {
}

// Cylinder has height and radius 1 centered at the origin.
type Cylinder struct {
}

// Cone has height and base radius 1 centered at the origin.
type Cone struct {
}

// Triangle is made up of the points (0, 0, 0), (1, 0, 0), (0, 1, 0).
type Triangle struct {
}

// Trimesh is a mesh of many triangles.
type Trimesh struct {
}

// CSG (constructive solid geometry) combines other objects using union, intersection and difference.
type CSG struct {
}

func makeAABB(w, h, d float64, transform mgl64.Mat4) *bvh.AABB {
	points := aabbPoints(w, h, d)
	transformPoints(points[:], transform)
	return aabbFromPoints(points)
}

func aabbPoints(w, h, d float64) [8]mgl64.Vec3 {
	hw := w / 2
	hh := h / 2
	hd := d / 2
	return [8]mgl64.Vec3{
		{-hw, -hh, -hd}, {-hw, -hh, hd}, {hw, -hh, -hd}, {hw, -hh, hd},
		{-hw, hh, -hd}, {-hw, hh, hd}, {hw, hh, -hd}, {hw, hh, hd},
	}
}

func transformPoints(points []mgl64.Vec3, transform mgl64.Mat4) {
	for i, p := range points {
		points[i] = mgl64.TransformCoordinate(p, transform)
	}
}

func aabbFromPoints(points [8]mgl64.Vec3) *bvh.AABB {
	aabb := bvh.AABB{
		Min: mgl64.Vec3{math.Inf(1), math.Inf(1), math.Inf(1)},
		Max: mgl64.Vec3{math.Inf(-1), math.Inf(-1), math.Inf(-1)},
	}

	for _, p := range points {
		for axis := 0; axis < 3; axis++ {
			if p[axis] < aabb.Min[axis] {
				aabb.Min[axis] = p[axis]
			}
			if p[axis] > aabb.Max[axis] {
				aabb.Max[axis] = p[axis]
			}
		}
	}

	return &aabb
}
<|endoftext|>


<commit_before>package xpath

//please check the search tests in gokogiri/xml and gokogiri/html
import "testing"

func TestCompileGoodExpr(t *testing.T) {
	defer CheckXmlMemoryLeaks(t)
	e := Compile(`./*`)
	if e == nil {
		t.Error("expr should be good")
	}
	e.Free()
}

func TestCompileBadExpr(t *testing.T) {
	defer CheckXmlMemoryLeaks(t)
	e := Compile("./")
	if e != nil {
		t.Error("expr should be bad")
	}
}
<commit_msg>a test that causes memory leaks in libxml<commit_after>package xpath

//please check the search tests in gokogiri/xml and gokogiri/html
import "testing"

func TestCompileGoodExpr(t *testing.T) {
	defer CheckXmlMemoryLeaks(t)
	e := Compile(`./*`)
	if e == nil {
		t.Error("expr should be good")
	}
	e.Free()
}

func TestCompileBadExpr(t *testing.T) {
	//defer CheckXmlMemoryLeaks(t)
	//this test causes memory leaks in libxml
	//however, the memory leak is very small and does not grow as more bad expressions are compiled
	e := Compile("./")
	if e != nil {
		t.Error("expr should be bad")
	}
	e = Compile(".//")
	if e != nil {
		t.Error("expr should be bad")
	}
}
<|endoftext|>


<commit_before>package stripe

import "encoding/json"

// WebhookEndpointParams is the set of parameters that can be used when creating a webhook endpoint.
// For more details see https://stripe.com/docs/api#create_webhook_endpoint.
type WebhookEndpointParams struct {
	Params        `form:"*"`
	Connect       *bool     `form:"connect"`
	Description   *string   `form:"description"`
	Disabled      *bool     `form:"disabled"`
	EnabledEvents []*string `form:"enabled_events"`
	URL           *string   `form:"url"`

	// This parameter is only available on creation.
	// We recommend setting the API version that the library is pinned to. See apiversion in stripe.go
	APIVersion *string `form:"api_version"`
}

// WebhookEndpointListParams is the set of parameters that can be used when listing webhook endpoints.
// For more detail see https://stripe.com/docs/api#list_webhook_endpoints.
type WebhookEndpointListParams struct {
	ListParams   `form:"*"`
	Created      *int64            `form:"created"`
	CreatedRange *RangeQueryParams `form:"created"`
}

// WebhookEndpoint is the resource representing a Stripe webhook endpoint.
// For more details see https://stripe.com/docs/api#webhook_endpoints.
type WebhookEndpoint struct {
	APIResource
	APIVersion    string   `json:"api_version"`
	Application   string   `json:"application"`
	Connect       bool     `json:"connect"`
	Created       int64    `json:"created"`
	Deleted       bool     `json:"deleted"`
	Description   string   `json:"description"`
	EnabledEvents []string `json:"enabled_events"`
	ID            string   `json:"id"`
	Livemode      bool     `json:"livemode"`
	Object        string   `json:"object"`
	Secret        string   `json:"secret"`
	Status        string   `json:"status"`
	URL           string   `json:"url"`
}

// WebhookEndpointList is a list of webhook endpoints as retrieved from a list endpoint.
type WebhookEndpointList struct {
	APIResource
	ListMeta
	Data []*WebhookEndpoint `json:"data"`
}

// UnmarshalJSON handles deserialization of a WebhookEndpoint.
// This custom unmarshaling is needed because the resulting
// property may be an id or the full struct if it was expanded.
func (c *WebhookEndpoint) UnmarshalJSON(data []byte) error {
	if id, ok := ParseID(data); ok {
		c.ID = id
		return nil
	}

	type endpoint WebhookEndpoint
	var v endpoint
	if err := json.Unmarshal(data, &v); err != nil {
		return err
	}

	*c = WebhookEndpoint(v)
	return nil
}
<commit_msg>Add `Metadata` on `WebhookEndpoint`<commit_after>package stripe

import "encoding/json"

// WebhookEndpointParams is the set of parameters that can be used when creating a webhook endpoint.
// For more details see https://stripe.com/docs/api#create_webhook_endpoint.
type WebhookEndpointParams struct {
	Params        `form:"*"`
	Connect       *bool     `form:"connect"`
	Description   *string   `form:"description"`
	Disabled      *bool     `form:"disabled"`
	EnabledEvents []*string `form:"enabled_events"`
	URL           *string   `form:"url"`

	// This parameter is only available on creation.
	// We recommend setting the API version that the library is pinned to. See apiversion in stripe.go
	APIVersion *string `form:"api_version"`
}

// WebhookEndpointListParams is the set of parameters that can be used when listing webhook endpoints.
// For more detail see https://stripe.com/docs/api#list_webhook_endpoints.
type WebhookEndpointListParams struct {
	ListParams   `form:"*"`
	Created      *int64            `form:"created"`
	CreatedRange *RangeQueryParams `form:"created"`
}

// WebhookEndpoint is the resource representing a Stripe webhook endpoint.
// For more details see https://stripe.com/docs/api#webhook_endpoints.
type WebhookEndpoint struct {
	APIResource
	APIVersion    string            `json:"api_version"`
	Application   string            `json:"application"`
	Connect       bool              `json:"connect"`
	Created       int64             `json:"created"`
	Deleted       bool              `json:"deleted"`
	Description   string            `json:"description"`
	EnabledEvents []string          `json:"enabled_events"`
	ID            string            `json:"id"`
	Livemode      bool              `json:"livemode"`
	Metadata      map[string]string `json:"metadata"`
	Object        string            `json:"object"`
	Secret        string            `json:"secret"`
	Status        string            `json:"status"`
	URL           string            `json:"url"`
}

// WebhookEndpointList is a list of webhook endpoints as retrieved from a list endpoint.
type WebhookEndpointList struct {
	APIResource
	ListMeta
	Data []*WebhookEndpoint `json:"data"`
}

// UnmarshalJSON handles deserialization of a WebhookEndpoint.
// This custom unmarshaling is needed because the resulting
// property may be an id or the full struct if it was expanded.
func (c *WebhookEndpoint) UnmarshalJSON(data []byte) error {
	if id, ok := ParseID(data); ok {
		c.ID = id
		return nil
	}

	type endpoint WebhookEndpoint
	var v endpoint
	if err := json.Unmarshal(data, &v); err != nil {
		return err
	}

	*c = WebhookEndpoint(v)
	return nil
}
<|endoftext|>