<commit_before>package npcChat

import (
	"log"
	"strconv"
	"sync"

	"github.com/Hucaru/Valhalla/channel"
	"github.com/Hucaru/Valhalla/character"
	"github.com/Hucaru/Valhalla/interop"
	"github.com/Hucaru/Valhalla/maplepacket"
	"github.com/Hucaru/Valhalla/nx"
	"github.com/Hucaru/Valhalla/packets"
	"github.com/mattn/anko/core"
	"github.com/mattn/anko/vm"
)

var sessionsMutex = &sync.RWMutex{}
var scriptsMutex = &sync.RWMutex{}

var sessions = make(map[interop.ClientConn]*session)
var scripts = make(map[int32]string)

func addScript(npcID int32, contents string) {
	scripts[npcID] = contents
}

func removeScripts(npcID int32) {
	delete(scripts, npcID)
}

func init() {
	// Load scripts
	loadScripts()
	go watchFiles()
}

func NewSession(conn interop.ClientConn, npcID int32, char *channel.MapleCharacter) {
	var script string

	scriptsMutex.RLock()
	if _, exists := scripts[npcID]; exists {
		script = scripts[npcID]
	} else {
		script = "if state == 1 {return SendOk('I have not been scripted. Please report #b" + strconv.Itoa(int(npcID)) + "#k on map #b" + strconv.Itoa(int(char.GetCurrentMap())) + "')}"
	}
	scriptsMutex.RUnlock()

	sessionsMutex.Lock()

	sessions[conn] = &session{conn: conn,
		state:       1,
		isYes:       false,
		selection:   0,
		stringInput: "",
		intInput:    0,
		script:      script,
		env:         vm.NewEnv(),
		npcID:       npcID}
	sessionsMutex.Unlock()

	scriptsMutex.RLock()
	sessions[conn].register(npcID, char)
	scriptsMutex.RUnlock()
}

func RemoveSession(conn interop.ClientConn) {
	sessionsMutex.Lock()
	delete(sessions, conn)
	sessionsMutex.Unlock()
}

func GetSession(conn interop.ClientConn) *session {
	scriptsMutex.RLock()
	result := sessions[conn]
	scriptsMutex.RUnlock()

	return result
}

type session struct {
	conn interop.ClientConn

	state       int
	isYes       bool
	selection   int
	stringInput string
	intInput    int
	style       int

	shopItemIndex   int16
	shopItemID      int32
	shopItemAmmount int16

	shopItems [][]int32

	script string
	env    *vm.Env
	npcID  int32
}

func (s *session) register(npcID int32, char *channel.MapleCharacter) {
	s.env.Define("SendYesNo", func(msg string) maplepacket.Packet {
		return packets.NPCChatYesNo(npcID, msg)
	})

	s.env.Define("SendOk", func(msg string) maplepacket.Packet {
		return packets.NPCChatBackNext(npcID, msg, false, false)
	})

	s.env.Define("SendNext", func(msg string) maplepacket.Packet {
		return packets.NPCChatBackNext(npcID, msg, false, true)
	})

	s.env.Define("SendBackNext", func(msg string) maplepacket.Packet {
		return packets.NPCChatBackNext(npcID, msg, true, true)
	})

	s.env.Define("SendBack", func(msg string) maplepacket.Packet {
		return packets.NPCChatBackNext(npcID, msg, true, false)
	})

	s.env.Define("SendUserStringInput", func(msg, defaultInput string, minLength, maxLength int16) maplepacket.Packet {
		return packets.NPCChatUserString(npcID, msg, defaultInput, minLength, maxLength)
	})

	s.env.Define("SendUserIntInput", func(msg string, defaultInput, minLength, maxLength int32) maplepacket.Packet {
		return packets.NPCChatUserNumber(npcID, msg, defaultInput, minLength, maxLength)
	})

	s.env.Define("SendSelection", func(msg string) maplepacket.Packet {
		return packets.NPCChatSelection(npcID, msg)
	})

	s.env.Define("SendStyleWindow", func(msg string, array []interface{}) maplepacket.Packet {
		var styles []int32

		for _, i := range array {
			val, ok := i.(int64)

			if ok {
				styles = append(styles, int32(val))
			}
		}

		return packets.NPCChatStyleWindow(npcID, msg, styles)
	})

	s.env.Define("SendShop", func(items []interface{}) maplepacket.Packet {
		tmp := make([][]int32, len(items))

		for i, v := range items {
			val := v.([]interface{})
			tmp[i] = []int32{}
			for _, j := range val {
				tmp[i] = append(tmp[i], int32(j.(int64)))
			}
		}
		s.shopItems = tmp

		return packets.NPCShop(npcID, tmp)
	})

	s.env.Define("SendPacketToMap", channel.Maps.GetMap(char.GetCurrentMap()).SendPacket)

	s.env.Define("state", &s.state)
	s.env.Define("isYes", &s.isYes)
	s.env.Define("selection", &s.selection)
	s.env.Define("stringInput", &s.stringInput)
	s.env.Define("intInput", &s.intInput)
	s.env.Define("style", &s.style)
	s.env.Define("shopItemIndex", &s.shopItemIndex)
	s.env.Define("shopItemID", &s.shopItemID)
	s.env.Define("shopItemAmmount", &s.shopItemAmmount)

	s.env.Define("player", char)
	s.env.Define("maps", &channel.Maps)

}

func (s *session) Run() {
	core.Import(s.env)
	packet, err := s.env.Execute(s.script)

	if err != nil {
		log.Println(err)
	}

	p, ok := packet.(maplepacket.Packet)

	if ok {
		s.conn.Write(p)
	} else {
		s.state = 1 // should probably delete the session here
	}
}

func (s *session) Continue(msgType byte, stateChange byte, reader maplepacket.Reader) {

	if s.state == 0 {

	} else {

		switch msgType {
		case 0:
			if stateChange == 1 {
				s.state += 1
			} else if stateChange == 0xFF {
				s.state = 0
			} else {
				s.state -= 1
			}

		case 1:
			s.state += 1
			if stateChange == 0 {
				s.isYes = false
			} else {
				s.isYes = true
			}

		case 2:
			s.state += 1

			if len(reader.GetRestAsBytes()) > 0 {
				s.stringInput = string(reader.GetRestAsBytes())
			} else {
				s.state = 0
			}

		case 3:
			s.state += 1

			if len(reader.GetRestAsBytes()) > 0 {
				s.intInput = int(reader.ReadUint32())
			} else {
				s.state = 0
			}

		case 4:
			s.state += 1

			if len(reader.GetRestAsBytes()) > 3 {
				s.selection = int(reader.ReadUint32())
			} else {
				s.state = 0
			}

		case 5:
			s.state += 1

			// need to do

		default:
			log.Println("Unkown npc msg type:", msgType)
		}

		s.Run()
	}
}

func (s *session) Shop(reader maplepacket.Reader) {
	operation := reader.ReadByte() // ?

	s.state += 1

	switch operation {
	case 0: // Buy item
		s.shopItemIndex = reader.ReadUint16()
		s.shopItemID = reader.ReadUint32()
		s.shopItemAmmount = reader.ReadUint16()

		for ind, info := range s.shopItems {
			if int16(ind) == (s.shopItemIndex) && info[0] == s.shopItemID {
				channel.Players.OnCharacterFromConn(s.conn, func(char *channel.MapleCharacter) {
					price := nx.Items[info[0]].Price

					if len(info) == 2 {
						price = info[1] * int32(s.shopItemAmmount)
					}

					if price > char.GetMesos() {
						// client is supposed to protect against this
					} else {
						char.TakeMesos(price)

						for i := int16(0); i < s.shopItemAmmount; i++ {
							char.GiveItem(character.CreateItemFromID(info[0], false)) // these do nothing for now
						}
					}
				})
			}
		}
	case 1: // sell item
		slotID := reader.ReadInt16()
		itemID := reader.ReadUint32()
		ammount := reader.ReadUint16()

		channel.Players.OnCharacterFromConn(s.conn, func(char *channel.MapleCharacter) {
			for _, item := range char.GetItems() {
				if item.GetItemID() == itemID && item.GetSlotID() == slotID {
					if ammount > int16(item.GetAmount()) {
						break
					}

					char.TakeItem(item.GetInvID(), slotID, ammount)
					char.GiveMesos(nx.Items[itemID].Price * int32(ammount))
					break
				}
			}
		})
	case 2: // recharge
		slotID := reader.ReadInt16()

		channel.Players.OnCharacterFromConn(s.conn, func(char *channel.MapleCharacter) {
			for _, item := range char.GetItems() {
				if item.GetInvID() == 2 && item.GetSlotID() == slotID && nx.IsRechargeAble(item.GetItemID()) {
					price := int32(nx.Items[item.GetItemID()].UnitPrice * float64(nx.Items[item.GetItemID()].SlotMax))

					if price > char.GetMesos() {
						s.conn.Write(packets.NPCShopNotEnoughMesos())
					} else {
						item.SetAmount(int16(nx.Items[item.GetItemID()].SlotMax))
						char.GiveItem(item)
						char.TakeMesos(price)
					}
				}
			}
		})
	case 3:
		// closed window, nothing to handle here, state system takes care of it
	default:
		log.Println("Unkown shop operation:", operation, reader)
	}

	s.Run()
}

func (s *session) Storage(reader maplepacket.Reader) {

}
<commit_msg>Removed redundant file<commit_after><|endoftext|>


<commit_before>package ataman

import (
	"github.com/workanator/go-ataman/decorate"
	"github.com/workanator/go-ataman/decorate/basic"
)

// BasicStyle returns teh basic decoration style.
func BasicStyle() decorate.Style {
	return basic.Style()
}
<commit_msg>Add curly style creation function<commit_after>package ataman

import (
	"github.com/workanator/go-ataman/decorate"
	"github.com/workanator/go-ataman/decorate/basic"
	"github.com/workanator/go-ataman/decorate/curly"
)

// BasicStyle returns the basic decoration style.
// Quick example: `<bold,light+green,bg:black>`
func BasicStyle() decorate.Style {
	return basic.Style()
}

// CurlyStyle returns the curly brackets decoration style.
// Quick example: `{bold+light_green+bg_black}`
func CurlyStyle() decorate.Style {
	return curly.Style()
}
<|endoftext|>


<commit_before>package core

import (
	"net/http"

	"github.com/gorilla/mux"
)

/*
	Handle HTTP requests
*/
func HTTPMatcher(r *http.Request, rm *mux.RouteMatch) bool {
	l.Verbose("Request URI:", r.RequestURI)
	return true
}

/*
	Run HTTP Server
*/
func RunHTTPServer() {
	r0 := mux.NewRouter()
	r1 := r0.Methods("GET").Subrouter()
	r2 := r1.MatcherFunc(HTTPMatcher).Subrouter()

	r2.HandleFunc("/info", HTTPHandlerInfo)
	r2.HandleFunc("/list", HTTPHandlerList)
	http.Handle("/", r0)

	http.ListenAndServe(DGConfig.DockerGuard.ListenInterface+":"+DGConfig.DockerGuard.ListenPort, r0)
}
<commit_msg>Better names<commit_after>package core

import (
	"net/http"

	"github.com/gorilla/mux"
)

/*
	Handle HTTP requests
*/
func HTTPMatcher(r *http.Request, rm *mux.RouteMatch) bool {
	l.Verbose("Request URI:", r.RequestURI)
	return true
}

/*
	Run HTTP Server
*/
func RunHTTPServer() {
	r := mux.NewRouter().MatcherFunc(HTTPMatcher).Subrouter()
	r_GET := r.Methods("GET").Subrouter()

	r_GET.HandleFunc("/info", HTTPHandlerInfo)
	r_GET.HandleFunc("/list", HTTPHandlerList)
	http.Handle("/", r)

	http.ListenAndServe(DGConfig.DockerGuard.ListenInterface+":"+DGConfig.DockerGuard.ListenPort, r)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"fmt"
	"os"
	"time"
    "github.com/garyburd/redigo/redis"
	"encoding/json"
	"flag"
	"unicode"
	"strings"
)

type Event struct {
	Entity	string `json:"entity"`
	Check	string `json:"check"`
	Type	string `json:"type"`
	State	string `json:"state"`
	Summary	string `json:"summary"`
	Time	int64  `json:"time"`
}

func (e Event) IsValid() (bool, string) {
	if len(e.Entity)  == 0 { return false, "No entity" }
	if len(e.Check)   == 0 { return false, "No check" }
	if len(e.State)   == 0 { return false, "No state" }
	if len(e.Summary) == 0 { return false, "No summary" }
	return true, "ok"
}

func submit(conn redis.Conn, event *Event) (interface{}) {
	valid, err := event.IsValid()
	if valid {
	    data, _ := json.Marshal(event)
		reply, err := conn.Do("LPUSH", "events", data)
		if err != nil {
			log.Println(reply)
			log.Println(err)
			os.Exit(2)
		}

		return reply
	} else {
		log.Println("Error: Invalid event:", err)
		return false
	}
}

func main() {

	entity   := flag.String("e", "", "Entity name")
	check    := flag.String("c", "", "Check name")
	state    := flag.String("s", "", "Current state")
	summary  := flag.String("u", "", "Summary of event")
	interval := flag.String("i", "0s", "How often event should be submitted e.g. 1s, 20ms")
	debug    := flag.Bool("v", false, "Turn on debugging messages")
	address  := flag.String("a", "localhost:6380", "Redis instance to connect to")
	database := flag.Int("d", 0, "Redis database to connect to")
    flag.Parse()

	if *debug {
		fmt.Println("entity:", *entity)
		fmt.Println("check:", *check)
		fmt.Println("state:", *state)
		fmt.Println("summary:", *summary)
		fmt.Println("interval:", *interval)
	}

	addr := strings.Split(*address, ":")
	if len(addr) != 2 {
		fmt.Println("Error: invalid address specified:", *address)
		fmt.Println("Should be in format `addr:port` (e.g. 127.0.0.1:6380)")
		os.Exit(1)
	}

	conn, err := redis.Dial("tcp", *address) // Connect to Redis
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		os.Exit(1)
	}
	conn.Do("SELECT", *database) // Switch database

	event := &Event{
       	Entity: 	*entity,
		Check: 		*check,
		Type:		"service",
		State:		*state,
		Summary:	*summary,
		Time:		time.Now().Unix(),
	}
	submit(conn, event) // Submit first event

	// Determine the interval to submit events
	i := *interval
	if !unicode.IsLetter(rune(i[(len(i) - 1)])) {
		i += "s"
	}
	_interval, _ := time.ParseDuration(i)

	if _interval > 0 {
		// Loop, submit, delay by interval
		for {
			reply := submit(conn, event)
			if *debug {
				log.Println("Queue length", reply)
				log.Println("Sleeping for", _interval)
			}
			time.Sleep(_interval)
		}
	}

}
<commit_msg>Fix indentation<commit_after>package main

import (
	"log"
	"fmt"
	"os"
	"time"
	"github.com/garyburd/redigo/redis"
	"encoding/json"
	"flag"
	"unicode"
	"strings"
)

type Event struct {
	Entity	string `json:"entity"`
	Check	string `json:"check"`
	Type	string `json:"type"`
	State	string `json:"state"`
	Summary	string `json:"summary"`
	Time	int64  `json:"time"`
}

func (e Event) IsValid() (bool, string) {
	if len(e.Entity)  == 0 { return false, "No entity" }
	if len(e.Check)   == 0 { return false, "No check" }
	if len(e.State)   == 0 { return false, "No state" }
	if len(e.Summary) == 0 { return false, "No summary" }
	return true, "ok"
}

func submit(conn redis.Conn, event *Event) (interface{}) {
	valid, err := event.IsValid()
	if valid {
		data, _ := json.Marshal(event)
		reply, err := conn.Do("LPUSH", "events", data)
		if err != nil {
			log.Println(reply)
			log.Println(err)
			os.Exit(2)
		}

		return reply
	} else {
		log.Println("Error: Invalid event:", err)
		return false
	}
}

func main() {

	entity   := flag.String("e", "", "Entity name")
	check    := flag.String("c", "", "Check name")
	state    := flag.String("s", "", "Current state")
	summary  := flag.String("u", "", "Summary of event")
	interval := flag.String("i", "0s", "How often event should be submitted e.g. 1s, 20ms")
	debug    := flag.Bool("v", false, "Turn on debugging messages")
	address  := flag.String("a", "localhost:6380", "Redis instance to connect to")
	database := flag.Int("d", 0, "Redis database to connect to")
	flag.Parse()

	if *debug {
		fmt.Println("entity:", *entity)
		fmt.Println("check:", *check)
		fmt.Println("state:", *state)
		fmt.Println("summary:", *summary)
		fmt.Println("interval:", *interval)
	}

	addr := strings.Split(*address, ":")
	if len(addr) != 2 {
		fmt.Println("Error: invalid address specified:", *address)
		fmt.Println("Should be in format `addr:port` (e.g. 127.0.0.1:6380)")
		os.Exit(1)
	}

	conn, err := redis.Dial("tcp", *address) // Connect to Redis
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		os.Exit(1)
	}
	conn.Do("SELECT", *database) // Switch database

	event := &Event{
		Entity: 	*entity,
		Check: 		*check,
		Type:		"service",
		State:		*state,
		Summary:	*summary,
		Time:		time.Now().Unix(),
	}
	submit(conn, event) // Submit first event

	// Determine the interval to submit events
	i := *interval
	if !unicode.IsLetter(rune(i[(len(i) - 1)])) {
		i += "s"
	}
	_interval, _ := time.ParseDuration(i)

	if _interval > 0 {
		// Loop, submit, delay by interval
		for {
			reply := submit(conn, event)
			if *debug {
				log.Println("Queue length", reply)
				log.Println("Sleeping for", _interval)
			}
			time.Sleep(_interval)
		}
	}

}
<|endoftext|>


<commit_before>package router

import (
	"strings"

	"github.com/kataras/iris/v12/context"
)

const (
	// ParamStart the character in string representation where the underline router starts its dynamic named parameter.
	ParamStart = ":"
	// paramStartCharacter is the character as rune of ParamStart.
	paramStartCharacter = ':'
	// WildcardParamStart the character in string representation where the underline router starts its dynamic wildcard
	// path parameter.
	WildcardParamStart = "*"
	// wildcardParamStartCharacter is the character as rune of WildcardParamStart.
	wildcardParamStartCharacter = '*'
)

// An iris-specific identical version of the https://github.com/kataras/muxie version 1.0.0 released at 15 Oct 2018
type trieNode struct {
	parent *trieNode

	children               map[string]*trieNode
	hasDynamicChild        bool     // does one of the children contains a parameter or wildcard?
	childNamedParameter    bool     // is the child a named parameter (single segmnet)
	childWildcardParameter bool     // or it is a wildcard (can be more than one path segments) ?
	paramKeys              []string // the param keys without : or *.
	end                    bool     // it is a complete node, here we stop and we can say that the node is valid.
	key                    string   // if end == true then key is filled with the original value of the insertion's key.
	// if key != "" && its parent has childWildcardParameter == true,
	// we need it to track the static part for the closest-wildcard's parameter storage.
	staticKey string

	// insert data.
	Route    context.RouteReadOnly
	Handlers context.Handlers
}

func newTrieNode() *trieNode {
	n := new(trieNode)
	return n
}

func (tn *trieNode) hasChild(s string) bool {
	return tn.getChild(s) != nil
}

func (tn *trieNode) getChild(s string) *trieNode {
	if tn.children == nil {
		return nil
	}

	return tn.children[s]
}

func (tn *trieNode) addChild(s string, n *trieNode) {
	if tn.children == nil {
		tn.children = make(map[string]*trieNode)
	}

	if _, exists := tn.children[s]; exists {
		return
	}

	n.parent = tn
	tn.children[s] = n
}

func (tn *trieNode) findClosestParentWildcardNode() *trieNode {
	tn = tn.parent
	for tn != nil {
		if tn.childWildcardParameter {
			return tn.getChild(WildcardParamStart)
		}

		tn = tn.parent
	}

	return nil
}

func (tn *trieNode) String() string {
	return tn.key
}

type trie struct {
	root *trieNode

	// if true then it will handle any path if not other parent wildcard exists,
	// so even 404 (on http services) is up to it, see trie#insert.
	hasRootWildcard bool
	hasRootSlash    bool

	statusCode int // for error codes only, method is ignored.
	method     string

	// subdomain is empty for default-hostname routes,
	// ex: mysubdomain.
	subdomain string
}

const (
	pathSep  = "/"
	pathSepB = '/'
)

func slowPathSplit(path string) []string {
	if path == "/" {
		return []string{"/"}
	}

	return strings.Split(path, pathSep)[1:]
}

func (tr *trie) insert(path string, route context.RouteReadOnly, handlers context.Handlers) {
	input := slowPathSplit(path)
	if len(input) == 0 {
		return
	}

	n := tr.root
	if path == pathSep {
		tr.hasRootSlash = true
	}

	var paramKeys []string

	for _, s := range input {
		if len(s) == 0 {
			continue
		}

		c := s[0]

		if isParam, isWildcard := c == paramStartCharacter, c == wildcardParamStartCharacter; isParam || isWildcard {
			n.hasDynamicChild = true
			paramKeys = append(paramKeys, s[1:]) // without : or *.

			// if node has already a wildcard, don't force a value, check for true only.
			if isParam {
				n.childNamedParameter = true
				s = ParamStart
			}

			if isWildcard {
				n.childWildcardParameter = true
				s = WildcardParamStart
				if tr.root == n {
					tr.hasRootWildcard = true
				}
			}
		}

		if !n.hasChild(s) {
			child := newTrieNode()
			n.addChild(s, child)
		}

		n = n.getChild(s)
	}

	n.Route = route
	n.Handlers = handlers

	n.paramKeys = paramKeys
	n.key = path
	n.end = true

	i := strings.Index(path, ParamStart)
	if i == -1 {
		i = strings.Index(path, WildcardParamStart)
	}
	if i == -1 {
		i = len(n.key)
	}

	n.staticKey = path[:i]
	// fmt.Printf("trie.insert: (whole path=%v) Path: %s, Route name: %s, Handlers len: %d\n", n.end, n.key, route.Name(), len(handlers))
}

func (tr *trie) search(q string, params *context.RequestParams) *trieNode {
	end := len(q)

	if end == 0 || (end == 1 && q[0] == pathSepB) {
		// fixes only root wildcard but no / registered at.
		if tr.hasRootSlash {
			return tr.root.getChild(pathSep)
		} else if tr.hasRootWildcard {
			// no need to going through setting parameters, this one has not but it is wildcard.
			return tr.root.getChild(WildcardParamStart)
		}

		return nil
	}

	n := tr.root
	start := 1
	i := 1
	var paramValues []string

	for {
		if i == end || q[i] == pathSepB {
			segment := q[start:i]
			if child := n.getChild(segment); child != nil {
				n = child
				// Possible reserved param character, should catch it as
				// dynamic node instead of static-path based.
				if segment == ParamStart { // len(n.paramKeys) > 0 && (segment == ParamStart || segment == WildcardParamStart)
					if ln := len(paramValues); cap(paramValues) > ln {
						paramValues = paramValues[:ln+1]
						paramValues[ln] = segment
					} else {
						paramValues = append(paramValues, segment)
					}
				}
			} else if n.childNamedParameter {
				n = n.getChild(ParamStart)
				if ln := len(paramValues); cap(paramValues) > ln {
					paramValues = paramValues[:ln+1]
					paramValues[ln] = segment
				} else {
					paramValues = append(paramValues, segment)
				}
			} else if n.childWildcardParameter {
				n = n.getChild(WildcardParamStart)
				if ln := len(paramValues); cap(paramValues) > ln {
					paramValues = paramValues[:ln+1]
					paramValues[ln] = q[start:]
				} else {
					paramValues = append(paramValues, q[start:])
				}
				break
			} else {
				n = n.findClosestParentWildcardNode()
				if n != nil && len(n.paramKeys) > 0 {
					// means that it has :param/static and *wildcard, we go trhough the :param
					// but the next path segment is not the /static, so go back to *wildcard
					// instead of not found.
					//
					// Fixes:
					// /hello/*p
					// /hello/:p1/static/:p2
					// req: http://localhost:8080/hello/dsadsa/static/dsadsa => found
					// req: http://localhost:8080/hello/dsadsa => but not found!
					// and
					// /second/wild/*p
					// /second/wild/static/otherstatic/
					// req: /second/wild/static/otherstatic/random => but not found!
					params.Set(n.paramKeys[0], q[len(n.staticKey):])
					return n
				}

				return nil
			}

			if i == end {
				break
			}

			i++
			start = i
			continue
		}

		i++
	}

	if n == nil || !n.end {
		if n != nil { // we need it on both places, on last segment (below) or on the first unnknown (above).
			if n = n.findClosestParentWildcardNode(); n != nil && len(n.paramKeys) > 0 {
				params.Set(n.paramKeys[0], q[len(n.staticKey):])
				return n
			}
		}

		if tr.hasRootWildcard {
			// that's the case for root wildcard, tests are passing
			// even without it but stick with it for reference.
			// Note ote that something like:
			// Routes: /other2/*myparam and /other2/static
			// Reqs: /other2/staticed will be handled
			// the /other2/*myparam and not the root wildcard, which is what we want.
			//
			n = tr.root.getChild(WildcardParamStart)
			if len(n.paramKeys) == 0 { // fix crashes on /*/*/*.
				return nil
			}

			params.Set(n.paramKeys[0], q[1:])
			return n
		}

		return nil
	}

	for i, paramValue := range paramValues {
		if len(n.paramKeys) > i {
			params.Set(n.paramKeys[i], paramValue)
		}
	}

	return n
}
<commit_msg>router: minor improvement<commit_after>package router

import (
	"strings"

	"github.com/kataras/iris/v12/context"
)

const (
	// ParamStart the character in string representation where the underline router starts its dynamic named parameter.
	ParamStart = ":"
	// paramStartCharacter is the character as rune of ParamStart.
	paramStartCharacter = ':'
	// WildcardParamStart the character in string representation where the underline router starts its dynamic wildcard
	// path parameter.
	WildcardParamStart = "*"
	// wildcardParamStartCharacter is the character as rune of WildcardParamStart.
	wildcardParamStartCharacter = '*'
)

// An iris-specific identical version of the https://github.com/kataras/muxie version 1.0.0 released at 15 Oct 2018
type trieNode struct {
	parent *trieNode

	children               map[string]*trieNode
	hasDynamicChild        bool     // does one of the children contains a parameter or wildcard?
	childNamedParameter    bool     // is the child a named parameter (single segmnet)
	childWildcardParameter bool     // or it is a wildcard (can be more than one path segments) ?
	paramKeys              []string // the param keys without : or *.
	end                    bool     // it is a complete node, here we stop and we can say that the node is valid.
	key                    string   // if end == true then key is filled with the original value of the insertion's key.
	// if key != "" && its parent has childWildcardParameter == true,
	// we need it to track the static part for the closest-wildcard's parameter storage.
	staticKey string

	// insert data.
	Route    context.RouteReadOnly
	Handlers context.Handlers
}

func newTrieNode() *trieNode {
	n := new(trieNode)
	return n
}

func (tn *trieNode) hasChild(s string) bool {
	return tn.getChild(s) != nil
}

func (tn *trieNode) getChild(s string) *trieNode {
	if tn.children == nil {
		return nil
	}

	return tn.children[s]
}

func (tn *trieNode) addChild(s string, n *trieNode) {
	if tn.children == nil {
		tn.children = make(map[string]*trieNode)
	}

	if _, exists := tn.children[s]; exists {
		return
	}

	n.parent = tn
	tn.children[s] = n
}

func (tn *trieNode) findClosestParentWildcardNode() *trieNode {
	tn = tn.parent
	for tn != nil {
		if tn.childWildcardParameter {
			return tn.getChild(WildcardParamStart)
		}

		tn = tn.parent
	}

	return nil
}

func (tn *trieNode) String() string {
	return tn.key
}

type trie struct {
	root *trieNode

	// if true then it will handle any path if not other parent wildcard exists,
	// so even 404 (on http services) is up to it, see trie#insert.
	hasRootWildcard bool
	hasRootSlash    bool

	statusCode int // for error codes only, method is ignored.
	method     string

	// subdomain is empty for default-hostname routes,
	// ex: mysubdomain.
	subdomain string
}

const (
	pathSep  = "/"
	pathSepB = '/'
)

func slowPathSplit(path string) []string {
	if path == "/" {
		return []string{"/"}
	}

	return strings.Split(path, pathSep)[1:]
}

func (tr *trie) insert(path string, route context.RouteReadOnly, handlers context.Handlers) {
	input := slowPathSplit(path)
	if len(input) == 0 {
		return
	}

	n := tr.root
	if path == pathSep {
		tr.hasRootSlash = true
	}

	var paramKeys []string

	for i, s := range input {
		if len(s) == 0 {
			continue
		}

		c := s[0]

		if len(s)-1 > i+1 && s[i+1] != '/' { // has next character and it's not slash.
			// get the next character, if not slash then this is a parameter.
			// E.g:
			// If /test/:param (or /test/*param) then it's dynamic.
			// If /test/: (or /test/*) then it's static.
			if c == paramStartCharacter {
				n.childNamedParameter = true
				s = ParamStart
			} else if c == wildcardParamStartCharacter {
				n.childWildcardParameter = true
				s = WildcardParamStart
				if tr.root == n {
					tr.hasRootWildcard = true
				}
			}
		}

		if !n.hasChild(s) {
			child := newTrieNode()
			n.addChild(s, child)
		}

		n = n.getChild(s)
	}

	n.Route = route
	n.Handlers = handlers

	n.paramKeys = paramKeys
	n.key = path
	n.end = true

	i := strings.Index(path, ParamStart)
	if i == -1 {
		i = strings.Index(path, WildcardParamStart)
	}
	if i == -1 {
		i = len(n.key)
	}

	n.staticKey = path[:i]
	// fmt.Printf("trie.insert: (whole path=%v) Path: %s, Route name: %s, Handlers len: %d\n", n.end, n.key, route.Name(), len(handlers))
}

func (tr *trie) search(q string, params *context.RequestParams) *trieNode {
	end := len(q)

	if end == 0 || (end == 1 && q[0] == pathSepB) {
		// fixes only root wildcard but no / registered at.
		if tr.hasRootSlash {
			return tr.root.getChild(pathSep)
		} else if tr.hasRootWildcard {
			// no need to going through setting parameters, this one has not but it is wildcard.
			return tr.root.getChild(WildcardParamStart)
		}

		return nil
	}

	n := tr.root
	start := 1
	i := 1
	var paramValues []string

	for {
		if i == end || q[i] == pathSepB {
			segment := q[start:i]
			if child := n.getChild(segment); child != nil {
				n = child
			} else if n.childNamedParameter {
				n = n.getChild(ParamStart)
				if ln := len(paramValues); cap(paramValues) > ln {
					paramValues = paramValues[:ln+1]
					paramValues[ln] = segment
				} else {
					paramValues = append(paramValues, segment)
				}
			} else if n.childWildcardParameter {
				n = n.getChild(WildcardParamStart)
				if ln := len(paramValues); cap(paramValues) > ln {
					paramValues = paramValues[:ln+1]
					paramValues[ln] = q[start:]
				} else {
					paramValues = append(paramValues, q[start:])
				}
				break
			} else {
				n = n.findClosestParentWildcardNode()
				if n != nil && len(n.paramKeys) > 0 {
					// means that it has :param/static and *wildcard, we go trhough the :param
					// but the next path segment is not the /static, so go back to *wildcard
					// instead of not found.
					//
					// Fixes:
					// /hello/*p
					// /hello/:p1/static/:p2
					// req: http://localhost:8080/hello/dsadsa/static/dsadsa => found
					// req: http://localhost:8080/hello/dsadsa => but not found!
					// and
					// /second/wild/*p
					// /second/wild/static/otherstatic/
					// req: /second/wild/static/otherstatic/random => but not found!
					params.Set(n.paramKeys[0], q[len(n.staticKey):])
					return n
				}

				return nil
			}

			if i == end {
				break
			}

			i++
			start = i
			continue
		}

		i++
	}

	if n == nil || !n.end {
		if n != nil { // we need it on both places, on last segment (below) or on the first unnknown (above).
			if n = n.findClosestParentWildcardNode(); n != nil && len(n.paramKeys) > 0 {
				params.Set(n.paramKeys[0], q[len(n.staticKey):])
				return n
			}
		}

		if tr.hasRootWildcard {
			// that's the case for root wildcard, tests are passing
			// even without it but stick with it for reference.
			// Note ote that something like:
			// Routes: /other2/*myparam and /other2/static
			// Reqs: /other2/staticed will be handled
			// the /other2/*myparam and not the root wildcard, which is what we want.
			//
			n = tr.root.getChild(WildcardParamStart)
			if len(n.paramKeys) == 0 { // fix crashes on /*/*/*.
				return nil
			}

			params.Set(n.paramKeys[0], q[1:])
			return n
		}

		return nil
	}

	for i, paramValue := range paramValues {
		if len(n.paramKeys) > i {
			params.Set(n.paramKeys[i], paramValue)
		}
	}

	return n
}
<|endoftext|>


<commit_before>package router

import (
	"strings"

	"github.com/kataras/iris/context"
)

const (
	// ParamStart the character in string representation where the underline router starts its dynamic named parameter.
	ParamStart = ":"
	// WildcardParamStart the character in string representation where the underline router starts its dynamic wildcard
	// path parameter.
	WildcardParamStart = "*"
)

// An iris-specific identical version of the https://github.com/kataras/muxie version 1.0.0 released at 15 Oct 2018
type trieNode struct {
	parent *trieNode

	children               map[string]*trieNode
	hasDynamicChild        bool     // does one of the children contains a parameter or wildcard?
	childNamedParameter    bool     // is the child a named parameter (single segmnet)
	childWildcardParameter bool     // or it is a wildcard (can be more than one path segments) ?
	paramKeys              []string // the param keys without : or *.
	end                    bool     // it is a complete node, here we stop and we can say that the node is valid.
	key                    string   // if end == true then key is filled with the original value of the insertion's key.
	// if key != "" && its parent has childWildcardParameter == true,
	// we need it to track the static part for the closest-wildcard's parameter storage.
	staticKey string

	// insert data.
	Handlers  context.Handlers
	RouteName string
}

func newTrieNode() *trieNode {
	n := new(trieNode)
	return n
}

func (tn *trieNode) hasChild(s string) bool {
	return tn.getChild(s) != nil
}

func (tn *trieNode) getChild(s string) *trieNode {
	if tn.children == nil {
		tn.children = make(map[string]*trieNode)
	}

	return tn.children[s]
}

func (tn *trieNode) addChild(s string, n *trieNode) {
	if tn.children == nil {
		tn.children = make(map[string]*trieNode)
	}

	if _, exists := tn.children[s]; exists {
		return
	}

	n.parent = tn
	tn.children[s] = n
}

func (tn *trieNode) findClosestParentWildcardNode() *trieNode {
	tn = tn.parent
	for tn != nil {
		if tn.childWildcardParameter {
			return tn.getChild(WildcardParamStart)
		}

		tn = tn.parent
	}

	return nil
}

func (tn *trieNode) String() string {
	return tn.key
}

type trie struct {
	root *trieNode

	// if true then it will handle any path if not other parent wildcard exists,
	// so even 404 (on http services) is up to it, see trie#insert.
	hasRootWildcard bool

	method string
	// subdomain is empty for default-hostname routes,
	// ex: mysubdomain.
	subdomain string
}

func newTrie() *trie {
	return &trie{
		root: newTrieNode(),
	}
}

const (
	pathSep  = "/"
	pathSepB = '/'
)

func slowPathSplit(path string) []string {
	if path == "/" {
		return []string{"/"}
	}

	return strings.Split(path, pathSep)[1:]
}

func (tr *trie) insert(path, routeName string, handlers context.Handlers) {
	input := slowPathSplit(path)

	n := tr.root
	var paramKeys []string

	for _, s := range input {
		c := s[0]

		if isParam, isWildcard := c == ParamStart[0], c == WildcardParamStart[0]; isParam || isWildcard {
			n.hasDynamicChild = true
			paramKeys = append(paramKeys, s[1:]) // without : or *.

			// if node has already a wildcard, don't force a value, check for true only.
			if isParam {
				n.childNamedParameter = true
				s = ParamStart
			}

			if isWildcard {
				n.childWildcardParameter = true
				s = WildcardParamStart
				if tr.root == n {
					tr.hasRootWildcard = true
				}
			}
		}

		if !n.hasChild(s) {
			child := newTrieNode()
			n.addChild(s, child)
		}

		n = n.getChild(s)
	}

	n.RouteName = routeName
	n.Handlers = handlers
	n.paramKeys = paramKeys
	n.key = path
	n.end = true

	i := strings.Index(path, ParamStart)
	if i == -1 {
		i = strings.Index(path, WildcardParamStart)
	}
	if i == -1 {
		i = len(n.key)
	}

	n.staticKey = path[:i]
}

func (tr *trie) search(q string, params *context.RequestParams) *trieNode {
	end := len(q)

	if end == 0 || (end == 1 && q[0] == pathSepB) {
		return tr.root.getChild(pathSep)
	}

	n := tr.root
	start := 1
	i := 1
	var paramValues []string

	for {
		if i == end || q[i] == pathSepB {
			if child := n.getChild(q[start:i]); child != nil {
				n = child
			} else if n.childNamedParameter {
				n = n.getChild(ParamStart)
				if ln := len(paramValues); cap(paramValues) > ln {
					paramValues = paramValues[:ln+1]
					paramValues[ln] = q[start:i]
				} else {
					paramValues = append(paramValues, q[start:i])
				}
			} else if n.childWildcardParameter {
				n = n.getChild(WildcardParamStart)
				if ln := len(paramValues); cap(paramValues) > ln {
					paramValues = paramValues[:ln+1]
					paramValues[ln] = q[start:]
				} else {
					paramValues = append(paramValues, q[start:])
				}
				break
			} else {
				n = n.findClosestParentWildcardNode()
				if n != nil {
					// means that it has :param/static and *wildcard, we go trhough the :param
					// but the next path segment is not the /static, so go back to *wildcard
					// instead of not found.
					//
					// Fixes:
					// /hello/*p
					// /hello/:p1/static/:p2
					// req: http://localhost:8080/hello/dsadsa/static/dsadsa => found
					// req: http://localhost:8080/hello/dsadsa => but not found!
					// and
					// /second/wild/*p
					// /second/wild/static/otherstatic/
					// req: /second/wild/static/otherstatic/random => but not found!
					params.Set(n.paramKeys[0], q[len(n.staticKey):])
					return n
				}

				return nil
			}

			if i == end {
				break
			}

			i++
			start = i
			continue
		}

		i++
	}

	if n == nil || !n.end {
		if n != nil { // we need it on both places, on last segment (below) or on the first unnknown (above).
			if n = n.findClosestParentWildcardNode(); n != nil {
				params.Set(n.paramKeys[0], q[len(n.staticKey):])
				return n
			}
		}

		if tr.hasRootWildcard {
			// that's the case for root wildcard, tests are passing
			// even without it but stick with it for reference.
			// Note ote that something like:
			// Routes: /other2/*myparam and /other2/static
			// Reqs: /other2/staticed will be handled
			// the /other2/*myparam and not the root wildcard, which is what we want.
			//
			n = tr.root.getChild(WildcardParamStart)
			params.Set(n.paramKeys[0], q[1:])
			return n
		}

		return nil
	}

	for i, paramValue := range paramValues {
		if len(n.paramKeys) > i {
			params.Set(n.paramKeys[i], paramValue)
		}
	}

	return n
}
<commit_msg>internal router improvement as a result of kataras/muxie sync for latest v11<commit_after>package router

import (
	"strings"

	"github.com/kataras/iris/context"
)

const (
	// ParamStart the character in string representation where the underline router starts its dynamic named parameter.
	ParamStart = ":"
	// WildcardParamStart the character in string representation where the underline router starts its dynamic wildcard
	// path parameter.
	WildcardParamStart = "*"
)

// An iris-specific identical version of the https://github.com/kataras/muxie version 1.0.0 released at 15 Oct 2018
type trieNode struct {
	parent *trieNode

	children               map[string]*trieNode
	hasDynamicChild        bool     // does one of the children contains a parameter or wildcard?
	childNamedParameter    bool     // is the child a named parameter (single segmnet)
	childWildcardParameter bool     // or it is a wildcard (can be more than one path segments) ?
	paramKeys              []string // the param keys without : or *.
	end                    bool     // it is a complete node, here we stop and we can say that the node is valid.
	key                    string   // if end == true then key is filled with the original value of the insertion's key.
	// if key != "" && its parent has childWildcardParameter == true,
	// we need it to track the static part for the closest-wildcard's parameter storage.
	staticKey string

	// insert data.
	Handlers  context.Handlers
	RouteName string
}

func newTrieNode() *trieNode {
	n := new(trieNode)
	return n
}

func (tn *trieNode) hasChild(s string) bool {
	return tn.getChild(s) != nil
}

func (tn *trieNode) getChild(s string) *trieNode {
	if tn.children == nil {
		return nil
	}

	return tn.children[s]
}

func (tn *trieNode) addChild(s string, n *trieNode) {
	if tn.children == nil {
		tn.children = make(map[string]*trieNode)
	}

	if _, exists := tn.children[s]; exists {
		return
	}

	n.parent = tn
	tn.children[s] = n
}

func (tn *trieNode) findClosestParentWildcardNode() *trieNode {
	tn = tn.parent
	for tn != nil {
		if tn.childWildcardParameter {
			return tn.getChild(WildcardParamStart)
		}

		tn = tn.parent
	}

	return nil
}

func (tn *trieNode) String() string {
	return tn.key
}

type trie struct {
	root *trieNode

	// if true then it will handle any path if not other parent wildcard exists,
	// so even 404 (on http services) is up to it, see trie#insert.
	hasRootWildcard bool
	hasRootSlash    bool

	method string
	// subdomain is empty for default-hostname routes,
	// ex: mysubdomain.
	subdomain string
}

func newTrie() *trie {
	return &trie{
		root: newTrieNode(),
	}
}

const (
	pathSep  = "/"
	pathSepB = '/'
)

func slowPathSplit(path string) []string {
	if path == "/" {
		return []string{"/"}
	}

	return strings.Split(path, pathSep)[1:]
}

func (tr *trie) insert(path, routeName string, handlers context.Handlers) {
	input := slowPathSplit(path)

	n := tr.root
	if path == pathSep {
		tr.hasRootSlash = true
	}

	var paramKeys []string

	for _, s := range input {
		c := s[0]

		if isParam, isWildcard := c == ParamStart[0], c == WildcardParamStart[0]; isParam || isWildcard {
			n.hasDynamicChild = true
			paramKeys = append(paramKeys, s[1:]) // without : or *.

			// if node has already a wildcard, don't force a value, check for true only.
			if isParam {
				n.childNamedParameter = true
				s = ParamStart
			}

			if isWildcard {
				n.childWildcardParameter = true
				s = WildcardParamStart
				if tr.root == n {
					tr.hasRootWildcard = true
				}
			}
		}

		if !n.hasChild(s) {
			child := newTrieNode()
			n.addChild(s, child)
		}

		n = n.getChild(s)
	}

	n.RouteName = routeName
	n.Handlers = handlers
	n.paramKeys = paramKeys
	n.key = path
	n.end = true

	i := strings.Index(path, ParamStart)
	if i == -1 {
		i = strings.Index(path, WildcardParamStart)
	}
	if i == -1 {
		i = len(n.key)
	}

	n.staticKey = path[:i]
}

func (tr *trie) search(q string, params *context.RequestParams) *trieNode {
	end := len(q)

	if end == 0 || (end == 1 && q[0] == pathSepB) {
		// fixes only root wildcard but no / registered at.
		if tr.hasRootSlash {
			return tr.root.getChild(pathSep)
		} else if tr.hasRootWildcard {
			// no need to going through setting parameters, this one has not but it is wildcard.
			return tr.root.getChild(WildcardParamStart)
		}

		return nil
	}

	n := tr.root
	start := 1
	i := 1
	var paramValues []string

	for {
		if i == end || q[i] == pathSepB {
			if child := n.getChild(q[start:i]); child != nil {
				n = child
			} else if n.childNamedParameter {
				n = n.getChild(ParamStart)
				if ln := len(paramValues); cap(paramValues) > ln {
					paramValues = paramValues[:ln+1]
					paramValues[ln] = q[start:i]
				} else {
					paramValues = append(paramValues, q[start:i])
				}
			} else if n.childWildcardParameter {
				n = n.getChild(WildcardParamStart)
				if ln := len(paramValues); cap(paramValues) > ln {
					paramValues = paramValues[:ln+1]
					paramValues[ln] = q[start:]
				} else {
					paramValues = append(paramValues, q[start:])
				}
				break
			} else {
				n = n.findClosestParentWildcardNode()
				if n != nil {
					// means that it has :param/static and *wildcard, we go trhough the :param
					// but the next path segment is not the /static, so go back to *wildcard
					// instead of not found.
					//
					// Fixes:
					// /hello/*p
					// /hello/:p1/static/:p2
					// req: http://localhost:8080/hello/dsadsa/static/dsadsa => found
					// req: http://localhost:8080/hello/dsadsa => but not found!
					// and
					// /second/wild/*p
					// /second/wild/static/otherstatic/
					// req: /second/wild/static/otherstatic/random => but not found!
					params.Set(n.paramKeys[0], q[len(n.staticKey):])
					return n
				}

				return nil
			}

			if i == end {
				break
			}

			i++
			start = i
			continue
		}

		i++
	}

	if n == nil || !n.end {
		if n != nil { // we need it on both places, on last segment (below) or on the first unnknown (above).
			if n = n.findClosestParentWildcardNode(); n != nil {
				params.Set(n.paramKeys[0], q[len(n.staticKey):])
				return n
			}
		}

		if tr.hasRootWildcard {
			// that's the case for root wildcard, tests are passing
			// even without it but stick with it for reference.
			// Note ote that something like:
			// Routes: /other2/*myparam and /other2/static
			// Reqs: /other2/staticed will be handled
			// the /other2/*myparam and not the root wildcard, which is what we want.
			//
			n = tr.root.getChild(WildcardParamStart)
			params.Set(n.paramKeys[0], q[1:])
			return n
		}

		return nil
	}

	for i, paramValue := range paramValues {
		if len(n.paramKeys) > i {
			params.Set(n.paramKeys[i], paramValue)
		}
	}

	return n
}
<|endoftext|>


<commit_before>// Sudoku is a generic solver for sudoku type puzzles. It can solve a puzzle of any shape and size.
package sudoku

var (
	s4 = [][]int{
		{0, 1, 2, 3},
		{4, 5, 6, 7},
		{8, 9, 10, 11},
		{12, 13, 14, 15},
		{0, 4, 8, 12},
		{1, 5, 9, 13},
		{2, 6, 10, 14},
		{3, 7, 11, 15},
		{0, 1, 4, 5},
		{2, 3, 6, 7},
		{8, 9, 12, 13},
		{10, 11, 14, 15},
	}
	c4 = []int{1, 2, 3, 4}
	s9 = [][]int{
		{0, 1, 2, 3, 4, 5, 6, 7, 8},
		{9, 10, 11, 12, 13, 14, 15, 16, 17},
		{18, 19, 20, 21, 22, 23, 24, 25, 26},
		{27, 28, 29, 30, 31, 32, 33, 34, 35},
		{36, 37, 38, 39, 40, 41, 42, 43, 44},
		{45, 46, 47, 48, 49, 50, 51, 52, 53},
		{54, 55, 56, 57, 58, 59, 60, 61, 62},
		{63, 64, 65, 66, 67, 68, 69, 70, 71},
		{72, 73, 74, 75, 76, 77, 78, 79, 80},
		{0, 9, 18, 27, 36, 45, 54, 63, 72},
		{1, 10, 19, 28, 37, 46, 55, 64, 73},
		{2, 11, 20, 29, 38, 47, 56, 65, 74},
		{3, 12, 21, 30, 39, 48, 57, 66, 75},
		{4, 13, 22, 31, 40, 49, 58, 67, 76},
		{5, 14, 23, 32, 41, 50, 59, 68, 77},
		{6, 15, 24, 33, 42, 51, 60, 69, 78},
		{7, 16, 25, 34, 43, 52, 61, 70, 79},
		{8, 17, 26, 35, 44, 53, 62, 71, 80},
		{0, 1, 2, 9, 10, 11, 18, 19, 20},
		{3, 4, 5, 12, 13, 14, 21, 22, 23},
		{6, 7, 8, 15, 16, 17, 24, 25, 26},
		{27, 28, 29, 36, 37, 38, 45, 46, 47},
		{30, 31, 32, 39, 40, 41, 48, 49, 50},
		{33, 34, 35, 42, 43, 44, 51, 52, 53},
		{54, 55, 56, 63, 64, 65, 72, 73, 74},
		{57, 58, 59, 66, 67, 68, 75, 76, 77},
		{60, 61, 62, 69, 70, 71, 78, 79, 80},
	}
	c9 = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
)

// A helper function to make it easier to create the sections in standard rectangular puzzles
func MakeBox(gridWidth, gridHeight, boxWidth, boxHeight int) [][]int {
	toRet := make([][]int, 0, gridWidth/boxWidth*gridHeight/boxHeight)
	for j := 0; j < gridHeight; j += boxHeight {
		for i := 0; i < gridWidth; i += boxWidth {
			thisGrid := make([]int, 0, boxWidth*boxHeight)
			for y := 0; y < boxHeight; y++ {
				for x := 0; x < boxWidth; x++ {
					thisGrid = append(thisGrid, i+x+(j+y)*gridWidth)
				}
			}
			toRet = append(toRet, thisGrid)
		}
	}
	return toRet
}

func inSlice(s []int, t int) bool {
	for _, i := range s {
		if i == t {
			return true
		}
	}
	return false
}

func removeFromSlice(s *[]int, t int) {
	a := make([]int, 0, len(*s))
	for _, i := range *s {
		if i != t {
			a = append(a, i)
		}
	}
	(*s) = a
}

// sudoku puzzle information
type sudoku struct {
	data      []int
	chars     []int
	structure [][]int
}

// A sudoku puzzle of the standard 9x9 format
func Solve9(data []int) bool {
	if len(data) != 81 {
		return false
	}
	s := &sudoku{
		data:      data,
		chars:     c9,
		structure: s9,
	}
	return s.solve()
}

// A sudoku puzzle of the 4x4 format
func Solve4(data []int) bool {
	if len(data) != 16 {
		return false
	}
	s := &sudoku{
		data:      data,
		chars:     c4,
		structure: s4,
	}
	return s.solve()
}

// Solve allows the creation of a non-standard Sudoku puzzle and solves it.
//
// data is the puzzle information, layed out left to right, then top to bottom
//
// chars is any valid 'character' the puzzle uses - 0 is used for an unfilled space
//
// structure is a slice of sections, each of which is a slice of positions, len(chars)
// in length, which describes the rows, columns, boxes or other shapes in which there
// can only be one of each character
//
// Will return true if puzzle is solveable and the solution will be stored in the data slice.
// Upon a failure, will return false and the data slice will be as original.
func Solve(data, chars []int, structure [][]int) bool {
	s := &sudoku{data, chars, structure}
	return s.solve()
}

func (s *sudoku) get(pos int) int {
	t := s.data[pos]
	if inSlice(s.chars, t) {
		return t
	}
	return 0
}

func (s *sudoku) possible(pos int) []int {
	if pos < 0 || pos > len(s.data) || s.data[pos] != 0 {
		return nil
	}
	toRet := make([]int, len(s.chars))
	copy(toRet, s.chars)
	for _, structure := range s.structure {
		if inSlice(structure, pos) {
			for _, p := range structure {
				removeFromSlice(&toRet, s.get(p))
			}
		}
	}
	return toRet
}

// Solve will solve any solveable puzzle and return whether is was sucessful.
func (s *sudoku) solve() bool {
	l := len(s.data)
	possibilities := make([][]int, l)
	var pos int
	for ; pos < l; pos++ {
		if p := s.possible(pos); p != nil {
			possibilities[pos] = p
			break
		}
	}
	for pos < l {
		if len(possibilities[pos]) == 0 {
			s.data[pos] = 0
			for pos--; pos >= 0 && len(possibilities[pos]) == 0; pos-- {
				if possibilities[pos] != nil {
					s.data[pos] = 0
				}
			}
			if pos < 0 {
				return false
			}
			continue
		}
		s.data[pos] = possibilities[pos][0]
		possibilities[pos] = possibilities[pos][1:]
		for pos++; pos < l; pos++ {
			if p := s.possible(pos); p != nil {
				possibilities[pos] = p
				break
			}
		}
	}
	return true
}
<commit_msg>Comment updates<commit_after>// Package sudoku is a generic solver for sudoku type puzzles. It can solve a puzzle of any shape and size.
package sudoku

var (
	s4 = [][]int{
		{0, 1, 2, 3},
		{4, 5, 6, 7},
		{8, 9, 10, 11},
		{12, 13, 14, 15},
		{0, 4, 8, 12},
		{1, 5, 9, 13},
		{2, 6, 10, 14},
		{3, 7, 11, 15},
		{0, 1, 4, 5},
		{2, 3, 6, 7},
		{8, 9, 12, 13},
		{10, 11, 14, 15},
	}
	c4 = []int{1, 2, 3, 4}
	s9 = [][]int{
		{0, 1, 2, 3, 4, 5, 6, 7, 8},
		{9, 10, 11, 12, 13, 14, 15, 16, 17},
		{18, 19, 20, 21, 22, 23, 24, 25, 26},
		{27, 28, 29, 30, 31, 32, 33, 34, 35},
		{36, 37, 38, 39, 40, 41, 42, 43, 44},
		{45, 46, 47, 48, 49, 50, 51, 52, 53},
		{54, 55, 56, 57, 58, 59, 60, 61, 62},
		{63, 64, 65, 66, 67, 68, 69, 70, 71},
		{72, 73, 74, 75, 76, 77, 78, 79, 80},
		{0, 9, 18, 27, 36, 45, 54, 63, 72},
		{1, 10, 19, 28, 37, 46, 55, 64, 73},
		{2, 11, 20, 29, 38, 47, 56, 65, 74},
		{3, 12, 21, 30, 39, 48, 57, 66, 75},
		{4, 13, 22, 31, 40, 49, 58, 67, 76},
		{5, 14, 23, 32, 41, 50, 59, 68, 77},
		{6, 15, 24, 33, 42, 51, 60, 69, 78},
		{7, 16, 25, 34, 43, 52, 61, 70, 79},
		{8, 17, 26, 35, 44, 53, 62, 71, 80},
		{0, 1, 2, 9, 10, 11, 18, 19, 20},
		{3, 4, 5, 12, 13, 14, 21, 22, 23},
		{6, 7, 8, 15, 16, 17, 24, 25, 26},
		{27, 28, 29, 36, 37, 38, 45, 46, 47},
		{30, 31, 32, 39, 40, 41, 48, 49, 50},
		{33, 34, 35, 42, 43, 44, 51, 52, 53},
		{54, 55, 56, 63, 64, 65, 72, 73, 74},
		{57, 58, 59, 66, 67, 68, 75, 76, 77},
		{60, 61, 62, 69, 70, 71, 78, 79, 80},
	}
	c9 = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
)

// MakeBox is a helper function to make it easier to create the sections in standard rectangular puzzles
func MakeBox(gridWidth, gridHeight, boxWidth, boxHeight int) [][]int {
	toRet := make([][]int, 0, gridWidth/boxWidth*gridHeight/boxHeight)
	for j := 0; j < gridHeight; j += boxHeight {
		for i := 0; i < gridWidth; i += boxWidth {
			thisGrid := make([]int, 0, boxWidth*boxHeight)
			for y := 0; y < boxHeight; y++ {
				for x := 0; x < boxWidth; x++ {
					thisGrid = append(thisGrid, i+x+(j+y)*gridWidth)
				}
			}
			toRet = append(toRet, thisGrid)
		}
	}
	return toRet
}

func inSlice(s []int, t int) bool {
	for _, i := range s {
		if i == t {
			return true
		}
	}
	return false
}

func removeFromSlice(s *[]int, t int) {
	a := make([]int, 0, len(*s))
	for _, i := range *s {
		if i != t {
			a = append(a, i)
		}
	}
	(*s) = a
}

// sudoku puzzle information
type sudoku struct {
	data      []int
	chars     []int
	structure [][]int
}

// Solve9 is a sudoku puzzle of the standard 9x9 format
func Solve9(data []int) bool {
	if len(data) != 81 {
		return false
	}
	s := &sudoku{
		data:      data,
		chars:     c9,
		structure: s9,
	}
	return s.solve()
}

// Solve4 is a sudoku puzzle of the 4x4 format
func Solve4(data []int) bool {
	if len(data) != 16 {
		return false
	}
	s := &sudoku{
		data:      data,
		chars:     c4,
		structure: s4,
	}
	return s.solve()
}

// Solve allows the creation of a non-standard Sudoku puzzle and solves it.
//
// data is the puzzle information, layed out left to right, then top to bottom
//
// chars is any valid 'character' the puzzle uses - 0 is used for an unfilled space
//
// structure is a slice of sections, each of which is a slice of positions, len(chars)
// in length, which describes the rows, columns, boxes or other shapes in which there
// can only be one of each character
//
// Will return true if puzzle is solveable and the solution will be stored in the data slice.
// Upon a failure, will return false and the data slice will be as original.
func Solve(data, chars []int, structure [][]int) bool {
	s := &sudoku{data, chars, structure}
	return s.solve()
}

func (s *sudoku) get(pos int) int {
	t := s.data[pos]
	if inSlice(s.chars, t) {
		return t
	}
	return 0
}

func (s *sudoku) possible(pos int) []int {
	if pos < 0 || pos > len(s.data) || s.data[pos] != 0 {
		return nil
	}
	toRet := make([]int, len(s.chars))
	copy(toRet, s.chars)
	for _, structure := range s.structure {
		if inSlice(structure, pos) {
			for _, p := range structure {
				removeFromSlice(&toRet, s.get(p))
			}
		}
	}
	return toRet
}

// Solve will solve any solveable puzzle and return whether is was sucessful.
func (s *sudoku) solve() bool {
	l := len(s.data)
	possibilities := make([][]int, l)
	var pos int
	for ; pos < l; pos++ {
		if p := s.possible(pos); p != nil {
			possibilities[pos] = p
			break
		}
	}
	for pos < l {
		if len(possibilities[pos]) == 0 {
			s.data[pos] = 0
			for pos--; pos >= 0 && len(possibilities[pos]) == 0; pos-- {
				if possibilities[pos] != nil {
					s.data[pos] = 0
				}
			}
			if pos < 0 {
				return false
			}
			continue
		}
		s.data[pos] = possibilities[pos][0]
		possibilities[pos] = possibilities[pos][1:]
		for pos++; pos < l; pos++ {
			if p := s.possible(pos); p != nil {
				possibilities[pos] = p
				break
			}
		}
	}
	return true
}
<|endoftext|>


<commit_before>package pubsub

import (
	"errors"
	"fmt"
	"github.com/Shopify/sarama"
	log "github.com/Sirupsen/logrus"
	"github.com/eclipse/paho.mqtt.golang"
	"github.com/garyburd/redigo/redis"
	"github.com/golang/protobuf/proto"
	"github.com/nats-io/go-nats"
	"ihmc.us/anglova/conn"
	"ihmc.us/anglova/msg"
	"ihmc.us/anglova/protocol"
	"ihmc.us/anglova/stats"
	"math/rand"
	"strings"
	"time"
	"sync"
	"os"
	"os/signal"
	"syscall"
	"encoding/csv"
	"strconv"
)

const StatsTopic = "stats"

type Sub struct {
	Protocol  string
	conn      conn.Conn
	statsConn conn.Conn
	ID        int32
	Topic     string
	host      string
	port      string
	statsAddr string
	statsPort string
}

//lock to sync the reading and writing operations on the below maps
var lock = sync.RWMutex{}

//PubID MsgId MsgSize sentTime
var sentTimes = make(map[int32]map[int32]map[int32]time.Time)
//PubId MsgID MsgSize SubID RcvTime
var rcvTimes = make(map[int32]map[int32]map[int32]map[int32]time.Time)

func NewSub(proto string, host string, port string, topic string, statsAddress string, statsPort string) (*Sub, error) {
	id, err := CreateNodeID()
	if err != nil {
		log.Error(err)
		id = rand.Int31()
	}
	connection, err := conn.New(proto, host, port, topic, false)
	if err != nil {
		log.Error("Error during the connection with the broker!")
		return nil, err
	}
	sConn, err := conn.New(protocol.NATS, statsAddress, statsPort, StatsTopic, true)
	if err != nil {
		log.Error("Error during the connection with the stats broker!")
		return nil, err
	}
	return &Sub{Protocol: proto,
		conn:         *connection,
		statsConn:    *sConn,
		ID:           id,
		Topic:        topic,
		host:         host,
		port:         port,
		statsAddr:    statsAddress,
		statsPort:    statsPort, }, nil
}

//stats server function
//the stat server subscribe to the sub topic to obtain the message info
//it will use the info to calculate the delayed time
func (sub Sub) SubscribeToStats() error {
        //channel to manage the CTRL-C
        signalCh := make(chan os.Signal, 1)
        signal.Notify(signalCh, syscall.SIGINT, syscall.SIGTERM)
	if sub.Protocol != protocol.NATS {
		return errors.New("SubscribeToStats only available with NATS Broker")
	}
	quit := make(chan bool)
	go handleStatInfo(&sub, quit)
	go handleStatGen(quit)
	<-signalCh
	fmt.Println("Exiting after a CTRL-C")
	return nil
}

//handle the StatsSenderTopic info
func handleStatInfo(sub *Sub, quit chan bool) error {
	sub.statsConn.NATSClient.Subscribe(StatsTopic, func(m *nats.Msg) {
		log.Info("Received stats of size: ", len(m.Data))
		s := &stats.Stats{}
		err := proto.Unmarshal(m.Data, s)
		if err != nil {
			log.Warn(" Unmarshalling error: ", err)
			return
		}
		lock.Lock()
		if s.ClientType == stats.ClientType_Publisher {
			log.Debug("Received statistics from publisher: ", s.PublisherId, s.SubscriberId, s.MessageId)
			if len(sentTimes[s.PublisherId]) == 0 {
				sentTimes[s.PublisherId] = make(map[int32]map[int32]time.Time)
			}
			if len(sentTimes[s.PublisherId][s.MessageId]) == 0 {
				sentTimes[s.PublisherId][s.MessageId] = make(map[int32]time.Time)
			}
			sentTimes[s.PublisherId][s.MessageId][s.MessageSize] = time.Now()
		} else {
			fmt.Println("Received statistics from subscriber: ", s.PublisherId, s.SubscriberId, s.MessageId)
			if len(rcvTimes[s.PublisherId]) == 0 {
				rcvTimes[s.PublisherId] = make(map[int32]map[int32]map[int32]time.Time)
			}
			if len(rcvTimes[s.PublisherId][s.MessageId]) == 0 {
				rcvTimes[s.PublisherId][s.MessageId] = make(map[int32]map[int32]time.Time)
			}
			if len(rcvTimes[s.PublisherId][s.MessageId][s.MessageSize]) == 0 {
				rcvTimes[s.PublisherId][s.MessageId][s.MessageSize] = make(map[int32]time.Time)
			}
			rcvTimes[s.PublisherId][s.MessageId][s.MessageSize][s.SubscriberId] = time.Now()
		}
		lock.Unlock()
	})
	<-quit
	return nil
}

func handleStatGen(quit chan bool) {
	//print the result on a CSV file periodically (60 seconds)
	for {
		file, err := os.Create("TimeResults.csv")
		if err != nil {
			log.Error("Impossible to create the csv File")
		}
		writer := csv.NewWriter(file)
		lock.RLock()
		for pubID, msgs := range rcvTimes {
			//log.Info("Pubs: ", msgs)
			fmt.Println("\n\nSUMMARY")
			for msgID, msgSizes := range msgs {
				for size, subs := range msgSizes {
					var totalDelayForMessage int64
					var reachedSubscribers int32
					for _, rTime := range subs {
						totalDelayForMessage += (rTime.UnixNano() - sentTimes[pubID][msgID][size].UnixNano()) / 1e6
						reachedSubscribers++
					}
					fmt.Println("PubId", pubID, "MsgId ", msgID, "MsgSize", size, "TotalDelayForMsg ", totalDelayForMessage, "ReachedSubs ", reachedSubscribers)
					res := []string{strconv.FormatInt(int64(pubID), 10), strconv.FormatInt(int64(msgID), 10), strconv.FormatInt(int64(size), 10),
							strconv.FormatInt(int64(totalDelayForMessage), 10), strconv.FormatInt(int64(reachedSubscribers), 10)}
					//log.Info("results: ", res)
					err := writer.Write(res)
					if err != nil {
						log.Error("Impossible to write on the CSV file")
					}
					writer.Flush()
				}
			}
			fmt.Println("\n\nEND SUMMARY\n\n")
		}
		file.Close()
		lock.RUnlock()
		time.Sleep(10 * time.Second)
	}
	<-quit
}
func (sub Sub) Subscribe(topic string) error {

	log.Info("Subscribe <-")

	imsgRcvCount := 0
	//this map contains the statistics per each node as defined in the struct Statistics
	//the uint32 is the identifier for the pub nodes
	statmap := make(map[int32]msg.Statistics)
	quit := make(chan bool)
	go printTestStat(statmap)
	switch sub.Protocol {
	case protocol.NATS:
		sub.conn.NATSClient.Subscribe(topic, func(m *nats.Msg) {
			handleSubTest(sub, m.Data, imsgRcvCount, statmap)
		})
		<-quit
	case protocol.RabbitMQ:
		channel := sub.conn.RabbitMQClient
		q, err := channel.QueueDeclare(
			"",    // name
			true,  // durable
			false, // delete when usused
			true,  // exclusive
			false, // no-wait
			nil,   // arguments
		)
		if err != nil {
			return errors.New("Unable to instantiate the queue")
		}
		err = channel.QueueBind(
			q.Name, // queue name
			"",     // routing key
			topic,  // exchange
			false,
			nil)
		if err != nil {
			return errors.New("Failed to bind a queue")
		}

		msgs, err := channel.Consume(
			q.Name, // queue
			"",     // consumer
			true,   // auto-ack
			false,  // exclusive
			false,  // no-local
			false,  // no-wait
			nil,    // args
		)
		if err != nil {
			return errors.New("Failed to bind a queue")
		}
		go func() {
			for m := range msgs {
				handleSubTest(sub, m.Body, imsgRcvCount, statmap)
			}
		}()
		<-quit
	case protocol.MQTT:
		if token := sub.conn.MQTTClient.Subscribe(topic, 0, func(client mqtt.Client, msg mqtt.Message) {
			handleSubTest(sub, msg.Payload(), imsgRcvCount, statmap)

		}); token.Wait() && token.Error() != nil {
			log.Error("MQTT Error")
			return errors.New("Impossible to subscribe to the topic " + topic)
		}
		<-quit
	case protocol.Kafka:
		//consumer, err := sarama.NewConsumer([]string{"10.100.0.168:9092"}, config)

		partitionList, err := sub.conn.KafkaClient.Consumer.Partitions(topic)
		if err != nil {
			return errors.New("Failed to find partitions")
		}

		//messages := make(chan *sarama.ConsumerMessage, 256)
		//create the map to store the statistics of the arrived messages
		statmap := make(map[int32]msg.Statistics)
		quit := make(chan bool)
		for _, partition := range partitionList {
			partitionConsumer, err := sub.conn.KafkaClient.Consumer.ConsumePartition(topic, partition, sarama.OffsetOldest)
			if err != nil {
				log.Error("Error while reading the partition: %s", err)
			} else {
				go func(partitionConsumer sarama.PartitionConsumer) {
					for message := range partitionConsumer.Messages() {
						handleSubTest(sub, message.Value, imsgRcvCount, statmap)
					}

				}(partitionConsumer)
			}
		}
		<-quit
		log.Info("Closing connection...")
		return nil
	case protocol.IPFS:
		subscription, err := sub.conn.IPFSClient.PubSubSubscribe(topic)
		if err != nil {
			return err
		}
		for record, err := subscription.Next(); err != nil; {
			handleSubTest(sub, record.Data(), imsgRcvCount, statmap)
		}
		<-quit
	case protocol.ZMQ:
		err := sub.conn.ZMQClient.SetSubscribe(topic)
		if err != nil {
			return err
		}
		for {
			message, err := sub.conn.ZMQClient.RecvMessageBytes(0)
			if err != nil {
				log.Fatal("Error receiving messages", err)
				break
			}
			handleSubTest(sub, message[1], imsgRcvCount, statmap)
		}
		<-quit
	case protocol.Redis:
		sub.conn.RedisClient.Subscribe(topic)
		for {
			switch v := sub.conn.RedisClient.Receive().(type) {
			case redis.Message:
				handleSubTest(sub, v.Data, imsgRcvCount, statmap)
			}
		}
		<-quit
	default:
		return errors.New("Error: Subscribe Incorrect Protocol")
	}
	return nil
}

func handleSubTest(sub Sub, data []byte, imsgRcvCount int, statmap map[int32]msg.Statistics) {
	//create the map to store the statistics of the arrived messages
	metaData := msg.ParseMetadata(data)
	delay := (time.Now().UnixNano() - metaData.Timestamp) / 1e6
	//if the clientID of the received message
	//is the same of the the local clientId do not increase the stat
	if metaData.ClientID != sub.ID {
		//is the msg out of order?
		outOfOrder := false
		if statmap[metaData.ClientID].ReceivedMsg != metaData.MsgId {
			log.Debug("Out of Order? ", imsgRcvCount, metaData.MsgId)
			outOfOrder = true
		}
		imsgRcvCount++
		//delay for the message in millisecond
		mstat := msg.Statistics{
			ReceivedMsg:     int32(statmap[metaData.ClientID].ReceivedMsg + 1),
			CumulativeDelay: int64(statmap[metaData.ClientID].CumulativeDelay + delay),
		}
		if outOfOrder {
			mstat.OutOfOrderMsgs++
		}
		statmap[metaData.ClientID] = mstat
		log.Info(" Received message: clientId ", metaData.ClientID, " msgSize ", len(data), " MsgId ", metaData.MsgId,
			"Total Received messages", imsgRcvCount, " ReceivedDelay(ms) ", delay, "OutofOrder: ", outOfOrder)
		//send the msg info to the stats server
		stat := &stats.Stats{}
		stat.ClientType = stats.ClientType_Subscriber
		stat.PublisherId = metaData.ClientID
		stat.SubscriberId = sub.ID
		stat.MessageId = metaData.MsgId
		stat.MessageSize = int32(len(data))
		buf, err := proto.Marshal(stat)
		if err != nil {
			log.Error("Impossible to Marshal the stat message")
		}
		//fmt.Println("about to send statistics ", stat.PublisherId, stat.SubscriberId, stat.MessageId )
		err = sub.statsConn.NATSClient.Publish(StatsTopic, buf)
		if err != nil {
			log.Error("Impossible to send the msg Info to the stats broker")
		}
	}
}

// print the statistics of the test on the console
// also write the result on a CSV file
// the correct cumulative delay may be found on the stat server
func printTestStat(statmap map[int32]msg.Statistics) {
	for {
		/*resFile, err := os.Create("nodeStats.csv")
		writer := csv.NewWriter(resFile)
		if err != nil {
			log.Error("Error in creating the csv file for the node stat results")
			//terminate this gorutine
			return
		}*/
		if len(statmap) != 0 {
			fmt.Printf("\n\n\n\n" + strings.Repeat("#", 80))
			fmt.Printf("\n\t\tSTAT SUMMARY\n\n")
			for clientId, clientStat := range statmap {
				fmt.Println("ClientId: %d  ReceveidMsg: %d CumulativeDelay: %d ms  OutOfOrderMsgs: %d\n", clientId,
					clientStat.ReceivedMsg, clientStat.CumulativeDelay, clientStat.OutOfOrderMsgs)
				//res := []string{strconv.FormatInt(int64(clientId), 10), strconv.FormatInt(int64(clientStat.ReceivedMsg), 10),
						//strconv.FormatInt(int64(clientStat.CumulativeDelay), 10), strconv.FormatInt(int64(clientStat.OutOfOrderMsgs), 10)}
				//writer.Write(res)
				//writer.Flush()
			}
			//resFile.Close()
			fmt.Printf("\n\n\n\n")
			fmt.Printf(strings.Repeat("#", 80) + "\n")
			time.Sleep(2000 * time.Millisecond)
		}
	}
}
<commit_msg>reconnets to stats server in the publisher<commit_after>package pubsub

import (
	"errors"
	"fmt"
	"github.com/Shopify/sarama"
	log "github.com/Sirupsen/logrus"
	"github.com/eclipse/paho.mqtt.golang"
	"github.com/garyburd/redigo/redis"
	"github.com/golang/protobuf/proto"
	"github.com/nats-io/go-nats"
	"ihmc.us/anglova/conn"
	"ihmc.us/anglova/msg"
	"ihmc.us/anglova/protocol"
	"ihmc.us/anglova/stats"
	"math/rand"
	"strings"
	"time"
	"sync"
	"os"
	"os/signal"
	"syscall"
	"encoding/csv"
	"strconv"
)

const StatsTopic = "stats"

type Sub struct {
	Protocol  string
	conn      conn.Conn
	statsConn conn.Conn
	ID        int32
	Topic     string
	host      string
	port      string
	statsAddr string
	statsPort string
}

//lock to sync the reading and writing operations on the below maps
var lock = sync.RWMutex{}

//PubID MsgId MsgSize sentTime
var sentTimes = make(map[int32]map[int32]map[int32]time.Time)
//PubId MsgID MsgSize SubID RcvTime
var rcvTimes = make(map[int32]map[int32]map[int32]map[int32]time.Time)

func NewSub(proto string, host string, port string, topic string, statsAddress string, statsPort string) (*Sub, error) {
	id, err := CreateNodeID()
	if err != nil {
		log.Error(err)
		id = rand.Int31()
	}
	connection, err := conn.New(proto, host, port, topic, false)
	if err != nil {
		log.Error("Error during the connection with the broker!")
		return nil, err
	}
	sConn, err := conn.New(protocol.NATS, statsAddress, statsPort, StatsTopic, true)
	if err != nil {
		log.Error("Error during the connection with the stats broker!")
		return nil, err
	}
	return &Sub{Protocol: proto,
		conn:         *connection,
		statsConn:    *sConn,
		ID:           id,
		Topic:        topic,
		host:         host,
		port:         port,
		statsAddr:    statsAddress,
		statsPort:    statsPort, }, nil
}

//stats server function
//the stat server subscribe to the sub topic to obtain the message info
//it will use the info to calculate the delayed time
func (sub Sub) SubscribeToStats() error {
        //channel to manage the CTRL-C
        signalCh := make(chan os.Signal, 1)
        signal.Notify(signalCh, syscall.SIGINT, syscall.SIGTERM)
	if sub.Protocol != protocol.NATS {
		return errors.New("SubscribeToStats only available with NATS Broker")
	}
	quit := make(chan bool)
	go handleStatInfo(&sub, quit)
	go handleStatGen(quit)
	<-signalCh
	fmt.Println("Exiting after a CTRL-C")
	return nil
}

//handle the StatsSenderTopic info
func handleStatInfo(sub *Sub, quit chan bool) error {
	sub.statsConn.NATSClient.Subscribe(StatsTopic, func(m *nats.Msg) {
		log.Info("Received stats of size: ", len(m.Data))
		s := &stats.Stats{}
		err := proto.Unmarshal(m.Data, s)
		if err != nil {
			log.Warn(" Unmarshalling error: ", err)
			return
		}
		lock.Lock()
		if s.ClientType == stats.ClientType_Publisher {
			log.Debug("Received statistics from publisher: ", s.PublisherId, s.SubscriberId, s.MessageId)
			if len(sentTimes[s.PublisherId]) == 0 {
				sentTimes[s.PublisherId] = make(map[int32]map[int32]time.Time)
			}
			if len(sentTimes[s.PublisherId][s.MessageId]) == 0 {
				sentTimes[s.PublisherId][s.MessageId] = make(map[int32]time.Time)
			}
			sentTimes[s.PublisherId][s.MessageId][s.MessageSize] = time.Now()
		} else {
			fmt.Println("Received statistics from subscriber: ", s.PublisherId, s.SubscriberId, s.MessageId)
			if len(rcvTimes[s.PublisherId]) == 0 {
				rcvTimes[s.PublisherId] = make(map[int32]map[int32]map[int32]time.Time)
			}
			if len(rcvTimes[s.PublisherId][s.MessageId]) == 0 {
				rcvTimes[s.PublisherId][s.MessageId] = make(map[int32]map[int32]time.Time)
			}
			if len(rcvTimes[s.PublisherId][s.MessageId][s.MessageSize]) == 0 {
				rcvTimes[s.PublisherId][s.MessageId][s.MessageSize] = make(map[int32]time.Time)
			}
			rcvTimes[s.PublisherId][s.MessageId][s.MessageSize][s.SubscriberId] = time.Now()
		}
		lock.Unlock()
	})
	<-quit
	return nil
}

func handleStatGen(quit chan bool) {
	//print the result on a CSV file periodically (60 seconds)
	for {
		file, err := os.Create("TimeResults.csv")
		if err != nil {
			log.Error("Impossible to create the csv File")
		}
		writer := csv.NewWriter(file)
		lock.RLock()
		for pubID, msgs := range rcvTimes {
			//log.Info("Pubs: ", msgs)
			fmt.Println("\n\nSUMMARY")
			for msgID, msgSizes := range msgs {
				for size, subs := range msgSizes {
					var totalDelayForMessage int64
					var reachedSubscribers int32
					for _, rTime := range subs {
						totalDelayForMessage += (rTime.UnixNano() - sentTimes[pubID][msgID][size].UnixNano()) / 1e6
						reachedSubscribers++
					}
					fmt.Println("PubId", pubID, "MsgId ", msgID, "MsgSize", size, "TotalDelayForMsg ", totalDelayForMessage, "ReachedSubs ", reachedSubscribers)
					res := []string{strconv.FormatInt(int64(pubID), 10), strconv.FormatInt(int64(msgID), 10), strconv.FormatInt(int64(size), 10),
							strconv.FormatInt(int64(totalDelayForMessage), 10), strconv.FormatInt(int64(reachedSubscribers), 10)}
					//log.Info("results: ", res)
					err := writer.Write(res)
					if err != nil {
						log.Error("Impossible to write on the CSV file")
					}
					writer.Flush()
				}
			}
			fmt.Println("\n\nEND SUMMARY\n\n")
		}
		file.Close()
		lock.RUnlock()
		time.Sleep(10 * time.Second)
	}
	<-quit
}
func (sub Sub) Subscribe(topic string) error {

	log.Info("Subscribe <-")

	imsgRcvCount := 0
	//this map contains the statistics per each node as defined in the struct Statistics
	//the uint32 is the identifier for the pub nodes
	statmap := make(map[int32]msg.Statistics)
	quit := make(chan bool)
	go printTestStat(statmap)
	switch sub.Protocol {
	case protocol.NATS:
		sub.conn.NATSClient.Subscribe(topic, func(m *nats.Msg) {
			handleSubTest(sub, m.Data, imsgRcvCount, statmap)
		})
		<-quit
	case protocol.RabbitMQ:
		channel := sub.conn.RabbitMQClient
		q, err := channel.QueueDeclare(
			"",    // name
			true,  // durable
			false, // delete when usused
			true,  // exclusive
			false, // no-wait
			nil,   // arguments
		)
		if err != nil {
			return errors.New("Unable to instantiate the queue")
		}
		err = channel.QueueBind(
			q.Name, // queue name
			"",     // routing key
			topic,  // exchange
			false,
			nil)
		if err != nil {
			return errors.New("Failed to bind a queue")
		}

		msgs, err := channel.Consume(
			q.Name, // queue
			"",     // consumer
			true,   // auto-ack
			false,  // exclusive
			false,  // no-local
			false,  // no-wait
			nil,    // args
		)
		if err != nil {
			return errors.New("Failed to bind a queue")
		}
		go func() {
			for m := range msgs {
				handleSubTest(sub, m.Body, imsgRcvCount, statmap)
			}
		}()
		<-quit
	case protocol.MQTT:
		if token := sub.conn.MQTTClient.Subscribe(topic, 0, func(client mqtt.Client, msg mqtt.Message) {
			handleSubTest(sub, msg.Payload(), imsgRcvCount, statmap)

		}); token.Wait() && token.Error() != nil {
			log.Error("MQTT Error")
			return errors.New("Impossible to subscribe to the topic " + topic)
		}
		<-quit
	case protocol.Kafka:
		//consumer, err := sarama.NewConsumer([]string{"10.100.0.168:9092"}, config)

		partitionList, err := sub.conn.KafkaClient.Consumer.Partitions(topic)
		if err != nil {
			return errors.New("Failed to find partitions")
		}

		//messages := make(chan *sarama.ConsumerMessage, 256)
		//create the map to store the statistics of the arrived messages
		statmap := make(map[int32]msg.Statistics)
		quit := make(chan bool)
		for _, partition := range partitionList {
			partitionConsumer, err := sub.conn.KafkaClient.Consumer.ConsumePartition(topic, partition, sarama.OffsetOldest)
			if err != nil {
				log.Error("Error while reading the partition: %s", err)
			} else {
				go func(partitionConsumer sarama.PartitionConsumer) {
					for message := range partitionConsumer.Messages() {
						handleSubTest(sub, message.Value, imsgRcvCount, statmap)
					}

				}(partitionConsumer)
			}
		}
		<-quit
		log.Info("Closing connection...")
		return nil
	case protocol.IPFS:
		subscription, err := sub.conn.IPFSClient.PubSubSubscribe(topic)
		if err != nil {
			return err
		}
		for record, err := subscription.Next(); err != nil; {
			handleSubTest(sub, record.Data(), imsgRcvCount, statmap)
		}
		<-quit
	case protocol.ZMQ:
		err := sub.conn.ZMQClient.SetSubscribe(topic)
		if err != nil {
			return err
		}
		for {
			message, err := sub.conn.ZMQClient.RecvMessageBytes(0)
			if err != nil {
				log.Fatal("Error receiving messages", err)
				break
			}
			handleSubTest(sub, message[1], imsgRcvCount, statmap)
		}
		<-quit
	case protocol.Redis:
		sub.conn.RedisClient.Subscribe(topic)
		for {
			switch v := sub.conn.RedisClient.Receive().(type) {
			case redis.Message:
				handleSubTest(sub, v.Data, imsgRcvCount, statmap)
			}
		}
		<-quit
	default:
		return errors.New("Error: Subscribe Incorrect Protocol")
	}
	return nil
}

func handleSubTest(sub Sub, data []byte, imsgRcvCount int, statmap map[int32]msg.Statistics) {
	//create the map to store the statistics of the arrived messages
	metaData := msg.ParseMetadata(data)
	delay := (time.Now().UnixNano() - metaData.Timestamp) / 1e6
	//if the clientID of the received message
	//is the same of the the local clientId do not increase the stat
	if metaData.ClientID != sub.ID {
		//is the msg out of order?
		outOfOrder := false
		if statmap[metaData.ClientID].ReceivedMsg != metaData.MsgId {
			log.Debug("Out of Order? ", imsgRcvCount, metaData.MsgId)
			outOfOrder = true
		}
		imsgRcvCount++
		//delay for the message in millisecond
		mstat := msg.Statistics{
			ReceivedMsg:     int32(statmap[metaData.ClientID].ReceivedMsg + 1),
			CumulativeDelay: int64(statmap[metaData.ClientID].CumulativeDelay + delay),
		}
		if outOfOrder {
			mstat.OutOfOrderMsgs++
		}
		statmap[metaData.ClientID] = mstat
		log.Info(" Received message: clientId ", metaData.ClientID, " msgSize ", len(data), " MsgId ", metaData.MsgId,
			"Total Received messages", imsgRcvCount, " ReceivedDelay(ms) ", delay, "OutofOrder: ", outOfOrder)
		//send the msg info to the stats server
		stat := &stats.Stats{}
		stat.ClientType = stats.ClientType_Subscriber
		stat.PublisherId = metaData.ClientID
		stat.SubscriberId = sub.ID
		stat.MessageId = metaData.MsgId
		stat.MessageSize = int32(len(data))
		buf, err := proto.Marshal(stat)
		if err != nil {
			log.Error("Impossible to Marshal the stat message")
		}
		//fmt.Println("about to send statistics ", stat.PublisherId, stat.SubscriberId, stat.MessageId )
		err = sub.statsConn.NATSClient.Publish(StatsTopic, buf)
		if err != nil {
			log.Error("Impossible to send the msg Info to the stats broker")
			scon, _ := conn.New(protocol.NATS, sub.statsAddr, sub.statsPort, StatsTopic, true)
			sub.statsConn = *scon
		}
	}
}

// print the statistics of the test on the console
// also write the result on a CSV file
// the correct cumulative delay may be found on the stat server
func printTestStat(statmap map[int32]msg.Statistics) {
	for {
		/*resFile, err := os.Create("nodeStats.csv")
		writer := csv.NewWriter(resFile)
		if err != nil {
			log.Error("Error in creating the csv file for the node stat results")
			//terminate this gorutine
			return
		}*/
		if len(statmap) != 0 {
			fmt.Printf("\n\n\n\n" + strings.Repeat("#", 80))
			fmt.Printf("\n\t\tSTAT SUMMARY\n\n")
			for clientId, clientStat := range statmap {
				fmt.Println("ClientId: %d  ReceveidMsg: %d CumulativeDelay: %d ms  OutOfOrderMsgs: %d\n", clientId,
					clientStat.ReceivedMsg, clientStat.CumulativeDelay, clientStat.OutOfOrderMsgs)
				//res := []string{strconv.FormatInt(int64(clientId), 10), strconv.FormatInt(int64(clientStat.ReceivedMsg), 10),
						//strconv.FormatInt(int64(clientStat.CumulativeDelay), 10), strconv.FormatInt(int64(clientStat.OutOfOrderMsgs), 10)}
				//writer.Write(res)
				//writer.Flush()
			}
			//resFile.Close()
			fmt.Printf("\n\n\n\n")
			fmt.Printf(strings.Repeat("#", 80) + "\n")
			time.Sleep(2000 * time.Millisecond)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	httptransport "github.com/go-swagger/go-swagger/httpkit/client"
	strfmt "github.com/go-swagger/go-swagger/strfmt"
	client_models "github.com/iron-io/titan/runner/client/models"
	titan_client "github.com/iron-io/titan/runner/client/titan"
	"github.com/iron-io/titan/runner/client/titan/jobs"
)

type Tasker struct {
	api   *titan_client.Titan
	dummy os.File
	log   log.FieldLogger
}

// Titan tasker.
func NewTasker(config *Config, log log.FieldLogger) *Tasker {
	api := titan_client.New(httptransport.New("localhost:8080", "/v1", []string{"http"}), strfmt.Default)
	f, _ := ioutil.TempFile("", "crap-")
	return &Tasker{api, *f, log}
}

func (t *Tasker) Job() *client_models.Job {
	l := t.log.WithField("action", "DequeueJob")
	var job *client_models.Job
	param := jobs.NewGetJobsParams()
	for {
		jobs, err := t.api.Jobs.GetJobs(param)
		if err != nil {
			l.WithError(err).Errorln("dequeue job from api")
		} else if len(jobs.Payload.Jobs) > 0 && jobs.Payload.Jobs[0] != nil {
			job = jobs.Payload.Jobs[0]
			break
		}
		time.Sleep(1 * time.Second)
	}
	return job
}

func (t *Tasker) Update(job *client_models.Job) error {
	l := t.log.WithFields(log.Fields{
		"action": "UpdateJob",
		"job_id": job.ID,
	})
	l.Debugln("Sending PATCH to update job", job)
	j, err := t.api.Jobs.PatchGroupsGroupNameJobsID(jobs.NewPatchGroupsGroupNameJobsIDParams().WithGroupName(job.GroupName).WithID(job.ID).WithBody(&client_models.JobWrapper{job}))
	if err != nil {
		l.WithError(err).Errorln("Update failed")
		return err
	}
	l.Infoln("Got back", j)
	return nil
}

// TODO: this should be on server side
func (t *Tasker) RetryTask(job *client_models.Job) error {
	panic("Not implemented Retry")
}

func (t *Tasker) IsCancelled(job *client_models.Job) bool {
	wrapper, err := t.api.Jobs.GetGroupsGroupNameJobsID(jobs.NewGetGroupsGroupNameJobsIDParams().WithGroupName(job.GroupName).WithID(job.ID))
	if err != nil {
		log.Errorln("JobIdGet from Cancel", "err", err)
		return false
	}

	return wrapper.Payload.Job.Status == "cancelled"
}

func (t *Tasker) Succeeded(job *client_models.Job, r *os.File) error {
	param := jobs.NewPostGroupsGroupNameJobsIDSuccessParams().WithGroupName(job.GroupName).WithID(job.ID)
	//if r != nil {
	//	param = param.WithLog(*r)
	//} else {
	//	param = param.WithLog(t.dummy)
	//}
	_, err := t.api.Jobs.PostGroupsGroupNameJobsIDSuccess(param)
	if err != nil {
		log.Errorln("JobIdSuccessPost", "jobId", job.ID, "err", err)
	}
	return nil
}

func (t *Tasker) Failed(job *client_models.Job, reason string, r *os.File) error {
	param := jobs.NewPostGroupsGroupNameJobsIDErrorParams().WithGroupName(job.GroupName).WithID(job.ID).WithReason(reason)
	//if r != nil {
	//	param = param.WithLog(*r)
	//} else {
	//	param = param.WithLog(t.dummy)
	//}

	_, err := t.api.Jobs.PostGroupsGroupNameJobsIDError(param)
	if err != nil {
		log.Errorln("JobIdFailPost", "jobId", job.ID, "err", err)
	}
	return nil
}

func (t *Tasker) Log(job *client_models.Job, logFile *os.File) error {
	panic("Not implemented")
	return nil
}
<commit_msg>Fix log upload and retrieval.<commit_after>package main

import (
	"io/ioutil"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	httptransport "github.com/go-swagger/go-swagger/httpkit/client"
	strfmt "github.com/go-swagger/go-swagger/strfmt"
	client_models "github.com/iron-io/titan/runner/client/models"
	titan_client "github.com/iron-io/titan/runner/client/titan"
	"github.com/iron-io/titan/runner/client/titan/jobs"
)

type Tasker struct {
	api   *titan_client.Titan
	dummy os.File
	log   log.FieldLogger
}

// Titan tasker.
func NewTasker(config *Config, log log.FieldLogger) *Tasker {
	api := titan_client.New(httptransport.New("localhost:8080", "/v1", []string{"http"}), strfmt.Default)
	f, _ := ioutil.TempFile("", "crap-")
	return &Tasker{api, *f, log}
}

func (t *Tasker) Job() *client_models.Job {
	l := t.log.WithField("action", "DequeueJob")
	var job *client_models.Job
	param := jobs.NewGetJobsParams()
	for {
		jobs, err := t.api.Jobs.GetJobs(param)
		if err != nil {
			l.WithError(err).Errorln("dequeue job from api")
		} else if len(jobs.Payload.Jobs) > 0 && jobs.Payload.Jobs[0] != nil {
			job = jobs.Payload.Jobs[0]
			break
		}
		time.Sleep(1 * time.Second)
	}
	return job
}

func (t *Tasker) Update(job *client_models.Job) error {
	l := t.log.WithFields(log.Fields{
		"action": "UpdateJob",
		"job_id": job.ID,
	})
	l.Debugln("Sending PATCH to update job", job)
	j, err := t.api.Jobs.PatchGroupsGroupNameJobsID(jobs.NewPatchGroupsGroupNameJobsIDParams().WithGroupName(job.GroupName).WithID(job.ID).WithBody(&client_models.JobWrapper{job}))
	if err != nil {
		l.WithError(err).Errorln("Update failed")
		return err
	}
	l.Infoln("Got back", j)
	return nil
}

// TODO: this should be on server side
func (t *Tasker) RetryTask(job *client_models.Job) error {
	panic("Not implemented Retry")
}

func (t *Tasker) IsCancelled(job *client_models.Job) bool {
	wrapper, err := t.api.Jobs.GetGroupsGroupNameJobsID(jobs.NewGetGroupsGroupNameJobsIDParams().WithGroupName(job.GroupName).WithID(job.ID))
	if err != nil {
		log.Errorln("JobIdGet from Cancel", "err", err)
		return false
	}

	return wrapper.Payload.Job.Status == "cancelled"
}

func (t *Tasker) Succeeded(job *client_models.Job, r *os.File) error {
	param := jobs.NewPostGroupsGroupNameJobsIDSuccessParams().WithGroupName(job.GroupName).WithID(job.ID)
	_, err := t.api.Jobs.PostGroupsGroupNameJobsIDSuccess(param)
	if err != nil {
		log.Errorln("JobIdSuccessPost", "jobId", job.ID, "err", err)
	}
	return t.Log(job, r)
}

func (t *Tasker) Failed(job *client_models.Job, reason string, r *os.File) error {
	param := jobs.NewPostGroupsGroupNameJobsIDErrorParams().WithGroupName(job.GroupName).WithID(job.ID).WithReason(reason)

	_, err := t.api.Jobs.PostGroupsGroupNameJobsIDError(param)
	if err != nil {
		log.Errorln("JobIdFailPost", "jobId", job.ID, "err", err)
	}
	return t.Log(job, r)
}

func (t *Tasker) Log(job *client_models.Job, logFile *os.File) error {
	param := jobs.NewPostGroupsGroupNameJobsIDLogParams().WithGroupName(job.GroupName).WithID(job.ID)
	if logFile != nil {
		param.WithLog(*logFile)
	} else {
		param.WithLog(t.dummy)
	}
	r, err := t.api.Jobs.PostGroupsGroupNameJobsIDLog(param)
	log.Println(r, err)
	if err != nil {
		log.WithError(err).Errorln("Uploading log")
	}

	return err
}
<|endoftext|>


<commit_before>// Package rabbit implements the Rabbit stream cipher (4503)
package rabbit

import (
	"crypto/cipher"
	"encoding/binary"
	"errors"
	"fmt"
)

var (
	_A = []uint32{
		0x4D34D34D, 0xD34D34D3, 0x34D34D34, 0x4D34D34D,
		0xD34D34D3, 0x34D34D34, 0x4D34D34D, 0xD34D34D3,
	}
)

type rabbit struct {
	x     [8]uint32
	c     [8]uint32
	carry uint32
	s     [16]byte
	ks    []byte
}

func New(key []byte, iv []byte) (cipher.Stream, error) {

	if len(key) != 16 {
		return nil, errors.New("rabbit: invalid key length")
	}

	if len(iv) != 0 && len(iv) != 8 {
		return nil, errors.New("rabbit: invalid iv length")
	}

	var k [4]uint32

	for i := range k {
		k[i] = binary.LittleEndian.Uint32(key[i*4:])
	}

	var r rabbit

	r.setupKey(k[:])

	if len(iv) != 0 {
		var v [4]uint16
		for i := range v {
			v[i] = binary.LittleEndian.Uint16(iv[i*2:])
		}
		r.setupIV(v[:])
	}

	fmt.Printf("%08x\n", k)
	return &r, nil
}

func (r *rabbit) setupKey(key []uint32) {

	r.x[0] = key[0]
	r.x[1] = key[3]<<16 | key[2]>>16
	r.x[2] = key[1]
	r.x[3] = key[0]<<16 | key[3]>>16
	r.x[4] = key[2]
	r.x[5] = key[1]<<16 | key[0]>>16
	r.x[6] = key[3]
	r.x[7] = key[2]<<16 | key[1]>>16

	r.c[0] = rotl(key[2], 16)
	r.c[1] = key[0] & 0xffff0000 | key[1] & 0xffff
	r.c[2] = rotl(key[3], 16)
	r.c[3] = key[1] & 0xffff0000 | key[2] & 0xffff
	r.c[4] = rotl(key[0], 16)
	r.c[5] = key[2] & 0xffff0000 | key[3] & 0xffff
	r.c[6] = rotl(key[1], 16)
	r.c[7] = key[3] & 0xffff0000 | key[0] & 0xffff

	for i := 0; i < 4; i++ {
		r.nextState()
	}

	r.c[0] ^= r.x[4]
	r.c[1] ^= r.x[5]
	r.c[2] ^= r.x[6]
	r.c[3] ^= r.x[7]
	r.c[4] ^= r.x[0]
	r.c[5] ^= r.x[1]
	r.c[6] ^= r.x[2]
	r.c[7] ^= r.x[3]
}

func (r *rabbit) setupIV(iv []uint16) {
	r.c[0] ^= uint32(iv[1])<<16 | uint32(iv[0])
	r.c[1] ^= uint32(iv[3])<<16 | uint32(iv[1])
	r.c[2] ^= uint32(iv[3])<<16 | uint32(iv[2])
	r.c[3] ^= uint32(iv[2])<<16 | uint32(iv[0])
	r.c[4] ^= uint32(iv[1])<<16 | uint32(iv[0])
	r.c[5] ^= uint32(iv[3])<<16 | uint32(iv[1])
	r.c[6] ^= uint32(iv[3])<<16 | uint32(iv[2])
	r.c[7] ^= uint32(iv[2])<<16 | uint32(iv[0])

	for i := 0; i < 4; i++ {
		r.nextState()
	}
}

func (r *rabbit) nextState() {
	var G [8]uint32

	for i := range r.c {
		r.carry, r.c[i] = adc32(_A[i], r.c[i], r.carry)
	}

	for i := range G {
		G[i] = g(r.x[i], r.c[i])
	}

	r.x[0] = G[0] + rotl(G[7], 16) + rotl(G[6], 16)
	r.x[1] = G[1] + rotl(G[0], 8) + G[7]
	r.x[2] = G[2] + rotl(G[1], 16) + rotl(G[0], 16)
	r.x[3] = G[3] + rotl(G[2], 8) + G[1]
	r.x[4] = G[4] + rotl(G[3], 16) + rotl(G[2], 16)
	r.x[5] = G[5] + rotl(G[4], 8) + G[3]
	r.x[6] = G[6] + rotl(G[5], 16) + rotl(G[4], 16)
	r.x[7] = G[7] + rotl(G[6], 8) + G[5]
}

func (r *rabbit) extract() {
	var sw [4]uint32

	r.nextState()

	// extract keystream
	sw[0] = r.x[0] ^ (r.x[5] >> 16 | r.x[3] << 16)
	sw[1] = r.x[2] ^ (r.x[7] >> 16 | r.x[5] << 16)
	sw[2] = r.x[4] ^ (r.x[2] >> 16 | r.x[7] << 16)
	sw[3] = r.x[6] ^ (r.x[3] >> 15 | r.x[1] << 16)

	for i := range sw {
		binary.LittleEndian.PutUint32(r.s[i*4:], sw[i])
	}
	r.ks = r.s[:]
}

func (r *rabbit) XORKeyStream(dst, src []byte) {
	for i := range src {
		if len(r.ks) == 0 {
			r.extract()
		}
		dst[i] = src[i] ^ r.ks[0]
		r.ks = r.ks[1:]
	}
}

func g(u, v uint32) uint32 {
	uv := uint64(u+v)
	uv *= uv
	return uint32(uv>>32) ^ uint32(uv)
}

func adc32(a, b, c uint32) (uint32, uint32) {
	x := uint64(a) + uint64(b) + uint64(c)
	return uint32(x >> 32), uint32(x)
}

func rotl(v, s uint32) uint32 {
	return (v << s) | (v >> (32 - s))
}
<commit_msg>remove debug printf<commit_after>// Package rabbit implements the Rabbit stream cipher
package rabbit

import (
	"crypto/cipher"
	"encoding/binary"
	"errors"
)

var (
	_A = []uint32{
		0x4D34D34D, 0xD34D34D3, 0x34D34D34, 0x4D34D34D,
		0xD34D34D3, 0x34D34D34, 0x4D34D34D, 0xD34D34D3,
	}
)

type rabbit struct {
	x     [8]uint32
	c     [8]uint32
	carry uint32
	s     [16]byte
	ks    []byte
}

func New(key []byte, iv []byte) (cipher.Stream, error) {

	if len(key) != 16 {
		return nil, errors.New("rabbit: invalid key length")
	}

	if len(iv) != 0 && len(iv) != 8 {
		return nil, errors.New("rabbit: invalid iv length")
	}

	var k [4]uint32

	for i := range k {
		k[i] = binary.LittleEndian.Uint32(key[i*4:])
	}

	var r rabbit

	r.setupKey(k[:])

	if len(iv) != 0 {
		var v [4]uint16
		for i := range v {
			v[i] = binary.LittleEndian.Uint16(iv[i*2:])
		}
		r.setupIV(v[:])
	}

	return &r, nil
}

func (r *rabbit) setupKey(key []uint32) {

	r.x[0] = key[0]
	r.x[1] = key[3]<<16 | key[2]>>16
	r.x[2] = key[1]
	r.x[3] = key[0]<<16 | key[3]>>16
	r.x[4] = key[2]
	r.x[5] = key[1]<<16 | key[0]>>16
	r.x[6] = key[3]
	r.x[7] = key[2]<<16 | key[1]>>16

	r.c[0] = rotl(key[2], 16)
	r.c[1] = key[0] & 0xffff0000 | key[1] & 0xffff
	r.c[2] = rotl(key[3], 16)
	r.c[3] = key[1] & 0xffff0000 | key[2] & 0xffff
	r.c[4] = rotl(key[0], 16)
	r.c[5] = key[2] & 0xffff0000 | key[3] & 0xffff
	r.c[6] = rotl(key[1], 16)
	r.c[7] = key[3] & 0xffff0000 | key[0] & 0xffff

	for i := 0; i < 4; i++ {
		r.nextState()
	}

	r.c[0] ^= r.x[4]
	r.c[1] ^= r.x[5]
	r.c[2] ^= r.x[6]
	r.c[3] ^= r.x[7]
	r.c[4] ^= r.x[0]
	r.c[5] ^= r.x[1]
	r.c[6] ^= r.x[2]
	r.c[7] ^= r.x[3]
}

func (r *rabbit) setupIV(iv []uint16) {
	r.c[0] ^= uint32(iv[1])<<16 | uint32(iv[0])
	r.c[1] ^= uint32(iv[3])<<16 | uint32(iv[1])
	r.c[2] ^= uint32(iv[3])<<16 | uint32(iv[2])
	r.c[3] ^= uint32(iv[2])<<16 | uint32(iv[0])
	r.c[4] ^= uint32(iv[1])<<16 | uint32(iv[0])
	r.c[5] ^= uint32(iv[3])<<16 | uint32(iv[1])
	r.c[6] ^= uint32(iv[3])<<16 | uint32(iv[2])
	r.c[7] ^= uint32(iv[2])<<16 | uint32(iv[0])

	for i := 0; i < 4; i++ {
		r.nextState()
	}
}

func (r *rabbit) nextState() {
	var G [8]uint32

	for i := range r.c {
		r.carry, r.c[i] = adc32(_A[i], r.c[i], r.carry)
	}

	for i := range G {
		G[i] = g(r.x[i], r.c[i])
	}

	r.x[0] = G[0] + rotl(G[7], 16) + rotl(G[6], 16)
	r.x[1] = G[1] + rotl(G[0], 8) + G[7]
	r.x[2] = G[2] + rotl(G[1], 16) + rotl(G[0], 16)
	r.x[3] = G[3] + rotl(G[2], 8) + G[1]
	r.x[4] = G[4] + rotl(G[3], 16) + rotl(G[2], 16)
	r.x[5] = G[5] + rotl(G[4], 8) + G[3]
	r.x[6] = G[6] + rotl(G[5], 16) + rotl(G[4], 16)
	r.x[7] = G[7] + rotl(G[6], 8) + G[5]
}

func (r *rabbit) extract() {
	var sw [4]uint32

	r.nextState()

	// extract keystream
	sw[0] = r.x[0] ^ (r.x[5] >> 16 | r.x[3] << 16)
	sw[1] = r.x[2] ^ (r.x[7] >> 16 | r.x[5] << 16)
	sw[2] = r.x[4] ^ (r.x[2] >> 16 | r.x[7] << 16)
	sw[3] = r.x[6] ^ (r.x[3] >> 15 | r.x[1] << 16)

	for i := range sw {
		binary.LittleEndian.PutUint32(r.s[i*4:], sw[i])
	}
	r.ks = r.s[:]
}

func (r *rabbit) XORKeyStream(dst, src []byte) {
	for i := range src {
		if len(r.ks) == 0 {
			r.extract()
		}
		dst[i] = src[i] ^ r.ks[0]
		r.ks = r.ks[1:]
	}
}

func g(u, v uint32) uint32 {
	uv := uint64(u+v)
	uv *= uv
	return uint32(uv>>32) ^ uint32(uv)
}

func adc32(a, b, c uint32) (uint32, uint32) {
	x := uint64(a) + uint64(b) + uint64(c)
	return uint32(x >> 32), uint32(x)
}

func rotl(v, s uint32) uint32 {
	return (v << s) | (v >> (32 - s))
}
<|endoftext|>