<commit_before>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func TestMerge(t *testing.T) {
	a := Config{
		KeyFile:              "aid",
		DataFile:             "adata",
		FilteringCommand:     "afil",
		UnprotectiveCommands: []string{"new", "migrate"},
	}
	b := Config{
		KeyFile:              "bid",
		DataFile:             "bdata",
		FilteringCommand:     "bfil",
		UnprotectiveCommands: []string{"remove"},
	}
	x := a.Merge(b)
	if x.KeyFile != "bid" {
		t.Errorf("KeyFile should be 'bid', but got %s", x.KeyFile)
	}
	if x.DataFile != "bdata" {
		t.Errorf("DataFile should be 'bdata', but got %s", x.DataFile)
	}
	if x.FilteringCommand != "bfil" {
		t.Errorf("FilteringCommand should be 'bfil', but got %s", x.FilteringCommand)
	}
	if len(x.UnprotectiveCommands) == 1 && x.UnprotectiveCommands[0] != "remove" {
		t.Errorf("UnprotectiveCommands should be overriden, but got %s", x.UnprotectiveCommands)
	}
}

func TestMergeNotOverwriteWithEmpty(t *testing.T) {
	a := Config{
		KeyFile:          "aid",
		DataFile:         "adata",
		FilteringCommand: "afil",
	}
	b := Config{
		KeyFile: "bid",
	}
	c := Config{
		DataFile: "cdata",
	}
	d := Config{
		FilteringCommand: "dfil",
	}
	z := Config{}

	x := a.Merge(b)
	if x.KeyFile != "bid" {
		t.Errorf("KeyFile should be 'bid', but got %s", x.KeyFile)
	}
	if x.DataFile != "adata" {
		t.Errorf("DataFile should not be empty, but got %s", x.DataFile)
	}
	if x.FilteringCommand != "afil" {
		t.Errorf("FilteringCommand should not be empty, but got %s", x.FilteringCommand)
	}
	x = a.Merge(c)
	if x.KeyFile != "aid" {
		t.Errorf("KeyFile should not be empty, but got %s", x.KeyFile)
	}
	if x.DataFile != "cdata" {
		t.Errorf("DataFile should be 'cdata', but got %s", x.DataFile)
	}
	if x.FilteringCommand != "afil" {
		t.Errorf("FilteringCommand should not be empty, but got %s", x.FilteringCommand)
	}
	x = a.Merge(d)
	if x.KeyFile != "aid" {
		t.Errorf("KeyFile should not be empty, but got %s", x.KeyFile)
	}
	if x.DataFile != "adata" {
		t.Errorf("DataFile should not be empty, but got %s", x.DataFile)
	}
	if x.FilteringCommand != "dfil" {
		t.Errorf("FilteringCommand should be 'dfil', but got %s", x.FilteringCommand)
	}
	x = a.Merge(z)
	if x.KeyFile != "aid" {
		t.Errorf("KeyFile should not be empty, but got %s", x.KeyFile)
	}
	if x.DataFile != "adata" {
		t.Errorf("DataFile should not be empty, but got %s", x.DataFile)
	}
	if x.FilteringCommand != "afil" {
		t.Errorf("FilteringCommand should not be empty, but got %s", x.FilteringCommand)
	}
}

func TestMergeNotOverwriteSelf(t *testing.T) {
	a := Config{
		KeyFile:          "aid",
		DataFile:         "adata",
		FilteringCommand: "afil",
	}
	b := Config{
		KeyFile:          "bid",
		DataFile:         "bdata",
		FilteringCommand: "bfil",
	}
	a.Merge(b)
	if a.KeyFile != "aid" {
		t.Errorf("self value should not be overwritten with other, but got %s", a.KeyFile)
	}
	if a.DataFile != "adata" {
		t.Errorf("self value should not be overwritten with other, but got %s", a.DataFile)
	}
	if a.FilteringCommand != "afil" {
		t.Errorf("self value should not be overwritten with other, but got %s", a.FilteringCommand)
	}
}

func TestMergeNotOverwriteOther(t *testing.T) {
	a := Config{
		KeyFile:          "aid",
		DataFile:         "adata",
		FilteringCommand: "afil",
	}
	b := Config{
		KeyFile:          "bid",
		DataFile:         "bdata",
		FilteringCommand: "bfil",
	}
	a.Merge(b)
	if b.KeyFile != "bid" {
		t.Errorf("other value should not be overwritten with other, but got %s", b.KeyFile)
	}
	if b.DataFile != "bdata" {
		t.Errorf("other value should not be overwritten with other, but got %s", b.DataFile)
	}
	if b.FilteringCommand != "bfil" {
		t.Errorf("other value should not be overwritten with other, but got %s", b.FilteringCommand)
	}
}

func TestDefaultConfig(t *testing.T) {
	td, err := ioutil.TempDir("", "")
	if err != nil {
		t.Error(err)
	}

	os.Setenv("HOME", td)
	os.Setenv("XDG_DATA_HOME", td)
	cfg, err := DefaultConfig()
	if err != nil {
		t.Error(err)
	}
	if cfg.KeyFile != filepath.Join(td, ".ssh", "id_rsa") {
		t.Errorf("default key file path is invalid, got %s", cfg.KeyFile)
	}
	if cfg.DataFile != filepath.Join(td, "spwd", "data.dat") {
		t.Errorf("default data file path is invalid, got %s", cfg.KeyFile)
	}
	if cfg.FilteringCommand != "peco" {
		t.Errorf("default filtering command is invalid, got %s", cfg.FilteringCommand)
	}
}

func TestFileConfigOnFileExist(t *testing.T) {
	td, err := ioutil.TempDir("", "")
	if err != nil {
		t.Error(err)
	}
	os.Setenv("XDG_CONFIG_HOME", td)
	fp := filepath.Join(td, "spwd", "config.yml")
	err = os.Mkdir(filepath.Dir(fp), 0755)
	if err != nil {
		t.Error(err)
	}
	f, err := os.Create(fp)
	if err != nil {
		t.Error(err)
	}
	f.WriteString(`key_file: /tmp/config.yml
data_file: /tmp/data.dat
filtering_command: fzf
`)
	cfg, ok := FileConfig()
	if !ok {
		t.Error("FileConfig should return true when config file exists")
	}
	if cfg.KeyFile != "/tmp/config.yml" {
		t.Error("FileConfig load invalid file.")
	}
	if cfg.DataFile != "/tmp/data.dat" {
		t.Error("FileConfig load invalid file.")
	}
	if cfg.FilteringCommand != "fzf" {
		t.Error("FileConfig load invalid file.")
	}
}

func TestFileConfigOnFileNotExist(t *testing.T) {
	td, err := ioutil.TempDir("", "")
	if err != nil {
		t.Error(err)
	}
	os.Setenv("XDG_CONFIG_HOME", td)
	_, ok := FileConfig()
	if ok {
		t.Error("FileConfig should return false when config file exists")
	}
}

func TestIsProtective(t *testing.T) {
	cfg := Config{
		KeyFile:              "aid",
		DataFile:             "adata",
		FilteringCommand:     "afil",
		UnprotectiveCommands: []string{"copy", "search", "new", "migrate"},
	}
	if cfg.IsProtective("new") {
		t.Errorf("new should not be protected")
	}
	if !cfg.IsProtective("remove") {
		t.Errorf("remove should be protected")
	}
	if !cfg.IsProtective("copy") {
		t.Errorf("copy should be always protected")
	}
	if !cfg.IsProtective("search") {
		t.Errorf("search should be always protected")
	}
}
<commit_msg>Fix misspel<commit_after>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func TestMerge(t *testing.T) {
	a := Config{
		KeyFile:              "aid",
		DataFile:             "adata",
		FilteringCommand:     "afil",
		UnprotectiveCommands: []string{"new", "migrate"},
	}
	b := Config{
		KeyFile:              "bid",
		DataFile:             "bdata",
		FilteringCommand:     "bfil",
		UnprotectiveCommands: []string{"remove"},
	}
	x := a.Merge(b)
	if x.KeyFile != "bid" {
		t.Errorf("KeyFile should be 'bid', but got %s", x.KeyFile)
	}
	if x.DataFile != "bdata" {
		t.Errorf("DataFile should be 'bdata', but got %s", x.DataFile)
	}
	if x.FilteringCommand != "bfil" {
		t.Errorf("FilteringCommand should be 'bfil', but got %s", x.FilteringCommand)
	}
	if len(x.UnprotectiveCommands) == 1 && x.UnprotectiveCommands[0] != "remove" {
		t.Errorf("UnprotectiveCommands should be overridden, but got %s", x.UnprotectiveCommands)
	}
}

func TestMergeNotOverwriteWithEmpty(t *testing.T) {
	a := Config{
		KeyFile:          "aid",
		DataFile:         "adata",
		FilteringCommand: "afil",
	}
	b := Config{
		KeyFile: "bid",
	}
	c := Config{
		DataFile: "cdata",
	}
	d := Config{
		FilteringCommand: "dfil",
	}
	z := Config{}

	x := a.Merge(b)
	if x.KeyFile != "bid" {
		t.Errorf("KeyFile should be 'bid', but got %s", x.KeyFile)
	}
	if x.DataFile != "adata" {
		t.Errorf("DataFile should not be empty, but got %s", x.DataFile)
	}
	if x.FilteringCommand != "afil" {
		t.Errorf("FilteringCommand should not be empty, but got %s", x.FilteringCommand)
	}
	x = a.Merge(c)
	if x.KeyFile != "aid" {
		t.Errorf("KeyFile should not be empty, but got %s", x.KeyFile)
	}
	if x.DataFile != "cdata" {
		t.Errorf("DataFile should be 'cdata', but got %s", x.DataFile)
	}
	if x.FilteringCommand != "afil" {
		t.Errorf("FilteringCommand should not be empty, but got %s", x.FilteringCommand)
	}
	x = a.Merge(d)
	if x.KeyFile != "aid" {
		t.Errorf("KeyFile should not be empty, but got %s", x.KeyFile)
	}
	if x.DataFile != "adata" {
		t.Errorf("DataFile should not be empty, but got %s", x.DataFile)
	}
	if x.FilteringCommand != "dfil" {
		t.Errorf("FilteringCommand should be 'dfil', but got %s", x.FilteringCommand)
	}
	x = a.Merge(z)
	if x.KeyFile != "aid" {
		t.Errorf("KeyFile should not be empty, but got %s", x.KeyFile)
	}
	if x.DataFile != "adata" {
		t.Errorf("DataFile should not be empty, but got %s", x.DataFile)
	}
	if x.FilteringCommand != "afil" {
		t.Errorf("FilteringCommand should not be empty, but got %s", x.FilteringCommand)
	}
}

func TestMergeNotOverwriteSelf(t *testing.T) {
	a := Config{
		KeyFile:          "aid",
		DataFile:         "adata",
		FilteringCommand: "afil",
	}
	b := Config{
		KeyFile:          "bid",
		DataFile:         "bdata",
		FilteringCommand: "bfil",
	}
	a.Merge(b)
	if a.KeyFile != "aid" {
		t.Errorf("self value should not be overwritten with other, but got %s", a.KeyFile)
	}
	if a.DataFile != "adata" {
		t.Errorf("self value should not be overwritten with other, but got %s", a.DataFile)
	}
	if a.FilteringCommand != "afil" {
		t.Errorf("self value should not be overwritten with other, but got %s", a.FilteringCommand)
	}
}

func TestMergeNotOverwriteOther(t *testing.T) {
	a := Config{
		KeyFile:          "aid",
		DataFile:         "adata",
		FilteringCommand: "afil",
	}
	b := Config{
		KeyFile:          "bid",
		DataFile:         "bdata",
		FilteringCommand: "bfil",
	}
	a.Merge(b)
	if b.KeyFile != "bid" {
		t.Errorf("other value should not be overwritten with other, but got %s", b.KeyFile)
	}
	if b.DataFile != "bdata" {
		t.Errorf("other value should not be overwritten with other, but got %s", b.DataFile)
	}
	if b.FilteringCommand != "bfil" {
		t.Errorf("other value should not be overwritten with other, but got %s", b.FilteringCommand)
	}
}

func TestDefaultConfig(t *testing.T) {
	td, err := ioutil.TempDir("", "")
	if err != nil {
		t.Error(err)
	}

	os.Setenv("HOME", td)
	os.Setenv("XDG_DATA_HOME", td)
	cfg, err := DefaultConfig()
	if err != nil {
		t.Error(err)
	}
	if cfg.KeyFile != filepath.Join(td, ".ssh", "id_rsa") {
		t.Errorf("default key file path is invalid, got %s", cfg.KeyFile)
	}
	if cfg.DataFile != filepath.Join(td, "spwd", "data.dat") {
		t.Errorf("default data file path is invalid, got %s", cfg.KeyFile)
	}
	if cfg.FilteringCommand != "peco" {
		t.Errorf("default filtering command is invalid, got %s", cfg.FilteringCommand)
	}
}

func TestFileConfigOnFileExist(t *testing.T) {
	td, err := ioutil.TempDir("", "")
	if err != nil {
		t.Error(err)
	}
	os.Setenv("XDG_CONFIG_HOME", td)
	fp := filepath.Join(td, "spwd", "config.yml")
	err = os.Mkdir(filepath.Dir(fp), 0755)
	if err != nil {
		t.Error(err)
	}
	f, err := os.Create(fp)
	if err != nil {
		t.Error(err)
	}
	f.WriteString(`key_file: /tmp/config.yml
data_file: /tmp/data.dat
filtering_command: fzf
`)
	cfg, ok := FileConfig()
	if !ok {
		t.Error("FileConfig should return true when config file exists")
	}
	if cfg.KeyFile != "/tmp/config.yml" {
		t.Error("FileConfig load invalid file.")
	}
	if cfg.DataFile != "/tmp/data.dat" {
		t.Error("FileConfig load invalid file.")
	}
	if cfg.FilteringCommand != "fzf" {
		t.Error("FileConfig load invalid file.")
	}
}

func TestFileConfigOnFileNotExist(t *testing.T) {
	td, err := ioutil.TempDir("", "")
	if err != nil {
		t.Error(err)
	}
	os.Setenv("XDG_CONFIG_HOME", td)
	_, ok := FileConfig()
	if ok {
		t.Error("FileConfig should return false when config file exists")
	}
}

func TestIsProtective(t *testing.T) {
	cfg := Config{
		KeyFile:              "aid",
		DataFile:             "adata",
		FilteringCommand:     "afil",
		UnprotectiveCommands: []string{"copy", "search", "new", "migrate"},
	}
	if cfg.IsProtective("new") {
		t.Errorf("new should not be protected")
	}
	if !cfg.IsProtective("remove") {
		t.Errorf("remove should be protected")
	}
	if !cfg.IsProtective("copy") {
		t.Errorf("copy should be always protected")
	}
	if !cfg.IsProtective("search") {
		t.Errorf("search should be always protected")
	}
}
<|endoftext|>


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

// Build constraints copied from go's src/os/dir_unix.go
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris

package main

import (
	"os/user"
	"path/filepath"
)

var defaultConfigPaths = []string{
	// This will be prepended by $HOME/.config/gobuster.conf
	"/etc/gobuster.conf",
}

func init() {
	if usr, err := user.Current(); err != nil {
		path := filepath.Join(usr.HomeDir, ".config", "gobuster.conf")
		defaultConfigPaths = append([]string{path}, defaultConfigPaths...)
	}
}
<commit_msg>Remove accidental duplicate config_unix.go.<commit_after><|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/gorilla/mux"

	"labix.org/v2/mgo/bson"
)

var r *mux.Router

func init() {
	r = mux.NewRouter()
	r.HandleFunc("/contacts", getContactsHandler).Methods("GET")
	r.HandleFunc("/contacts", postContactsHandler).Methods("POST")
	r.HandleFunc("/contacts/{id}", getContactHandler).Methods("GET")
}

// getContactsHandler returns a json response containing all
// the contacts.
//
// URL: GET /contacts
//
// For example, If there were only two contacts in total,
// GET /contacts and
// would yield the following response.
//
// Response:
// [
//  {
//    "id": "53a14760e3bdea4286000003",
//    "company": "Encom Inc.",
//    "person": "Sam Flynni !",
//    "email": "samflynn@encom.com",
//    "phone": "103-345-456",
//    "skypeid": "sam_flynn",
//    "country": "USA"
//  },
//  {
//    "id": "53a14760e3bdea4286000004",
//    "company": "Encom Inc.",
//    "person": "Kevin Flynn",
//    "email": "kevinflynn@encom.com",
//    "phone": "234-877-988",
//    "skypeid": "kevin_flynn",
//    "country": "USA"
//  }
// ]
func getContactsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	c, err := GetAllContacts()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// postContactsHandler creates a new contact in the database.
// URL: POST /contacts
// Request:
// {
//   "company": "Encom Inc.",
//   "person": "Sam Flynn",
//   "email": "samflynn@encom.com",
//   "phone": "103-345-456",
//   "skypeid": "sam_flynn",
//   "country": "USA"
// }
// Response: HTTP 200
func postContactsHandler(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var c contact
	err := decoder.Decode(&c)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	_, err = NewContact(c.Company, c.Person, c.Email, c.Phone, c.SkypeId, c.Country)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// getContactHandler returns json data pertaining to a specific contact.
//
// URL: GET /contacts/{id}
//
// For example,
// GET /contacts/53a15a07e3bdea53d0000002
// Response:
// {
//   "id": "53a15a07e3bdea53d0000002",
//   "company": "Encom Inc.",
//   "person": "Flynn",
//   "email": "flynn@encom.com",
//   "country": "USA"
// }
func getContactHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	i := vars["id"]
	id := bson.ObjectIdHex(i)
	c, err := GetContact(id)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<commit_msg>Correct doc<commit_after>package main

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/gorilla/mux"

	"labix.org/v2/mgo/bson"
)

var r *mux.Router

func init() {
	r = mux.NewRouter()
	r.HandleFunc("/contacts", getContactsHandler).Methods("GET")
	r.HandleFunc("/contacts", postContactsHandler).Methods("POST")
	r.HandleFunc("/contacts/{id}", getContactHandler).Methods("GET")
}

// getContactsHandler returns a json response containing all
// the contacts.
//
// URL: GET /contacts
//
// For example, If there were only two contacts in total,
// GET /contacts and
// would yield the following response.
//
// Response:
// [
//  {
//    "id": "53a14760e3bdea4286000003",
//    "company": "Encom Inc.",
//    "person": "Sam Flynn",
//    "email": "samflynn@encom.com",
//    "phone": "103-345-456",
//    "skypeid": "sam_flynn",
//    "country": "USA"
//  },
//  {
//    "id": "53a14760e3bdea4286000004",
//    "company": "Encom Inc.",
//    "person": "Kevin Flynn",
//    "email": "kevinflynn@encom.com",
//    "phone": "234-877-988",
//    "skypeid": "kevin_flynn",
//    "country": "USA"
//  }
// ]
func getContactsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	c, err := GetAllContacts()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// postContactsHandler creates a new contact in the database.
// URL: POST /contacts
// Request:
// {
//   "company": "Encom Inc.",
//   "person": "Sam Flynn",
//   "email": "samflynn@encom.com",
//   "phone": "103-345-456",
//   "skypeid": "sam_flynn",
//   "country": "USA"
// }
// Response: HTTP 200
func postContactsHandler(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var c contact
	err := decoder.Decode(&c)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	_, err = NewContact(c.Company, c.Person, c.Email, c.Phone, c.SkypeId, c.Country)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// getContactHandler returns json data pertaining to a specific contact.
//
// URL: GET /contacts/{id}
//
// For example,
// GET /contacts/53a15a07e3bdea53d0000002
// Response:
// {
//   "id": "53a15a07e3bdea53d0000002",
//   "company": "Encom Inc.",
//   "person": "Flynn",
//   "email": "flynn@encom.com",
//   "country": "USA"
// }
func getContactHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	i := vars["id"]
	id := bson.ObjectIdHex(i)
	c, err := GetContact(id)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package core

import (
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/dghubble/sling"
	"github.com/kristjank/ark-go/arkcoin"
)

//ArkNetworkType for network switching
type ArkNetworkType int

const (
	//MAINNET connection
	MAINNET = iota
	//DEVNET connection
	DEVNET
)

//TO HELP DIVIDE
//TODO rename
const (
	SATOSHI = 100000000
)

//EnvironmentParams - Global ARK EnvironmentParams read from acitve peers
var EnvironmentParams = new(ArkEnvParams)

//ArkEnvParams structure to hold parameters from autoconfigure
//structure is filled from peers at arkclient init call
type ArkEnvParams struct {
	Success bool    `json:"success"`
	Network Network `json:"network"`
	Fees    Fees    `json:"fees"`
}

//Fees constant parameters for active configuration
type Fees struct {
	Send            int64 `json:"send"`
	Vote            int64 `json:"vote"`
	SecondSignature int64 `json:"secondsignature"`
	Delegate        int64 `json:"delegate"`
	MultiSignature  int64 `json:"multisignature"`
}

//Network parameters
type Network struct {
	Nethash        string         `json:"nethash"`
	Token          string         `json:"token"`
	Symbol         string         `json:"symbol"`
	Explorer       string         `json:"explorer"`
	AddressVersion byte           `json:"version"` //this is address generator version!!!
	Type           ArkNetworkType //holding ark networktype
	ActivePeer     Peer
	PeerList       []Peer
}

//LoadActiveConfiguration reads arknetwork parameters from the Network
//and fills the EnvironmentParams structure
//selected and connected peer address is returned
func LoadActiveConfiguration(arknetwork ArkNetworkType) string {
	s1 := rand.NewSource(time.Now().UnixNano())
	r1 := rand.New(s1)

	selectedPeer := ""
	EnvironmentParams.Network.Type = arknetwork
	//looping peers comunication until we get autoconfigure response
	for selectedPeer == "" {
		switch arknetwork {
		case MAINNET:
			log.Println("Active network is MAINNET")
			selectedPeer = seedList[r1.Intn(len(seedList))]
			log.Println("Random peer selected: ", selectedPeer)

		case DEVNET:
			log.Println("Active network is DEVNET")
			selectedPeer = testSeedList[r1.Intn(len(testSeedList))]
			log.Println("Random peer selected: ", selectedPeer)
		}

		//reading basic network params
		res, err := http.Get("http://" + selectedPeer + "/api/loader/autoconfigure")
		if err != nil {
			log.Fatal("Error receiving autoloader params rest from: ", selectedPeer, err.Error())
			selectedPeer = ""
		}
		json.NewDecoder(res.Body).Decode(&EnvironmentParams)
	}

	//reading fees
	res, err := http.Get("http://" + selectedPeer + "/api/blocks/getfees")
	if err != nil {
		log.Fatal("Error receiving fees params rest from: ", selectedPeer)
	}
	json.NewDecoder(res.Body).Decode(&EnvironmentParams)

	//getting connected peer params from peer
	peerParams := strings.Split(selectedPeer, ":")
	peerRes := new(PeerResponse)
	res, err = http.Get("http://" + selectedPeer + "/api/peers/get/?ip=" + peerParams[0] + "&port=" + peerParams[1])
	if err != nil {
		log.Fatal("Error receiving peer status from: ", selectedPeer, err.Error(), res.StatusCode)
	}
	json.NewDecoder(res.Body).Decode(peerRes)
	//saving peer parameters to globals
	EnvironmentParams.Network.ActivePeer = peerRes.SinglePeer

	return "http://" + optimizePeerList(selectedPeer)
}

func optimizePeerList(selectedPeer string) string {
	tmpClient := &ArkClient{
		sling: sling.New().Client(nil).Base("http://"+selectedPeer).
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}

	peerResp, err, _ := tmpClient.GetAllPeers()
	if err.ErrorObj != nil {
		log.Println("Error getting peer list")
		return selectedPeer
	}

	EnvironmentParams.Network.PeerList = peerResp.Peers

	//Clean the peer list (filters not working as they shoud) - so checking again here
	maxHeight := EnvironmentParams.Network.ActivePeer.Height
	for i := len(EnvironmentParams.Network.PeerList) - 1; i >= 0; i-- {
		peer := EnvironmentParams.Network.PeerList[i]

		// Condition to decide if current element has to be deleted:
		if peer.Status != "OK" && peer.Port != EnvironmentParams.Network.ActivePeer.Port {
			EnvironmentParams.Network.PeerList = append(EnvironmentParams.Network.PeerList[:i], EnvironmentParams.Network.PeerList[i+1:]...)
			log.Println("Removing peer", peer.IP, peer.Status, peer.Height)
			continue
		}
		//if all is ok and height is higher - we preffer peers with higher hight
		if peer.Height > maxHeight {
			log.Println("Setting new active peer, found OK peer with bigger block height", peer.Height, maxHeight)
			EnvironmentParams.Network.ActivePeer = peer
			selectedPeer = fmt.Sprintf("%s:%d", peer.IP, peer.Port)
			maxHeight = peer.Height
		}
	}
	return selectedPeer
}

func switchNetwork(arkNetwork ArkNetworkType) {
	BaseURL = LoadActiveConfiguration(arkNetwork)
	var wifHeader = []byte{170}

	if arkNetwork == DEVNET {
		wifHeader = []byte{239}
	}

	coinParams := arkcoin.Params{
		AddressHeader:          EnvironmentParams.Network.AddressVersion,
		DumpedPrivateKeyHeader: wifHeader,
	}
	arkcoin.SetActiveCoinConfiguration(&coinParams)
}

//SetActiveConfiguration sets a new client connection, switches network and reads network settings from peer
//usage - must reassing new pointer value: arkapi = arkapi.SetActiveConfiguration(MAINNET)
func (s *ArkClient) SetActiveConfiguration(arkNetwork ArkNetworkType) *ArkClient {
	switchNetwork(arkNetwork)
	return NewArkClient(nil)
}

var seedList = [...]string{
	"5.39.9.240:4001",
	"5.39.9.241:4001",
	"5.39.9.242:4001",
	"5.39.9.243:4001",
	"5.39.9.244:4001",
	"5.39.9.250:4001",
	"5.39.9.251:4001",
	"5.39.9.252:4001",
	"5.39.9.253:4001",
	"5.39.9.254:4001",
	"5.39.9.255:4001",
	"5.39.53.48:4001",
	"5.39.53.49:4001",
	"5.39.53.50:4001",
	"5.39.53.51:4001",
	"5.39.53.52:4001",
	"5.39.53.53:4001",
	"5.39.53.54:4001",
	"5.39.53.55:4001",
	"37.59.129.160:4001",
	"37.59.129.161:4001",
	"37.59.129.162:4001",
	"37.59.129.163:4001",
	"37.59.129.164:4001",
	"37.59.129.165:4001",
	"37.59.129.166:4001",
	"37.59.129.167:4001",
	"37.59.129.168:4001",
	"37.59.129.169:4001",
	"37.59.129.170:4001",
	"37.59.129.171:4001",
	"37.59.129.172:4001",
	"37.59.129.173:4001",
	"37.59.129.174:4001",
	"37.59.129.175:4001",
	"193.70.72.80:4001",
	"193.70.72.81:4001",
	"193.70.72.82:4001",
	"193.70.72.83:4001",
	"193.70.72.84:4001",
	"193.70.72.85:4001",
	"193.70.72.86:4001",
	"193.70.72.87:4001",
	"193.70.72.88:4001",
	"193.70.72.89:4001",
	"193.70.72.90:4001"}

var testSeedList = [...]string{
	"164.8.251.179:4002",
	"164.8.251.172:4002",
	"164.8.251.91:4002",
	"167.114.43.48:4002",
	"167.114.29.49:4002",
	"167.114.43.43:4002",
	"167.114.29.54:4002",
	"167.114.29.45:4002",
	"167.114.29.40:4002",
	"167.114.29.56:4002",
	"167.114.43.35:4002",
	"167.114.29.51:4002",
	"167.114.29.59:4002",
	"167.114.43.42:4002",
	"167.114.29.34:4002",
	"167.114.29.62:4002",
	"167.114.43.49:4002",
	"167.114.29.44:4002",
	"167.114.43.37:4002",
	"167.114.29.63:4002",
	"167.114.29.42:4002",
	"167.114.29.48:4002",
	"167.114.29.61:4002",
	"167.114.43.36:4002",
	"167.114.29.57:4002",
	"167.114.43.33:4002",
	"167.114.29.52:4002",
	"167.114.29.50:4002",
	"167.114.43.47:4002",
	"167.114.29.47:4002",
	"167.114.29.36:4002",
	"167.114.29.35:4002",
	"167.114.43.39:4002",
	"167.114.43.45:4002",
	"167.114.29.46:4002",
	"167.114.29.41:4002",
	"167.114.43.34:4002",
	"167.114.29.43:4002",
	"167.114.43.41:4002",
	"167.114.29.60:4002",
	"167.114.43.32:4002",
	"167.114.29.55:4002",
	"167.114.29.53:4002",
	"167.114.29.38:4002",
	"167.114.43.40:4002",
	"167.114.29.32:4002",
	"167.114.43.46:4002",
	"167.114.43.38:4002",
	"167.114.29.33:4002",
	"167.114.43.44:4002",
	"167.114.43.50:4002",
	"167.114.29.37:4002",
	"167.114.29.58:4002",
	"167.114.29.39:4002"}
<commit_msg>added retrying when starting http client... after that optimization is called<commit_after>package core

import (
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/dghubble/sling"
	"github.com/kristjank/ark-go/arkcoin"
)

//ArkNetworkType for network switching
type ArkNetworkType int

const (
	//MAINNET connection
	MAINNET = iota
	//DEVNET connection
	DEVNET
)

//TO HELP DIVIDE
//TODO rename
const (
	SATOSHI = 100000000
)

//EnvironmentParams - Global ARK EnvironmentParams read from acitve peers
var EnvironmentParams = new(ArkEnvParams)

//ArkEnvParams structure to hold parameters from autoconfigure
//structure is filled from peers at arkclient init call
type ArkEnvParams struct {
	Success bool    `json:"success"`
	Network Network `json:"network"`
	Fees    Fees    `json:"fees"`
}

//Fees constant parameters for active configuration
type Fees struct {
	Send            int64 `json:"send"`
	Vote            int64 `json:"vote"`
	SecondSignature int64 `json:"secondsignature"`
	Delegate        int64 `json:"delegate"`
	MultiSignature  int64 `json:"multisignature"`
}

//Network parameters
type Network struct {
	Nethash        string         `json:"nethash"`
	Token          string         `json:"token"`
	Symbol         string         `json:"symbol"`
	Explorer       string         `json:"explorer"`
	AddressVersion byte           `json:"version"` //this is address generator version!!!
	Type           ArkNetworkType //holding ark networktype
	ActivePeer     Peer
	PeerList       []Peer
}

//LoadActiveConfiguration reads arknetwork parameters from the Network
//and fills the EnvironmentParams structure
//selected and connected peer address is returned
func LoadActiveConfiguration(arknetwork ArkNetworkType) string {
	s1 := rand.NewSource(time.Now().UnixNano())
	r1 := rand.New(s1)

	selectedPeer := ""
	EnvironmentParams.Network.Type = arknetwork
	//looping peers comunication until we get autoconfigure response
	i := 0
	for selectedPeer == "" && i < 10 {

		i++
		switch arknetwork {
		case MAINNET:
			log.Println("Active network is MAINNET")
			selectedPeer = seedList[r1.Intn(len(seedList))]
			log.Println("Random peer selected: ", selectedPeer)

		case DEVNET:
			log.Println("Active network is DEVNET")
			selectedPeer = testSeedList[r1.Intn(len(testSeedList))]
			log.Println("Random peer selected: ", selectedPeer)
		}
		log.Println("Connecting to random peer", selectedPeer, r1.Intn(len(seedList)))
		//reading basic network params
		res, err := http.Get("http://" + selectedPeer + "/api/loader/autoconfigure")
		if err != nil {
			log.Fatal("Error receiving autoloader params rest from: ", selectedPeer, " Error: ", err.Error())
			selectedPeer = ""
		}
		json.NewDecoder(res.Body).Decode(&EnvironmentParams)
	}

	if selectedPeer == "" {
		log.Fatal("Unable to coonnect to blockchain, exiting")
	}

	//reading fees
	res, err := http.Get("http://" + selectedPeer + "/api/blocks/getfees")
	if err != nil {
		log.Fatal("Error receiving fees params rest from: ", selectedPeer)
	}
	json.NewDecoder(res.Body).Decode(&EnvironmentParams)

	//getting connected peer params from peer
	peerParams := strings.Split(selectedPeer, ":")
	peerRes := new(PeerResponse)
	res, err = http.Get("http://" + selectedPeer + "/api/peers/get/?ip=" + peerParams[0] + "&port=" + peerParams[1])
	if err != nil {
		log.Fatal("Error receiving peer status from: ", selectedPeer, err.Error(), res.StatusCode)
	}
	json.NewDecoder(res.Body).Decode(peerRes)
	//saving peer parameters to globals
	EnvironmentParams.Network.ActivePeer = peerRes.SinglePeer

	return "http://" + optimizePeerList(selectedPeer)
}

func optimizePeerList(selectedPeer string) string {
	tmpClient := &ArkClient{
		sling: sling.New().Client(nil).Base("http://"+selectedPeer).
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}

	peerResp, err, _ := tmpClient.GetAllPeers()
	if err.ErrorObj != nil {
		log.Println("Error getting peer list")
		return selectedPeer
	}

	EnvironmentParams.Network.PeerList = peerResp.Peers

	//Clean the peer list (filters not working as they shoud) - so checking again here
	maxHeight := EnvironmentParams.Network.ActivePeer.Height
	for i := len(EnvironmentParams.Network.PeerList) - 1; i >= 0; i-- {
		peer := EnvironmentParams.Network.PeerList[i]

		// Condition to decide if current element has to be deleted:
		if peer.Status != "OK" && peer.Port != EnvironmentParams.Network.ActivePeer.Port {
			EnvironmentParams.Network.PeerList = append(EnvironmentParams.Network.PeerList[:i], EnvironmentParams.Network.PeerList[i+1:]...)
			log.Println("Removing peer", peer.IP, peer.Status, peer.Height)
			continue
		}
		//if all is ok and height is higher - we preffer peers with higher hight
		if peer.Height > maxHeight {
			log.Println("Setting new active peer, found OK peer with bigger block height", peer.Height, maxHeight)
			EnvironmentParams.Network.ActivePeer = peer
			selectedPeer = fmt.Sprintf("%s:%d", peer.IP, peer.Port)
			maxHeight = peer.Height
		}
	}
	return selectedPeer
}

func switchNetwork(arkNetwork ArkNetworkType) {
	BaseURL = LoadActiveConfiguration(arkNetwork)
	var wifHeader = []byte{170}

	if arkNetwork == DEVNET {
		wifHeader = []byte{239}
	}

	coinParams := arkcoin.Params{
		AddressHeader:          EnvironmentParams.Network.AddressVersion,
		DumpedPrivateKeyHeader: wifHeader,
	}
	arkcoin.SetActiveCoinConfiguration(&coinParams)
}

//SetActiveConfiguration sets a new client connection, switches network and reads network settings from peer
//usage - must reassing new pointer value: arkapi = arkapi.SetActiveConfiguration(MAINNET)
func (s *ArkClient) SetActiveConfiguration(arkNetwork ArkNetworkType) *ArkClient {
	switchNetwork(arkNetwork)
	return NewArkClient(nil)
}

var seedList = [...]string{
	"5.39.9.240:4001",
	"5.39.9.241:4001",
	"5.39.9.242:4001",
	"5.39.9.243:4001",
	"5.39.9.244:4001",
	"5.39.9.250:4001",
	"5.39.9.251:4001",
	"5.39.9.252:4001",
	"5.39.9.253:4001",
	"5.39.9.254:4001",
	"5.39.9.255:4001",
	"5.39.53.48:4001",
	"5.39.53.49:4001",
	"5.39.53.50:4001",
	"5.39.53.51:4001",
	"5.39.53.52:4001",
	"5.39.53.53:4001",
	"5.39.53.54:4001",
	"5.39.53.55:4001",
	"37.59.129.160:4001",
	"37.59.129.161:4001",
	"37.59.129.162:4001",
	"37.59.129.163:4001",
	"37.59.129.164:4001",
	"37.59.129.165:4001",
	"37.59.129.166:4001",
	"37.59.129.167:4001",
	"37.59.129.168:4001",
	"37.59.129.169:4001",
	"37.59.129.170:4001",
	"37.59.129.171:4001",
	"37.59.129.172:4001",
	"37.59.129.173:4001",
	"37.59.129.174:4001",
	"37.59.129.175:4001",
	"193.70.72.80:4001",
	"193.70.72.81:4001",
	"193.70.72.82:4001",
	"193.70.72.83:4001",
	"193.70.72.84:4001",
	"193.70.72.85:4001",
	"193.70.72.86:4001",
	"193.70.72.87:4001",
	"193.70.72.88:4001",
	"193.70.72.89:4001",
	"193.70.72.90:4001"}

var testSeedList = [...]string{
	"164.8.251.179:4002",
	"164.8.251.172:4002",
	"164.8.251.91:4002",
	"167.114.43.48:4002",
	"167.114.29.49:4002",
	"167.114.43.43:4002",
	"167.114.29.54:4002",
	"167.114.29.45:4002",
	"167.114.29.40:4002",
	"167.114.29.56:4002",
	"167.114.43.35:4002",
	"167.114.29.51:4002",
	"167.114.29.59:4002",
	"167.114.43.42:4002",
	"167.114.29.34:4002",
	"167.114.29.62:4002",
	"167.114.43.49:4002",
	"167.114.29.44:4002",
	"167.114.43.37:4002",
	"167.114.29.63:4002",
	"167.114.29.42:4002",
	"167.114.29.48:4002",
	"167.114.29.61:4002",
	"167.114.43.36:4002",
	"167.114.29.57:4002",
	"167.114.43.33:4002",
	"167.114.29.52:4002",
	"167.114.29.50:4002",
	"167.114.43.47:4002",
	"167.114.29.47:4002",
	"167.114.29.36:4002",
	"167.114.29.35:4002",
	"167.114.43.39:4002",
	"167.114.43.45:4002",
	"167.114.29.46:4002",
	"167.114.29.41:4002",
	"167.114.43.34:4002",
	"167.114.29.43:4002",
	"167.114.43.41:4002",
	"167.114.29.60:4002",
	"167.114.43.32:4002",
	"167.114.29.55:4002",
	"167.114.29.53:4002",
	"167.114.29.38:4002",
	"167.114.43.40:4002",
	"167.114.29.32:4002",
	"167.114.43.46:4002",
	"167.114.43.38:4002",
	"167.114.29.33:4002",
	"167.114.43.44:4002",
	"167.114.43.50:4002",
	"167.114.29.37:4002",
	"167.114.29.58:4002",
	"167.114.29.39:4002"}
<|endoftext|>


<commit_before>package curator

import (
	"sync"
	"testing"

	"github.com/samuel/go-zookeeper/zk"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

type CreateBuilderTestSuite struct {
	mockContainerTestSuite
}

func TestCreateBuilder(t *testing.T) {
	suite.Run(t, new(CreateBuilderTestSuite))
}

func (s *CreateBuilderTestSuite) TestCreate() {
	s.With(func(builder *CuratorFrameworkBuilder, client CuratorFramework, conn *mockConn) {
		acls := zk.WorldACL(zk.PermAll)

		conn.On("Create", "/node", builder.DefaultData, int32(EPHEMERAL), acls).Return("/node", nil).Once()

		path, err := client.Create().WithMode(EPHEMERAL).WithACL(acls...).ForPath("/node")

		assert.Equal(s.T(), "/node", path)
		assert.NoError(s.T(), err)
	})
}

func (s *CreateBuilderTestSuite) TestNamespace() {
	s.WithNamespace("parent", func(builder *CuratorFrameworkBuilder, client CuratorFramework, conn *mockConn) {
		acls := zk.WorldACL(zk.PermAll)

		conn.On("Exists", "/parent").Return(false, nil, nil).Once()
		conn.On("Create", "/parent", []byte{}, int32(PERSISTENT), acls).Return("/parent", nil).Once()
		conn.On("Create", "/parent/child", builder.DefaultData, int32(EPHEMERAL), acls).Return("/parent/child", nil).Once()

		path, err := client.Create().WithMode(EPHEMERAL).WithACL(acls...).ForPath("/child")

		assert.Equal(s.T(), "/child", path)
		assert.NoError(s.T(), err)
	})
}

func (s *CreateBuilderTestSuite) TestBackground() {
	s.WithNamespace("parent", func(client CuratorFramework, conn *mockConn, wg *sync.WaitGroup, data []byte, acls []zk.ACL) {
		ctxt := "context"

		conn.On("Exists", "/parent").Return(true, nil, nil).Once()
		conn.On("Create", "/parent/child", data, int32(PERSISTENT), acls).Return("", zk.ErrAPIError).Once()

		path, err := client.Create().WithACL(acls...).InBackgroundWithCallbackAndContext(
			func(client CuratorFramework, event CuratorEvent) error {
				defer wg.Done()

				assert.Equal(s.T(), CREATE, event.Type())
				assert.Equal(s.T(), "/child", event.Path())
				assert.Equal(s.T(), data, event.Data())
				assert.Equal(s.T(), acls, event.ACLs())
				assert.EqualError(s.T(), event.Err(), zk.ErrAPIError.Error())
				assert.Equal(s.T(), "child", event.Name())
				assert.Equal(s.T(), ctxt, event.Context())

				return nil
			}, ctxt).ForPathWithData("/child", data)

		assert.Equal(s.T(), "/child", path)
		assert.NoError(s.T(), err)
	})
}

func (s *CreateBuilderTestSuite) TestCompression() {
	s.With(func(client CuratorFramework, conn *mockConn, compress *mockCompressionProvider, data []byte, acls []zk.ACL) {
		compressedData := []byte("compressedData")

		compress.On("Compress", "/node", data).Return(compressedData, nil).Once()
		conn.On("Create", "/node", compressedData, int32(PERSISTENT), acls).Return("/node", nil).Once()

		path, err := client.Create().Compressed().WithACL(acls...).ForPathWithData("/node", data)

		assert.Equal(s.T(), "/node", path)
		assert.NoError(s.T(), err)
	})
}

func (s *CreateBuilderTestSuite) TestCreateParents() {
	s.With(func(builder *CuratorFrameworkBuilder, client CuratorFramework, conn *mockConn) {
		conn.On("Create", "/parent/child", builder.DefaultData, int32(PERSISTENT), []zk.ACL(nil)).Return("", zk.ErrNoNode).Once()
		conn.On("Exists", "/parent").Return(false, nil, nil).Once()
		conn.On("Create", "/parent", []byte{}, int32(PERSISTENT), zk.WorldACL(zk.PermAll)).Return("/parent", nil).Once()
		conn.On("Create", "/parent/child", builder.DefaultData, int32(PERSISTENT), []zk.ACL(nil)).Return("/parent/child", nil).Once()

		path, err := client.Create().CreatingParentsIfNeeded().ForPath("/parent/child")

		assert.Equal(s.T(), "/parent/child", path)
		assert.NoError(s.T(), err)
	})
}
<commit_msg>use mock generate acts<commit_after>package curator

import (
	"sync"
	"testing"

	"github.com/samuel/go-zookeeper/zk"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

type CreateBuilderTestSuite struct {
	mockContainerTestSuite
}

func TestCreateBuilder(t *testing.T) {
	suite.Run(t, new(CreateBuilderTestSuite))
}

func (s *CreateBuilderTestSuite) TestCreate() {
	s.With(func(builder *CuratorFrameworkBuilder, client CuratorFramework, conn *mockConn, acls []zk.ACL) {
		conn.On("Create", "/node", builder.DefaultData, int32(EPHEMERAL), acls).Return("/node", nil).Once()

		path, err := client.Create().WithMode(EPHEMERAL).WithACL(acls...).ForPath("/node")

		assert.Equal(s.T(), "/node", path)
		assert.NoError(s.T(), err)
	})
}

func (s *CreateBuilderTestSuite) TestNamespace() {
	s.WithNamespace("parent", func(builder *CuratorFrameworkBuilder, client CuratorFramework, conn *mockConn, acls []zk.ACL) {
		conn.On("Exists", "/parent").Return(false, nil, nil).Once()
		conn.On("Create", "/parent", []byte{}, int32(PERSISTENT), acls).Return("/parent", nil).Once()
		conn.On("Create", "/parent/child", builder.DefaultData, int32(EPHEMERAL), acls).Return("/parent/child", nil).Once()

		path, err := client.Create().WithMode(EPHEMERAL).WithACL(acls...).ForPath("/child")

		assert.Equal(s.T(), "/child", path)
		assert.NoError(s.T(), err)
	})
}

func (s *CreateBuilderTestSuite) TestBackground() {
	s.WithNamespace("parent", func(client CuratorFramework, conn *mockConn, wg *sync.WaitGroup, data []byte, acls []zk.ACL) {
		ctxt := "context"

		conn.On("Exists", "/parent").Return(true, nil, nil).Once()
		conn.On("Create", "/parent/child", data, int32(PERSISTENT), acls).Return("", zk.ErrAPIError).Once()

		path, err := client.Create().WithACL(acls...).InBackgroundWithCallbackAndContext(
			func(client CuratorFramework, event CuratorEvent) error {
				defer wg.Done()

				assert.Equal(s.T(), CREATE, event.Type())
				assert.Equal(s.T(), "/child", event.Path())
				assert.Equal(s.T(), data, event.Data())
				assert.Equal(s.T(), acls, event.ACLs())
				assert.EqualError(s.T(), event.Err(), zk.ErrAPIError.Error())
				assert.Equal(s.T(), "child", event.Name())
				assert.Equal(s.T(), ctxt, event.Context())

				return nil
			}, ctxt).ForPathWithData("/child", data)

		assert.Equal(s.T(), "/child", path)
		assert.NoError(s.T(), err)
	})
}

func (s *CreateBuilderTestSuite) TestCompression() {
	s.With(func(client CuratorFramework, conn *mockConn, compress *mockCompressionProvider, data []byte, acls []zk.ACL) {
		compressedData := []byte("compressedData")

		compress.On("Compress", "/node", data).Return(compressedData, nil).Once()
		conn.On("Create", "/node", compressedData, int32(PERSISTENT), acls).Return("/node", nil).Once()

		path, err := client.Create().Compressed().WithACL(acls...).ForPathWithData("/node", data)

		assert.Equal(s.T(), "/node", path)
		assert.NoError(s.T(), err)
	})
}

func (s *CreateBuilderTestSuite) TestCreateParents() {
	s.With(func(builder *CuratorFrameworkBuilder, client CuratorFramework, conn *mockConn) {
		conn.On("Create", "/parent/child", builder.DefaultData, int32(PERSISTENT), []zk.ACL(nil)).Return("", zk.ErrNoNode).Once()
		conn.On("Exists", "/parent").Return(false, nil, nil).Once()
		conn.On("Create", "/parent", []byte{}, int32(PERSISTENT), zk.WorldACL(zk.PermAll)).Return("/parent", nil).Once()
		conn.On("Create", "/parent/child", builder.DefaultData, int32(PERSISTENT), []zk.ACL(nil)).Return("/parent/child", nil).Once()

		path, err := client.Create().CreatingParentsIfNeeded().ForPath("/parent/child")

		assert.Equal(s.T(), "/parent/child", path)
		assert.NoError(s.T(), err)
	})
}
<|endoftext|>


<commit_before>package class

import (
    //"fmt"
    . "jvmgo/any"
    //"jvmgo/classfile"
    //"jvmgo/rtda"
)

const (
    _initializing = 1
    _initialized  = 2
)

type Class struct {
    obj                 *Obj // static fields live here
    jClass              *Obj // java.lang.Class instance
    constantPool        *ConstantPool
    name                string
    superClassName      string
    interfaceNames      []string
    fields              []*Field
    methods             []*Method
    classLoader         *ClassLoader
    staticFieldCount    uint
    instanceFieldCount  uint
    state               int
    // todo
}

// func (self *Class) Fields() ([]*Field){
//     return self.fields
// }

// todo
func (self *Class) Obj() (*Obj) {
    return self.obj
}
func (self *Class) JClass() (*Obj) {
    return self.jClass
}
func (self *Class) ConstantPool() (*ConstantPool) {
    return self.constantPool
}
func (self *Class) Name() (string) {
    return self.name
}
func (self *Class) ClassLoader() (*ClassLoader) {
    return self.classLoader
}

func (self *Class) InitializationNotStarted() (bool) {
    return self.state < _initializing // todo
}
func (self *Class) MarkInitializing() {
    self.state = _initializing
}
func (self *Class) MarkInitialized() {
    self.state = _initialized
}

func (self *Class) GetField(name, descriptor string) (*Field) {
    for _, field := range self.fields {
        if field.name == name && field.descriptor == descriptor {
            return field
        }
    }
    // todo
    return nil
}

func (self *Class) GetMainMethod() (*Method) {
    return self.getStaticMethod(mainMethodName, mainMethodDesc)
}
func (self *Class) GetClinitMethod() (*Method) {
    return self.getStaticMethod(clinitMethodName, clinitMethodDesc)
}
func (self *Class) getStaticMethod(name, descriptor string) (*Method) {
    method := self.GetMethod(name, descriptor)
    if method != nil && method.IsStatic() {
        return method
    } else {
        return nil
    }
}
func (self *Class) GetMethod(name, descriptor string) (*Method) {
    for _, method := range self.methods {
        if method.name == name && method.descriptor == descriptor {
            return method
        }
    }
    // todo
    return nil
}

func (self *Class) NewObj() (*Obj) {
    if self.instanceFieldCount > 0 {
        fields := make([]Any, self.instanceFieldCount)
        return &Obj{self, fields}
    } else {
        return &Obj{self, nil}
    }
}

// func newClass() (*Class) {
//     class := &Class{}
//     class.obj = &Obj{class:class}
//     return class
// }
<commit_msg>code refactor<commit_after>package class

import (
    //"fmt"
    . "jvmgo/any"
    //"jvmgo/classfile"
    //"jvmgo/rtda"
)

const (
    _initializing = 1
    _initialized  = 2
)

type Class struct {
    obj                 *Obj // static fields live here
    jClass              *Obj // java.lang.Class instance
    constantPool        *ConstantPool
    name                string
    superClassName      string
    interfaceNames      []string
    fields              []*Field
    methods             []*Method
    classLoader         *ClassLoader
    staticFieldCount    uint
    instanceFieldCount  uint
    state               int
    // todo
}

// func (self *Class) Fields() ([]*Field){
//     return self.fields
// }

// todo
func (self *Class) Obj() (*Obj) {
    return self.obj
}
func (self *Class) JClass() (*Obj) {
    return self.jClass
}
func (self *Class) ConstantPool() (*ConstantPool) {
    return self.constantPool
}
func (self *Class) Name() (string) {
    return self.name
}
func (self *Class) ClassLoader() (*ClassLoader) {
    return self.classLoader
}

func (self *Class) InitializationNotStarted() (bool) {
    return self.state < _initializing // todo
}
func (self *Class) MarkInitializing() {
    self.state = _initializing
}
func (self *Class) MarkInitialized() {
    self.state = _initialized
}

func (self *Class) GetField(name, descriptor string) (*Field) {
    for _, field := range self.fields {
        if field.name == name && field.descriptor == descriptor {
            return field
        }
    }
    // todo
    return nil
}

func (self *Class) GetMainMethod() (*Method) {
    return self.GetStaticMethod(mainMethodName, mainMethodDesc)
}
func (self *Class) GetClinitMethod() (*Method) {
    return self.GetStaticMethod(clinitMethodName, clinitMethodDesc)
}
func (self *Class) GetStaticMethod(name, descriptor string) (*Method) {
    method := self.GetMethod(name, descriptor)
    if method != nil && method.IsStatic() {
        return method
    } else {
        return nil
    }
}
func (self *Class) GetMethod(name, descriptor string) (*Method) {
    for _, method := range self.methods {
        if method.name == name && method.descriptor == descriptor {
            return method
        }
    }
    // todo
    return nil
}

func (self *Class) NewObj() (*Obj) {
    if self.instanceFieldCount > 0 {
        fields := make([]Any, self.instanceFieldCount)
        return &Obj{self, fields}
    } else {
        return &Obj{self, nil}
    }
}

// func newClass() (*Class) {
//     class := &Class{}
//     class.obj = &Obj{class:class}
//     return class
// }
<|endoftext|>


<commit_before>package class

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

const (
    _initializing = 1
    _initialized  = 2
)

type Class struct {
    superClass          *Class
    obj                 *Obj // static fields live here
    jClass              *Obj // java.lang.Class instance
    constantPool        *ConstantPool
    name                string
    superClassName      string
    interfaceNames      []string
    fields              []*Field
    methods             []*Method
    classLoader         *ClassLoader
    staticFieldCount    uint
    instanceFieldCount  uint
    state               int
    // todo
}

// func (self *Class) Fields() ([]*Field){
//     return self.fields
// }

// todo
func (self *Class) Obj() (*Obj) {
    return self.obj
}
func (self *Class) JClass() (*Obj) {
    return self.jClass
}
func (self *Class) ConstantPool() (*ConstantPool) {
    return self.constantPool
}
func (self *Class) Name() (string) {
    return self.name
}
func (self *Class) ClassLoader() (*ClassLoader) {
    return self.classLoader
}

func (self *Class) InitializationNotStarted() (bool) {
    return self.state < _initializing // todo
}
func (self *Class) MarkInitializing() {
    self.state = _initializing
}
func (self *Class) MarkInitialized() {
    self.state = _initialized
}

func (self *Class) GetField(name, descriptor string) (*Field) {
    for _, field := range self.fields {
        if field.name == name && field.descriptor == descriptor {
            return field
        }
    }
    // todo
    return nil
}

func (self *Class) GetMainMethod() (*Method) {
    return self.GetStaticMethod(mainMethodName, mainMethodDesc)
}
func (self *Class) GetClinitMethod() (*Method) {
    return self.GetStaticMethod(clinitMethodName, clinitMethodDesc)
}
func (self *Class) GetStaticMethod(name, descriptor string) (*Method) {
    method := self.GetMethod(name, descriptor)
    if method != nil && method.IsStatic() {
        return method
    } else {
        return nil
    }
}
func (self *Class) GetMethod(name, descriptor string) (*Method) {
    for _, method := range self.methods {
        if method.name == name && method.descriptor == descriptor {
            return method
        }
    }
    // todo
    return nil
}

func (self *Class) NewObj() (*Obj) {
    if self.instanceFieldCount > 0 {
        fields := make([]Any, self.instanceFieldCount)
        obj := &Obj{self, fields}
        obj.zeroFields()
        return obj
    } else {
        return &Obj{self, nil}
    }
}

func (self *Class) zeroStaticFields() {
    staticFields := self.obj.fields.([]Any)
    for _, f := range self.fields {
        if f.IsStatic() {
            staticFields[f.slot] = f.zeroValue()
        }
    }
}
<commit_msg>code refactor<commit_after>package class

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

const (
    _initializing = 1
    _initialized  = 2
)

type Class struct {
    obj                 *Obj // static fields live here
    jClass              *Obj // java.lang.Class instance
    superClass          *Class
    constantPool        *ConstantPool
    classLoader         *ClassLoader // defining class loader
    name                string
    superClassName      string
    interfaceNames      []string
    fields              []*Field
    methods             []*Method
    staticFieldCount    uint
    instanceFieldCount  uint
    state               int
    // todo
}

// func (self *Class) Fields() ([]*Field){
//     return self.fields
// }

// todo
func (self *Class) Obj() (*Obj) {
    return self.obj
}
func (self *Class) JClass() (*Obj) {
    return self.jClass
}
func (self *Class) ConstantPool() (*ConstantPool) {
    return self.constantPool
}
func (self *Class) Name() (string) {
    return self.name
}
func (self *Class) ClassLoader() (*ClassLoader) {
    return self.classLoader
}

func (self *Class) InitializationNotStarted() (bool) {
    return self.state < _initializing // todo
}
func (self *Class) MarkInitializing() {
    self.state = _initializing
}
func (self *Class) MarkInitialized() {
    self.state = _initialized
}

func (self *Class) GetField(name, descriptor string) (*Field) {
    for _, field := range self.fields {
        if field.name == name && field.descriptor == descriptor {
            return field
        }
    }
    // todo
    return nil
}

func (self *Class) GetMainMethod() (*Method) {
    return self.GetStaticMethod(mainMethodName, mainMethodDesc)
}
func (self *Class) GetClinitMethod() (*Method) {
    return self.GetStaticMethod(clinitMethodName, clinitMethodDesc)
}
func (self *Class) GetStaticMethod(name, descriptor string) (*Method) {
    method := self.GetMethod(name, descriptor)
    if method != nil && method.IsStatic() {
        return method
    } else {
        return nil
    }
}
func (self *Class) GetMethod(name, descriptor string) (*Method) {
    for _, method := range self.methods {
        if method.name == name && method.descriptor == descriptor {
            return method
        }
    }
    // todo
    return nil
}

func (self *Class) NewObj() (*Obj) {
    if self.instanceFieldCount > 0 {
        fields := make([]Any, self.instanceFieldCount)
        obj := &Obj{self, fields}
        obj.zeroFields()
        return obj
    } else {
        return &Obj{self, nil}
    }
}

func (self *Class) zeroStaticFields() {
    staticFields := self.obj.fields.([]Any)
    for _, f := range self.fields {
        if f.IsStatic() {
            staticFields[f.slot] = f.zeroValue()
        }
    }
}
<|endoftext|>


<commit_before>package desugar

import (
	"testing"

	"github.com/coel-lang/coel/src/lib/ast"
	"github.com/coel-lang/coel/src/lib/debug"
	"github.com/stretchr/testify/assert"
)

func TestNamesFindWithLetVar(t *testing.T) {
	n := "x"
	assert.True(t, newNames(n).findInLetVar(ast.NewLetVar(n, n)).include(n))
}

func TestNamesFindWithLetFunction(t *testing.T) {
	n := "x"

	for _, test := range []struct {
		letFunc ast.LetFunction
		answer  bool
	}{
		{
			ast.NewLetFunction(
				n,
				ast.NewSignature(nil, nil, "", nil, nil, ""),
				nil,
				n,
				debug.NewGoInfo(0)),
			true,
		},
		{
			ast.NewLetFunction(
				n,
				ast.NewSignature(nil, nil, "", nil, nil, ""),
				[]interface{}{ast.NewLetVar(n, "y")},
				n,
				debug.NewGoInfo(0)),
			false,
		},
	} {
		assert.Equal(t, test.answer, newNames(n).findInLetFunction(test.letFunc).include(n))
	}
}
<commit_msg>Fix test names<commit_after>package desugar

import (
	"testing"

	"github.com/coel-lang/coel/src/lib/ast"
	"github.com/coel-lang/coel/src/lib/debug"
	"github.com/stretchr/testify/assert"
)

func TestNamesFindInLetVar(t *testing.T) {
	n := "x"
	assert.True(t, newNames(n).findInLetVar(ast.NewLetVar(n, n)).include(n))
}

func TestNamesFindInLetFunction(t *testing.T) {
	n := "x"

	for _, test := range []struct {
		letFunc ast.LetFunction
		answer  bool
	}{
		{
			ast.NewLetFunction(
				n,
				ast.NewSignature(nil, nil, "", nil, nil, ""),
				nil,
				n,
				debug.NewGoInfo(0)),
			true,
		},
		{
			ast.NewLetFunction(
				n,
				ast.NewSignature(nil, nil, "", nil, nil, ""),
				[]interface{}{ast.NewLetVar(n, "y")},
				n,
				debug.NewGoInfo(0)),
			false,
		},
	} {
		assert.Equal(t, test.answer, newNames(n).findInLetFunction(test.letFunc).include(n))
	}
}
<|endoftext|>


<commit_before>package db

import (
	"reflect"
	"errors"
	"fmt"
	"strings"
)

var (
	ormTypes map[string]*ormType
)

func init() {
	ormTypes = make(map[string]*ormType)
}

type ormType struct {
	tableName   string
	reflectType reflect.Type
	columns map[string]string
	columnTypes map[string]reflect.Kind
}

// create new orm type
func newOrmType(obj interface {}) (*ormType, error) {
	reflectType := reflect.TypeOf(obj)
	// check pointer
	if reflectType.Kind() == reflect.Ptr {
		reflectType = reflectType.Elem()
	}
	if reflectType.Kind() != reflect.Struct {
		return nil, errors.New("must define struct for orm")
	}
	key := fmt.Sprint(reflectType)
	// count fields
	fieldNum := reflectType.NumField()
	if fieldNum < 1 {
		return nil, errors.New("must define struct with fields")
	}
	ormTp := &ormType{}
	ormTp.reflectType = reflectType
	ormTp.columns = make(map[string]string)
	ormTp.columnTypes = make(map[string]reflect.Kind)
	// parse fields
	for i := 0; i < fieldNum; i++ {
		rf := reflectType.Field(i)
		table, col := rf.Tag.Get("tbl"), rf.Tag.Get("col")
		if table != "" {
			ormTp.tableName = table
		}
		ormTp.columns[col] = rf.Name
		ormTp.columnTypes[col] = rf.Type.Kind()
	}
	if ormTp.tableName == "" {
		return nil, errors.New("must define struct with table name")
	}
	ormTypes[key] = ormTp
	return ormTp, nil
}

// get defined orm type
func getOrmType(name string) *ormType {
	return ormTypes[name]
}

// define orm type, return errors slice if some of them fail.
// the orm type named as packageName.StructName such as main.XXX
func Define(objects...interface {}) []error {
	errors := make([]error, 0)
	for _, obj := range objects {
		_, e := newOrmType(obj)
		if e != nil {
			errors = append(errors, e)
		}
	}
	return errors
}

// convert map to defined orm struct
func MapToStruct(mapData map[string]string, typeName string) (interface {}, error) {
	ormType := getOrmType(typeName)
	if ormType == nil {
		return nil, errors.New("wrong orm struct type name (forget define ?)")
	}
	rv := reflect.New(ormType.reflectType)
	for col, field := range ormType.columns {
		strValue := mapData[col]
		colType := ormType.columnTypes[col]
		reflectField := rv.Elem().FieldByName(field)
		switch colType{
		case reflect.Float32, reflect.Float64:
			reflectField.SetFloat(strToFloat64(strValue))
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			reflectField.SetInt(strToInt64(strValue))
		case reflect.Bool:
			reflectField.SetBool(strToBool(strValue))
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			reflectField.SetUint(strToUint64(strValue))
		default :
			reflectField.SetString(strValue)
		}
	}
	return rv.Interface(), nil
}

// convert defined orm struct to map
func StructToMap(obj interface {}, typeName string) (map[string]string, error) {
	ormType := getOrmType(typeName)
	if ormType == nil {
		return nil, errors.New("wrong orm struct type name (forget define ?)")
	}
	rv := reflect.ValueOf(obj)
	// check pointer
	if rv.Kind() == reflect.Ptr {
		rv = rv.Elem()
	}
	mapData := make(map[string]string)
	for col, field := range ormType.columns {
		value := fmt.Sprint(rv.FieldByName(field).Interface())
		if value == "<nil>" {
			value = ""
		}
		mapData[col] = value
	}
	return mapData, nil
}

type InkOrm struct {
	db *InkDatabase
}

// insert orm struct
func (this *InkOrm) Insert(obj interface {}) (int, error) {
	objType := strings.TrimPrefix(fmt.Sprint(reflect.TypeOf(obj)), "*")
	ormTp := getOrmType(objType)
	mapData, e := StructToMap(obj, objType)
	if e != nil {
		return -1, e
	}
	this.db.trigger("orm.insert.before", obj)
	keys := make([]string, len(mapData))
	values := make([]interface {}, len(mapData))
	i := 0
	for k, v := range mapData {
		keys[i] = k
		values[i] = v
		i++
	}
	sql := NewSql(ormTp.tableName, keys...)
	result, e := this.db.Exec(sql.Insert(), values...)
	if e != nil {
		return -1, e
	}
	return result.lastInsertId, nil
}

// delete orm struct by key column value
func (this *InkOrm) Delete(obj interface {}, keyColumn string) (int, error) {
	objType := strings.TrimPrefix(fmt.Sprint(reflect.TypeOf(obj)), "*")
	ormTp := getOrmType(objType)
	mapData, e := StructToMap(obj, objType)
	if e != nil {
		return -1, e
	}
	this.db.trigger("orm.delete.before", obj, &keyColumn)
	value := mapData[keyColumn]
	sql := NewSql(ormTp.tableName).Where("`" + keyColumn + "` = ?")
	result, e := this.db.Exec(sql.Delete(), value)
	if e != nil {
		return -1, e
	}
	return result.affectedRows, nil
}

// update orm struct by key column value ( with specific columns )
func (this *InkOrm) Update(obj interface {}, keyColumn string, columns...string) (int, error) {
	objType := strings.TrimPrefix(fmt.Sprint(reflect.TypeOf(obj)), "*")
	ormTp := getOrmType(objType)
	mapData, e := StructToMap(obj, objType)
	if e != nil {
		return -1, e
	}
	this.db.trigger("orm.update.before", obj, &keyColumn, &columns)
	keyValue := mapData[keyColumn]
	delete(mapData, keyColumn)
	keys := make([]string, 0)
	values := make([]interface {}, 0)
	if len(columns) > 0 {
		for _, col := range columns {
			if col == keyColumn {
				return -1, errors.New("can not update column markd as update-key column")
			}
			v, ok := mapData[col]
			if !ok {
				return -1, errors.New("no column named '" + col + "' in this object")
			}
			values = append(values, v)
		}
		keys = columns;
	}else {
		for k, v := range mapData {
			keys = append(keys, k)
			values = append(values, v)
		}
	}
	values = append(values, keyValue)
	sql := NewSql(ormTp.tableName, keys...).Where("`" + keyColumn + "` = ?").Update()
	result, e := this.db.Exec(sql, values...)
	if e != nil {
		return -1, e
	}
	return result.affectedRows, nil
}

// find as orm struct type with sql conditions and arguments,
// return interface slice, you need assert type by yourself.
func (this *InkOrm) Find(typeName string, sqlCondition *InkSql, args...interface {}) ([]interface {}, error) {
	ormTp := getOrmType(typeName)
	if sqlCondition == nil{
		sqlCondition = NewSql("")
	}
	sqlCondition.Table = ormTp.tableName
	data, e := this.db.Query(sqlCondition.Select(), args...)
	if e != nil {
		return nil, e
	}
	this.db.trigger("orm.find.before", &typeName, sqlCondition, &args)
	resultData := make([]interface {}, len(data.Maps()))
	for i, v := range data.Maps() {
		resultData[i], e = MapToStruct(v, typeName)
		if e != nil {
			return nil, e
		}
	}
	return resultData, nil
}

// find one orm struct
func (this *InkOrm) FindOne(typeName string, sqlCondition *InkSql, args...interface {}) (interface {}, error) {
	ormTp := getOrmType(typeName)
	if sqlCondition == nil{
		sqlCondition = NewSql("")
	}
	sqlCondition.Table = ormTp.tableName
	this.db.trigger("orm.find.one.before", &typeName, sqlCondition, &args)
	data, e := this.db.Query(sqlCondition.Select(), args...)
	if e != nil {
		return nil, e
	}
	return MapToStruct(data.Map(), typeName)
}

// create new struct
func NewOrm(db *InkDatabase) *InkOrm {
	orm := &InkOrm{}
	orm.db = db
	return orm
}
<commit_msg>ignore empty string and zero value when inserting by orm<commit_after>package db

import (
	"reflect"
	"errors"
	"fmt"
	"strings"
)

var (
	ormTypes map[string]*ormType
)

func init() {
	ormTypes = make(map[string]*ormType)
}

type ormType struct {
	tableName   string
	reflectType reflect.Type
	columns map[string]string
	columnTypes map[string]reflect.Kind
}

// create new orm type
func newOrmType(obj interface {}) (*ormType, error) {
	reflectType := reflect.TypeOf(obj)
	// check pointer
	if reflectType.Kind() == reflect.Ptr {
		reflectType = reflectType.Elem()
	}
	if reflectType.Kind() != reflect.Struct {
		return nil, errors.New("must define struct for orm")
	}
	key := fmt.Sprint(reflectType)
	// count fields
	fieldNum := reflectType.NumField()
	if fieldNum < 1 {
		return nil, errors.New("must define struct with fields")
	}
	ormTp := &ormType{}
	ormTp.reflectType = reflectType
	ormTp.columns = make(map[string]string)
	ormTp.columnTypes = make(map[string]reflect.Kind)
	// parse fields
	for i := 0; i < fieldNum; i++ {
		rf := reflectType.Field(i)
		table, col := rf.Tag.Get("tbl"), rf.Tag.Get("col")
		if table != "" {
			ormTp.tableName = table
		}
		ormTp.columns[col] = rf.Name
		ormTp.columnTypes[col] = rf.Type.Kind()
	}
	if ormTp.tableName == "" {
		return nil, errors.New("must define struct with table name")
	}
	ormTypes[key] = ormTp
	return ormTp, nil
}

// get defined orm type
func getOrmType(name string) *ormType {
	return ormTypes[name]
}

// define orm type, return errors slice if some of them fail.
// the orm type named as packageName.StructName such as main.XXX
func Define(objects...interface {}) []error {
	errors := make([]error, 0)
	for _, obj := range objects {
		_, e := newOrmType(obj)
		if e != nil {
			errors = append(errors, e)
		}
	}
	return errors
}

// convert map to defined orm struct
func MapToStruct(mapData map[string]string, typeName string) (interface {}, error) {
	ormType := getOrmType(typeName)
	if ormType == nil {
		return nil, errors.New("wrong orm struct type name (forget define ?)")
	}
	rv := reflect.New(ormType.reflectType)
	for col, field := range ormType.columns {
		strValue := mapData[col]
		colType := ormType.columnTypes[col]
		reflectField := rv.Elem().FieldByName(field)
		switch colType{
		case reflect.Float32, reflect.Float64:
			reflectField.SetFloat(strToFloat64(strValue))
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			reflectField.SetInt(strToInt64(strValue))
		case reflect.Bool:
			reflectField.SetBool(strToBool(strValue))
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			reflectField.SetUint(strToUint64(strValue))
		default :
			reflectField.SetString(strValue)
		}
	}
	return rv.Interface(), nil
}

// convert defined orm struct to map
func StructToMap(obj interface {}, typeName string) (map[string]string, error) {
	ormType := getOrmType(typeName)
	if ormType == nil {
		return nil, errors.New("wrong orm struct type name (forget define ?)")
	}
	rv := reflect.ValueOf(obj)
	// check pointer
	if rv.Kind() == reflect.Ptr {
		rv = rv.Elem()
	}
	mapData := make(map[string]string)
	for col, field := range ormType.columns {
		value := fmt.Sprint(rv.FieldByName(field).Interface())
		if value == "<nil>" {
			value = ""
		}
		mapData[col] = value
	}
	return mapData, nil
}

type InkOrm struct {
	db *InkDatabase
}

// insert orm struct
func (this *InkOrm) Insert(obj interface {}) (int, error) {
	objType := strings.TrimPrefix(fmt.Sprint(reflect.TypeOf(obj)), "*")
	ormTp := getOrmType(objType)
	mapData, e := StructToMap(obj, objType)
	if e != nil {
		return -1, e
	}
	this.db.trigger("orm.insert.before", obj)
	keys := make([]string, 0)
	values := make([]interface {}, 0)
	i := 0
	for k, v := range mapData {
		// ignore empty string and zero
		if len(v) > 0 && v != "0" {
			keys = append(keys, k)
			values = append(values, v)
		}
		i++
	}
	sql := NewSql(ormTp.tableName, keys...)
	result, e := this.db.Exec(sql.Insert(), values...)
	if e != nil {
		return -1, e
	}
	return result.lastInsertId, nil
}

// delete orm struct by key column value
func (this *InkOrm) Delete(obj interface {}, keyColumn string) (int, error) {
	objType := strings.TrimPrefix(fmt.Sprint(reflect.TypeOf(obj)), "*")
	ormTp := getOrmType(objType)
	mapData, e := StructToMap(obj, objType)
	if e != nil {
		return -1, e
	}
	this.db.trigger("orm.delete.before", obj, &keyColumn)
	value := mapData[keyColumn]
	sql := NewSql(ormTp.tableName).Where("`" + keyColumn + "` = ?")
	result, e := this.db.Exec(sql.Delete(), value)
	if e != nil {
		return -1, e
	}
	return result.affectedRows, nil
}

// update orm struct by key column value ( with specific columns )
func (this *InkOrm) Update(obj interface {}, keyColumn string, columns...string) (int, error) {
	objType := strings.TrimPrefix(fmt.Sprint(reflect.TypeOf(obj)), "*")
	ormTp := getOrmType(objType)
	mapData, e := StructToMap(obj, objType)
	if e != nil {
		return -1, e
	}
	this.db.trigger("orm.update.before", obj, &keyColumn, &columns)
	keyValue := mapData[keyColumn]
	delete(mapData, keyColumn)
	keys := make([]string, 0)
	values := make([]interface {}, 0)
	if len(columns) > 0 {
		for _, col := range columns {
			if col == keyColumn {
				return -1, errors.New("can not update column markd as update-key column")
			}
			v, ok := mapData[col]
			if !ok {
				return -1, errors.New("no column named '" + col + "' in this object")
			}
			values = append(values, v)
		}
		keys = columns;
	}else {
		for k, v := range mapData {
			keys = append(keys, k)
			values = append(values, v)
		}
	}
	values = append(values, keyValue)
	sql := NewSql(ormTp.tableName, keys...).Where("`" + keyColumn + "` = ?").Update()
	result, e := this.db.Exec(sql, values...)
	if e != nil {
		return -1, e
	}
	return result.affectedRows, nil
}

// find as orm struct type with sql conditions and arguments,
// return interface slice, you need assert type by yourself.
func (this *InkOrm) Find(typeName string, sqlCondition *InkSql, args...interface {}) ([]interface {}, error) {
	ormTp := getOrmType(typeName)
	if sqlCondition == nil {
		sqlCondition = NewSql("")
	}
	sqlCondition.Table = ormTp.tableName
	data, e := this.db.Query(sqlCondition.Select(), args...)
	if e != nil {
		return nil, e
	}
	this.db.trigger("orm.find.before", &typeName, sqlCondition, &args)
	resultData := make([]interface {}, len(data.Maps()))
	for i, v := range data.Maps() {
		resultData[i], e = MapToStruct(v, typeName)
		if e != nil {
			return nil, e
		}
	}
	return resultData, nil
}

// find one orm struct
func (this *InkOrm) FindOne(typeName string, sqlCondition *InkSql, args...interface {}) (interface {}, error) {
	ormTp := getOrmType(typeName)
	if sqlCondition == nil {
		sqlCondition = NewSql("")
	}
	sqlCondition.Table = ormTp.tableName
	this.db.trigger("orm.find.one.before", &typeName, sqlCondition, &args)
	data, e := this.db.Query(sqlCondition.Select(), args...)
	if e != nil {
		return nil, e
	}
	return MapToStruct(data.Map(), typeName)
}

// create new struct
func NewOrm(db *InkDatabase) *InkOrm {
	orm := &InkOrm{}
	orm.db = db
	return orm
}
<|endoftext|>


<commit_before>package toml

import (
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
)

func parseInteger(b []byte) (int64, error) {
	if len(b) > 2 && b[0] == '0' {
		switch b[1] {
		case 'x':
			return parseIntHex(b)
		case 'b':
			return parseIntBin(b)
		case 'o':
			return parseIntOct(b)
		default:
			return 0, fmt.Errorf("invalid base: '%c'", b[1])
		}
	}
	return parseIntDec(b)
}

func parseLocalDate(b []byte) (LocalDate, error) {
	// full-date      = date-fullyear "-" date-month "-" date-mday
	// date-fullyear  = 4DIGIT
	// date-month     = 2DIGIT  ; 01-12
	// date-mday      = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year

	date := LocalDate{}

	if len(b) != 10 || b[4] != '-' || b[7] != '-' {
		return date, fmt.Errorf("dates are expected to have the format YYYY-MM-DD")
	}

	var err error

	date.Year, err = parseDecimalDigits(b[0:4])
	if err != nil {
		return date, err
	}

	v, err := parseDecimalDigits(b[5:7])
	if err != nil {
		return date, err
	}
	date.Month = time.Month(v)

	date.Day, err = parseDecimalDigits(b[8:10])

	return date, nil
}

func parseDecimalDigits(b []byte) (int, error) {
	v := 0
	for _, c := range b {
		if !isDigit(c) {
			return 0, fmt.Errorf("expected digit")
		}
		v *= 10
		v += int(c - '0')
	}
	return v, nil
}

func parseDateTime(b []byte) (time.Time, error) {
	// offset-date-time = full-date time-delim full-time
	// full-time      = partial-time time-offset
	// time-offset    = "Z" / time-numoffset
	// time-numoffset = ( "+" / "-" ) time-hour ":" time-minute

	dt, b, err := parseLocalDateTime(b)
	if err != nil {
		return time.Time{}, nil
	}

	var zone *time.Location

	if len(b) == 0 {
		return time.Time{}, fmt.Errorf("date-time missing timezone information")
	}

	if b[0] == 'Z' {
		b = b[1:]
		zone = time.UTC
	} else {
		if len(b) != 6 {
			return time.Time{}, fmt.Errorf("invalid date-time timezone")
		}
		direction := 1
		switch b[0] {
		case '+':
		case '-':
			direction = -1
		default:
			return time.Time{}, fmt.Errorf("invalid timezone offset character")
		}

		hours := digitsToInt(b[1:3])
		minutes := digitsToInt(b[4:6])
		seconds := direction * (hours*3600 + minutes*60)
		zone = time.FixedZone("", seconds)
	}

	if len(b) > 0 {
		return time.Time{}, fmt.Errorf("extra bytes at the end of the timezone")
	}

	t := time.Date(
		dt.Date.Year,
		dt.Date.Month,
		dt.Date.Day,
		dt.Time.Hour,
		dt.Time.Minute,
		dt.Time.Second,
		dt.Time.Nanosecond,
		zone)

	return t, nil
}

func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
	dt := LocalDateTime{}

	if len(b) < 11 {
		return dt, nil, fmt.Errorf("local datetimes are expected to have the format YYYY-MM-DDTHH:MM:SS[.NNNNNN]")
	}

	date, err := parseLocalDate(b[:10])
	if err != nil {
		return dt, nil, err
	}
	dt.Date = date

	sep := b[10]
	if sep != 'T' && sep != ' ' {
		return dt, nil, fmt.Errorf("datetime separator is expected to be T or a space")
	}

	t, rest, err := parseLocalTime(b[11:])
	if err != nil {
		return dt, nil, err
	}
	dt.Time = t

	return dt, rest, nil
}

// parseLocalTime is a bit different because it also returns the remaining
// []byte that is didn't need. This is to allow parseDateTime to parse those
// remaining bytes as a timezone.
func parseLocalTime(b []byte) (LocalTime, []byte, error) {
	t := LocalTime{}

	if len(b) < 8 {
		return t, nil, fmt.Errorf("times are expected to have the format HH:MM:SS[.NNNNNN]")
	}

	var err error
	t.Hour, err = parseDecimalDigits(b[0:2])
	if err != nil {
		return t, nil, err
	}
	t.Minute, err = parseDecimalDigits(b[3:5])
	if err != nil {
		return t, nil, err
	}
	t.Second, err = parseDecimalDigits(b[6:8])
	if err != nil {
		return t, nil, err
	}

	if len(b) >= 15 && b[8] == '.' {
		t.Nanosecond, err = parseDecimalDigits(b[9:15])
		return t, b[15:], nil
	}

	return t, b[8:], nil
}

func parseFloat(b []byte) (float64, error) {
	// TODO: inefficient
	if len(b) == 4 && (b[0] == '+' || b[0] == '-') && b[1] == 'n' && b[2] == 'a' && b[3] == 'n' {
		return math.NaN(), nil
	}

	tok := string(b)
	err := numberContainsInvalidUnderscore(tok)
	if err != nil {
		return 0, err
	}
	cleanedVal := cleanupNumberToken(tok)
	return strconv.ParseFloat(cleanedVal, 64)
}

func parseIntHex(b []byte) (int64, error) {
	tok := string(b)
	cleanedVal := cleanupNumberToken(tok)
	err := hexNumberContainsInvalidUnderscore(cleanedVal)
	if err != nil {
		return 0, nil
	}
	return strconv.ParseInt(cleanedVal[2:], 16, 64)
}

func parseIntOct(b []byte) (int64, error) {
	tok := string(b)
	cleanedVal := cleanupNumberToken(tok)
	err := numberContainsInvalidUnderscore(cleanedVal)
	if err != nil {
		return 0, err
	}
	return strconv.ParseInt(cleanedVal[2:], 8, 64)
}

func parseIntBin(b []byte) (int64, error) {
	tok := string(b)
	cleanedVal := cleanupNumberToken(tok)
	err := numberContainsInvalidUnderscore(cleanedVal)
	if err != nil {
		return 0, err
	}
	return strconv.ParseInt(cleanedVal[2:], 2, 64)
}

func parseIntDec(b []byte) (int64, error) {
	tok := string(b)
	cleanedVal := cleanupNumberToken(tok)
	err := numberContainsInvalidUnderscore(cleanedVal)
	if err != nil {
		return 0, err
	}
	return strconv.ParseInt(cleanedVal, 10, 64)
}

func numberContainsInvalidUnderscore(value string) error {
	// For large numbers, you may use underscores between digits to enhance
	// readability. Each underscore must be surrounded by at least one digit on
	// each side.

	hasBefore := false
	for idx, r := range value {
		if r == '_' {
			if !hasBefore || idx+1 >= len(value) {
				// can't end with an underscore
				return errInvalidUnderscore
			}
		}
		hasBefore = isDigitRune(r)
	}
	return nil
}

func hexNumberContainsInvalidUnderscore(value string) error {
	hasBefore := false
	for idx, r := range value {
		if r == '_' {
			if !hasBefore || idx+1 >= len(value) {
				// can't end with an underscore
				return errInvalidUnderscoreHex
			}
		}
		hasBefore = isHexDigit(r)
	}
	return nil
}

func cleanupNumberToken(value string) string {
	cleanedVal := strings.Replace(value, "_", "", -1)
	return cleanedVal
}

func isHexDigit(r rune) bool {
	return isDigitRune(r) ||
		(r >= 'a' && r <= 'f') ||
		(r >= 'A' && r <= 'F')
}

func isDigitRune(r rune) bool {
	return r >= '0' && r <= '9'
}

var errInvalidUnderscore = errors.New("invalid use of _ in number")
var errInvalidUnderscoreHex = errors.New("invalid use of _ in hex number")
<commit_msg>Fix datetime error checking<commit_after>package toml

import (
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
)

func parseInteger(b []byte) (int64, error) {
	if len(b) > 2 && b[0] == '0' {
		switch b[1] {
		case 'x':
			return parseIntHex(b)
		case 'b':
			return parseIntBin(b)
		case 'o':
			return parseIntOct(b)
		default:
			return 0, fmt.Errorf("invalid base: '%c'", b[1])
		}
	}
	return parseIntDec(b)
}

func parseLocalDate(b []byte) (LocalDate, error) {
	// full-date      = date-fullyear "-" date-month "-" date-mday
	// date-fullyear  = 4DIGIT
	// date-month     = 2DIGIT  ; 01-12
	// date-mday      = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year

	date := LocalDate{}

	if len(b) != 10 || b[4] != '-' || b[7] != '-' {
		return date, fmt.Errorf("dates are expected to have the format YYYY-MM-DD")
	}

	var err error

	date.Year, err = parseDecimalDigits(b[0:4])
	if err != nil {
		return date, err
	}

	v, err := parseDecimalDigits(b[5:7])
	if err != nil {
		return date, err
	}
	date.Month = time.Month(v)

	date.Day, err = parseDecimalDigits(b[8:10])

	return date, nil
}

func parseDecimalDigits(b []byte) (int, error) {
	v := 0
	for _, c := range b {
		if !isDigit(c) {
			return 0, fmt.Errorf("expected digit")
		}
		v *= 10
		v += int(c - '0')
	}
	return v, nil
}

func parseDateTime(b []byte) (time.Time, error) {
	// offset-date-time = full-date time-delim full-time
	// full-time      = partial-time time-offset
	// time-offset    = "Z" / time-numoffset
	// time-numoffset = ( "+" / "-" ) time-hour ":" time-minute

	dt, b, err := parseLocalDateTime(b)
	if err != nil {
		return time.Time{}, err
	}

	var zone *time.Location

	if len(b) == 0 {
		return time.Time{}, fmt.Errorf("date-time missing timezone information")
	}

	if b[0] == 'Z' {
		b = b[1:]
		zone = time.UTC
	} else {
		if len(b) != 6 {
			return time.Time{}, fmt.Errorf("invalid date-time timezone")
		}
		direction := 1
		switch b[0] {
		case '+':
		case '-':
			direction = -1
		default:
			return time.Time{}, fmt.Errorf("invalid timezone offset character")
		}

		hours := digitsToInt(b[1:3])
		minutes := digitsToInt(b[4:6])
		seconds := direction * (hours*3600 + minutes*60)
		zone = time.FixedZone("", seconds)
	}

	if len(b) > 0 {
		return time.Time{}, fmt.Errorf("extra bytes at the end of the timezone")
	}

	t := time.Date(
		dt.Date.Year,
		dt.Date.Month,
		dt.Date.Day,
		dt.Time.Hour,
		dt.Time.Minute,
		dt.Time.Second,
		dt.Time.Nanosecond,
		zone)

	return t, nil
}

func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
	dt := LocalDateTime{}

	if len(b) < 11 {
		return dt, nil, fmt.Errorf("local datetimes are expected to have the format YYYY-MM-DDTHH:MM:SS[.NNNNNN]")
	}

	date, err := parseLocalDate(b[:10])
	if err != nil {
		return dt, nil, err
	}
	dt.Date = date

	sep := b[10]
	if sep != 'T' && sep != ' ' {
		return dt, nil, fmt.Errorf("datetime separator is expected to be T or a space")
	}

	t, rest, err := parseLocalTime(b[11:])
	if err != nil {
		return dt, nil, err
	}
	dt.Time = t

	return dt, rest, nil
}

// parseLocalTime is a bit different because it also returns the remaining
// []byte that is didn't need. This is to allow parseDateTime to parse those
// remaining bytes as a timezone.
func parseLocalTime(b []byte) (LocalTime, []byte, error) {
	t := LocalTime{}

	if len(b) < 8 {
		return t, nil, fmt.Errorf("times are expected to have the format HH:MM:SS[.NNNNNN]")
	}

	var err error
	t.Hour, err = parseDecimalDigits(b[0:2])
	if err != nil {
		return t, nil, err
	}
	if b[2] != ':' {
		return t, nil, fmt.Errorf("expecting colon between hours and minutes")
	}
	t.Minute, err = parseDecimalDigits(b[3:5])
	if err != nil {
		return t, nil, err
	}
	if b[5] != ':' {
		return t, nil, fmt.Errorf("expecting colon between minutes and seconds")
	}
	t.Second, err = parseDecimalDigits(b[6:8])
	if err != nil {
		return t, nil, err
	}

	if len(b) >= 15 && b[8] == '.' {
		t.Nanosecond, err = parseDecimalDigits(b[9:15])
		return t, b[15:], nil
	}

	return t, b[8:], nil
}

func parseFloat(b []byte) (float64, error) {
	// TODO: inefficient
	if len(b) == 4 && (b[0] == '+' || b[0] == '-') && b[1] == 'n' && b[2] == 'a' && b[3] == 'n' {
		return math.NaN(), nil
	}

	tok := string(b)
	err := numberContainsInvalidUnderscore(tok)
	if err != nil {
		return 0, err
	}
	cleanedVal := cleanupNumberToken(tok)
	return strconv.ParseFloat(cleanedVal, 64)
}

func parseIntHex(b []byte) (int64, error) {
	tok := string(b)
	cleanedVal := cleanupNumberToken(tok)
	err := hexNumberContainsInvalidUnderscore(cleanedVal)
	if err != nil {
		return 0, nil
	}
	return strconv.ParseInt(cleanedVal[2:], 16, 64)
}

func parseIntOct(b []byte) (int64, error) {
	tok := string(b)
	cleanedVal := cleanupNumberToken(tok)
	err := numberContainsInvalidUnderscore(cleanedVal)
	if err != nil {
		return 0, err
	}
	return strconv.ParseInt(cleanedVal[2:], 8, 64)
}

func parseIntBin(b []byte) (int64, error) {
	tok := string(b)
	cleanedVal := cleanupNumberToken(tok)
	err := numberContainsInvalidUnderscore(cleanedVal)
	if err != nil {
		return 0, err
	}
	return strconv.ParseInt(cleanedVal[2:], 2, 64)
}

func parseIntDec(b []byte) (int64, error) {
	tok := string(b)
	cleanedVal := cleanupNumberToken(tok)
	err := numberContainsInvalidUnderscore(cleanedVal)
	if err != nil {
		return 0, err
	}
	return strconv.ParseInt(cleanedVal, 10, 64)
}

func numberContainsInvalidUnderscore(value string) error {
	// For large numbers, you may use underscores between digits to enhance
	// readability. Each underscore must be surrounded by at least one digit on
	// each side.

	hasBefore := false
	for idx, r := range value {
		if r == '_' {
			if !hasBefore || idx+1 >= len(value) {
				// can't end with an underscore
				return errInvalidUnderscore
			}
		}
		hasBefore = isDigitRune(r)
	}
	return nil
}

func hexNumberContainsInvalidUnderscore(value string) error {
	hasBefore := false
	for idx, r := range value {
		if r == '_' {
			if !hasBefore || idx+1 >= len(value) {
				// can't end with an underscore
				return errInvalidUnderscoreHex
			}
		}
		hasBefore = isHexDigit(r)
	}
	return nil
}

func cleanupNumberToken(value string) string {
	cleanedVal := strings.Replace(value, "_", "", -1)
	return cleanedVal
}

func isHexDigit(r rune) bool {
	return isDigitRune(r) ||
		(r >= 'a' && r <= 'f') ||
		(r >= 'A' && r <= 'F')
}

func isDigitRune(r rune) bool {
	return r >= '0' && r <= '9'
}

var errInvalidUnderscore = errors.New("invalid use of _ in number")
var errInvalidUnderscoreHex = errors.New("invalid use of _ in hex number")
<|endoftext|>


<commit_before>// Copyright 2016 Russ Olsen. All Rights Reserved.
//
// This code is a Go port of the Java version created and maintained by Cognitect, therefore:
//
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package transit

import (
	"encoding/json"
	"io"
	"strings"
)

type Handler func(Decoder, interface{}) (interface{}, error)

type Decoder struct {
	jsd      *json.Decoder
	decoders map[string]Handler
	Cache    *RollingCache
}

// NewDecoder returns a new Decoder, ready to write to r.
func NewDecoder(r io.Reader) *Decoder {
	jsd := json.NewDecoder(r)
	jsd.UseNumber()

	decoders := make(map[string]Handler)

	d := Decoder{jsd: jsd, decoders: decoders, Cache: NewRollingCache()}

	d.AddHandler("_", DecodeNil)
	d.AddHandler(":", DecodeKeyword)
	d.AddHandler("?", DecodeBoolean)
	d.AddHandler("b", DecodeByte)
	d.AddHandler("d", DecodeDecimal)
	d.AddHandler("i", DecodeInteger)
	d.AddHandler("n", DecodeBigInteger)
	d.AddHandler("f", DecodeBigDecimal)
	d.AddHandler("c", DecodeRune)
	d.AddHandler("$", DecodeSymbol)
	d.AddHandler("t", DecodeRFC3339)
	d.AddHandler("m", DecodeTime)
	d.AddHandler("u", DecodeUUID)
	d.AddHandler("r", DecodeURI)
	d.AddHandler("'", DecodeQuote)
	d.AddHandler("z", DecodeSpecialNumber)

	d.AddHandler("set", DecodeSet)
	d.AddHandler("link", DecodeLink)
	d.AddHandler("list", DecodeList)
	d.AddHandler("cmap", DecodeCMap)
	d.AddHandler("ratio", DecodeRatio)
	d.AddHandler("unknown", DecodeIdentity)

	return &d
}

// AddHandler adds a new handler to the decoder, allowing you to extend the types it can handle.
func (d Decoder) AddHandler(tag string, valueDecoder Handler) {
	d.decoders[tag] = valueDecoder
}

func (d Decoder) parseString(s string) (interface{}, error) {

	if d.Cache.HasKey(s) {
		return d.Parse(d.Cache.Read(s), false)

	} else if !strings.HasPrefix(s, start) {
		return s, nil

	} else if strings.HasPrefix(s, startTag) {
		return TagId(s[2:]), nil

	} else if vd := d.decoders[s[1:2]]; vd != nil {
		return vd(d, s[2:])

	} else if strings.HasPrefix(s, escapeTag) ||
		strings.HasPrefix(s, escapeSub) ||
		strings.HasPrefix(s, escapeRes) {
		return s[1:], nil

	} else {
		tv := TaggedValue{TagId(s[1:2]), s[2:]}
		return d.decoders["unknown"](d, tv)
	}
}

func (d Decoder) parseSingleEntryMap(m map[string]interface{}) (interface{}, error) {
	// The loop here is just a convenient way to get at the only
	// entry in the map.
	for k, v := range m {
		key, err := d.Parse(k, true)
		if err != nil {
			return nil, err
		}

		value, err := d.Parse(v, true)
		if err != nil {
			return nil, err
		}

		if tag, isTag := key.(TagId); isTag {
			tv := TaggedValue{Tag: tag, Value: value}
			valueDecoder := d.DecoderFor(tag)
			return valueDecoder(d, tv)
		} else {
			return map[interface{}]interface{}{key: value}, nil
		}
	}

	return nil, nil // Should never get here
}

func (d Decoder) parseMultiEntryMap(m map[string]interface{}) (interface{}, error) {
	var result = make(map[interface{}]interface{})

	for k, v := range m {
		key, err := d.Parse(k, true)
		if err != nil {
			return nil, err
		}

		value, err := d.Parse(v, false)
		if err != nil {
			return nil, err
		}

		result[key] = value
	}

	return result, nil
}

func (d Decoder) parseMap(m map[string]interface{}) (interface{}, error) {
	if len(m) != 1 {
		return d.parseMultiEntryMap(m)
	} else {
		return d.parseSingleEntryMap(m)
	}
}

func (d Decoder) parseNormalArray(x []interface{}) (interface{}, error) {
	var result = make([]interface{}, len(x))

	for i, v := range x {
		var err error
		result[i], err = d.Parse(v, false)
		if err != nil {
			return nil, err
		}
	}

	return result, nil
}

func (d Decoder) parseCMap(x []interface{}) (interface{}, error) {
	var result = NewCMap()

	l := len(x)

	for i := 1; i < l; i += 2 {
		key, err := d.Parse(x[i], true)
		if err != nil {
			return nil, err
		}

		value, err := d.Parse(x[i+1], false)
		if err != nil {
			return nil, err
		}
		result.Append(key, value)
	}

	return result, nil
}

func (d Decoder) parseArrayMap(x []interface{}) (interface{}, error) {
	result := make(map[interface{}]interface{})

	l := len(x)

	for i := 1; i < l; i += 2 {
		key, err := d.Parse(x[i], true)
		if err != nil {
			return nil, err
		}

		value, err := d.Parse(x[i+1], false)
		if err != nil {
			return nil, err
		}
		result[key] = value
	}

	return result, nil
}

func (d Decoder) DecoderFor(tagid TagId) Handler {
	key := string(tagid)

	handler := d.decoders[key]
	if handler == nil {
		handler = d.decoders["unknown"]
	}
	return handler
}

func (d Decoder) parseArray(x []interface{}) (interface{}, error) {
	if len(x) == 0 {
		return x, nil
	}

	e0, err := d.Parse(x[0], false)

	if err != nil {
		return nil, err
	}

	if e0 == mapAsArray {
		return d.parseArrayMap(x)
	}

	if tagId, isTag := e0.(TagId); isTag {
		var value interface{}

		if value, err = d.Parse(x[1], false); err != nil {
			return nil, err
		}

		tv := TaggedValue{Tag: tagId, Value: value}
		valueDecoder := d.DecoderFor(tagId)
		return valueDecoder(d, tv)
	}

	return d.parseNormalArray(x)
}

func (d Decoder) parseNumber(x json.Number) (interface{}, error) {
	var s = x.String()
	var err error

	var result interface{}

	if strings.ContainsAny(s, ".Ee") {
		result, err = x.Float64()
	} else {
		result, err = x.Int64()
	}

	return result, err
}

func (d Decoder) Parse(x interface{}, asKey bool) (interface{}, error) {

	switch v := x.(type) {
	default:
		return nil, &TransitError{Message: "Unexpected type"}
	case nil:
		return v, nil

	case bool:
		return v, nil

	case json.Number:
		return d.parseNumber(v)

	case string:
		result, err := d.parseString(v)

		if err == nil && d.Cache.IsCacheable(v, asKey) {
			d.Cache.Write(v)
		}
		return result, err

	case map[string]interface{}:
		return d.parseMap(v)

	case []interface{}:
		return d.parseArray(v)
	}
}

// Decode decodes the next Transit value from the stream.
func (d Decoder) Decode() (interface{}, error) {
	var jsonObject interface{}
	var err = d.jsd.Decode(&jsonObject)

	if err != nil {
		return nil, err
	} else {
		return d.Parse(jsonObject, false)
	}
}

// DecodeFromString is a handly function that decodes Transit data held in a string.
func DecodeFromString(s string) (interface{}, error) {
	reader := strings.NewReader(s)
	decoder := NewDecoder(reader)
	return decoder.Decode()
}
<commit_msg>Bloomify: Make Cache field on Decoder private.<commit_after>// Copyright 2016 Russ Olsen. All Rights Reserved.
//
// This code is a Go port of the Java version created and maintained by Cognitect, therefore:
//
// Copyright 2014 Cognitect. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package transit

import (
	"encoding/json"
	"io"
	"strings"
)

type Handler func(Decoder, interface{}) (interface{}, error)

type Decoder struct {
	jsd      *json.Decoder
	decoders map[string]Handler
	cache    *RollingCache
}

// NewDecoder returns a new Decoder, ready to write to r.
func NewDecoder(r io.Reader) *Decoder {
	jsd := json.NewDecoder(r)
	jsd.UseNumber()

	decoders := make(map[string]Handler)

	d := Decoder{jsd: jsd, decoders: decoders, cache: NewRollingCache()}

	d.AddHandler("_", DecodeNil)
	d.AddHandler(":", DecodeKeyword)
	d.AddHandler("?", DecodeBoolean)
	d.AddHandler("b", DecodeByte)
	d.AddHandler("d", DecodeDecimal)
	d.AddHandler("i", DecodeInteger)
	d.AddHandler("n", DecodeBigInteger)
	d.AddHandler("f", DecodeBigDecimal)
	d.AddHandler("c", DecodeRune)
	d.AddHandler("$", DecodeSymbol)
	d.AddHandler("t", DecodeRFC3339)
	d.AddHandler("m", DecodeTime)
	d.AddHandler("u", DecodeUUID)
	d.AddHandler("r", DecodeURI)
	d.AddHandler("'", DecodeQuote)
	d.AddHandler("z", DecodeSpecialNumber)

	d.AddHandler("set", DecodeSet)
	d.AddHandler("link", DecodeLink)
	d.AddHandler("list", DecodeList)
	d.AddHandler("cmap", DecodeCMap)
	d.AddHandler("ratio", DecodeRatio)
	d.AddHandler("unknown", DecodeIdentity)

	return &d
}

// AddHandler adds a new handler to the decoder, allowing you to extend the types it can handle.
func (d Decoder) AddHandler(tag string, valueDecoder Handler) {
	d.decoders[tag] = valueDecoder
}

func (d Decoder) parseString(s string) (interface{}, error) {

	if d.cache.HasKey(s) {
		return d.Parse(d.cache.Read(s), false)

	} else if !strings.HasPrefix(s, start) {
		return s, nil

	} else if strings.HasPrefix(s, startTag) {
		return TagId(s[2:]), nil

	} else if vd := d.decoders[s[1:2]]; vd != nil {
		return vd(d, s[2:])

	} else if strings.HasPrefix(s, escapeTag) ||
		strings.HasPrefix(s, escapeSub) ||
		strings.HasPrefix(s, escapeRes) {
		return s[1:], nil

	} else {
		tv := TaggedValue{TagId(s[1:2]), s[2:]}
		return d.decoders["unknown"](d, tv)
	}
}

func (d Decoder) parseSingleEntryMap(m map[string]interface{}) (interface{}, error) {
	// The loop here is just a convenient way to get at the only
	// entry in the map.
	for k, v := range m {
		key, err := d.Parse(k, true)
		if err != nil {
			return nil, err
		}

		value, err := d.Parse(v, true)
		if err != nil {
			return nil, err
		}

		if tag, isTag := key.(TagId); isTag {
			tv := TaggedValue{Tag: tag, Value: value}
			valueDecoder := d.DecoderFor(tag)
			return valueDecoder(d, tv)
		} else {
			return map[interface{}]interface{}{key: value}, nil
		}
	}

	return nil, nil // Should never get here
}

func (d Decoder) parseMultiEntryMap(m map[string]interface{}) (interface{}, error) {
	var result = make(map[interface{}]interface{})

	for k, v := range m {
		key, err := d.Parse(k, true)
		if err != nil {
			return nil, err
		}

		value, err := d.Parse(v, false)
		if err != nil {
			return nil, err
		}

		result[key] = value
	}

	return result, nil
}

func (d Decoder) parseMap(m map[string]interface{}) (interface{}, error) {
	if len(m) != 1 {
		return d.parseMultiEntryMap(m)
	} else {
		return d.parseSingleEntryMap(m)
	}
}

func (d Decoder) parseNormalArray(x []interface{}) (interface{}, error) {
	var result = make([]interface{}, len(x))

	for i, v := range x {
		var err error
		result[i], err = d.Parse(v, false)
		if err != nil {
			return nil, err
		}
	}

	return result, nil
}

func (d Decoder) parseCMap(x []interface{}) (interface{}, error) {
	var result = NewCMap()

	l := len(x)

	for i := 1; i < l; i += 2 {
		key, err := d.Parse(x[i], true)
		if err != nil {
			return nil, err
		}

		value, err := d.Parse(x[i+1], false)
		if err != nil {
			return nil, err
		}
		result.Append(key, value)
	}

	return result, nil
}

func (d Decoder) parseArrayMap(x []interface{}) (interface{}, error) {
	result := make(map[interface{}]interface{})

	l := len(x)

	for i := 1; i < l; i += 2 {
		key, err := d.Parse(x[i], true)
		if err != nil {
			return nil, err
		}

		value, err := d.Parse(x[i+1], false)
		if err != nil {
			return nil, err
		}
		result[key] = value
	}

	return result, nil
}

func (d Decoder) DecoderFor(tagid TagId) Handler {
	key := string(tagid)

	handler := d.decoders[key]
	if handler == nil {
		handler = d.decoders["unknown"]
	}
	return handler
}

func (d Decoder) parseArray(x []interface{}) (interface{}, error) {
	if len(x) == 0 {
		return x, nil
	}

	e0, err := d.Parse(x[0], false)

	if err != nil {
		return nil, err
	}

	if e0 == mapAsArray {
		return d.parseArrayMap(x)
	}

	if tagId, isTag := e0.(TagId); isTag {
		var value interface{}

		if value, err = d.Parse(x[1], false); err != nil {
			return nil, err
		}

		tv := TaggedValue{Tag: tagId, Value: value}
		valueDecoder := d.DecoderFor(tagId)
		return valueDecoder(d, tv)
	}

	return d.parseNormalArray(x)
}

func (d Decoder) parseNumber(x json.Number) (interface{}, error) {
	var s = x.String()
	var err error

	var result interface{}

	if strings.ContainsAny(s, ".Ee") {
		result, err = x.Float64()
	} else {
		result, err = x.Int64()
	}

	return result, err
}

func (d Decoder) Parse(x interface{}, asKey bool) (interface{}, error) {

	switch v := x.(type) {
	default:
		return nil, &TransitError{Message: "Unexpected type"}
	case nil:
		return v, nil

	case bool:
		return v, nil

	case json.Number:
		return d.parseNumber(v)

	case string:
		result, err := d.parseString(v)

		if err == nil && d.cache.IsCacheable(v, asKey) {
			d.cache.Write(v)
		}
		return result, err

	case map[string]interface{}:
		return d.parseMap(v)

	case []interface{}:
		return d.parseArray(v)
	}
}

// Decode decodes the next Transit value from the stream.
func (d Decoder) Decode() (interface{}, error) {
	var jsonObject interface{}
	var err = d.jsd.Decode(&jsonObject)

	if err != nil {
		return nil, err
	} else {
		return d.Parse(jsonObject, false)
	}
}

// DecodeFromString is a handly function that decodes Transit data held in a string.
func DecodeFromString(s string) (interface{}, error) {
	reader := strings.NewReader(s)
	decoder := NewDecoder(reader)
	return decoder.Decode()
}
<|endoftext|>