<commit_before>package deje

import (
	"errors"
	"log"
	"sort"

	"github.com/DJDNS/go-deje/document"
	"github.com/DJDNS/go-deje/state"
	"github.com/DJDNS/go-deje/util"
)

// Wraps the low-level capabilities of the basic Client to provide
// an easier, more useful API to downstream code.
type SimpleClient struct {
	client *Client
	tip    string
	logger *log.Logger
}

// Unless you want to manually specify router URL and topic separately,
// you should probably use Open() instead of NewSimpleClient().
func NewSimpleClient(topic string, logger *log.Logger) *SimpleClient {
	raw_client := NewClient(topic)
	simple_client := &SimpleClient{&raw_client, "", logger}
	raw_client.SetEventCallback(func(event interface{}) {
		err := simple_client.onRcv(event)
		if err != nil && simple_client.logger != nil {
			simple_client.logger.Println(err)
		}
	})
	if false {
		logger.Println("This will never happen")
	}
	return simple_client
}

// The preferred way to create SimpleClients. Handles the Connect() call, and
// uses GetRouterAndTopic() to turn a single deje://... URL into a router URL
// and topic.
func Open(deje_url string, logger *log.Logger, cb state.OnPrimitiveCallback) (*SimpleClient, error) {
	router, topic, err := GetRouterAndTopic(deje_url)
	if err != nil {
		return nil, err
	}

	sc := NewSimpleClient(topic, logger)
	sc.SetPrimitiveCallback(cb)
	if err = sc.Connect(router); err != nil {
		return nil, err
	}
	return sc, nil
}

func (sc *SimpleClient) rcvEventList(parent map[string]interface{}, key string) error {
	doc := sc.GetDoc()
	events, ok := parent[key].([]interface{})
	if !ok {
		return errors.New("Message with bad '" + key + "' param")
	}
	for _, serial_event := range events {
		doc_ev := doc.NewEvent("")
		err := util.CloneMarshal(serial_event, &doc_ev)
		if err != nil {
			return err
		}
		doc_ev.Register()
	}
	return nil
}

func (sc *SimpleClient) onRcv(event interface{}) error {
	map_ev, ok := event.(map[string]interface{})
	if !ok {
		return errors.New("Non-{} message")
	}
	evtype, ok := map_ev["type"].(string)
	if !ok {
		return errors.New("Message with no 'type' param")
	}

	doc := sc.GetDoc()
	switch evtype {
	case "01-request-tip":
		sc.PublishTip()
	case "01-publish-tip":
		hash, ok := map_ev["tip_hash"].(string)
		if !ok {
			return errors.New("Message with bad 'tip_hash' param")
		}
		if sc.tip != hash {
			sc.RequestHistory()
		}
	case "01-request-history":
		sc.PublishHistory()
	case "01-publish-history":
		// This is intentionally structured so that the
		// coverage tests will be helpful for catching all
		// possible circumstances.
		if err := sc.rcvEventList(map_ev, "history"); err != nil {
			return err
		}
		hash, ok := map_ev["tip_hash"].(string)
		if !ok {
			return errors.New("Message with bad 'tip_hash' param")
		}
		tip_event, ok := doc.Events[hash]
		if !ok {
			return errors.New("Unknown event " + hash)
		}
		err := tip_event.Goto()
		if err != nil {
			return err
		}
		sc.tip = hash
		if sc.logger != nil {
			sc.logger.Printf("Updated content: %#v", sc.Export())
		}
	case "01-request-events":
		sc.PublishEvents()
	case "01-publish-events":
		return sc.rcvEventList(map_ev, "events")
	case "01-request-timestamps":
		sc.PublishTimestamps()
	case "01-publish-timestamps":
		ts, ok := map_ev["timestamps"].([]interface{})
		if !ok {
			return errors.New("Message with bad 'timestamps' param")
		}
		ts_strings := make([]string, len(ts))
		for i, timestamp := range ts {
			ts_string, ok := timestamp.(string)
			if !ok {
				return errors.New("Message with bad 'timestamps' param")
			}
			ts_strings[i] = ts_string
		}
		doc.Timestamps = ts_strings
	default:
		return errors.New("Unfamiliar message type: '" + evtype + "'")
	}
	return nil
}

// Connect and immediately request the tip event hash.
func (sc *SimpleClient) Connect(url string) error {
	err := sc.client.Connect(url)
	if err != nil {
		return err
	}
	return sc.RequestTip()
}

func (sc *SimpleClient) RequestTip() error {
	return sc.client.Publish(map[string]interface{}{
		"type": "01-request-tip",
	})
}

func (sc *SimpleClient) PublishTip() error {
	return sc.client.Publish(map[string]interface{}{
		"type":     "01-publish-tip",
		"tip_hash": sc.tip,
	})
}

func (sc *SimpleClient) RequestHistory() error {
	return sc.client.Publish(map[string]interface{}{
		"type": "01-request-history",
	})
}

func (sc *SimpleClient) PublishHistory() error {
	response := map[string]interface{}{
		"type":     "01-publish-history",
		"tip_hash": sc.tip,
	}
	doc := sc.GetDoc()
	ev, ok := doc.Events[sc.tip]
	if !ok {
		response["error"] = "not-found"
		return sc.client.Publish(response)
	}

	history, ok := ev.GetHistory()
	if !ok {
		response["error"] = "root-not-found"
		return sc.client.Publish(response)
	}
	response["history"] = history
	return sc.client.Publish(response)
}

func (sc *SimpleClient) RequestEvents() error {
	return sc.client.Publish(map[string]interface{}{
		"type": "01-request-events",
	})
}

func (sc *SimpleClient) PublishEvents() error {
	doc := sc.GetDoc()
	hashes := make([]string, len(doc.Events))
	events := make([]*document.Event, len(doc.Events))

	// Provide events in hash-sorted order
	var i int
	for hash := range doc.Events {
		hashes[i] = hash
		i++
	}
	sort.Strings(hashes)
	for i, hash := range hashes {
		events[i] = doc.Events[hash]
	}

	return sc.client.Publish(map[string]interface{}{
		"type":   "01-publish-events",
		"events": events,
	})
}

func (sc *SimpleClient) RequestTimestamps() error {
	return sc.client.Publish(map[string]interface{}{
		"type": "01-request-timestamps",
	})
}

func (sc *SimpleClient) PublishTimestamps() error {
	return sc.client.Publish(map[string]interface{}{
		"type":       "01-publish-timestamps",
		"timestamps": sc.GetDoc().Timestamps,
	})
}

// Navigate the Document to an Event, and promote it as the tip.
func (sc *SimpleClient) Promote(ev document.Event) error {
	doc := sc.GetDoc()

	if err := ev.Goto(); err != nil {
		return err
	}
	sc.tip = ev.Hash()
	sc.PublishTip() // Ignore error - believe it or not, this cannot error

	doc.Timestamps = append(doc.Timestamps, ev.Hash())
	return sc.PublishTimestamps()
}

// Set a callback for when primitives are applied to the document state.
func (sc *SimpleClient) SetPrimitiveCallback(c state.OnPrimitiveCallback) {
	sc.GetDoc().State.SetPrimitiveCallback(c)
}

// Get the Document object owned by this Client.
func (sc *SimpleClient) GetDoc() *document.Document {
	return sc.client.Doc
}

// Return the current contents of the document.
func (sc *SimpleClient) Export() interface{} {
	return sc.client.Doc.State.Export()
}
<commit_msg>Close #35: Travis CI coverage testing works<commit_after>package deje

import (
	"errors"
	"log"
	"sort"

	"github.com/DJDNS/go-deje/document"
	"github.com/DJDNS/go-deje/state"
	"github.com/DJDNS/go-deje/util"
)

// Wraps the low-level capabilities of the basic Client to provide
// an easier, more useful API to downstream code.
type SimpleClient struct {
	client *Client
	tip    string
	logger *log.Logger
}

// Unless you want to manually specify router URL and topic separately,
// you should probably use Open() instead of NewSimpleClient().
func NewSimpleClient(topic string, logger *log.Logger) *SimpleClient {
	raw_client := NewClient(topic)
	simple_client := &SimpleClient{&raw_client, "", logger}
	raw_client.SetEventCallback(func(event interface{}) {
		err := simple_client.onRcv(event)
		if err != nil && simple_client.logger != nil {
			simple_client.logger.Println(err)
		}
	})
	return simple_client
}

// The preferred way to create SimpleClients. Handles the Connect() call, and
// uses GetRouterAndTopic() to turn a single deje://... URL into a router URL
// and topic.
func Open(deje_url string, logger *log.Logger, cb state.OnPrimitiveCallback) (*SimpleClient, error) {
	router, topic, err := GetRouterAndTopic(deje_url)
	if err != nil {
		return nil, err
	}

	sc := NewSimpleClient(topic, logger)
	sc.SetPrimitiveCallback(cb)
	if err = sc.Connect(router); err != nil {
		return nil, err
	}
	return sc, nil
}

func (sc *SimpleClient) rcvEventList(parent map[string]interface{}, key string) error {
	doc := sc.GetDoc()
	events, ok := parent[key].([]interface{})
	if !ok {
		return errors.New("Message with bad '" + key + "' param")
	}
	for _, serial_event := range events {
		doc_ev := doc.NewEvent("")
		err := util.CloneMarshal(serial_event, &doc_ev)
		if err != nil {
			return err
		}
		doc_ev.Register()
	}
	return nil
}

func (sc *SimpleClient) onRcv(event interface{}) error {
	map_ev, ok := event.(map[string]interface{})
	if !ok {
		return errors.New("Non-{} message")
	}
	evtype, ok := map_ev["type"].(string)
	if !ok {
		return errors.New("Message with no 'type' param")
	}

	doc := sc.GetDoc()
	switch evtype {
	case "01-request-tip":
		sc.PublishTip()
	case "01-publish-tip":
		hash, ok := map_ev["tip_hash"].(string)
		if !ok {
			return errors.New("Message with bad 'tip_hash' param")
		}
		if sc.tip != hash {
			sc.RequestHistory()
		}
	case "01-request-history":
		sc.PublishHistory()
	case "01-publish-history":
		// This is intentionally structured so that the
		// coverage tests will be helpful for catching all
		// possible circumstances.
		if err := sc.rcvEventList(map_ev, "history"); err != nil {
			return err
		}
		hash, ok := map_ev["tip_hash"].(string)
		if !ok {
			return errors.New("Message with bad 'tip_hash' param")
		}
		tip_event, ok := doc.Events[hash]
		if !ok {
			return errors.New("Unknown event " + hash)
		}
		err := tip_event.Goto()
		if err != nil {
			return err
		}
		sc.tip = hash
		if sc.logger != nil {
			sc.logger.Printf("Updated content: %#v", sc.Export())
		}
	case "01-request-events":
		sc.PublishEvents()
	case "01-publish-events":
		return sc.rcvEventList(map_ev, "events")
	case "01-request-timestamps":
		sc.PublishTimestamps()
	case "01-publish-timestamps":
		ts, ok := map_ev["timestamps"].([]interface{})
		if !ok {
			return errors.New("Message with bad 'timestamps' param")
		}
		ts_strings := make([]string, len(ts))
		for i, timestamp := range ts {
			ts_string, ok := timestamp.(string)
			if !ok {
				return errors.New("Message with bad 'timestamps' param")
			}
			ts_strings[i] = ts_string
		}
		doc.Timestamps = ts_strings
	default:
		return errors.New("Unfamiliar message type: '" + evtype + "'")
	}
	return nil
}

// Connect and immediately request the tip event hash.
func (sc *SimpleClient) Connect(url string) error {
	err := sc.client.Connect(url)
	if err != nil {
		return err
	}
	return sc.RequestTip()
}

func (sc *SimpleClient) RequestTip() error {
	return sc.client.Publish(map[string]interface{}{
		"type": "01-request-tip",
	})
}

func (sc *SimpleClient) PublishTip() error {
	return sc.client.Publish(map[string]interface{}{
		"type":     "01-publish-tip",
		"tip_hash": sc.tip,
	})
}

func (sc *SimpleClient) RequestHistory() error {
	return sc.client.Publish(map[string]interface{}{
		"type": "01-request-history",
	})
}

func (sc *SimpleClient) PublishHistory() error {
	response := map[string]interface{}{
		"type":     "01-publish-history",
		"tip_hash": sc.tip,
	}
	doc := sc.GetDoc()
	ev, ok := doc.Events[sc.tip]
	if !ok {
		response["error"] = "not-found"
		return sc.client.Publish(response)
	}

	history, ok := ev.GetHistory()
	if !ok {
		response["error"] = "root-not-found"
		return sc.client.Publish(response)
	}
	response["history"] = history
	return sc.client.Publish(response)
}

func (sc *SimpleClient) RequestEvents() error {
	return sc.client.Publish(map[string]interface{}{
		"type": "01-request-events",
	})
}

func (sc *SimpleClient) PublishEvents() error {
	doc := sc.GetDoc()
	hashes := make([]string, len(doc.Events))
	events := make([]*document.Event, len(doc.Events))

	// Provide events in hash-sorted order
	var i int
	for hash := range doc.Events {
		hashes[i] = hash
		i++
	}
	sort.Strings(hashes)
	for i, hash := range hashes {
		events[i] = doc.Events[hash]
	}

	return sc.client.Publish(map[string]interface{}{
		"type":   "01-publish-events",
		"events": events,
	})
}

func (sc *SimpleClient) RequestTimestamps() error {
	return sc.client.Publish(map[string]interface{}{
		"type": "01-request-timestamps",
	})
}

func (sc *SimpleClient) PublishTimestamps() error {
	return sc.client.Publish(map[string]interface{}{
		"type":       "01-publish-timestamps",
		"timestamps": sc.GetDoc().Timestamps,
	})
}

// Navigate the Document to an Event, and promote it as the tip.
func (sc *SimpleClient) Promote(ev document.Event) error {
	doc := sc.GetDoc()

	if err := ev.Goto(); err != nil {
		return err
	}
	sc.tip = ev.Hash()
	sc.PublishTip() // Ignore error - believe it or not, this cannot error

	doc.Timestamps = append(doc.Timestamps, ev.Hash())
	return sc.PublishTimestamps()
}

// Set a callback for when primitives are applied to the document state.
func (sc *SimpleClient) SetPrimitiveCallback(c state.OnPrimitiveCallback) {
	sc.GetDoc().State.SetPrimitiveCallback(c)
}

// Get the Document object owned by this Client.
func (sc *SimpleClient) GetDoc() *document.Document {
	return sc.client.Doc
}

// Return the current contents of the document.
func (sc *SimpleClient) Export() interface{} {
	return sc.client.Doc.State.Export()
}
<|endoftext|>


<commit_before>package view

import (
	"fmt"
	"github.com/ungerik/go-start/model"
	"github.com/ungerik/go-start/utils"
	"strings"
	//	"github.com/ungerik/go-start/debug"
)

type GetFormModelFunc func(form *Form, context *Context) (model interface{}, err error)

func FormModel(model interface{}) GetFormModelFunc {
	return func(form *Form, context *Context) (interface{}, error) {
		return model, nil
	}
}

/*
FormLayout is responsible for creating and structuring all dynamic content
of the form including the submit button.
It uses From.GetFieldFactory() to create the field views.
*/
type FormLayout interface {
	NewField_old(form *Form, modelValue model.Value, metaData *model.MetaData, errors []*model.ValidationError) View

	BeforeFormContent(form *Form) View
	AfterFormContent(form *Form) View

	BeforeStruct(form *Form, data interface{}, metaData *model.MetaData) View
	StructField(form *Form, data interface{}, metaData *model.MetaData) View
	AfterStruct(form *Form, data interface{}, metaData *model.MetaData) View

	BeforeArray(form *Form, data interface{}, metaData *model.MetaData) View
	ArrayField(form *Form, data interface{}, metaData *model.MetaData) View
	AfterArray(form *Form, data interface{}, metaData *model.MetaData) View

	BeforeSlice(form *Form, data interface{}, metaData *model.MetaData) View
	SliceField(form *Form, data interface{}, metaData *model.MetaData) View
	AfterSlice(form *Form, data interface{}, metaData *model.MetaData) View
}

type FormFieldFactory interface {
	NewInput(form *Form, data interface{}, metaData *model.MetaData) View
	NewLabel(form *Form, forView View, data interface{}, metaData *model.MetaData) View
	NewFieldErrorMessage(form *Form, message string, metaData *model.MetaData) View
	NewFormErrorMessage(form *Form, message string) View
	NewSuccessMessage(form *Form, message string) View
	NewSubmitButton(form *Form, text string) View
	NewAddSliceItemButton(form *Form) View
	NewRemoveSliceItemButton(form *Form) View
}

///////////////////////////////////////////////////////////////////////////////
// Form

type Form struct {
	ViewBaseWithId
	Class         string
	Action        string // Default is "." plus any URL params
	Method        string
	FormID        string
	CSRFProtector CSRFProtector
	Layout        FormLayout       // Config.DefaultFormLayout will be used if nil
	FieldFactory  FormFieldFactory // Config.DefaultFormFieldFactory will be used if nil
	// Static content rendered before the dynamic form fields
	// that are generated via GetModel()
	StaticContent View
	GetModel      GetFormModelFunc
	// If redirect result is non nil, it will be used instead of Form.Redirect
	OnSubmit            func(form *Form, formModel interface{}, context *Context) (redirect URL, err error)
	ModelMaxDepth       int      // if zero, no depth limit
	HideFields          []string // Use point notation for nested fields
	DisableFields       []string // Use point notation for nested fields
	RequireFields       []string // Also available as static struct field tag. Use point notation for nested fields
	ErrorMessageClass   string   // If empty, Config.Form.DefaultErrorMessageClass will be used
	SuccessMessageClass string   // If empty, Config.Form.DefaultSuccessMessageClass will be used
	RequiredMarker      View     // If nil, Config.Form.DefaultRequiredMarker will be used
	SuccessMessage      string
	SubmitButtonText    string
	SubmitButtonClass   string
	Redirect            URL // 302 redirect after successful Save()
	ShowRefIDs          bool
}

// GetLayout returns self.Layout if not nil,
// else Config.Form.DefaultLayout will be returned.
func (self *Form) GetLayout() FormLayout {
	if self.Layout == nil {
		return Config.Form.DefaultLayout
	}
	return self.Layout
}

// GetFieldFactory returns self.FieldFactory if not nil,
// else Config.Form.DefaultFieldFactory will be returned.
func (self *Form) GetFieldFactory() FormFieldFactory {
	if self.FieldFactory == nil {
		return Config.Form.DefaultFieldFactory
	}
	return self.FieldFactory
}

// GetCSRFProtector returns self.CSRFProtector if not nil,
// else Config.Form.DefaultCSRFProtector will be returned.
func (self *Form) GetCSRFProtector() CSRFProtector {
	if self.CSRFProtector == nil {
		return Config.Form.DefaultCSRFProtector
	}
	return self.CSRFProtector
}

func (self *Form) GetErrorMessageClass() string {
	if self.ErrorMessageClass == "" {
		return Config.Form.DefaultErrorMessageClass
	}
	return self.ErrorMessageClass
}

func (self *Form) GetSuccessMessageClass() string {
	if self.SuccessMessageClass == "" {
		return Config.Form.DefaultSuccessMessageClass
	}
	return self.SuccessMessageClass
}

func (self *Form) GetSubmitButtonClass() string {
	if self.SubmitButtonClass == "" {
		return Config.Form.DefaultSubmitButtonClass
	}
	return self.SubmitButtonClass
}

func (self *Form) GetRequiredMarker() View {
	if self.RequiredMarker == nil {
		return Config.Form.DefaultRequiredMarker
	}
	return self.RequiredMarker
}

func (self *Form) IterateChildren(callback IterateChildrenCallback) {
	if self.StaticContent != nil {
		callback(self, self.StaticContent)
	}
}

func (self *Form) IsFieldRequired(metaData *model.MetaData) bool {
	if metaData.BoolAttrib("required") {
		return true
	}
	selector := metaData.Selector()
	arrayWildcardSelector := metaData.ArrayWildcardSelector()
	return utils.StringIn(selector, self.RequireFields) || utils.StringIn(arrayWildcardSelector, self.RequireFields)
}

func (self *Form) isFieldRequiredSelectors(metaData *model.MetaData, selector, arrayWildcardSelector string) bool {
	if metaData.BoolAttrib("required") {
		return true
	}
	return utils.StringIn(selector, self.RequireFields) || utils.StringIn(arrayWildcardSelector, self.RequireFields)
}

func (self *Form) IsFieldDisabled(metaData *model.MetaData) bool {
	if metaData.BoolAttrib("disabled") {
		return true
	}
	selector := metaData.Selector()
	arrayWildcardSelector := metaData.ArrayWildcardSelector()
	return utils.StringIn(selector, self.DisableFields) || utils.StringIn(arrayWildcardSelector, self.DisableFields)
}

func (self *Form) Render(context *Context, writer *utils.XMLWriter) (err error) {

	var dynamicFields Views

	if self.OnSubmit != nil {
		// Determine if it's a POST request for this form:
		isPOST := false
		if context.Request.Method == "POST" {
			// Every HTML form gets an ID to allow more than one form per page:
			id, ok := context.Params["form_id"]
			if ok && id == self.FormID {
				isPOST = true
			}
		}

		// Create views for form fields:

		// Set a view before and after the form fields
		// if there is an error or success message
		// (won't be rendered if nil)
		// Also add a hidden form field with the form id
		// and a submit button
		dynamicFields = make(Views, 1, 32)

		numValueErrors := 0
		generalErrors := []*model.ValidationError{}

		var formModel interface{}

		if self.GetModel != nil {
			formModel, err = self.GetModel(self, context)
			if err != nil {
				return err
			}
			model.WalkStructure(formModel, self.ModelMaxDepth,
				func(data interface{}, metaData *model.MetaData) {
					if modelValue, ok := data.(model.Value); ok {
						if metaData == nil {
							panic(fmt.Sprintf("model.Value must be a struct member to get a label and meta data for the form field. Passed as root model.Value: %T", modelValue))
						}
						selector := metaData.Selector()
						arrayWildcardSelector := metaData.ArrayWildcardSelector()

						if utils.StringIn(selector, self.HideFields) || utils.StringIn(arrayWildcardSelector, self.HideFields) {
							return
						}

						var valueErrors []*model.ValidationError
						if isPOST {
							formValue, ok := context.Params[selector]
							if b, isBool := modelValue.(*model.Bool); isBool {
								b.Set(formValue != "")
							} else if ok {
								err = modelValue.SetString(formValue)
								if err == nil {
									valueErrors = modelValue.Validate(metaData)
									if len(valueErrors) == 0 {
										if modelValue.IsEmpty() && self.isFieldRequiredSelectors(metaData, selector, arrayWildcardSelector) {
											valueErrors = []*model.ValidationError{model.NewRequiredValidationError(metaData)}
										}
									}
								} else {
									valueErrors = model.NewValidationErrors(err, metaData)
								}
								numValueErrors += len(valueErrors)
							}
						}

						dynamicFields = append(dynamicFields, self.GetLayout().NewField_old(self, modelValue, metaData, valueErrors))

					} else if validator, ok := data.(model.Validator); ok {

						generalErrors = append(generalErrors, validator.Validate(metaData)...)

					}
				},
			)
		}

		hasErrors := numValueErrors > 0 || len(generalErrors) > 0

		if isPOST {
			var message string
			if hasErrors {
				message = "Form not saved because of invalid values! "
				for _, err := range generalErrors {
					message = message + err.WrappedError.Error() + ". "
				}
			} else {
				// Try to save the new form field values
				redirect, err := self.OnSubmit(self, formModel, context)
				if err == nil {
					message = self.SuccessMessage
					if redirect == nil {
						redirect = self.Redirect
					}
				} else {
					message = err.Error()
					hasErrors = true
				}

				// Redirect if saved without errors and redirect URL is set
				if !hasErrors && redirect != nil {
					return Redirect(redirect.URL(context))
				}
			}

			if hasErrors {
				dynamicFields[0] = DIV(self.GetErrorMessageClass(), Escape(message))
				if len(dynamicFields)-1 > Config.Form.NumFieldRepeatMessage {
					dynamicFields = append(dynamicFields, DIV(self.GetErrorMessageClass(), Escape(message)))
				}
			} else {
				dynamicFields[0] = DIV(self.GetSuccessMessageClass(), Escape(message))
				if len(dynamicFields)-1 > Config.Form.NumFieldRepeatMessage {
					dynamicFields = append(dynamicFields, DIV(self.GetSuccessMessageClass(), Escape(message)))
				}
			}

		}

		// Add submit button and form ID:
		buttonText := self.SubmitButtonText
		if buttonText == "" {
			buttonText = "Save"
		}
		formId := &HiddenInput{Name: "form_id", Value: self.FormID}
		submitButton := self.GetFieldFactory().NewSubmitButton(self, buttonText)
		dynamicFields = append(dynamicFields, formId, submitButton)
	}

	// Render HTML form element
	method := self.Method
	if method == "" {
		method = "POST"
	}
	action := self.Action
	if action == "" {
		action = "."
		if i := strings.Index(context.Request.RequestURI, "?"); i != -1 {
			action += context.Request.RequestURI[i:]
		}
	}

	writer.OpenTag("form").Attrib("id", self.id).AttribIfNotDefault("class", self.Class)
	writer.Attrib("method", method)
	writer.Attrib("action", action)
	err = RenderChildViewsHTML(self, context, writer)
	if err != nil {
		return err
	}
	if dynamicFields != nil {
		dynamicFields.Init(dynamicFields)
		err = dynamicFields.Render(context, writer)
		if err != nil {
			return err
		}
	}
	writer.ExtraCloseTag() // form
	return nil
}

func getLabel(metaData *model.MetaData) string {
	names := make([]string, metaData.Depth)
	for i, m := metaData.Depth-1, metaData; i >= 0; i-- {
		label, ok := m.Attrib("label")
		if !ok {
			label = strings.Replace(m.Name, "_", " ", -1)
		}
		names[i] = label
		m = m.Parent
	}
	return strings.Join(names, " ")
}

func getClass(metaData *model.MetaData) string {
	class, _ := metaData.Attrib("class")
	return class
}
<commit_msg>renamed view.Form.HideFields to ExcludeFields<commit_after>package view

import (
	"fmt"
	"github.com/ungerik/go-start/model"
	"github.com/ungerik/go-start/utils"
	"strings"
	//	"github.com/ungerik/go-start/debug"
)

type GetFormModelFunc func(form *Form, context *Context) (model interface{}, err error)

func FormModel(model interface{}) GetFormModelFunc {
	return func(form *Form, context *Context) (interface{}, error) {
		return model, nil
	}
}

/*
FormLayout is responsible for creating and structuring all dynamic content
of the form including the submit button.
It uses From.GetFieldFactory() to create the field views.
*/
type FormLayout interface {
	NewField_old(form *Form, modelValue model.Value, metaData *model.MetaData, errors []*model.ValidationError) View

	BeforeFormContent(form *Form) View
	AfterFormContent(form *Form) View

	BeforeStruct(form *Form, data interface{}, metaData *model.MetaData) View
	StructField(form *Form, data interface{}, metaData *model.MetaData) View
	AfterStruct(form *Form, data interface{}, metaData *model.MetaData) View

	BeforeArray(form *Form, data interface{}, metaData *model.MetaData) View
	ArrayField(form *Form, data interface{}, metaData *model.MetaData) View
	AfterArray(form *Form, data interface{}, metaData *model.MetaData) View

	BeforeSlice(form *Form, data interface{}, metaData *model.MetaData) View
	SliceField(form *Form, data interface{}, metaData *model.MetaData) View
	AfterSlice(form *Form, data interface{}, metaData *model.MetaData) View
}

type FormFieldFactory interface {
	NewInput(form *Form, data interface{}, metaData *model.MetaData) View
	NewLabel(form *Form, forView View, data interface{}, metaData *model.MetaData) View
	NewFieldErrorMessage(form *Form, message string, metaData *model.MetaData) View
	NewFormErrorMessage(form *Form, message string) View
	NewSuccessMessage(form *Form, message string) View
	NewSubmitButton(form *Form, text string) View
	NewAddSliceItemButton(form *Form) View
	NewRemoveSliceItemButton(form *Form) View
}

///////////////////////////////////////////////////////////////////////////////
// Form

type Form struct {
	ViewBaseWithId
	Class         string
	Action        string // Default is "." plus any URL params
	Method        string
	FormID        string
	CSRFProtector CSRFProtector
	Layout        FormLayout       // Config.DefaultFormLayout will be used if nil
	FieldFactory  FormFieldFactory // Config.DefaultFormFieldFactory will be used if nil
	// Static content rendered before the dynamic form fields
	// that are generated via GetModel()
	StaticContent View
	GetModel      GetFormModelFunc
	// If redirect result is non nil, it will be used instead of Form.Redirect
	OnSubmit            func(form *Form, formModel interface{}, context *Context) (redirect URL, err error)
	ModelMaxDepth       int      // if zero, no depth limit
	ExcludeFields       []string // Use point notation for nested fields
	DisableFields       []string // Use point notation for nested fields
	RequireFields       []string // Also available as static struct field tag. Use point notation for nested fields
	ErrorMessageClass   string   // If empty, Config.Form.DefaultErrorMessageClass will be used
	SuccessMessageClass string   // If empty, Config.Form.DefaultSuccessMessageClass will be used
	RequiredMarker      View     // If nil, Config.Form.DefaultRequiredMarker will be used
	SuccessMessage      string
	SubmitButtonText    string
	SubmitButtonClass   string
	Redirect            URL // 302 redirect after successful Save()
	ShowRefIDs          bool
}

// GetLayout returns self.Layout if not nil,
// else Config.Form.DefaultLayout will be returned.
func (self *Form) GetLayout() FormLayout {
	if self.Layout == nil {
		return Config.Form.DefaultLayout
	}
	return self.Layout
}

// GetFieldFactory returns self.FieldFactory if not nil,
// else Config.Form.DefaultFieldFactory will be returned.
func (self *Form) GetFieldFactory() FormFieldFactory {
	if self.FieldFactory == nil {
		return Config.Form.DefaultFieldFactory
	}
	return self.FieldFactory
}

// GetCSRFProtector returns self.CSRFProtector if not nil,
// else Config.Form.DefaultCSRFProtector will be returned.
func (self *Form) GetCSRFProtector() CSRFProtector {
	if self.CSRFProtector == nil {
		return Config.Form.DefaultCSRFProtector
	}
	return self.CSRFProtector
}

func (self *Form) GetErrorMessageClass() string {
	if self.ErrorMessageClass == "" {
		return Config.Form.DefaultErrorMessageClass
	}
	return self.ErrorMessageClass
}

func (self *Form) GetSuccessMessageClass() string {
	if self.SuccessMessageClass == "" {
		return Config.Form.DefaultSuccessMessageClass
	}
	return self.SuccessMessageClass
}

func (self *Form) GetSubmitButtonClass() string {
	if self.SubmitButtonClass == "" {
		return Config.Form.DefaultSubmitButtonClass
	}
	return self.SubmitButtonClass
}

func (self *Form) GetRequiredMarker() View {
	if self.RequiredMarker == nil {
		return Config.Form.DefaultRequiredMarker
	}
	return self.RequiredMarker
}

func (self *Form) IterateChildren(callback IterateChildrenCallback) {
	if self.StaticContent != nil {
		callback(self, self.StaticContent)
	}
}

func (self *Form) IsFieldRequired(metaData *model.MetaData) bool {
	if metaData.BoolAttrib("required") {
		return true
	}
	selector := metaData.Selector()
	arrayWildcardSelector := metaData.ArrayWildcardSelector()
	return utils.StringIn(selector, self.RequireFields) || utils.StringIn(arrayWildcardSelector, self.RequireFields)
}

func (self *Form) isFieldRequiredSelectors(metaData *model.MetaData, selector, arrayWildcardSelector string) bool {
	if metaData.BoolAttrib("required") {
		return true
	}
	return utils.StringIn(selector, self.RequireFields) || utils.StringIn(arrayWildcardSelector, self.RequireFields)
}

func (self *Form) IsFieldDisabled(metaData *model.MetaData) bool {
	if metaData.BoolAttrib("disabled") {
		return true
	}
	selector := metaData.Selector()
	arrayWildcardSelector := metaData.ArrayWildcardSelector()
	return utils.StringIn(selector, self.DisableFields) || utils.StringIn(arrayWildcardSelector, self.DisableFields)
}

func (self *Form) Render(context *Context, writer *utils.XMLWriter) (err error) {

	var dynamicFields Views

	if self.OnSubmit != nil {
		// Determine if it's a POST request for this form:
		isPOST := false
		if context.Request.Method == "POST" {
			// Every HTML form gets an ID to allow more than one form per page:
			id, ok := context.Params["form_id"]
			if ok && id == self.FormID {
				isPOST = true
			}
		}

		// Create views for form fields:

		// Set a view before and after the form fields
		// if there is an error or success message
		// (won't be rendered if nil)
		// Also add a hidden form field with the form id
		// and a submit button
		dynamicFields = make(Views, 1, 32)

		numValueErrors := 0
		generalErrors := []*model.ValidationError{}

		var formModel interface{}

		if self.GetModel != nil {
			formModel, err = self.GetModel(self, context)
			if err != nil {
				return err
			}
			model.WalkStructure(formModel, self.ModelMaxDepth,
				func(data interface{}, metaData *model.MetaData) {
					if modelValue, ok := data.(model.Value); ok {
						if metaData == nil {
							panic(fmt.Sprintf("model.Value must be a struct member to get a label and meta data for the form field. Passed as root model.Value: %T", modelValue))
						}
						selector := metaData.Selector()
						arrayWildcardSelector := metaData.ArrayWildcardSelector()

						if utils.StringIn(selector, self.ExcludeFields) || utils.StringIn(arrayWildcardSelector, self.ExcludeFields) {
							return
						}

						var valueErrors []*model.ValidationError
						if isPOST {
							formValue, ok := context.Params[selector]
							if b, isBool := modelValue.(*model.Bool); isBool {
								b.Set(formValue != "")
							} else if ok {
								err = modelValue.SetString(formValue)
								if err == nil {
									valueErrors = modelValue.Validate(metaData)
									if len(valueErrors) == 0 {
										if modelValue.IsEmpty() && self.isFieldRequiredSelectors(metaData, selector, arrayWildcardSelector) {
											valueErrors = []*model.ValidationError{model.NewRequiredValidationError(metaData)}
										}
									}
								} else {
									valueErrors = model.NewValidationErrors(err, metaData)
								}
								numValueErrors += len(valueErrors)
							}
						}

						dynamicFields = append(dynamicFields, self.GetLayout().NewField_old(self, modelValue, metaData, valueErrors))

					} else if validator, ok := data.(model.Validator); ok {

						generalErrors = append(generalErrors, validator.Validate(metaData)...)

					}
				},
			)
		}

		hasErrors := numValueErrors > 0 || len(generalErrors) > 0

		if isPOST {
			var message string
			if hasErrors {
				message = "Form not saved because of invalid values! "
				for _, err := range generalErrors {
					message = message + err.WrappedError.Error() + ". "
				}
			} else {
				// Try to save the new form field values
				redirect, err := self.OnSubmit(self, formModel, context)
				if err == nil {
					message = self.SuccessMessage
					if redirect == nil {
						redirect = self.Redirect
					}
				} else {
					message = err.Error()
					hasErrors = true
				}

				// Redirect if saved without errors and redirect URL is set
				if !hasErrors && redirect != nil {
					return Redirect(redirect.URL(context))
				}
			}

			if hasErrors {
				dynamicFields[0] = DIV(self.GetErrorMessageClass(), Escape(message))
				if len(dynamicFields)-1 > Config.Form.NumFieldRepeatMessage {
					dynamicFields = append(dynamicFields, DIV(self.GetErrorMessageClass(), Escape(message)))
				}
			} else {
				dynamicFields[0] = DIV(self.GetSuccessMessageClass(), Escape(message))
				if len(dynamicFields)-1 > Config.Form.NumFieldRepeatMessage {
					dynamicFields = append(dynamicFields, DIV(self.GetSuccessMessageClass(), Escape(message)))
				}
			}

		}

		// Add submit button and form ID:
		buttonText := self.SubmitButtonText
		if buttonText == "" {
			buttonText = "Save"
		}
		formId := &HiddenInput{Name: "form_id", Value: self.FormID}
		submitButton := self.GetFieldFactory().NewSubmitButton(self, buttonText)
		dynamicFields = append(dynamicFields, formId, submitButton)
	}

	// Render HTML form element
	method := self.Method
	if method == "" {
		method = "POST"
	}
	action := self.Action
	if action == "" {
		action = "."
		if i := strings.Index(context.Request.RequestURI, "?"); i != -1 {
			action += context.Request.RequestURI[i:]
		}
	}

	writer.OpenTag("form").Attrib("id", self.id).AttribIfNotDefault("class", self.Class)
	writer.Attrib("method", method)
	writer.Attrib("action", action)
	err = RenderChildViewsHTML(self, context, writer)
	if err != nil {
		return err
	}
	if dynamicFields != nil {
		dynamicFields.Init(dynamicFields)
		err = dynamicFields.Render(context, writer)
		if err != nil {
			return err
		}
	}
	writer.ExtraCloseTag() // form
	return nil
}

func getLabel(metaData *model.MetaData) string {
	names := make([]string, metaData.Depth)
	for i, m := metaData.Depth-1, metaData; i >= 0; i-- {
		label, ok := m.Attrib("label")
		if !ok {
			label = strings.Replace(m.Name, "_", " ", -1)
		}
		names[i] = label
		m = m.Parent
	}
	return strings.Join(names, " ")
}

func getClass(metaData *model.MetaData) string {
	class, _ := metaData.Attrib("class")
	return class
}
<|endoftext|>


<commit_before>package pwr

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"

	"github.com/itchio/wharf/state"
	"github.com/itchio/wharf/wire"
)

func swap(a []int, i, j int) { a[i], a[j] = a[j], a[i] }

// Ternary-Split Quicksort, cf. http://www.larsson.dogma.net/ssrev-tr.pdf
func split(I, V []int, start, length, h int) {
	var i, j, k, x, jj, kk int

	if length < 16 {
		for k = start; k < start+length; k += j {
			j = 1
			x = V[I[k]+h]
			for i = 1; k+i < start+length; i++ {
				if V[I[k+i]+h] < x {
					x = V[I[k+i]+h]
					j = 0
				}
				if V[I[k+i]+h] == x {
					swap(I, k+i, k+j)
					j++
				}
			}
			for i = 0; i < j; i++ {
				V[I[k+i]] = k + j - 1
			}
			if j == 1 {
				I[k] = -1
			}
		}
		return
	}

	x = V[I[start+length/2]+h]
	jj = 0
	kk = 0
	for i = start; i < start+length; i++ {
		if V[I[i]+h] < x {
			jj++
		}
		if V[I[i]+h] == x {
			kk++
		}
	}
	jj += start
	kk += jj

	i = start
	j = 0
	k = 0
	for i < jj {
		if V[I[i]+h] < x {
			i++
		} else if V[I[i]+h] == x {
			swap(I, i, jj+j)
			j++
		} else {
			swap(I, i, kk+k)
			k++
		}
	}

	for jj+j < kk {
		if V[I[jj+j]+h] == x {
			j++
		} else {
			swap(I, jj+j, kk+k)
			k++
		}
	}

	if jj > start {
		split(I, V, start, jj-start, h)
	}

	for i = 0; i < kk-jj; i++ {
		V[I[jj+i]] = kk - 1
	}
	if jj == kk-1 {
		I[jj] = -1
	}

	if start+length > kk {
		split(I, V, kk, start+length-kk, h)
	}
}

// Faster Suffix Sorting, see: http://www.larsson.dogma.net/ssrev-tr.pdf
// Output `I` is a sorted suffix array.
func qsufsort(obuf []byte) []int {
	var buckets [256]int
	var i, h int
	I := make([]int, len(obuf)+1)
	V := make([]int, len(obuf)+1)

	for _, c := range obuf {
		buckets[c]++
	}
	for i = 1; i < 256; i++ {
		buckets[i] += buckets[i-1]
	}
	copy(buckets[1:], buckets[:])
	buckets[0] = 0

	for i, c := range obuf {
		buckets[c]++
		I[buckets[c]] = i
	}

	I[0] = len(obuf)
	for i, c := range obuf {
		V[i] = buckets[c]
	}

	V[len(obuf)] = 0
	for i = 1; i < 256; i++ {
		if buckets[i] == buckets[i-1]+1 {
			I[buckets[i]] = -1
		}
	}
	I[0] = -1

	for h = 1; I[0] != -(len(obuf) + 1); h += h {
		var n int
		for i = 0; i < len(obuf)+1; {
			if I[i] < 0 {
				n -= I[i]
				i -= I[i]
			} else {
				if n != 0 {
					I[i-n] = -n
				}
				n = V[I[i]] + 1 - i
				split(I, V, i, n, h)
				i += n
				n = 0
			}
		}
		if n != 0 {
			I[i-n] = -n
		}
	}

	for i = 0; i < len(obuf)+1; i++ {
		I[V[i]] = i
	}
	return I
}

// Returns the number of bytes common to a and b
func matchlen(a, b []byte) (i int) {
	for i < len(a) && i < len(b) && a[i] == b[i] {
		i++
	}
	return i
}

func search(I []int, obuf, nbuf []byte, st, en int) (pos, n int) {
	if en-st < 2 {
		x := matchlen(obuf[I[st]:], nbuf)
		y := matchlen(obuf[I[en]:], nbuf)

		if x > y {
			return I[st], x
		}
		return I[en], y
	}

	x := st + (en-st)/2
	if bytes.Compare(obuf[I[x]:], nbuf) < 0 {
		return search(I, obuf, nbuf, x, en)
	}
	return search(I, obuf, nbuf, st, x)
}

// BSDiff computes the difference between old and new, according to the bsdiff
// algorithm, and writes the result to patch.
func BSDiff(old, new io.Reader, patch *wire.WriteContext, consumer *state.Consumer) error {
	obuf, err := ioutil.ReadAll(old)
	if err != nil {
		return err
	}

	nbuf, err := ioutil.ReadAll(new)
	if err != nil {
		return err
	}

	consumer.ProgressLabel("Suffix sorting...")

	var lenf int
	I := qsufsort(obuf)
	db := make([]byte, len(nbuf))
	eb := make([]byte, len(nbuf))

	bsdc := &BsdiffControl{}

	consumer.ProgressLabel("Scanning...")

	// Compute the differences, writing ctrl as we go
	var scan, pos, length int
	var lastscan, lastpos, lastoffset int
	for scan < len(nbuf) {
		var oldscore int
		scan += length

		progress := float64(scan) / float64(len(nbuf))
		consumer.Progress(progress)

		for scsc := scan; scan < len(nbuf); scan++ {
			pos, length = search(I, obuf, nbuf[scan:], 0, len(obuf))

			for ; scsc < scan+length; scsc++ {
				if scsc+lastoffset < len(obuf) &&
					obuf[scsc+lastoffset] == nbuf[scsc] {
					oldscore++
				}
			}

			if (length == oldscore && length != 0) || length > oldscore+8 {
				break
			}

			if scan+lastoffset < len(obuf) && obuf[scan+lastoffset] == nbuf[scan] {
				oldscore--
			}
		}

		if length != oldscore || scan == len(nbuf) {
			var s, Sf int
			lenf = 0
			for i := 0; lastscan+i < scan && lastpos+i < len(obuf); {
				if obuf[lastpos+i] == nbuf[lastscan+i] {
					s++
				}
				i++
				if s*2-i > Sf*2-lenf {
					Sf = s
					lenf = i
				}
			}

			lenb := 0
			if scan < len(nbuf) {
				var s, Sb int
				for i := 1; (scan >= lastscan+i) && (pos >= i); i++ {
					if obuf[pos-i] == nbuf[scan-i] {
						s++
					}
					if s*2-i > Sb*2-lenb {
						Sb = s
						lenb = i
					}
				}
			}

			if lastscan+lenf > scan-lenb {
				overlap := (lastscan + lenf) - (scan - lenb)
				s := 0
				Ss := 0
				lens := 0
				for i := 0; i < overlap; i++ {
					if nbuf[lastscan+lenf-overlap+i] == obuf[lastpos+lenf-overlap+i] {
						s++
					}
					if nbuf[scan-lenb+i] == obuf[pos-lenb+i] {
						s--
					}
					if s > Ss {
						Ss = s
						lens = i + 1
					}
				}

				lenf += lens - overlap
				lenb -= lens
			}

			for i := 0; i < lenf; i++ {
				db[i] = nbuf[lastscan+i] - obuf[lastpos+i]
			}
			for i := 0; i < (scan-lenb)-(lastscan+lenf); i++ {
				eb[i] = nbuf[lastscan+lenf+i]
			}

			bsdc.Add = db[:lenf]
			bsdc.Copy = eb[:(scan-lenb)-(lastscan+lenf)]
			bsdc.Seek = int64((pos - lenb) - (lastpos + lenf))

			err := patch.WriteMessage(bsdc)
			if err != nil {
				return err
			}

			lastscan = scan - lenb
			lastpos = pos - lenb
			lastoffset = pos - scan
		}
	}

	// Write sentinel control message
	bsdc.Reset()
	bsdc.Seek = -1
	err = patch.WriteMessage(bsdc)
	if err != nil {
		return err
	}

	return nil
}

// ErrCorrupt indicates that a patch is corrupted, most often that it would produce a longer file
// than specified
var ErrCorrupt = errors.New("corrupt patch")

// BSPatch applies patch to old, according to the bspatch algorithm,
// and writes the result to new.
func BSPatch(old io.Reader, new io.Writer, newSize int64, patch *wire.ReadContext) error {
	obuf, err := ioutil.ReadAll(old)
	if err != nil {
		return err
	}

	nbuf := make([]byte, newSize)

	var oldpos, newpos int64

	ctrl := &BsdiffControl{}

	for {
		ctrl.Reset()

		err = patch.ReadMessage(ctrl)
		if err != nil {
			return err
		}

		if ctrl.Seek == -1 {
			break
		}

		// Sanity-check
		if newpos+int64(len(ctrl.Add)) > newSize {
			return ErrCorrupt
		}

		// Add old data to diff string
		for i := int64(0); i < int64(len(ctrl.Add)); i++ {
			nbuf[newpos+i] = ctrl.Add[i] + obuf[oldpos+i]
		}

		// Adjust pointers
		newpos += int64(len(ctrl.Add))
		oldpos += int64(len(ctrl.Add))

		// Sanity-check
		if newpos+int64(len(ctrl.Copy)) > newSize {
			return ErrCorrupt
		}

		// Read extra string
		copy(nbuf[newpos:], ctrl.Copy)

		// Adjust pointers
		newpos += int64(len(ctrl.Copy))
		oldpos += ctrl.Seek
	}

	// Write the new file
	for len(nbuf) > 0 {
		n, err := new.Write(nbuf)
		if err != nil {
			return err
		}
		nbuf = nbuf[n:]
	}

	return nil
}
<commit_msg>Progress indicators for suffix sorting<commit_after>package pwr

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"

	"github.com/itchio/wharf/state"
	"github.com/itchio/wharf/wire"
)

func swap(a []int, i, j int) { a[i], a[j] = a[j], a[i] }

// Ternary-Split Quicksort, cf. http://www.larsson.dogma.net/ssrev-tr.pdf
func split(I, V []int, start, length, h int) {
	var i, j, k, x, jj, kk int

	if length < 16 {
		for k = start; k < start+length; k += j {
			j = 1
			x = V[I[k]+h]
			for i = 1; k+i < start+length; i++ {
				if V[I[k+i]+h] < x {
					x = V[I[k+i]+h]
					j = 0
				}
				if V[I[k+i]+h] == x {
					swap(I, k+i, k+j)
					j++
				}
			}
			for i = 0; i < j; i++ {
				V[I[k+i]] = k + j - 1
			}
			if j == 1 {
				I[k] = -1
			}
		}
		return
	}

	x = V[I[start+length/2]+h]
	jj = 0
	kk = 0
	for i = start; i < start+length; i++ {
		if V[I[i]+h] < x {
			jj++
		}
		if V[I[i]+h] == x {
			kk++
		}
	}
	jj += start
	kk += jj

	i = start
	j = 0
	k = 0
	for i < jj {
		if V[I[i]+h] < x {
			i++
		} else if V[I[i]+h] == x {
			swap(I, i, jj+j)
			j++
		} else {
			swap(I, i, kk+k)
			k++
		}
	}

	for jj+j < kk {
		if V[I[jj+j]+h] == x {
			j++
		} else {
			swap(I, jj+j, kk+k)
			k++
		}
	}

	if jj > start {
		split(I, V, start, jj-start, h)
	}

	for i = 0; i < kk-jj; i++ {
		V[I[jj+i]] = kk - 1
	}
	if jj == kk-1 {
		I[jj] = -1
	}

	if start+length > kk {
		split(I, V, kk, start+length-kk, h)
	}
}

// Faster Suffix Sorting, see: http://www.larsson.dogma.net/ssrev-tr.pdf
// Output `I` is a sorted suffix array.
func qsufsort(obuf []byte, consumer *state.Consumer) []int {
	var buckets [256]int
	var i, h int
	I := make([]int, len(obuf)+1)
	V := make([]int, len(obuf)+1)

	for _, c := range obuf {
		buckets[c]++
	}
	for i = 1; i < 256; i++ {
		buckets[i] += buckets[i-1]
	}
	copy(buckets[1:], buckets[:])
	buckets[0] = 0

	for i, c := range obuf {
		buckets[c]++
		I[buckets[c]] = i
	}

	I[0] = len(obuf)
	for i, c := range obuf {
		V[i] = buckets[c]
	}

	V[len(obuf)] = 0
	for i = 1; i < 256; i++ {
		if buckets[i] == buckets[i-1]+1 {
			I[buckets[i]] = -1
		}
	}
	I[0] = -1

	const progressInterval = 64 * 1024

	for h = 1; I[0] != -(len(obuf) + 1); h += h {
		consumer.ProgressLabel(fmt.Sprintf("Suffix sorting (%d-order)", h))

		lastI := 0

		var n int
		for i = 0; i < len(obuf)+1; {
			if i-lastI > progressInterval {
				progress := float64(i) / float64(len(obuf))
				consumer.Progress(progress)
				lastI = i
			}

			if I[i] < 0 {
				n -= I[i]
				i -= I[i]
			} else {
				if n != 0 {
					I[i-n] = -n
				}
				n = V[I[i]] + 1 - i
				split(I, V, i, n, h)
				i += n
				n = 0
			}
		}
		if n != 0 {
			I[i-n] = -n
		}
	}

	for i = 0; i < len(obuf)+1; i++ {
		I[V[i]] = i
	}
	return I
}

// Returns the number of bytes common to a and b
func matchlen(a, b []byte) (i int) {
	for i < len(a) && i < len(b) && a[i] == b[i] {
		i++
	}
	return i
}

func search(I []int, obuf, nbuf []byte, st, en int) (pos, n int) {
	if en-st < 2 {
		x := matchlen(obuf[I[st]:], nbuf)
		y := matchlen(obuf[I[en]:], nbuf)

		if x > y {
			return I[st], x
		}
		return I[en], y
	}

	x := st + (en-st)/2
	if bytes.Compare(obuf[I[x]:], nbuf) < 0 {
		return search(I, obuf, nbuf, x, en)
	}
	return search(I, obuf, nbuf, st, x)
}

// BSDiff computes the difference between old and new, according to the bsdiff
// algorithm, and writes the result to patch.
func BSDiff(old, new io.Reader, patch *wire.WriteContext, consumer *state.Consumer) error {
	obuf, err := ioutil.ReadAll(old)
	if err != nil {
		return err
	}

	nbuf, err := ioutil.ReadAll(new)
	if err != nil {
		return err
	}

	var lenf int
	I := qsufsort(obuf, consumer)
	db := make([]byte, len(nbuf))
	eb := make([]byte, len(nbuf))

	bsdc := &BsdiffControl{}

	consumer.ProgressLabel("Scanning...")

	// Compute the differences, writing ctrl as we go
	var scan, pos, length int
	var lastscan, lastpos, lastoffset int
	for scan < len(nbuf) {
		var oldscore int
		scan += length

		progress := float64(scan) / float64(len(nbuf))
		consumer.Progress(progress)

		for scsc := scan; scan < len(nbuf); scan++ {
			pos, length = search(I, obuf, nbuf[scan:], 0, len(obuf))

			for ; scsc < scan+length; scsc++ {
				if scsc+lastoffset < len(obuf) &&
					obuf[scsc+lastoffset] == nbuf[scsc] {
					oldscore++
				}
			}

			if (length == oldscore && length != 0) || length > oldscore+8 {
				break
			}

			if scan+lastoffset < len(obuf) && obuf[scan+lastoffset] == nbuf[scan] {
				oldscore--
			}
		}

		if length != oldscore || scan == len(nbuf) {
			var s, Sf int
			lenf = 0
			for i := 0; lastscan+i < scan && lastpos+i < len(obuf); {
				if obuf[lastpos+i] == nbuf[lastscan+i] {
					s++
				}
				i++
				if s*2-i > Sf*2-lenf {
					Sf = s
					lenf = i
				}
			}

			lenb := 0
			if scan < len(nbuf) {
				var s, Sb int
				for i := 1; (scan >= lastscan+i) && (pos >= i); i++ {
					if obuf[pos-i] == nbuf[scan-i] {
						s++
					}
					if s*2-i > Sb*2-lenb {
						Sb = s
						lenb = i
					}
				}
			}

			if lastscan+lenf > scan-lenb {
				overlap := (lastscan + lenf) - (scan - lenb)
				s := 0
				Ss := 0
				lens := 0
				for i := 0; i < overlap; i++ {
					if nbuf[lastscan+lenf-overlap+i] == obuf[lastpos+lenf-overlap+i] {
						s++
					}
					if nbuf[scan-lenb+i] == obuf[pos-lenb+i] {
						s--
					}
					if s > Ss {
						Ss = s
						lens = i + 1
					}
				}

				lenf += lens - overlap
				lenb -= lens
			}

			for i := 0; i < lenf; i++ {
				db[i] = nbuf[lastscan+i] - obuf[lastpos+i]
			}
			for i := 0; i < (scan-lenb)-(lastscan+lenf); i++ {
				eb[i] = nbuf[lastscan+lenf+i]
			}

			bsdc.Add = db[:lenf]
			bsdc.Copy = eb[:(scan-lenb)-(lastscan+lenf)]
			bsdc.Seek = int64((pos - lenb) - (lastpos + lenf))

			err := patch.WriteMessage(bsdc)
			if err != nil {
				return err
			}

			lastscan = scan - lenb
			lastpos = pos - lenb
			lastoffset = pos - scan
		}
	}

	// Write sentinel control message
	bsdc.Reset()
	bsdc.Seek = -1
	err = patch.WriteMessage(bsdc)
	if err != nil {
		return err
	}

	return nil
}

// ErrCorrupt indicates that a patch is corrupted, most often that it would produce a longer file
// than specified
var ErrCorrupt = errors.New("corrupt patch")

// BSPatch applies patch to old, according to the bspatch algorithm,
// and writes the result to new.
func BSPatch(old io.Reader, new io.Writer, newSize int64, patch *wire.ReadContext) error {
	obuf, err := ioutil.ReadAll(old)
	if err != nil {
		return err
	}

	nbuf := make([]byte, newSize)

	var oldpos, newpos int64

	ctrl := &BsdiffControl{}

	for {
		ctrl.Reset()

		err = patch.ReadMessage(ctrl)
		if err != nil {
			return err
		}

		if ctrl.Seek == -1 {
			break
		}

		// Sanity-check
		if newpos+int64(len(ctrl.Add)) > newSize {
			return ErrCorrupt
		}

		// Add old data to diff string
		for i := int64(0); i < int64(len(ctrl.Add)); i++ {
			nbuf[newpos+i] = ctrl.Add[i] + obuf[oldpos+i]
		}

		// Adjust pointers
		newpos += int64(len(ctrl.Add))
		oldpos += int64(len(ctrl.Add))

		// Sanity-check
		if newpos+int64(len(ctrl.Copy)) > newSize {
			return ErrCorrupt
		}

		// Read extra string
		copy(nbuf[newpos:], ctrl.Copy)

		// Adjust pointers
		newpos += int64(len(ctrl.Copy))
		oldpos += ctrl.Seek
	}

	// Write the new file
	for len(nbuf) > 0 {
		n, err := new.Write(nbuf)
		if err != nil {
			return err
		}
		nbuf = nbuf[n:]
	}

	return nil
}
<|endoftext|>


<commit_before>package polynomial

import (
	"math"
)

// Closed is a basis in [0, 1]^n.
type Closed struct {
	nd uint
	np uint
}

// NewClosed creates a basis in [0, 1]^n.
func NewClosed(dimensions uint, order uint) *Closed {
	return &Closed{dimensions, order}
}

// Compute evaluates a basis function.
func (self *Closed) Compute(index []uint64, point []float64) float64 {
	nd, np := self.nd, uint64(self.np)

	value := 1.0
	for i := uint(0); i < nd; i++ {
		level, power := levelMask&index[i], np
		if level < power {
			power = level
		}
		if power == 0 {
			continue // value *= 1.0
		}

		order := index[i] >> levelSize
		xi, step := closedNode(level, order)

		x := point[i]
		delta := math.Abs(x - xi)
		if delta >= step {
			return 0.0 // value *= 0.0
		}

		if power == 1 {
			// Use two linear segments. The reason is that there are three
			// points (including the endpoints), but a first-order polynomial
			// can satisfy only two of them in general.
			value *= 1.0 - delta/step
			continue
		}

		// The left endpoint of the local support.
		xl := xi - step
		value *= (x - xl) / (xi - xl)
		power -= 1

		// The right endpoint of the local support.
		xr := xi + step
		value *= (x - xr) / (xi - xr)
		power -= 1

		// Find the rest of the needed ancestors.
		for power > 0 {
			level, order = closedParent(level, order)
			xj, _ := closedNode(level, order)
			if equal(xj, xl) || equal(xj, xr) {
				continue
			}
			value *= (x - xj) / (xi - xj)
			power -= 1
		}
	}

	return value
}

// Integrate computes the integral of a basis function.
func (self *Closed) Integrate(index []uint64) float64 {
	nd, np := self.nd, uint64(self.np)

	value := 1.0
	for i := uint(0); i < nd; i++ {
		level, power := levelMask&index[i], np
		if level < power {
			power = level
		}
		if power == 0 {
			continue // value *= 1.0
		}

		order := index[i] >> levelSize
		_, step := closedNode(level, order)

		if power == 1 {
			// Use two liner segments. See the corresponding comment in Compute.
			if level == 1 {
				value *= 0.25
			} else {
				value *= step
			}
			continue
		}

		panic("not implemented")
	}

	return value
}

func closedNode(level, order uint64) (x, step float64) {
	if level == 0 {
		x, step = 0.5, 1.0
	} else {
		step = 1.0 / float64(uint64(2)<<(level-1))
		x = float64(order) * step
	}
	return
}

func closedParent(level, order uint64) (uint64, uint64) {
	switch level {
	case 0:
		panic("the root does not have a parent")
	case 1:
		level = 0
		order = 0
	case 2:
		level = 1
		order -= 1
	default:
		level -= 1
		if ((order-1)/2)%2 == 0 {
			order = (order + 1) / 2
		} else {
			order = (order - 1) / 2
		}
	}
	return level, order
}
<commit_msg>b/polynomial: decompose Compute and Integrate<commit_after>package polynomial

import (
	"math"
)

// Closed is a basis in [0, 1]^n.
type Closed struct {
	nd uint
	np uint
}

// NewClosed creates a basis in [0, 1]^n.
func NewClosed(dimensions uint, order uint) *Closed {
	return &Closed{dimensions, order}
}

// Compute evaluates a basis function.
func (self *Closed) Compute(index []uint64, point []float64) float64 {
	nd, np, value := self.nd, self.np, 1.0
	for i := uint(0); i < nd && value != 0.0; i++ {
		value *= closedCompute(levelMask&index[i], index[i]>>levelSize, np, point[i])
	}
	return value
}

// Integrate computes the integral of a basis function.
func (self *Closed) Integrate(index []uint64) float64 {
	nd, np, value := self.nd, self.np, 1.0
	for i := uint(0); i < nd && value != 0.0; i++ {
		value *= closedIntegrate(levelMask&index[i], index[i]>>levelSize, np)
	}
	return value
}

func closedCompute(level, order uint64, power uint, x float64) float64 {
	if level < uint64(power) {
		power = uint(level)
	}
	if power == 0 {
		return 1.0
	}

	xi, step := closedNode(level, order)

	delta := math.Abs(x - xi)
	if delta >= step {
		return 0.0
	}

	if power == 1 {
		// Use two linear segments. The reason is that there are three points
		// (including the endpoints), but a first-order polynomial can satisfy
		// only two of them in general.
		return 1.0 - delta/step
	}

	value := 1.0

	// The left endpoint of the local support.
	xl := xi - step
	value *= (x - xl) / (xi - xl)
	power -= 1

	// The right endpoint of the local support.
	xr := xi + step
	value *= (x - xr) / (xi - xr)
	power -= 1

	// Find the rest of the needed ancestors.
	for power > 0 {
		level, order = closedParent(level, order)
		xj, _ := closedNode(level, order)
		if equal(xj, xl) || equal(xj, xr) {
			continue
		}
		value *= (x - xj) / (xi - xj)
		power -= 1
	}

	return value
}

func closedIntegrate(level, order uint64, power uint) float64 {
	if level < uint64(power) {
		power = uint(level)
	}
	if power == 0 {
		return 1.0
	}

	_, step := closedNode(level, order)

	if power == 1 {
		// Use two liner segments. See the corresponding comment in
		// computeClosed.
		if level == 1 {
			return 0.25
		} else {
			return step
		}
	}

	panic("not implemented")
}

func closedNode(level, order uint64) (x, step float64) {
	if level == 0 {
		x, step = 0.5, 1.0
	} else {
		step = 1.0 / float64(uint64(2)<<(level-1))
		x = float64(order) * step
	}
	return
}

func closedParent(level, order uint64) (uint64, uint64) {
	switch level {
	case 0:
		panic("the root does not have a parent")
	case 1:
		level = 0
		order = 0
	case 2:
		level = 1
		order -= 1
	default:
		level -= 1
		if ((order-1)/2)%2 == 0 {
			order = (order + 1) / 2
		} else {
			order = (order - 1) / 2
		}
	}
	return level, order
}
<|endoftext|>


<commit_before>package vreg

import "testing"

func TestQuery(t *testing.T) {
	Query("JJJ895AX")
}
<commit_msg>added test for invalid vpn<commit_after>package vreg

import "testing"

func TestQuery(t *testing.T) {
	Query("JJJ895AX")
}

func TestQueryInvalid(t *testing.T) {
	Query("JJJ895AX2")
}
<|endoftext|>


<commit_before>package iec61499

import "errors"

/* an example of a conversion

//event A is from Plant
//event B is from Controller
//A and B cannot happen simultaneously, A and B alternate starting with an A. B should be true within 5 ticks of B.

policyFB AB5Policy;
interface of AB5Policy {
	in event A;  //in here means that they're going from PLANT to CONTROLLER
	out event B; //out here means that they're going from CONTROLLER to PLANT
}

architecture of AB5Policy {
	internals {
		dtimer v;
	}

	states {
		s0 {														//first state is initial, and represents "We're waiting for an A"
			-> s0 on (!A and !B): v := 0;							//if we receive neither A nor B, do nothing
			-> s1 on (A and !B): v := 0;							//if we receive an A only, head to state s1
			-> violation on ((!A and B) or (A and B));				//if we receive a B, or an A and a B (i.e. if we receive a B) then VIOLATION
		}

		s1 {														//s1 is "we're waiting for a B, and it needs to get here within 5 ticks"
			-> s1 on (!A and !B and v < 5);							//if we receive nothing, and we aren't over-time, then we do nothing
			-> s0 on (!A and B);									//if we receive a B only, head to state s0
			-> violation on ((v >= 5) or (A and B) or (A and !B));	//if we go overtime, or we receive another A, then VIOLATION
		}
	}
}

CAN DERIVE TO INPUT POLICY (Remember, replace all outputs and things that depend on outputs with TRUE)

policyFB AB5Policy_INPUT;
interface of AB5Policy_INPUT {
	in event A;  //in here means that they're going from PLANT to CONTROLLER
}

architecture of AB5Policy_INPUT {
	internals {
		dtimer v;
	}

	states {
		s0 {
			-> s0 on (!A and (true)): v := 0;
			-> s1 on (A and (true)): v := 0;
			-> violation on ((!A and (true)) or (A and (true)));
		}

		s1 {
			-> s1 on (!A and (true) and v < 5);
			-> s0 on (!A and (true));
			-> violation on ((v >= 5) or (A and (true)) or (A and (true)));
		}
	}
}

IS EQUIVALENT TO

policyFB AB5Policy_INPUT;
interface of AB5Policy_INPUT {
	in event A;  //in here means that they're going from PLANT to CONTROLLER
}

architecture of AB5Policy_INPUT {
	internals {
		dtimer v;
	}

	states {
		s0 {
			-> s0 on (!A): v := 0;
			-> s1 on (A): v := 0;
			-> violation on (!A or A);
		}

		s1 {
			-> s1 on (!A and v < 5);
			-> s0 on (!A);
			-> violation on ((v >= 5) or (A));
		}
	}
}

Now remember, the enforcer for input will only make a change if an input _cannot_ result in a safe state.

In this case, in s0, every input (of A) can only result in a safe state, as both s0 is state and s1 has the potential to be safe
(I.e. we don't have to take the transition to the violation, so why would we?

In s1, if we receive an A, we're always going to end up in a violation. Stink!
So, what we'll do instead is get our enforcer to prevent the transition from occuring by instead picking a non-violating transition.
Both other transitions suggest !A, so that's what we'll do instead.

In s1, if v >= 5, that doesn't mean a violation _has_ to occur, because a !A could also have a non-violation.

WE CONVERT THESE TO ENFORCERS

*/

//TranslatePFBtoSIFB will take a Policy Function Block and compile it to its enforcer as a
// Service Interface Function Block
//It operates according to the algorithm specified in [TODO: Paper link]
func (f *FB) TranslatePFBtoSIFB() error {
	if f.PolicyFB == nil {
		return errors.New("TranslatePFBtoBFB can only be called on an PolicyFB")
	}

	return errors.New("Not yet implemented")
}

/*

policyFB AEIPolicy;
interface of AEIPolicy {
	in event AS, VS; //in here means that they're going from PLANT to CONTROLLER, and the EnforcerI is derived from this
	out event AP, VP;//out here means that they're going from CONTROLLER to PLANT
}
architecture of AEIPolicy {
	internals {
		ulint AEI_ns := 900000000;
		dtimer tAEI; //DTIMER increases in DISCRETE TIME continuously
	}

	//P3: AS or AP must be true within AEI after a ventricular event VS or VP.

	states {
		s1 {
			//-> <destination> [on guard] [: output expression][, output expression...] ;
			-> s2 on (VS or VP): tAEI := 0;
		}

		s2 {
			-> s1 on (AS or AP);
			-> violation on (tAEI > AEI_ns);
		}
	}
}

SHOULD BECOME TWO BLOCKS

serviceFB AEIPolicyEnforcerI;
interface of AEIPolicyEnforcerI {
	in event AS_poci, VS_poci; //PLANT OUT CONTROLLER IN, IN/OUT w.r.t. ENFORCER
	out event AS_poci_prime, VS_poci_prime;
}

architecture of AEIPolicyEnforcerI {

}

serviceFB AEIPolicyEnforcerO;
interface of AEIPolicyEnforcerO {
	in event AS_poci_prime, VS_poci_prime; //PLANT OUT CONTROLLER IN, IN/OUT w.r.t. ENFORCER

	in event AP_pico, VP_pico; //PLANT IN CONTROLLER OUT, IN/OUT w.r.t. ENFORCER
	out event AP_pico_prime, VP_pico_prime;
}
architecture of AEIPolicyEnforcerI {
	internals {
		ulint AEI_ns := 900000000;
		dtimer tAEI; //DTIMER increases in DISCRETE TIME continuously
		int _STATE := 0;
	}

	init in 'ST' `

	`;

	run in 'ST' `
		IF WE GO TO SAFE I STATE
			_poci_outs <= _poci_ins
		ELSE
			_poci_outs <= modified(poci_ins)
		END IF

		RUN CONTROLLER

		IF WE GO TO SAFE STATE
			_pico_outs <= pico_ins
		ELSE
			_pico_outs <= modified(pico_outs)
		END IF

		RUN PLANT

		//CAN we pipeline this?

		//ie run every tick, where we take PRE

		//        controller... enforcer... plant
		//tick 0             <-          <-  a
		//tick 0             ->          ->

		//tick 1             <-     a    <-  b
		//tick 1             ->          ->

		//tick 2       a'    <-     b    <-  c
		//tick 2             ->          ->

		//tick 3       b'    <-     c    <-  d
		//tick 3             ->     a''  ->

		//tick 4       c'    <-     d    <-  e
		//tick 4             ->     b''  ->  a'''

		//MULTICYCLE (4 cycles per synchronous tick)

		//        controller... enforcer... plant
		//tick 0             <-          <-  a
		//tick 0             ->          ->

		//tick 1             <-     a    <-
		//tick 1             ->          ->

		//tick 2       a'    <-          <-
		//tick 2             ->          ->

		//tick 3             <-          <-
		//tick 3             ->     a''  ->

		//tick 4             <-          <-
		//tick 4             ->          ->  a'''
	`;

}

*/
<commit_msg>add more thoughts<commit_after>package iec61499

import "errors"

/* an example of a conversion

//event A is from Plant
//event B is from Controller
//A and B cannot happen simultaneously, A and B alternate starting with an A. B should be true within 5 ticks of B.

policyFB AB5Policy;
interface of AB5Policy {
	in event A;  //in here means that they're going from PLANT to CONTROLLER
	out event B; //out here means that they're going from CONTROLLER to PLANT
}

architecture of AB5Policy {
	internals {
		dtimer v;
	}

	states {
		s0 {														//first state is initial, and represents "We're waiting for an A"
			-> s0 on (!A and !B): v := 0;							//if we receive neither A nor B, do nothing
			-> s1 on (A and !B): v := 0;							//if we receive an A only, head to state s1
			-> violation on ((!A and B) or (A and B));				//if we receive a B, or an A and a B (i.e. if we receive a B) then VIOLATION
		}

		s1 {														//s1 is "we're waiting for a B, and it needs to get here within 5 ticks"
			-> s1 on (!A and !B and v < 5);							//if we receive nothing, and we aren't over-time, then we do nothing
			-> s0 on (!A and B);									//if we receive a B only, head to state s0
			-> violation on ((v >= 5) or (A and B) or (A and !B));	//if we go overtime, or we receive another A, then VIOLATION
		}
	}
}

CAN DERIVE TO INPUT POLICY (Remember, replace all outputs and things that depend on outputs with TRUE)

policyFB AB5Policy_INPUT;
interface of AB5Policy_INPUT {
	in event A;  //in here means that they're going from PLANT to CONTROLLER
}

architecture of AB5Policy_INPUT {
	internals {
		dtimer v;
	}

	states {
		s0 {
			-> s0 on (!A and (true)): v := 0;
			-> s1 on (A and (true)): v := 0;
			-> violation on ((!A and (true)) or (A and (true)));
		}

		s1 {
			-> s1 on (!A and (true) and v < 5);
			-> s0 on (!A and (true));
			-> violation on ((v >= 5) or (A and (true)) or (A and (true)));
		}
	}
}

IS EQUIVALENT TO

policyFB AB5Policy_INPUT;
interface of AB5Policy_INPUT {
	in event A;  //in here means that they're going from PLANT to CONTROLLER
}

architecture of AB5Policy_INPUT {
	internals {
		dtimer v;
	}

	states {
		s0 {
			-> s0 on (!A): v := 0;
			-> s1 on (A): v := 0;
			-> violation on (!A or A);
		}

		s1 {
			-> s1 on (!A and v < 5);
			-> s0 on (!A);
			-> violation on ((v >= 5) or (A));
		}
	}
}

Now remember, the enforcer for input will only make a change if an input _cannot_ result in a safe state.

In this case, in s0, every input (of A) can only result in a safe state, as both s0 is state and s1 has the potential to be safe
(I.e. we don't have to take the transition to the violation, so why would we?

In s1, if we receive an A, we're always going to end up in a violation. Stink!
So, what we'll do instead is get our enforcer to prevent the transition from occuring by instead picking a non-violating transition.
Both other transitions suggest !A, so that's what we'll do instead.

In s1, if v >= 5, that doesn't mean a violation _has_ to occur, because a !A could also have a non-violation.

WE CONVERT THESE TO ENFORCERS

every violation potential must be associated with a non-violating transition
//-> s0 on (!A): v := 0;
//-> s1 on (A): v := 0;
//-> violation on (!A or A);
s0 {
	if(!A) { 			//violation potential "(!A)"
						//auto-selected non-violating transition "-> s0 on (!A)", no edits required
	}

	if(A) {				//violation potential
						//auto-selected non-violating transition "-> s1 on (A)", no edits required
	}
}

//-> s1 on (!A and v < 5);
//-> s0 on (!A);
//-> violation on ((v >= 5) or (A));
s1 {
	if(v >= 5) { 		//violation potential "(v >= 5)"
		A = 0;			//auto-selected non-violating transition "-> s0 on (!A)", edit might be required
	}
	if(A) { 			//violation potential "(A)"
		A = 0;			//auto-selected non-violating transition "-> s0 on (!A)", edit might be required
	}
}

OUTPUT:

//-> violation on ((!A and B) or (A and B));
s0 {
	-> s0 on (!A and !B): v := 0;
	-> s1 on (A and !B): v := 0;
	-> violation on ((!A and B) or (A and B));
}

s1 {
	-> s1 on (!A and !B and v < 5);
	-> s0 on (!A and B);
	-> violation on ((v >= 5) or (A and B) or (A and !B));
}

*/

//TranslatePFBtoSIFB will take a Policy Function Block and compile it to its enforcer as a
// Service Interface Function Block
//It operates according to the algorithm specified in [TODO: Paper link]
func (f *FB) TranslatePFBtoSIFB() error {
	if f.PolicyFB == nil {
		return errors.New("TranslatePFBtoBFB can only be called on an PolicyFB")
	}

	return errors.New("Not yet implemented")
}

/*

policyFB AEIPolicy;
interface of AEIPolicy {
	in event AS, VS; //in here means that they're going from PLANT to CONTROLLER, and the EnforcerI is derived from this
	out event AP, VP;//out here means that they're going from CONTROLLER to PLANT
}
architecture of AEIPolicy {
	internals {
		ulint AEI_ns := 900000000;
		dtimer tAEI; //DTIMER increases in DISCRETE TIME continuously
	}

	//P3: AS or AP must be true within AEI after a ventricular event VS or VP.

	states {
		s1 {
			//-> <destination> [on guard] [: output expression][, output expression...] ;
			-> s2 on (VS or VP): tAEI := 0;
		}

		s2 {
			-> s1 on (AS or AP);
			-> violation on (tAEI > AEI_ns);
		}
	}
}

SHOULD BECOME TWO BLOCKS

serviceFB AEIPolicyEnforcerI;
interface of AEIPolicyEnforcerI {
	in event AS_poci, VS_poci; //PLANT OUT CONTROLLER IN, IN/OUT w.r.t. ENFORCER
	out event AS_poci_prime, VS_poci_prime;
}

architecture of AEIPolicyEnforcerI {

}

serviceFB AEIPolicyEnforcerO;
interface of AEIPolicyEnforcerO {
	in event AS_poci_prime, VS_poci_prime; //PLANT OUT CONTROLLER IN, IN/OUT w.r.t. ENFORCER

	in event AP_pico, VP_pico; //PLANT IN CONTROLLER OUT, IN/OUT w.r.t. ENFORCER
	out event AP_pico_prime, VP_pico_prime;
}
architecture of AEIPolicyEnforcerI {
	internals {
		ulint AEI_ns := 900000000;
		dtimer tAEI; //DTIMER increases in DISCRETE TIME continuously
		int _STATE := 0;
	}

	init in 'ST' `

	`;

	run in 'ST' `
		IF WE GO TO SAFE I STATE
			_poci_outs <= _poci_ins
		ELSE
			_poci_outs <= modified(poci_ins)
		END IF

		RUN CONTROLLER

		IF WE GO TO SAFE STATE
			_pico_outs <= pico_ins
		ELSE
			_pico_outs <= modified(pico_outs)
		END IF

		RUN PLANT

		//CAN we pipeline this?

		//ie run every tick, where we take PRE

		//        controller... enforcer... plant
		//tick 0             <-          <-  a
		//tick 0             ->          ->

		//tick 1             <-     a    <-  b
		//tick 1             ->          ->

		//tick 2       a'    <-     b    <-  c
		//tick 2             ->          ->

		//tick 3       b'    <-     c    <-  d
		//tick 3             ->     a''  ->

		//tick 4       c'    <-     d    <-  e
		//tick 4             ->     b''  ->  a'''

		//MULTICYCLE (4 cycles per synchronous tick)

		//        controller... enforcer... plant
		//tick 0             <-          <-  a
		//tick 0             ->          ->

		//tick 1             <-     a    <-
		//tick 1             ->          ->

		//tick 2       a'    <-          <-
		//tick 2             ->          ->

		//tick 3             <-          <-
		//tick 3             ->     a''  ->

		//tick 4             <-          <-
		//tick 4             ->          ->  a'''
	`;

}

*/
<|endoftext|>


<commit_before>package command

import (
	"flag"
	"strings"
	"time"

	"github.com/koding/kite"
	"github.com/koding/kite/kitekey"
	"github.com/mitchellh/cli"
)

type Register struct {
	KiteClient *kite.Kite
	Ui         cli.Ui
}

func NewRegister() cli.CommandFactory {
	return func() (cli.Command, error) {
		return &Register{
			KiteClient: DefaultKiteClient,
			Ui:         DefaultUi,
		}, nil
	}
}

func (c *Register) Synopsis() string {
	return "Registers this host to a kite authority"
}

func (c *Register) Help() string {
	helpText := `
Usage: kitectl register [options]

  Registers this host to a kite authority.

Options:

  -to=http://127.0.0.1  Kontrol URL.
  -username=koding
`
	return strings.TrimSpace(helpText)
}

func (c *Register) Run(args []string) int {
	flags := flag.NewFlagSet("register", flag.ExitOnError)
	to := flags.String("to", "", "target registration server")
	username := flags.String("username", "", "pick a username")
	flags.Parse(args)

	if *to == "" || *username == "" {
		c.Ui.Output(c.Help())
		return 1
	}

	c.KiteClient.Config.Username = *username

	if _, err := kitekey.Read(); err == nil {
		c.Ui.Info("Already registered. Registering again...")
	}

	kontrol := c.KiteClient.NewClient(*to)
	if err := kontrol.Dial(); err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	result, err := kontrol.TellWithTimeout("registerMachine", 5*time.Minute, *username)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	if err := kitekey.Write(result.MustString()); err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	c.Ui.Info("Registered successfully")

	return 0
}
<commit_msg>kitectl: Open up a prompt when the command is invoked without a username.<commit_after>package command

import (
	"flag"
	"fmt"
	"strings"
	"time"

	"github.com/koding/kite"
	"github.com/koding/kite/kitekey"
	"github.com/mitchellh/cli"
)

const (
	defaultKontrolURL = "https://discover.koding.io/kite"
	defaultUsername   = "koding"
)

type Register struct {
	KiteClient *kite.Kite
	Ui         cli.Ui
}

func NewRegister() cli.CommandFactory {
	return func() (cli.Command, error) {
		return &Register{
			KiteClient: DefaultKiteClient,
			Ui:         DefaultUi,
		}, nil
	}
}

func (c *Register) Synopsis() string {
	return "Registers this host to a kite authority"
}

func (c *Register) Help() string {
	helpText := `
Usage: kitectl register [options]

  Registers your host to a kite authority.
  If no server is specified, "https://discovery.koding.io/kite" is the default.

Options:

  -to=https://discovery.koding.io/kite  Kontrol URL
  -username=koding                      Username
`
	return strings.TrimSpace(helpText)
}

func (c *Register) Run(args []string) int {
	var kontrolURL, username string
	var err error

	flags := flag.NewFlagSet("register", flag.ExitOnError)
	flags.StringVar(&kontrolURL, "to", defaultKontrolURL, "Kontrol URL")
	flags.StringVar(&username, "username", "", "Username")
	flags.Parse(args)

	// Open up a prompt
	if username == "" {
		username, err = c.Ui.Ask(fmt.Sprintf("Username (%s):", defaultUsername))
		if err != nil {
			c.Ui.Error(err.Error())
			return 1
		}
		// User can just press enter to use the default on the prompt
		if username == "" {
			username = defaultUsername
		}
	}

	c.KiteClient.Config.Username = username

	if _, err := kitekey.Read(); err == nil {
		c.Ui.Info("Already registered. Registering again...")
	}

	kontrol := c.KiteClient.NewClient(kontrolURL)
	if err := kontrol.Dial(); err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	result, err := kontrol.TellWithTimeout("registerMachine", 5*time.Minute, username)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	if err := kitekey.Write(result.MustString()); err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	c.Ui.Info("Registered successfully")

	return 0
}
<|endoftext|>


<commit_before>package contrib

import (
	"encoding/base64"
	"encoding/binary"
	"fmt"
	"io"
	"time"

	"github.com/gin-gonic/gin"
	"qiniupkg.com/x/xlog.v7"
)

var pid = uint32(time.Now().UnixNano() % 4294967291)

func genReqId() string {
	var b [12]byte
	binary.LittleEndian.PutUint32(b[:], pid)
	binary.LittleEndian.PutUint64(b[4:], uint64(time.Now().UnixNano()))
	return base64.URLEncoding.EncodeToString(b[:])
}

func GenReqId() string {
	return genReqId()
}

var (
	green   = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	white   = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
	yellow  = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
	red     = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
	blue    = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
	magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
	cyan    = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
	reset   = string([]byte{27, 91, 48, 109})
)

func ErrorLogger() gin.HandlerFunc {
	return ErrorLoggerT(gin.ErrorTypeAny)
}

func ErrorLoggerT(typ gin.ErrorType) gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Next()
		// avoid writting if we already wrote into the response body
		if !c.Writer.Written() {
			errors := c.Errors.ByType(typ)
			if len(errors) > 0 {
				c.JSON(-1, errors)
			}
		}
	}
}

// Instances a Logger middleware that will write the logs to gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
func Logger() gin.HandlerFunc {
	return LoggerWithWriter(gin.DefaultWriter)
}

// Instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func LoggerWithWriter(out io.Writer, notlogged ...string) gin.HandlerFunc {
	var skip map[string]struct{}

	if length := len(notlogged); length > 0 {
		skip = make(map[string]struct{}, length)

		for _, path := range notlogged {
			skip[path] = struct{}{}
		}
	}

	return func(c *gin.Context) {
		// Start timer
		start := time.Now()

		xReqid := c.Request.Header.Get("X-Reqid")

		if xReqid == "" {
			xReqid = GenReqId()
		}

		logger := xlog.New(xReqid)

		c.Header("X-Reqid", logger.ReqId)

		path := c.Request.URL.RequestURI()

		clientIP := c.ClientIP()
		method := c.Request.Method
		methodColor := colorForMethod(method)

		// Log only when path is not being skipped
		if _, ok := skip[path]; !ok {
			fmt.Fprintf(out, "[GIN] [%s] [Route Start]\t%v |%s  %s %-7s %s\n",
				logger.ReqId,
				start.Format("2006/01/02 - 15:04:05"),
				methodColor, reset, method,
				path,
			)
			logger.Infof("%+v", c.Request)
		}

		// Process request
		c.Next()

		// Log only when path is not being skipped
		if _, ok := skip[path]; !ok {
			// Stop timer
			end := time.Now()
			latency := end.Sub(start)

			comment := c.Errors.ByType(gin.ErrorTypePrivate).String()

			statusCode := c.Writer.Status()
			statusColor := colorForStatus(statusCode)
			methodColor = colorForMethod(method)

			fmt.Fprintf(out, "[GIN] [%s] [Route End]\t%v |%s %3d %s| %13v | %s |%s  %s %-7s %s\n%s",
				logger.ReqId,
				end.Format("2006/01/02 - 15:04:05"),
				statusColor, statusCode, reset,
				latency,
				clientIP,
				methodColor, reset, method,
				path,
				comment,
			)
		}
	}
}

func colorForStatus(code int) string {
	switch {
	case code >= 200 && code < 300:
		return green
	case code >= 300 && code < 400:
		return white
	case code >= 400 && code < 500:
		return yellow
	default:
		return red
	}
}

func colorForMethod(method string) string {
	switch method {
	case "GET":
		return blue
	case "POST":
		return cyan
	case "PUT":
		return yellow
	case "DELETE":
		return red
	case "PATCH":
		return green
	case "HEAD":
		return magenta
	case "OPTIONS":
		return white
	default:
		return reset
	}
}
<commit_msg>Update logger.GenReqId method<commit_after>package contrib

import (
	"encoding/base64"
	"encoding/binary"
	"fmt"
	"io"
	"time"

	"github.com/gin-gonic/gin"
	"qiniupkg.com/x/xlog.v7"
)

var pid = uint32(time.Now().UnixNano() % 4294967291)

func GenReqId() string {
	var b [12]byte
	binary.LittleEndian.PutUint32(b[:], pid)
	binary.LittleEndian.PutUint64(b[4:], uint64(time.Now().UnixNano()))
	return base64.URLEncoding.EncodeToString(b[:])
}

var (
	green   = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	white   = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
	yellow  = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
	red     = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
	blue    = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
	magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
	cyan    = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
	reset   = string([]byte{27, 91, 48, 109})
)

func ErrorLogger() gin.HandlerFunc {
	return ErrorLoggerT(gin.ErrorTypeAny)
}

func ErrorLoggerT(typ gin.ErrorType) gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Next()
		// avoid writting if we already wrote into the response body
		if !c.Writer.Written() {
			errors := c.Errors.ByType(typ)
			if len(errors) > 0 {
				c.JSON(-1, errors)
			}
		}
	}
}

// Instances a Logger middleware that will write the logs to gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
func Logger() gin.HandlerFunc {
	return LoggerWithWriter(gin.DefaultWriter)
}

// Instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func LoggerWithWriter(out io.Writer, notlogged ...string) gin.HandlerFunc {
	var skip map[string]struct{}

	if length := len(notlogged); length > 0 {
		skip = make(map[string]struct{}, length)

		for _, path := range notlogged {
			skip[path] = struct{}{}
		}
	}

	return func(c *gin.Context) {
		// Start timer
		start := time.Now()

		xReqid := c.Request.Header.Get("X-Reqid")

		if xReqid == "" {
			xReqid = GenReqId()
		}

		logger := xlog.New(xReqid)

		c.Header("X-Reqid", logger.ReqId)

		path := c.Request.URL.RequestURI()

		clientIP := c.ClientIP()
		method := c.Request.Method
		methodColor := colorForMethod(method)

		// Log only when path is not being skipped
		if _, ok := skip[path]; !ok {
			fmt.Fprintf(out, "[GIN] [%s] [Route Start]\t%v |%s  %s %-7s %s\n",
				logger.ReqId,
				start.Format("2006/01/02 - 15:04:05"),
				methodColor, reset, method,
				path,
			)
			logger.Infof("%+v", c.Request)
		}

		// Process request
		c.Next()

		// Log only when path is not being skipped
		if _, ok := skip[path]; !ok {
			// Stop timer
			end := time.Now()
			latency := end.Sub(start)

			comment := c.Errors.ByType(gin.ErrorTypePrivate).String()

			statusCode := c.Writer.Status()
			statusColor := colorForStatus(statusCode)
			methodColor = colorForMethod(method)

			fmt.Fprintf(out, "[GIN] [%s] [Route End]\t%v |%s %3d %s| %13v | %s |%s  %s %-7s %s\n%s",
				logger.ReqId,
				end.Format("2006/01/02 - 15:04:05"),
				statusColor, statusCode, reset,
				latency,
				clientIP,
				methodColor, reset, method,
				path,
				comment,
			)
		}
	}
}

func colorForStatus(code int) string {
	switch {
	case code >= 200 && code < 300:
		return green
	case code >= 300 && code < 400:
		return white
	case code >= 400 && code < 500:
		return yellow
	default:
		return red
	}
}

func colorForMethod(method string) string {
	switch method {
	case "GET":
		return blue
	case "POST":
		return cyan
	case "PUT":
		return yellow
	case "DELETE":
		return red
	case "PATCH":
		return green
	case "HEAD":
		return magenta
	case "OPTIONS":
		return white
	default:
		return reset
	}
}
<|endoftext|>


<commit_before>package core

// Arguments represents a structured set of arguments passed to a predicate.
// It allows destructive operations to internal properties because it is
// guaranteed by Thunks that arguments objects are never reused as a function
// call creates a Thunk.
type Arguments struct {
	positionals   []*Thunk
	expandedList  *Thunk
	keywords      []KeywordArgument
	expandedDicts []*Thunk
}

// NewArguments creates a new Arguments.
func NewArguments(
	ps []PositionalArgument,
	ks []KeywordArgument,
	ds []*Thunk) Arguments {
	ts := make([]*Thunk, 0, len(ps))
	l := (*Thunk)(nil)

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

		ts = append(ts, p.value)
	}

	return Arguments{ts, l, ks, ds}
}

func mergePositionalArguments(ps []PositionalArgument) *Thunk {
	t := EmptyList

	for i := range ps {
		p := ps[len(ps)-i-1]

		if p.expanded {
			t = PApp(Merge, p.value, t)
		} else {
			t = PApp(Prepend, p.value, t)
		}
	}

	return t
}

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

	if args.expandedList == nil {
		return nil
	}

	l := args.expandedList
	args.expandedList = PApp(Rest, l)
	return PApp(First, l)
}

func (args *Arguments) restPositionals() *Thunk {
	ts := args.positionals
	l := args.expandedList
	args.positionals = nil
	args.expandedList = nil

	if l == nil {
		return NewList(ts...)
	}

	return PApp(Merge, NewList(ts...), l)
}

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

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

		if !ok {
			return NotDictionaryError(v)
		}

		k := StringType(s)

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

	return nil
}

func (args *Arguments) restKeywords() *Thunk {
	ks := args.keywords
	ds := args.expandedDicts
	args.keywords = nil
	args.expandedDicts = nil

	t := EmptyDictionary

	for _, k := range ks {
		t = PApp(Insert, t, NewString(k.name), k.value)
	}

	return PApp(Merge, append([]*Thunk{t}, ds...)...)
}

// Merge merges 2 sets of arguments into one.
func (args Arguments) Merge(old Arguments) Arguments {
	var ps []*Thunk
	var l *Thunk

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

		if old.expandedList != nil {
			l = PApp(Merge, l, old.expandedList)
		}
	}

	return Arguments{
		ps,
		l,
		append(args.keywords, old.keywords...),
		append(args.expandedDicts, old.expandedDicts...),
	}
}

func (args Arguments) empty() *Thunk {
	if len(args.positionals) > 0 {
		return argumentError("%d positional arguments are left", len(args.positionals))
	}

	// Testing args.expandedList is impossible because we cannot know its length
	// without evaluating it.

	n := 0

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

		if !ok {
			return NotDictionaryError(v)
		}

		n += d.Size()
	}

	if n != 0 || args.keywords != nil && len(args.keywords) > 0 {
		return argumentError("%d keyword arguments are left", len(args.keywords)+n)
	}

	return nil
}
<commit_msg>Prefer prepend as it seems to be more lightweight<commit_after>package core

// Arguments represents a structured set of arguments passed to a predicate.
// It allows destructive operations to internal properties because it is
// guaranteed by Thunks that arguments objects are never reused as a function
// call creates a Thunk.
type Arguments struct {
	positionals   []*Thunk
	expandedList  *Thunk
	keywords      []KeywordArgument
	expandedDicts []*Thunk
}

// NewArguments creates a new Arguments.
func NewArguments(
	ps []PositionalArgument,
	ks []KeywordArgument,
	ds []*Thunk) Arguments {
	ts := make([]*Thunk, 0, len(ps))
	l := (*Thunk)(nil)

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

		ts = append(ts, p.value)
	}

	return Arguments{ts, l, ks, ds}
}

func mergePositionalArguments(ps []PositionalArgument) *Thunk {
	t := EmptyList

	for i := range ps {
		p := ps[len(ps)-i-1]

		if p.expanded {
			t = PApp(Merge, p.value, t)
		} else {
			t = PApp(Prepend, p.value, t)
		}
	}

	return t
}

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

	if args.expandedList == nil {
		return nil
	}

	l := args.expandedList
	args.expandedList = PApp(Rest, l)
	return PApp(First, l)
}

func (args *Arguments) restPositionals() *Thunk {
	ts := args.positionals
	l := args.expandedList
	args.positionals = nil
	args.expandedList = nil

	if l == nil {
		return NewList(ts...)
	}

	return PApp(Prepend, append(ts, l)...)
}

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

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

		if !ok {
			return NotDictionaryError(v)
		}

		k := StringType(s)

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

	return nil
}

func (args *Arguments) restKeywords() *Thunk {
	ks := args.keywords
	ds := args.expandedDicts
	args.keywords = nil
	args.expandedDicts = nil

	t := EmptyDictionary

	for _, k := range ks {
		t = PApp(Insert, t, NewString(k.name), k.value)
	}

	return PApp(Merge, append([]*Thunk{t}, ds...)...)
}

// Merge merges 2 sets of arguments into one.
func (args Arguments) Merge(old Arguments) Arguments {
	var ps []*Thunk
	var l *Thunk

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

		if old.expandedList != nil {
			l = PApp(Merge, l, old.expandedList)
		}
	}

	return Arguments{
		ps,
		l,
		append(args.keywords, old.keywords...),
		append(args.expandedDicts, old.expandedDicts...),
	}
}

func (args Arguments) empty() *Thunk {
	if len(args.positionals) > 0 {
		return argumentError("%d positional arguments are left", len(args.positionals))
	}

	// Testing args.expandedList is impossible because we cannot know its length
	// without evaluating it.

	n := 0

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

		if !ok {
			return NotDictionaryError(v)
		}

		n += d.Size()
	}

	if n != 0 || args.keywords != nil && len(args.keywords) > 0 {
		return argumentError("%d keyword arguments are left", len(args.keywords)+n)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/codegangsta/cli"
	"github.com/digitalocean/godo"

	"golang.org/x/oauth2"
)

var SSHCommand = cli.Command{
	Name:    "sshkey",
	Usage:   "SSH Key commands.",
	Aliases: []string{"ssh", "keys"},
	Action:  sshList,
	Subcommands: []cli.Command{
		{
			Name:    "create",
			Usage:   "<name> <path to ssh key(~/.ssh/id_rsa)>Create SSH key.",
			Aliases: []string{"c"},
			Action:  sshCreate,
		},
		{
			Name:    "list",
			Usage:   "List all SSH keys.",
			Aliases: []string{"l"},
			Action:  sshList,
		},
		{
			Name:    "show",
			Usage:   "<name> Show SSH key.",
			Aliases: []string{"s"},
			Action:  sshShow,
		},
		{
			Name:    "destroy",
			Usage:   "<name> Destroy SSH key.",
			Aliases: []string{"d"},
			Action:  sshDestroy,
		},
	},
}

func sshCreate(ctx *cli.Context) {
	if len(ctx.Args()) != 2 {
		fmt.Printf("Must provide name and public key file.\n")
		os.Exit(1)
	}

	tokenSource := &TokenSource{
		AccessToken: APIKey,
	}
	oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
	client := godo.NewClient(oauthClient)

	file, err := os.Open(ctx.Args()[1])
	if err != nil {
		fmt.Printf("Error opening key file: %s\n", err)
		os.Exit(1)
	}

	keyData, err := ioutil.ReadAll(file)
	if err != nil {
		fmt.Printf("Error reading key file: %s\n", err)
		os.Exit(1)
	}

	createRequest := &godo.KeyCreateRequest{
		Name:      ctx.Args().First(),
		PublicKey: string(keyData),
	}
	key, _, err := client.Keys.Create(createRequest)
	if err != nil {
		fmt.Printf("%s\n", err)
		os.Exit(1)
	}

	WriteOutput(key)
}

func sshList(ctx *cli.Context) {
	if ctx.BoolT("help") == true {
		cli.ShowAppHelp(ctx)
		os.Exit(1)
	}

	tokenSource := &TokenSource{
		AccessToken: APIKey,
	}
	oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
	client := godo.NewClient(oauthClient)

	opt := &godo.ListOptions{}
	keyList := []godo.Key{}

	for {
		keyPage, resp, err := client.Keys.List(opt)
		if err != nil {
			fmt.Printf("Unable to list SSH Keys: %s\n", err)
			os.Exit(1)
		}

		// append the current page's droplets to our list
		for _, d := range keyPage {
			keyList = append(keyList, d)
		}

		// if we are at the last page, break out the for loop
		if resp.Links == nil || resp.Links.IsLastPage() {
			break
		}

		page, err := resp.Links.CurrentPage()
		if err != nil {
			fmt.Printf("Unable to get pagination: %s\n", err)
			os.Exit(1)
		}

		// set the page we want for the next request
		opt.Page = page + 1
	}

	cliOut := NewCLIOutput()
	defer cliOut.Flush()
	cliOut.Header("ID", "Name", "Fingerprint")
	for _, key := range keyList {
		cliOut.Writeln("%d\t%s\t%s\n", key.ID, key.Name, key.Fingerprint)
	}
}

func sshShow(ctx *cli.Context) {
	if len(ctx.Args()) != 1 {
		fmt.Printf("Error: Must provide name for Key.\n")
		os.Exit(1)
	}

	name := ctx.Args().First()

	tokenSource := &TokenSource{
		AccessToken: APIKey,
	}
	oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
	client := godo.NewClient(oauthClient)

	key, err := FindKeyByName(client, name)
	if err != nil {
		fmt.Printf("%s\n", err)
		os.Exit(64)
	}

	WriteOutput(key)
}

func sshDestroy(ctx *cli.Context) {
	if len(ctx.Args()) != 1 {
		fmt.Printf("Error: Must provide name for SSH Key.\n")
		os.Exit(1)
	}

	name := ctx.Args().First()

	tokenSource := &TokenSource{
		AccessToken: APIKey,
	}
	oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
	client := godo.NewClient(oauthClient)

	var id int
	key, err := FindKeyByName(client, name)
	if err != nil {
		fmt.Printf("%s\n", err)
		os.Exit(64)
	}
	id = key.ID

	_, err = client.Keys.DeleteByID(id)
	if err != nil {
		fmt.Printf("Unable to destroy SSH Key: %s\n", err)
		os.Exit(1)
	}

	fmt.Printf("Key %s destroyed.\n", name)
}
<commit_msg>[key] [destroy] Add options to specify by id or fingerprint.<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/codegangsta/cli"
	"github.com/digitalocean/godo"

	"golang.org/x/oauth2"
)

var SSHCommand = cli.Command{
	Name:    "sshkey",
	Usage:   "SSH Key commands.",
	Aliases: []string{"ssh", "keys"},
	Action:  sshList,
	Subcommands: []cli.Command{
		{
			Name:    "create",
			Usage:   "<name> <path to ssh key(~/.ssh/id_rsa)>Create SSH key.",
			Aliases: []string{"c"},
			Action:  sshCreate,
		},
		{
			Name:    "list",
			Usage:   "List all SSH keys.",
			Aliases: []string{"l"},
			Action:  sshList,
		},
		{
			Name:    "show",
			Usage:   "<name> Show SSH key.",
			Aliases: []string{"s"},
			Action:  sshFind,
		},
		{
			Name:    "destroy",
			Usage:   "[--id | --fingerprint | <name>] Destroy SSH key.",
			Aliases: []string{"d"},
			Action:  sshDestroy,
			Flags: []cli.Flag{
				cli.IntFlag{Name: "id", Usage: "ID for SSH Key. (e.g. 1234567)"},
				cli.StringFlag{Name: "id", Usage: "Fingerprint for SSH Key. (e.g. aa:bb:cc)"},
			},
		},
	},
}

func sshCreate(ctx *cli.Context) {
	if len(ctx.Args()) != 2 {
		fmt.Printf("Must provide name and public key file.\n")
		os.Exit(1)
	}

	tokenSource := &TokenSource{
		AccessToken: APIKey,
	}
	oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
	client := godo.NewClient(oauthClient)

	file, err := os.Open(ctx.Args()[1])
	if err != nil {
		fmt.Printf("Error opening key file: %s\n", err)
		os.Exit(1)
	}

	keyData, err := ioutil.ReadAll(file)
	if err != nil {
		fmt.Printf("Error reading key file: %s\n", err)
		os.Exit(1)
	}

	createRequest := &godo.KeyCreateRequest{
		Name:      ctx.Args().First(),
		PublicKey: string(keyData),
	}
	key, _, err := client.Keys.Create(createRequest)
	if err != nil {
		fmt.Printf("%s\n", err)
		os.Exit(1)
	}

	WriteOutput(key)
}

func sshList(ctx *cli.Context) {
	if ctx.BoolT("help") == true {
		cli.ShowAppHelp(ctx)
		os.Exit(1)
	}

	tokenSource := &TokenSource{
		AccessToken: APIKey,
	}
	oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
	client := godo.NewClient(oauthClient)

	opt := &godo.ListOptions{}
	keyList := []godo.Key{}

	for {
		keyPage, resp, err := client.Keys.List(opt)
		if err != nil {
			fmt.Printf("Unable to list SSH Keys: %s\n", err)
			os.Exit(1)
		}

		// append the current page's droplets to our list
		for _, d := range keyPage {
			keyList = append(keyList, d)
		}

		// if we are at the last page, break out the for loop
		if resp.Links == nil || resp.Links.IsLastPage() {
			break
		}

		page, err := resp.Links.CurrentPage()
		if err != nil {
			fmt.Printf("Unable to get pagination: %s\n", err)
			os.Exit(1)
		}

		// set the page we want for the next request
		opt.Page = page + 1
	}

	cliOut := NewCLIOutput()
	defer cliOut.Flush()
	cliOut.Header("ID", "Name", "Fingerprint")
	for _, key := range keyList {
		cliOut.Writeln("%d\t%s\t%s\n", key.ID, key.Name, key.Fingerprint)
	}
}

func sshFind(ctx *cli.Context) {
	if len(ctx.Args()) != 1 {
		fmt.Printf("Error: Must provide name for Key.\n")
		os.Exit(1)
	}

	name := ctx.Args().First()

	tokenSource := &TokenSource{
		AccessToken: APIKey,
	}
	oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
	client := godo.NewClient(oauthClient)

	key, err := FindKeyByName(client, name)
	if err != nil {
		fmt.Printf("%s\n", err)
		os.Exit(64)
	}

	WriteOutput(key)
}

func sshDestroy(ctx *cli.Context) {
	if ctx.Int("id") == 0 && ctx.String("fingerprint") == "" && len(ctx.Args()) < 1 {
		fmt.Printf("Error: Must provide ID, fingerprint or name for SSH Key to destroy.\n")
		os.Exit(1)
	}

	tokenSource := &TokenSource{
		AccessToken: APIKey,
	}
	oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
	client := godo.NewClient(oauthClient)

	id := ctx.Int("id")
	fingerprint := ctx.String("fingerprint")
	var key godo.Key
	if id == 0 && fingerprint == "" {
		key, err := FindKeyByName(client, ctx.Args().First())
		if err != nil {
			fmt.Printf("%s\n", err)
			os.Exit(64)
		} else {
			id = key.ID
		}
	} else if id != 0 {
		key, _, err := client.Keys.GetByID(id)
		if err != nil {
			fmt.Printf("Unable to find SSH Key: %s\n", err)
			os.Exit(1)
		} else {
			id = key.ID
		}
	} else {
		key, _, err := client.Keys.GetByFingerprint(fingerprint)
		if err != nil {
			fmt.Printf("Unable to find SSH Key: %s\n", err)
			os.Exit(1)
		} else {
			id = key.ID
		}
	}

	_, err := client.Keys.DeleteByID(id)
	if err != nil {
		fmt.Printf("Unable to destroy SSH Key: %s\n", err)
		os.Exit(1)
	}

	fmt.Printf("Key %s destroyed.\n", key.Name)
}
<|endoftext|>


<commit_before>package common

type Status int
const (
  STATUS_ACCEPTED Status = iota
  STATUS_QUEUED
  STATUS_PROCESSING
  STATUS_FINISHED
)

var status_text = [...]string {
  "Accepted",
  "Queued",
  "Processing",
  "Finished",
}

var status_descr = [...]string {
  "Your submission has been accepted and is awaiting scheduling",
  "Your submission is in queue to be processed",
  "Your submission is being processed",
  "Your assessment is ready",
}

func (s Status) String() string {
  return status_text[s]
}

func (s Status) Description() string {
  return status_descr[s]
}

type SubmissionType int
const (
  SUBMISSION_NORMAL SubmissionType = iota
  SUBMISSION_ASSESSMENT
)
<commit_msg>Added failed status<commit_after>package common

type Status int
const (
  STATUS_ACCEPTED Status = iota
  STATUS_QUEUED
  STATUS_PROCESSING
  STATUS_FINISHED
  STATUS_FAILED
)

var status_text = [...]string {
  "Accepted",
  "Queued",
  "Processing",
  "Finished",
  "Failed",
}

var status_descr = [...]string {
  "Your submission has been accepted and is awaiting scheduling",
  "Your submission is in queue to be processed",
  "Your submission is being processed",
  "Your assessment is ready",
  "Assessment failed due to an internal processing error. Please contact an admin"
}

func (s Status) String() string {
  return status_text[s]
}

func (s Status) Description() string {
  return status_descr[s]
}

type SubmissionType int
const (
  SUBMISSION_NORMAL SubmissionType = iota
  SUBMISSION_ASSESSMENT
)
<|endoftext|>