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

package event

import (
	"encoding/json"
	"encoding/xml"
)

// Name - event type enum.
// Refer http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#notification-how-to-event-types-and-destinations
type Name int

// Values of Name
const (
	ObjectAccessedAll Name = 1 + iota
	ObjectAccessedGet
	ObjectAccessedGetRetention
	ObjectAccessedHead
	ObjectCreatedAll
	ObjectCreatedCompleteMultipartUpload
	ObjectCreatedCopy
	ObjectCreatedPost
	ObjectCreatedPut
	ObjectCreatedPutRetention
	ObjectRemovedAll
	ObjectRemovedDelete
)

// Expand - returns expanded values of abbreviated event type.
func (name Name) Expand() []Name {
	switch name {
	case ObjectAccessedAll:
		return []Name{ObjectAccessedGet, ObjectAccessedHead, ObjectAccessedGetRetention}
	case ObjectCreatedAll:
		return []Name{ObjectCreatedCompleteMultipartUpload, ObjectCreatedCopy, ObjectCreatedPost, ObjectCreatedPut, ObjectCreatedPutRetention}
	case ObjectRemovedAll:
		return []Name{ObjectRemovedDelete}
	default:
		return []Name{name}
	}
}

// String - returns string representation of event type.
func (name Name) String() string {
	switch name {
	case ObjectAccessedAll:
		return "s3:ObjectAccessed:*"
	case ObjectAccessedGet:
		return "s3:ObjectAccessed:Get"
	case ObjectAccessedGetRetention:
		return "s3:ObjectAccessed:GetRetention"
	case ObjectAccessedHead:
		return "s3:ObjectAccessed:Head"
	case ObjectCreatedAll:
		return "s3:ObjectCreated:*"
	case ObjectCreatedCompleteMultipartUpload:
		return "s3:ObjectCreated:CompleteMultipartUpload"
	case ObjectCreatedCopy:
		return "s3:ObjectCreated:Copy"
	case ObjectCreatedPost:
		return "s3:ObjectCreated:Post"
	case ObjectCreatedPut:
		return "s3:ObjectCreated:Put"
	case ObjectCreatedPutRetention:
		return "s3:ObjectAccessed:PutRetention"
	case ObjectRemovedAll:
		return "s3:ObjectRemoved:*"
	case ObjectRemovedDelete:
		return "s3:ObjectRemoved:Delete"
	}

	return ""
}

// MarshalXML - encodes to XML data.
func (name Name) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	return e.EncodeElement(name.String(), start)
}

// UnmarshalXML - decodes XML data.
func (name *Name) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var s string
	if err := d.DecodeElement(&s, &start); err != nil {
		return err
	}

	eventName, err := ParseName(s)
	if err != nil {
		return err
	}

	*name = eventName
	return nil
}

// MarshalJSON - encodes to JSON data.
func (name Name) MarshalJSON() ([]byte, error) {
	return json.Marshal(name.String())
}

// UnmarshalJSON - decodes JSON data.
func (name *Name) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}

	eventName, err := ParseName(s)
	if err != nil {
		return err
	}

	*name = eventName
	return nil
}

// ParseName - parses string to Name.
func ParseName(s string) (Name, error) {
	switch s {
	case "s3:ObjectAccessed:*":
		return ObjectAccessedAll, nil
	case "s3:ObjectAccessed:Get":
		return ObjectAccessedGet, nil
	case "s3:ObjectAccessed:GetRetention":
		return ObjectAccessedGetRetention, nil
	case "s3:ObjectAccessed:Head":
		return ObjectAccessedHead, nil
	case "s3:ObjectCreated:*":
		return ObjectCreatedAll, nil
	case "s3:ObjectCreated:CompleteMultipartUpload":
		return ObjectCreatedCompleteMultipartUpload, nil
	case "s3:ObjectCreated:Copy":
		return ObjectCreatedCopy, nil
	case "s3:ObjectCreated:Post":
		return ObjectCreatedPost, nil
	case "s3:ObjectCreated:Put":
		return ObjectCreatedPut, nil
	case "s3:ObjectCreated:PutRetention":
		return ObjectCreatedPutRetention, nil
	case "s3:ObjectRemoved:*":
		return ObjectRemovedAll, nil
	case "s3:ObjectRemoved:Delete":
		return ObjectRemovedDelete, nil
	default:
		return 0, &ErrInvalidEventName{s}
	}
}
<commit_msg>Fix typo in event name (#8545)<commit_after>/*
 * MinIO Cloud Storage, (C) 2018 MinIO, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package event

import (
	"encoding/json"
	"encoding/xml"
)

// Name - event type enum.
// Refer http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#notification-how-to-event-types-and-destinations
type Name int

// Values of Name
const (
	ObjectAccessedAll Name = 1 + iota
	ObjectAccessedGet
	ObjectAccessedGetRetention
	ObjectAccessedHead
	ObjectCreatedAll
	ObjectCreatedCompleteMultipartUpload
	ObjectCreatedCopy
	ObjectCreatedPost
	ObjectCreatedPut
	ObjectCreatedPutRetention
	ObjectRemovedAll
	ObjectRemovedDelete
)

// Expand - returns expanded values of abbreviated event type.
func (name Name) Expand() []Name {
	switch name {
	case ObjectAccessedAll:
		return []Name{ObjectAccessedGet, ObjectAccessedHead, ObjectAccessedGetRetention}
	case ObjectCreatedAll:
		return []Name{ObjectCreatedCompleteMultipartUpload, ObjectCreatedCopy, ObjectCreatedPost, ObjectCreatedPut, ObjectCreatedPutRetention}
	case ObjectRemovedAll:
		return []Name{ObjectRemovedDelete}
	default:
		return []Name{name}
	}
}

// String - returns string representation of event type.
func (name Name) String() string {
	switch name {
	case ObjectAccessedAll:
		return "s3:ObjectAccessed:*"
	case ObjectAccessedGet:
		return "s3:ObjectAccessed:Get"
	case ObjectAccessedGetRetention:
		return "s3:ObjectAccessed:GetRetention"
	case ObjectAccessedHead:
		return "s3:ObjectAccessed:Head"
	case ObjectCreatedAll:
		return "s3:ObjectCreated:*"
	case ObjectCreatedCompleteMultipartUpload:
		return "s3:ObjectCreated:CompleteMultipartUpload"
	case ObjectCreatedCopy:
		return "s3:ObjectCreated:Copy"
	case ObjectCreatedPost:
		return "s3:ObjectCreated:Post"
	case ObjectCreatedPut:
		return "s3:ObjectCreated:Put"
	case ObjectCreatedPutRetention:
		return "s3:ObjectCreated:PutRetention"
	case ObjectRemovedAll:
		return "s3:ObjectRemoved:*"
	case ObjectRemovedDelete:
		return "s3:ObjectRemoved:Delete"
	}

	return ""
}

// MarshalXML - encodes to XML data.
func (name Name) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	return e.EncodeElement(name.String(), start)
}

// UnmarshalXML - decodes XML data.
func (name *Name) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var s string
	if err := d.DecodeElement(&s, &start); err != nil {
		return err
	}

	eventName, err := ParseName(s)
	if err != nil {
		return err
	}

	*name = eventName
	return nil
}

// MarshalJSON - encodes to JSON data.
func (name Name) MarshalJSON() ([]byte, error) {
	return json.Marshal(name.String())
}

// UnmarshalJSON - decodes JSON data.
func (name *Name) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}

	eventName, err := ParseName(s)
	if err != nil {
		return err
	}

	*name = eventName
	return nil
}

// ParseName - parses string to Name.
func ParseName(s string) (Name, error) {
	switch s {
	case "s3:ObjectAccessed:*":
		return ObjectAccessedAll, nil
	case "s3:ObjectAccessed:Get":
		return ObjectAccessedGet, nil
	case "s3:ObjectAccessed:GetRetention":
		return ObjectAccessedGetRetention, nil
	case "s3:ObjectAccessed:Head":
		return ObjectAccessedHead, nil
	case "s3:ObjectCreated:*":
		return ObjectCreatedAll, nil
	case "s3:ObjectCreated:CompleteMultipartUpload":
		return ObjectCreatedCompleteMultipartUpload, nil
	case "s3:ObjectCreated:Copy":
		return ObjectCreatedCopy, nil
	case "s3:ObjectCreated:Post":
		return ObjectCreatedPost, nil
	case "s3:ObjectCreated:Put":
		return ObjectCreatedPut, nil
	case "s3:ObjectCreated:PutRetention":
		return ObjectCreatedPutRetention, nil
	case "s3:ObjectRemoved:*":
		return ObjectRemovedAll, nil
	case "s3:ObjectRemoved:Delete":
		return ObjectRemovedDelete, nil
	default:
		return 0, &ErrInvalidEventName{s}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 CodeIgnition. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package policy

import (
	"errors"
	"testing"
	"time"

	"golang.org/x/net/context"
)

func fakePolicyHandler(ctx context.Context, p Policy) (<-chan Event, error) {
	foo, ok := p.M["foo"]
	if !ok {
		return nil, errors.New(`"foo" key missing in fake policy`)
	}
	interval, ok := p.M["interval"]
	if !ok {
		return nil, errors.New(`"interval" key missing in fake policy`)
	}
	d, err := time.ParseDuration(interval)
	if err != nil {
		return nil, err
	}

	// This check is here to ensure time.Ticker(d) doesn't panic
	if d <= 0 {
		return nil, errors.New("interval must be a positive quantity")
	}

	out := make(chan Event)
	go func() {
		t := time.NewTicker(d)
		for {
			select {
			case <-ctx.Done():
				t.Stop()
				close(out)
				return
			case <-t.C:
				out <- Event{
					Time:   time.Now(),
					Policy: p,
					Data: map[string]interface{}{
						"foo": foo,
					},
				}
			}
		}
	}()
	return out, nil
}

func TestRegisterHandler(t *testing.T) {
	err := RegisterHandler("", fakePolicyHandler)
	if err == nil {
		t.Fatal(errors.New("NewHandler should return an error when the type is empty"))
	}
	err = RegisterHandler("fake", fakePolicyHandler)
	if err != nil {
		t.Fatal(err)
	}

	// test registering twice
	err = RegisterHandler("fake", fakePolicyHandler)
	if err == nil {
		t.Fatal(`want error "handler for the policy type already exists"; got nil`)
	}
}

func TestValid(t *testing.T) {
	p := Policy{
		Name: "",
	}
	if err := p.Valid(); err == nil {
		t.Error(`want error "policy name can't be empty"; got nil`)
	}
	p = Policy{
		Name: "dummy",
		Type: "unknownDummyType",
	}
	if err := p.Valid(); err == nil {
		t.Error(`want error "policy type unknown"; got nil`)
	}
}

func TestExecuteInvalidPolicy(t *testing.T) {
	p := Policy{
		Name: "dummy",
		Type: "unknownDummyType",
	}
	if _, err := p.Execute(context.TODO()); err == nil {
		t.Error(`want error "policy type unknown"; got nil`)
	}
}

func TestExecute(t *testing.T) {
	p := Policy{
		Name: "dummy",
		Type: "fake",
		M: map[string]string{
			"foo":      "foo_value",
			"interval": "200ms",
		},
	}
	ctx, cancel := context.WithCancel(context.Background())
	out, err := p.Execute(ctx)
	if err != nil {
		t.Error(err)
	}
	go func() {
		time.Sleep(1 * time.Second)
		cancel()
	}()

	var count int
	// Here, we are also able to test whether out is being
	// closed when cancel() is called. If out is not closed,
	// this test should have been running forever.
	for evt := range out {
		count++
		if evt.Data["foo"] != "foo_value" {
			t.Errorf(`want evt.Data["foo"] = %s; got %s`, "foo", evt.Data["foo"])
		}
	}

	// The interval for the dummy policy is 200ms.
	// We are calling cancel after 1 sec. Typically, we receive
	// 4 or 5 events in that duration.
	if count != 4 && count != 5 {
		t.Errorf(`want count to be either 4 or 5; got %d`, count)
	}
}
<commit_msg>policy: fix t.Fatal call<commit_after>// Copyright 2015 CodeIgnition. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package policy

import (
	"errors"
	"testing"
	"time"

	"golang.org/x/net/context"
)

func fakePolicyHandler(ctx context.Context, p Policy) (<-chan Event, error) {
	foo, ok := p.M["foo"]
	if !ok {
		return nil, errors.New(`"foo" key missing in fake policy`)
	}
	interval, ok := p.M["interval"]
	if !ok {
		return nil, errors.New(`"interval" key missing in fake policy`)
	}
	d, err := time.ParseDuration(interval)
	if err != nil {
		return nil, err
	}

	// This check is here to ensure time.Ticker(d) doesn't panic
	if d <= 0 {
		return nil, errors.New("interval must be a positive quantity")
	}

	out := make(chan Event)
	go func() {
		t := time.NewTicker(d)
		for {
			select {
			case <-ctx.Done():
				t.Stop()
				close(out)
				return
			case <-t.C:
				out <- Event{
					Time:   time.Now(),
					Policy: p,
					Data: map[string]interface{}{
						"foo": foo,
					},
				}
			}
		}
	}()
	return out, nil
}

func TestRegisterHandler(t *testing.T) {
	err := RegisterHandler("", fakePolicyHandler)
	if err == nil {
		t.Fatal(`NewHandler should return an error when the type is empty`)
	}
	err = RegisterHandler("fake", fakePolicyHandler)
	if err != nil {
		t.Fatal(err)
	}

	// test registering twice
	err = RegisterHandler("fake", fakePolicyHandler)
	if err == nil {
		t.Fatal(`want error "handler for the policy type already exists"; got nil`)
	}
}

func TestValid(t *testing.T) {
	p := Policy{
		Name: "",
	}
	if err := p.Valid(); err == nil {
		t.Error(`want error "policy name can't be empty"; got nil`)
	}
	p = Policy{
		Name: "dummy",
		Type: "unknownDummyType",
	}
	if err := p.Valid(); err == nil {
		t.Error(`want error "policy type unknown"; got nil`)
	}
}

func TestExecuteInvalidPolicy(t *testing.T) {
	p := Policy{
		Name: "dummy",
		Type: "unknownDummyType",
	}
	if _, err := p.Execute(context.TODO()); err == nil {
		t.Error(`want error "policy type unknown"; got nil`)
	}
}

func TestExecute(t *testing.T) {
	p := Policy{
		Name: "dummy",
		Type: "fake",
		M: map[string]string{
			"foo":      "foo_value",
			"interval": "200ms",
		},
	}
	ctx, cancel := context.WithCancel(context.Background())
	out, err := p.Execute(ctx)
	if err != nil {
		t.Error(err)
	}
	go func() {
		time.Sleep(1 * time.Second)
		cancel()
	}()

	var count int
	// Here, we are also able to test whether out is being
	// closed when cancel() is called. If out is not closed,
	// this test should have been running forever.
	for evt := range out {
		count++
		if evt.Data["foo"] != "foo_value" {
			t.Errorf(`want evt.Data["foo"] = %s; got %s`, "foo", evt.Data["foo"])
		}
	}

	// The interval for the dummy policy is 200ms.
	// We are calling cancel after 1 sec. Typically, we receive
	// 4 or 5 events in that duration.
	if count != 4 && count != 5 {
		t.Errorf(`want count to be either 4 or 5; got %d`, count)
	}
}
<|endoftext|>


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

package hl7

import (
	"bytes"
	"fmt"
	"net"
	"os"
	"syscall"
	"time"

	"github.com/pkg/errors"
)

// Sender is an interface for sending HL7 messages.
type Sender interface {
	Send([]byte) error
	Close() error
}

// stdoutSender sends HL7 messages to the standard output.
type stdoutSender struct{}

// NewStdoutSender returns a sender that sends HL7 messages to the standard output.
func NewStdoutSender() Sender {
	return &stdoutSender{}
}

// Send sends a message to stdout.
func (s *stdoutSender) Send(message []byte) error {
	fmt.Print(string(bytes.Replace(message, []byte(SegmentTerminatorStr), []byte("\n"), -1)))
	fmt.Print("\n")
	return nil
}

// Close is no-op.
func (s *stdoutSender) Close() error {
	return nil
}

var recoverableErrs = map[syscall.Errno]bool{syscall.EPIPE: true, syscall.ECONNRESET: true}

// mllpSender sends HL7 messages via the MLLP protocol.
type mllpSender struct {
	client              *MLLPClient
	conn                net.Conn
	address             string
	mllpKeepAlive       bool
	mllpKeepAlivePeriod time.Duration
}

// NewMLLPSender returns a sender that sends HL7 messages via the MLLP protocol.
func NewMLLPSender(address string, mllpKeepAlive bool, mllpKeepAlivePeriod time.Duration) (Sender, error) {
	sender := &mllpSender{
		address:             address,
		mllpKeepAlive:       mllpKeepAlive,
		mllpKeepAlivePeriod: mllpKeepAlivePeriod,
	}
	if err := sender.establishConnection(); err != nil {
		return nil, errors.Wrapf(err, "cannot establish mllp connection on sender %+v", sender)
	}
	return sender, nil
}

func isRecoverable(err error) bool {
	if opError, ok := err.(*net.OpError); ok {
		if syscallErr, ok := opError.Err.(*os.SyscallError); ok {
			if errno, ok := syscallErr.Err.(syscall.Errno); ok && recoverableErrs[errno] {
				return true
			}
		}
	}

	return false
}

func (s *mllpSender) establishConnection() error {
	conn, err := net.Dial("tcp", s.address)
	if err != nil {
		return errors.Wrapf(err, "cannot connect to tcp address %s", s.address)
	}

	if s.mllpKeepAlive {
		if err := conn.(*net.TCPConn).SetKeepAlive(true); err != nil {
			return errors.Wrapf(err, "cannot set keep alive on connection %v", conn)
		}
		if err := conn.(*net.TCPConn).SetKeepAlivePeriod(s.mllpKeepAlivePeriod); err != nil {
			return errors.Wrapf(err, "cannot set keep alive period on connection %v", conn)
		}
	}

	s.conn = conn
	s.client = NewMLLPClient(conn)
	return nil
}

// Send sends a messages via the MLLP protocol.
// It returns an error if the message cannot be sent or was not acknowledged.
func (s *mllpSender) Send(message []byte) error {
	if err := s.client.Write(message); err != nil {
		if !isRecoverable(err) {
			return errors.Wrap(err, "cannot send message")
		}
		// If the socket was closed by the peer, handle it by trying to
		// write once again on a new connection.
		if err = s.establishConnection(); err != nil {
			return errors.Wrap(err, "cannot send message: error when re-establishing connection")
		}
		if err = s.client.Write(message); err != nil {
			return errors.Wrap(err, "cannot send message after re-establishing connection")
		}
	}

	ack, err := s.client.Read()
	if err != nil {
		return errors.Wrap(err, "cannot read an ack after sending message")
	}

	if _, err = ParseMessage(ack); err != nil {
		return errors.Wrap(err, "ack message cannot be parsed")
	}
	return nil
}

// Close closes the underlying TCP connection.
// It should be called, when the mllpSender is not needed anymore or at the program exit.
func (s *mllpSender) Close() error {
	if err := s.conn.Close(); err != nil {
		return errors.Wrap(err, "closing mllp sender connection")
	}
	return nil
}

// fileSender sends HL7 messages to a file.
type fileSender struct {
	file *os.File
}

// NewFileSender creates a sender that sends HL7 messages to a file.
func NewFileSender(destFilename string) (Sender, error) {
	if destFilename == "" {
		return nil, errors.New("output filename must be nonempty if outputting to a file")
	}
	file, err := os.Create(destFilename)
	if err != nil {
		return nil, errors.Wrapf(err, "cannot create output file %s", destFilename)
	}
	return &fileSender{file: file}, nil
}

// Send sends a message to the file.
func (s *fileSender) Send(message []byte) error {
	if _, err := s.file.Write(append(message, []byte("\n\n")...)); err != nil {
		return errors.Wrap(err, "cannot write a message")
	}
	return nil
}

// Close closes the underlying file.
// It should be called, when the mllpSender is not needed anymore or at the program exit.
func (s *fileSender) Close() error {
	if err := s.file.Close(); err != nil {
		return errors.Wrap(err, "closing file sender")
	}
	return nil
}
<commit_msg>Internal change<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hl7

import (
	"bytes"
	"fmt"
	"net"
	"os"
	"syscall"
	"time"

	"github.com/pkg/errors"
)

// Sender is an interface for sending HL7 messages.
type Sender interface {
	Send([]byte) error
	Close() error
}

// stdoutSender sends HL7 messages to the standard output.
type stdoutSender struct {
	count int
}

// NewStdoutSender returns a sender that sends HL7 messages to the standard output.
func NewStdoutSender() Sender {
	return &stdoutSender{}
}

// Send sends a message to stdout.
func (s *stdoutSender) Send(message []byte) error {
	fmt.Print(string(bytes.Replace(message, []byte(SegmentTerminatorStr), []byte("\n"), -1)))
	fmt.Print("\n")
	s.count++
	return nil
}

// Close prints the number of messages that have been sent.
func (s *stdoutSender) Close() error {
	log.Infof("Messages successfully sent by the stdoutSender: %d", s.count)
	return nil
}

var recoverableErrs = map[syscall.Errno]bool{syscall.EPIPE: true, syscall.ECONNRESET: true}

// mllpSender sends HL7 messages via the MLLP protocol.
type mllpSender struct {
	client              *MLLPClient
	conn                net.Conn
	address             string
	mllpKeepAlive       bool
	mllpKeepAlivePeriod time.Duration
	count               int
}

// NewMLLPSender returns a sender that sends HL7 messages via the MLLP protocol.
func NewMLLPSender(address string, mllpKeepAlive bool, mllpKeepAlivePeriod time.Duration) (Sender, error) {
	sender := &mllpSender{
		address:             address,
		mllpKeepAlive:       mllpKeepAlive,
		mllpKeepAlivePeriod: mllpKeepAlivePeriod,
	}
	if err := sender.establishConnection(); err != nil {
		return nil, errors.Wrapf(err, "cannot establish mllp connection on sender %+v", sender)
	}
	return sender, nil
}

func isRecoverable(err error) bool {
	if opError, ok := err.(*net.OpError); ok {
		if syscallErr, ok := opError.Err.(*os.SyscallError); ok {
			if errno, ok := syscallErr.Err.(syscall.Errno); ok && recoverableErrs[errno] {
				return true
			}
		}
	}

	return false
}

func (s *mllpSender) establishConnection() error {
	conn, err := net.Dial("tcp", s.address)
	if err != nil {
		return errors.Wrapf(err, "cannot connect to tcp address %s", s.address)
	}

	if s.mllpKeepAlive {
		if err := conn.(*net.TCPConn).SetKeepAlive(true); err != nil {
			return errors.Wrapf(err, "cannot set keep alive on connection %v", conn)
		}
		if err := conn.(*net.TCPConn).SetKeepAlivePeriod(s.mllpKeepAlivePeriod); err != nil {
			return errors.Wrapf(err, "cannot set keep alive period on connection %v", conn)
		}
	}

	s.conn = conn
	s.client = NewMLLPClient(conn)
	return nil
}

// Send sends a messages via the MLLP protocol.
// It returns an error if the message cannot be sent or was not acknowledged.
func (s *mllpSender) Send(message []byte) error {
	if err := s.client.Write(message); err != nil {
		if !isRecoverable(err) {
			return errors.Wrap(err, "cannot send message")
		}
		// If the socket was closed by the peer, handle it by trying to
		// write once again on a new connection.
		if err = s.establishConnection(); err != nil {
			return errors.Wrap(err, "cannot send message: error when re-establishing connection")
		}
		if err = s.client.Write(message); err != nil {
			return errors.Wrap(err, "cannot send message after re-establishing connection")
		}
	}

	ack, err := s.client.Read()
	if err != nil {
		return errors.Wrap(err, "cannot read an ack after sending message")
	}

	if _, err = ParseMessage(ack); err != nil {
		return errors.Wrap(err, "ack message cannot be parsed")
	}
	s.count++
	return nil
}

// Close closes the underlying TCP connection.
// It should be called, when the mllpSender is not needed anymore or at the program exit.
// Close prints the number of messages that have been sent.
func (s *mllpSender) Close() error {
	log.Infof("Messages successfully sent by the mllpSender: %d", s.count)
	if err := s.conn.Close(); err != nil {
		return errors.Wrap(err, "closing mllp sender connection")
	}
	return nil
}

// fileSender sends HL7 messages to a file.
type fileSender struct {
	file  *os.File
	count int
}

// NewFileSender creates a sender that sends HL7 messages to a file.
func NewFileSender(destFilename string) (Sender, error) {
	if destFilename == "" {
		return nil, errors.New("output filename must be nonempty if outputting to a file")
	}
	file, err := os.Create(destFilename)
	if err != nil {
		return nil, errors.Wrapf(err, "cannot create output file %s", destFilename)
	}
	return &fileSender{file: file}, nil
}

// Send sends a message to the file.
func (s *fileSender) Send(message []byte) error {
	if _, err := s.file.Write(append(message, []byte("\n\n")...)); err != nil {
		return errors.Wrap(err, "cannot write a message")
	}
	s.count++
	return nil
}

// Close closes the underlying file.
// It should be called, when the mllpSender is not needed anymore or at the program exit.
// Close prints the number of messages that have been sent.
func (s *fileSender) Close() error {
	log.Infof("Messages successfully sent by the fileSender: %d", s.count)
	if err := s.file.Close(); err != nil {
		return errors.Wrap(err, "closing file sender")
	}
	return nil
}
<|endoftext|>


<commit_before>package response

// 设置状态元的状态码
func (r *HTTPResponse) SS(status int) *HTTPResponse {
	r.State.S(status)
	r.Success = r.IsSuccess()
	return r
}

func (r *HTTPResponse) SF() *HTTPResponse {
	r.State.S(Status_fail)
	r.Success = false
	return r
}

func (r *HTTPResponse) SFF() *HTTPResponse {
	r.State.S(Status_fail_frequently)
	r.Success = false
	return r
}

// 设置执行成功
func (r *HTTPResponse) Finish() *HTTPResponse {
	r.State.Success()
	r.E(nil).Success = true
	return r
}

func (r *HTTPResponse) IsSuccess() bool {
	return (r.State.Status == Status_success || r.State.Status == Status_ignore)
}

func (r *HTTPResponse) IsInvalidToken() bool {
	return (r.State.Status == Status_invalid_token)
}

func (r *HTTPResponse) IsTimeoutToken() bool {
	return (r.State.Status == Status_token_timeout)
}
<commit_msg>fix: status<commit_after>package response

// 设置状态元的状态码
func (r *HTTPResponse) SS(status int) *HTTPResponse {
	r.State.S(status)
	r.Success = r.IsSuccess()
	return r
}

func (r *HTTPResponse) SF() *HTTPResponse {
	r.State.S(Status_fail)
	r.Success = false
	return r
}

func (r *HTTPResponse) SFF() *HTTPResponse {
	r.State.S(Status_fail_frequently)
	r.Success = false
	return r
}

// 设置执行成功
func (r *HTTPResponse) Finish() *HTTPResponse {
	r.State.Success()
	r.E(nil).Success = true
	return r
}

func (r *HTTPResponse) IsSuccess() bool {
	return (r.State.Status == Status_success || r.State.Status == Status_ignore)
}

func (r *HTTPResponse) IsInvalidToken() bool {
	return (r.State.Status == Status_invalid_token)
}

func (r *HTTPResponse) IsTimeoutToken() bool {
	return (r.State.Status == Status_invalid_token)
}
<|endoftext|>


<commit_before>package ptgen

import (
	"math"
	"math/rand"
	"strconv"
	"strings"
	"time"

	"github.com/icrowley/fake"
	"github.com/intervention-engine/fhir/models"
	"github.com/jmcvetta/randutil"
)

// Context contains information about the patient that can be used when
// generating information
type Context struct {
	Smoker       string
	Hypertention string
	Alcohol      string
	Cholesterol  string
	Diabetes     string
	Height       int
	Weight       int
	BirthDate    time.Time
}

func GeneratePatient() []interface{} {
	ctx := NewContext()
	tempID := strconv.FormatInt(rand.Int63(), 10)
	pt := GenerateDemographics()
	ctx.Height, ctx.Weight = initialHeightAndWeight(pt.Gender)
	ctx.BirthDate = pt.BirthDate.Time
	pt.Id = tempID
	md := LoadConditions()
	mmd := LoadMedications()
	conditions := GenerateConditions(ctx, md)
	var m []interface{}
	m = append(m, &pt)
	for i := range conditions {
		c := conditions[i]
		c.Patient = &models.Reference{Reference: "cid:" + tempID}
		m = append(m, &c)
		conditionMetadata := conditionByName(c.Code.Text, md)
		med := GenerateMedication(conditionMetadata.MedicationID, c.OnsetDateTime, c.AbatementDateTime, mmd)
		if med != nil {
			med.Patient = &models.Reference{Reference: "cid:" + tempID}
			m = append(m, med)
		}
	}

	for i := 0; i < 3; i++ {
		t := time.Now()
		encounterDate := &models.FHIRDateTime{Time: t.AddDate(-i, rand.Intn(2), rand.Intn(5)), Precision: models.Date}
		encounter := models.Encounter{}
		encounter.Type = []models.CodeableConcept{{Coding: []models.Coding{{Code: "99213", System: "http://www.ama-assn.org/go/cpt"}}, Text: "Office Visit"}}
		encounter.Period = &models.Period{Start: encounterDate}
		encounter.Patient = &models.Reference{Reference: "cid:" + tempID}
		m = append(m, &encounter)
		obs := GenerateBP(ctx)
		obs = append(obs, GenerateBloodSugars(ctx)...)
		obs = append(obs, GenerateWeightAndHeight(ctx)...)
		for j := range obs {
			o := obs[j]
			o.EffectiveDateTime = encounterDate
			o.Subject = &models.Reference{Reference: "cid:" + tempID}
			m = append(m, &o)
		}
	}

	return m
}

func GenerateDemographics() models.Patient {
	patient := models.Patient{}
	patient.Gender = strings.ToLower(fake.Gender())
	name := models.HumanName{}
	var firstName string
	if patient.Gender == "male" {
		firstName = fake.MaleFirstName()
	} else {
		firstName = fake.FemaleFirstName()
	}
	name.Given = []string{firstName}
	name.Family = []string{fake.LastName()}
	patient.Name = []models.HumanName{name}
	patient.BirthDate = &models.FHIRDateTime{Time: RandomBirthDate(), Precision: models.Date}
	patient.Address = []models.Address{GenerateAddress()}
	return patient
}

// RandomBirthDate generates a random birth date between 65 and 85 years ago
func RandomBirthDate() time.Time {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	randomYears := r.Intn(20)
	yearsAgo := randomYears + 65
	randomMonth := r.Intn(11)
	randomDay := r.Intn(28)
	t := time.Now()
	return t.AddDate(-yearsAgo, -randomMonth, -randomDay).Truncate(time.Hour * 24)
}

func GenerateAddress() models.Address {
	address := models.Address{}
	address.Line = []string{fake.Street()}
	address.City = fake.City()
	address.State = fake.StateAbbrev()
	address.PostalCode = fake.Zip()
	return address
}

// NewContext generates a new context with randomly populated content
func NewContext() Context {
	ctx := Context{}
	smokingChoices := []randutil.Choice{
		{2, "Smoker"},
		{3, "Non-smoker"},
		{1, "Ex-smoker"}}
	sc, _ := randutil.WeightedChoice(smokingChoices)
	ctx.Smoker = sc.Item.(string)

	alcoholChoices := []randutil.Choice{
		{2, "Occasional"},
		{1, "Heavy"},
		{1, "None"}}
	ac, _ := randutil.WeightedChoice(alcoholChoices)
	ctx.Alcohol = ac.Item.(string)

	cholesterolChoices := []randutil.Choice{
		{3, "Optimal"},
		{1, "Near Optimal"},
		{2, "Borderline"},
		{1, "High"},
		{2, "Very High"}}
	cc, _ := randutil.WeightedChoice(cholesterolChoices)
	ctx.Cholesterol = cc.Item.(string)

	hc, _ := randutil.ChoiceString([]string{"Normal", "Pre-hypertension", "Hypertension"})
	ctx.Hypertention = hc

	dc, _ := randutil.ChoiceString([]string{"Normal", "Pre-diabetes", "Diabetes"})
	ctx.Diabetes = dc
	return ctx
}

func initialHeightAndWeight(gender string) (h, w int) {
	if gender == "male" {
		h = 60 + rand.Intn(20)
	} else {
		h = 55 + rand.Intn(20)
	}
	minBMI := float64(18)
	englishBMIConstant := float64(703)
	minWeight := (minBMI / englishBMIConstant) * math.Pow(float64(h), float64(2))
	w = int(minWeight) + rand.Intn(200)
	return
}
<commit_msg>Add random digits to the end of last names to signal that these are synthetic patients<commit_after>package ptgen

import (
	"fmt"
	"math"
	"math/rand"
	"strconv"
	"strings"
	"time"

	"github.com/icrowley/fake"
	"github.com/intervention-engine/fhir/models"
	"github.com/jmcvetta/randutil"
)

// Context contains information about the patient that can be used when
// generating information
type Context struct {
	Smoker       string
	Hypertention string
	Alcohol      string
	Cholesterol  string
	Diabetes     string
	Height       int
	Weight       int
	BirthDate    time.Time
}

func GeneratePatient() []interface{} {
	ctx := NewContext()
	tempID := strconv.FormatInt(rand.Int63(), 10)
	pt := GenerateDemographics()
	ctx.Height, ctx.Weight = initialHeightAndWeight(pt.Gender)
	ctx.BirthDate = pt.BirthDate.Time
	pt.Id = tempID
	md := LoadConditions()
	mmd := LoadMedications()
	conditions := GenerateConditions(ctx, md)
	var m []interface{}
	m = append(m, &pt)
	for i := range conditions {
		c := conditions[i]
		c.Patient = &models.Reference{Reference: "cid:" + tempID}
		m = append(m, &c)
		conditionMetadata := conditionByName(c.Code.Text, md)
		med := GenerateMedication(conditionMetadata.MedicationID, c.OnsetDateTime, c.AbatementDateTime, mmd)
		if med != nil {
			med.Patient = &models.Reference{Reference: "cid:" + tempID}
			m = append(m, med)
		}
	}

	for i := 0; i < 3; i++ {
		t := time.Now()
		encounterDate := &models.FHIRDateTime{Time: t.AddDate(-i, rand.Intn(2), rand.Intn(5)), Precision: models.Date}
		encounter := models.Encounter{}
		encounter.Type = []models.CodeableConcept{{Coding: []models.Coding{{Code: "99213", System: "http://www.ama-assn.org/go/cpt"}}, Text: "Office Visit"}}
		encounter.Period = &models.Period{Start: encounterDate}
		encounter.Patient = &models.Reference{Reference: "cid:" + tempID}
		m = append(m, &encounter)
		obs := GenerateBP(ctx)
		obs = append(obs, GenerateBloodSugars(ctx)...)
		obs = append(obs, GenerateWeightAndHeight(ctx)...)
		for j := range obs {
			o := obs[j]
			o.EffectiveDateTime = encounterDate
			o.Subject = &models.Reference{Reference: "cid:" + tempID}
			m = append(m, &o)
		}
	}

	return m
}

func GenerateDemographics() models.Patient {
	patient := models.Patient{}
	patient.Gender = strings.ToLower(fake.Gender())
	name := models.HumanName{}
	var firstName string
	if patient.Gender == "male" {
		firstName = fake.MaleFirstName()
	} else {
		firstName = fake.FemaleFirstName()
	}
	name.Given = []string{firstName}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	ln := fmt.Sprintf("%s%04d", fake.LastName(), r.Intn(10000))
	name.Family = []string{ln}
	patient.Name = []models.HumanName{name}
	patient.BirthDate = &models.FHIRDateTime{Time: RandomBirthDate(), Precision: models.Date}
	patient.Address = []models.Address{GenerateAddress()}
	return patient
}

// RandomBirthDate generates a random birth date between 65 and 85 years ago
func RandomBirthDate() time.Time {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	randomYears := r.Intn(20)
	yearsAgo := randomYears + 65
	randomMonth := r.Intn(11)
	randomDay := r.Intn(28)
	t := time.Now()
	return t.AddDate(-yearsAgo, -randomMonth, -randomDay).Truncate(time.Hour * 24)
}

func GenerateAddress() models.Address {
	address := models.Address{}
	address.Line = []string{fake.Street()}
	address.City = fake.City()
	address.State = fake.StateAbbrev()
	address.PostalCode = fake.Zip()
	return address
}

// NewContext generates a new context with randomly populated content
func NewContext() Context {
	ctx := Context{}
	smokingChoices := []randutil.Choice{
		{2, "Smoker"},
		{3, "Non-smoker"},
		{1, "Ex-smoker"}}
	sc, _ := randutil.WeightedChoice(smokingChoices)
	ctx.Smoker = sc.Item.(string)

	alcoholChoices := []randutil.Choice{
		{2, "Occasional"},
		{1, "Heavy"},
		{1, "None"}}
	ac, _ := randutil.WeightedChoice(alcoholChoices)
	ctx.Alcohol = ac.Item.(string)

	cholesterolChoices := []randutil.Choice{
		{3, "Optimal"},
		{1, "Near Optimal"},
		{2, "Borderline"},
		{1, "High"},
		{2, "Very High"}}
	cc, _ := randutil.WeightedChoice(cholesterolChoices)
	ctx.Cholesterol = cc.Item.(string)

	hc, _ := randutil.ChoiceString([]string{"Normal", "Pre-hypertension", "Hypertension"})
	ctx.Hypertention = hc

	dc, _ := randutil.ChoiceString([]string{"Normal", "Pre-diabetes", "Diabetes"})
	ctx.Diabetes = dc
	return ctx
}

func initialHeightAndWeight(gender string) (h, w int) {
	if gender == "male" {
		h = 60 + rand.Intn(20)
	} else {
		h = 55 + rand.Intn(20)
	}
	minBMI := float64(18)
	englishBMIConstant := float64(703)
	minWeight := (minBMI / englishBMIConstant) * math.Pow(float64(h), float64(2))
	w = int(minWeight) + rand.Intn(200)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"go/format"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"sync"
	"text/template"
	"unicode"
)

var reservedWords = map[string]string{
	"break":       "break_",
	"default":     "default_",
	"func":        "func_",
	"interface":   "interface_",
	"select":      "select_",
	"case":        "case_",
	"defer":       "defer_",
	"go":          "go_",
	"map":         "map_",
	"struct":      "struct_",
	"chan":        "chan_",
	"else":        "else_",
	"goto":        "goto_",
	"package":     "package_",
	"switch":      "switch_",
	"const":       "const_",
	"fallthrough": "fallthrough_",
	"if":          "if_",
	"range":       "range_",
	"type":        "type_",
	"continue":    "continue_",
	"for":         "for_",
	"import":      "import_",
	"return":      "return_",
	"var":         "var_",
}

func replaceReservedWords(identifier string) string {
	value := reservedWords[identifier]
	if value != "" {
		return value
	}
	return identifier
}

var xsd2GoTypes = map[string]string{
	"string":        "string",
	"token":         "string",
	"float":         "float32",
	"double":        "float64",
	"decimal":       "float64",
	"integer":       "int32",
	"int":           "int32",
	"short":         "int16",
	"byte":          "int8",
	"long":          "int64",
	"boolean":       "bool",
	"dateTime":      "time.Time",
	"date":          "time.Time",
	"time":          "time.Time",
	"base64Binary":  "[]byte",
	"hexBinary":     "[]byte",
	"unsignedInt":   "uint32",
	"unsignedShort": "uint16",
	"unsignedByte":  "byte",
	"unsignedLong":  "uint64",
	"anyType":       "interface{}",
}

func toGoType(xsdType string) string {
	if xsdType == "" {
		return ""
	}

	//Handles name space, ie. xsd:string, xs:long
	r := strings.Split(xsdType, ":")

	type_ := r[0]

	if len(r) == 2 {
		type_ = r[1]
	}

	value := xsd2GoTypes[type_]

	if value != "" {
		return value
	}

	if strings.HasSuffix(type_, "[]") {
		type_ = type_[:len(type_)-2]
		if _, ok := xsd2GoTypes[type_]; ok {
			type_ = "[]" + type_
		} else {
			type_ = "[]*" + type_
		}
	} else {
		type_ = "*" + type_
	}

	return type_
}

func stripns(xsdType string) string {
	r := strings.Split(xsdType, ":")
	type_ := r[0]

	if len(r) == 2 {
		type_ = r[1]
	}

	return type_
}

func makePublic(field_ string, public bool) string {
	field := []rune(field_)
	if len(field) == 0 {
		return field_
	}

	if public {
		field[0] = unicode.ToUpper(field[0])
	} else {
		field[0] = unicode.ToLower(field[0])
	}
	return string(field)
}

func comment(text string) string {
	lines := strings.Split(text, "\n")

	var output string
	if len(lines) == 1 && lines[0] == "" {
		return ""
	}

	// Helps to determine if
	// there is an actual comment
	// without screwing newlines
	// in real comments.
	hasComment := false

	for _, line := range lines {
		line = strings.TrimLeftFunc(line, unicode.IsSpace)
		if line != "" {
			hasComment = true
		}
		output += "\n// " + line
	}

	if hasComment {
		return output
	}
	return ""
}

var funcMap = template.FuncMap{
	"toGoType":             toGoType,
	"stripns":              stripns,
	"replaceReservedWords": replaceReservedWords,
	"makePublic":           makePublic,
	"comment":              comment,
}

func generate(apiDefFile string) {
	apiDef, err := ioutil.ReadFile(apiDefFile)
	if err != nil {
		log.Fatalln(err)
	}

	var objects []Object
	err = json.Unmarshal(apiDef, &objects)
	if err != nil {
		log.Fatalln(err)
	}

	mainPkg := "./vim"
	os.Mkdir(mainPkg, 0744)

	var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		defer wg.Done()
		genCode(objects, mainPkg, moTmpl, "mo")
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		genCode(objects, mainPkg, doTmpl, "do")
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		genCode(objects, mainPkg, enumTmpl, "enum")
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		genCode(objects, mainPkg, faultTmpl, "fault")
	}()

	wg.Wait()
}

func genCode(objects []Object, mainPkg, tmpl, namespace string) {
	var fd *os.File
	pkg := mainPkg + "/" + namespace

	if ok, err := exists(pkg); !ok && err == nil {
		os.Mkdir(pkg, 0744)
	}

	file := pkg + "/" + namespace + ".go"
	fd, err := os.Create(file)
	if err != nil {
		log.Fatalln(err)
	}
	defer fd.Close()

	data := new(bytes.Buffer)
	data.WriteString(headerTmpl)
	data.WriteString("package " + namespace + "\n")
	if namespace == "do" {
		data.WriteString(`
			import (
				"github.com/c4milo/govsphere/vim/mo"
				"time"
			)
		`)
	} else if namespace == "mo" {
		data.WriteString(`
			import (
				"time"
			)
		`)
	}

	for _, obj := range objects {
		if obj.Namespace != namespace {
			continue
		}

		tmpl := template.Must(template.New(obj.Namespace).Funcs(funcMap).Parse(tmpl))
		err = tmpl.Execute(data, obj)
		if err != nil {
			log.Fatalln(err)
		}
		//obj.Methods[0].ReturnValue.
	}

	source := data.Bytes()
	fsource, err := format.Source(source)
	if err != nil {
		fd.Write(source)
		log.Fatalf("There are errors in the generated source for %s: %s\n", file, err.Error())
	}
	fd.Write(fsource)
}
<commit_msg>Adds support to resolve types packages<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"go/format"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"sync"
	"text/template"
	"unicode"
)

var reservedWords = map[string]string{
	"break":       "break_",
	"default":     "default_",
	"func":        "func_",
	"interface":   "interface_",
	"select":      "select_",
	"case":        "case_",
	"defer":       "defer_",
	"go":          "go_",
	"map":         "map_",
	"struct":      "struct_",
	"chan":        "chan_",
	"else":        "else_",
	"goto":        "goto_",
	"package":     "package_",
	"switch":      "switch_",
	"const":       "const_",
	"fallthrough": "fallthrough_",
	"if":          "if_",
	"range":       "range_",
	"type":        "type_",
	"continue":    "continue_",
	"for":         "for_",
	"import":      "import_",
	"return":      "return_",
	"var":         "var_",
}

func replaceReservedWords(identifier string) string {
	value := reservedWords[identifier]
	if value != "" {
		return value
	}
	return identifier
}

var xsd2GoTypes = map[string]string{
	"string":        "string",
	"token":         "string",
	"float":         "float32",
	"double":        "float64",
	"decimal":       "float64",
	"integer":       "int32",
	"int":           "int32",
	"short":         "int16",
	"byte":          "int8",
	"long":          "int64",
	"boolean":       "bool",
	"dateTime":      "time.Time",
	"date":          "time.Time",
	"time":          "time.Time",
	"base64Binary":  "[]byte",
	"hexBinary":     "[]byte",
	"unsignedInt":   "uint32",
	"unsignedShort": "uint16",
	"unsignedByte":  "byte",
	"unsignedLong":  "uint64",
	"anyType":       "interface{}",
}

func toGoType(xsdType string) string {
	if xsdType == "" {
		return ""
	}

	//Handles name space, ie. xsd:string, xs:long
	r := strings.Split(xsdType, ":")

	type_ := r[0]

	if len(r) == 2 {
		type_ = r[1]
	}

	value := xsd2GoTypes[type_]

	if value != "" {
		return value
	}

	if strings.HasSuffix(type_, "[]") {
		type_ = type_[:len(type_)-2]
		if _, ok := xsd2GoTypes[type_]; ok {
			type_ = "[]" + type_
		} else {
			type_ = "[]*" + type_
		}
	} else {
		type_ = "*" + type_
	}

	return type_
}

func stripns(xsdType string) string {
	r := strings.Split(xsdType, ":")
	type_ := r[0]

	if len(r) == 2 {
		type_ = r[1]
	}

	return type_
}

func makePublic(field_ string, public bool) string {
	field := []rune(field_)
	if len(field) == 0 {
		return field_
	}

	if public {
		field[0] = unicode.ToUpper(field[0])
	} else {
		field[0] = unicode.ToLower(field[0])
	}
	return string(field)
}

func comment(text string) string {
	lines := strings.Split(text, "\n")

	var output string
	if len(lines) == 1 && lines[0] == "" {
		return ""
	}

	// Helps to determine if
	// there is an actual comment
	// without screwing newlines
	// in real comments.
	hasComment := false

	for _, line := range lines {
		line = strings.TrimLeftFunc(line, unicode.IsSpace)
		if line != "" {
			hasComment = true
		}
		output += "\n// " + line
	}

	if hasComment {
		return output
	}
	return ""
}

//This is how we look for the package
//or namespace associated to one particular
//type. This is needed because 4 packages
//are being created such as: mo, enum, do and faults
//in order to make the API more idiomatic
//for users to use. Once a type is found
//this map is going to be used to find its
//namespace or package.
var objnsmap map[string]string

func lookUpNamespace(type_, currentNs string) string {
	//Embeddeds or extends are often times empty
	if type_ == "" {
		return type_
	}

	var prefix string
	if type_[0:1] == "*" {
		prefix = "*"
		type_ = type_[1:]
	} else if type_[0:3] == "[]*" {
		prefix = "[]*"
		type_ = type_[3:]
	} else if type_[0:2] == "[]" {
		prefix = "[]"
		type_ = type_[2:]
	}
	targetNs := objnsmap[type_]
	if targetNs == "" || targetNs == currentNs {
		return prefix + type_
	}

	return prefix + targetNs + "." + type_
}

var funcMap = template.FuncMap{
	"toGoType":             toGoType,
	"stripns":              stripns,
	"replaceReservedWords": replaceReservedWords,
	"makePublic":           makePublic,
	"comment":              comment,
	"lookUpNamespace":      lookUpNamespace,
}

func generate(apiDefFile string) {
	apiDef, err := ioutil.ReadFile(apiDefFile)
	if err != nil {
		log.Fatalln(err)
	}

	var objects []Object
	err = json.Unmarshal(apiDef, &objects)
	if err != nil {
		log.Fatalln(err)
	}

	//Populates objnsmap
	objnsmap = make(map[string]string)
	for _, obj := range objects {
		objnsmap[obj.Name] = obj.Namespace
	}

	mainPkg := "./vim"
	os.Mkdir(mainPkg, 0744)

	var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		defer wg.Done()
		genCode(objects, mainPkg, moTmpl, "mo")
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		genCode(objects, mainPkg, doTmpl, "do")
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		genCode(objects, mainPkg, enumTmpl, "enum")
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		genCode(objects, mainPkg, faultTmpl, "fault")
	}()

	wg.Wait()
}

func genCode(objects []Object, mainPkg, tmpl, namespace string) {
	var fd *os.File
	pkg := mainPkg + "/" + namespace

	if ok, err := exists(pkg); !ok && err == nil {
		os.Mkdir(pkg, 0744)
	}

	file := pkg + "/" + namespace + ".go"
	fd, err := os.Create(file)
	if err != nil {
		log.Fatalln(err)
	}
	defer fd.Close()

	data := new(bytes.Buffer)
	data.WriteString(headerTmpl)
	data.WriteString("package " + namespace + "\n")
	if namespace == "do" {
		data.WriteString(`
			import (
				"github.com/c4milo/govsphere/vim/mo"
				"time"
			)
		`)
	} else if namespace == "mo" {
		data.WriteString(`
			import (
				"github.com/c4milo/govsphere/vim/do"
				"time"
			)
		`)
	}

	for _, obj := range objects {
		if obj.Namespace != namespace {
			continue
		}

		tmpl := template.Must(template.New(obj.Namespace).Funcs(funcMap).Parse(tmpl))
		err = tmpl.Execute(data, obj)
		if err != nil {
			log.Fatalln(err)
		}
		//obj.Methods[0].ReturnValue.
	}

	source := data.Bytes()
	fsource, err := format.Source(source)
	if err != nil {
		fd.Write(source)
		log.Fatalf("There are errors in the generated source for %s: %s\n", file, err.Error())
	}
	fd.Write(fsource)
}
<|endoftext|>


<commit_before>// +build ignore

package main

import (
	"bufio"

	"flag"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"sync"

	"code.google.com/p/go.net/idna"
	"github.com/domainr/whois"
)

var (
	v, quick       bool
	oneZone        string
	concurrency    int
	zones          []string
	prefixes       []string
	_, _file, _, _ = runtime.Caller(0)
	_dir           = filepath.Dir(_file)
)

func init() {
	flag.BoolVar(&v, "v", false, "verbose output (to stderr)")
	flag.BoolVar(&quick, "quick", false, "Only query a shorter subset of zones")
	flag.StringVar(&oneZone, "zone", "", "Only query a specific zone")
	flag.IntVar(&concurrency, "concurrency", 32, "Set maximum number of concurrent requests")
}

func main() {
	flag.Parse()

	if err := main1(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func main1() error {
	var err error
	zones, err = readLines("zones.txt")
	if err != nil {
		return err
	}
	prefixes, err = readLines("prefixes.txt")
	if err != nil {
		return err
	}

	// Quick for debugging?
	if quick {
		fmt.Fprintf(os.Stderr, "Quick mode enabled\n")
		zones = []string{"com", "net", "org", "co", "io", "nr", "kr", "jp"}
		concurrency = 4 // Don’t slam the .org whois server
	}

	// One zone?
	if oneZone != "" {
		fmt.Fprintf(os.Stderr, "Querying single zone: %s\n", oneZone)
		zones = []string{oneZone}
		concurrency = 1
	}

	re := regexp.MustCompile(`^[^\.]+\.`)

	domains := make(map[string]bool, len(zones)*len(prefixes))
	for _, zone := range zones {
		for _, prefix := range prefixes {
			domain := prefix + "." + zone
			domains[domain] = true
			req, err := whois.Resolve(domain)
			if err == nil {
				hostParent := re.ReplaceAllLiteralString(req.Host, "")
				if _, ok := domains[hostParent]; !ok && hostParent != "" {
					fmt.Fprintf(os.Stderr, "  + %s\n", hostParent)
					domains[hostParent] = true
				}
			}
		}
	}

	fmt.Fprintf(os.Stderr, "Querying whois for %d domains (%d prefixes × %d zones + extras)\n", len(domains), len(prefixes), len(zones))

	responses := make(chan *whois.Response)
	limiter := make(chan struct{}, concurrency) // semaphore to limit concurrency
	for domain, _ := range domains {
		go func(domain string) {
			var res *whois.Response

			limiter <- struct{}{} // acquire semaphore
			defer func() {        // release semaphore
				responses <- res
				<-limiter
			}()

			req, err := whois.Resolve(domain)
			if err != nil {
				return
			}

			if v {
				fmt.Fprintf(os.Stderr, "Fetching %s from %s\n", req.Query, req.Host)
			}
			res, err = req.Fetch()
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error fetching whois for %s: %s\n", req.Query, err)
				return
			}
		}(domain)
	}

	// Collect from goroutines
	var wg sync.WaitGroup
	wg.Add(len(domains))
	for i := 0; i < len(domains); i++ {
		go func() {
			res := <-responses
			defer wg.Done()

			if res == nil {
				return
			}

			if res.Host == "" {
				fmt.Fprintf(os.Stderr, "Response for %q had no host\n", res.Query)
				return
			}

			if len(res.Body) == 0 {
				fmt.Fprintf(os.Stderr, "Response for %q had empty body\n", res.Query)
				return
			}

			dir := filepath.Join(_dir, "data", "responses", res.Host)
			err := os.MkdirAll(dir, os.ModePerm)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error creating response directory for %s: %s\n", res.Host, err)
				return
			}

			fn := filepath.Join(dir, (res.Checksum() + ".mime"))
			f, err := os.Create(fn)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error creating response file for %s: %s\n", res.Query, err)
				return
			}
			defer f.Close()
			res.WriteMIME(f)
		}()
	}
	wg.Wait()

	return nil
}

var whitespaceAndComments = regexp.MustCompile(`\s+|#.+$`)

func readLines(fn string) ([]string, error) {
	fmt.Fprintf(os.Stderr, "Reading %s\n", fn)
	f, err := os.Open(filepath.Join(_dir, "data", fn))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var out []string
	s := bufio.NewScanner(f)
	for s.Scan() {
		line := whitespaceAndComments.ReplaceAllLiteralString(s.Text(), "")
		if line == "" {
			continue
		}
		if line, ierr := idna.ToASCII(line); ierr == nil {
			out = append(out, line)
		}
	}
	return out, s.Err()
}
<commit_msg>Add .de and .in to default “quick” set<commit_after>// +build ignore

package main

import (
	"bufio"

	"flag"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"sync"

	"code.google.com/p/go.net/idna"
	"github.com/domainr/whois"
)

var (
	v, quick       bool
	oneZone        string
	concurrency    int
	zones          []string
	prefixes       []string
	_, _file, _, _ = runtime.Caller(0)
	_dir           = filepath.Dir(_file)
)

func init() {
	flag.BoolVar(&v, "v", false, "verbose output (to stderr)")
	flag.BoolVar(&quick, "quick", false, "Only query a shorter subset of zones")
	flag.StringVar(&oneZone, "zone", "", "Only query a specific zone")
	flag.IntVar(&concurrency, "concurrency", 32, "Set maximum number of concurrent requests")
}

func main() {
	flag.Parse()

	if err := main1(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func main1() error {
	var err error
	zones, err = readLines("zones.txt")
	if err != nil {
		return err
	}
	prefixes, err = readLines("prefixes.txt")
	if err != nil {
		return err
	}

	// Quick for debugging?
	if quick {
		fmt.Fprintf(os.Stderr, "Quick mode enabled\n")
		zones = []string{"com", "net", "org", "co", "io", "nr", "kr", "jp", "de", "in"}
	}

	// One zone?
	if oneZone != "" {
		fmt.Fprintf(os.Stderr, "Querying single zone: %s\n", oneZone)
		zones = []string{oneZone}
		concurrency = 1
	}

	re := regexp.MustCompile(`^[^\.]+\.`)

	domains := make(map[string]bool, len(zones)*len(prefixes))
	for _, zone := range zones {
		for _, prefix := range prefixes {
			domain := prefix + "." + zone
			domains[domain] = true
			req, err := whois.Resolve(domain)
			if err == nil {
				hostParent := re.ReplaceAllLiteralString(req.Host, "")
				if _, ok := domains[hostParent]; !ok && hostParent != "" {
					fmt.Fprintf(os.Stderr, "  + %s\n", hostParent)
					domains[hostParent] = true
				}
			}
		}
	}

	fmt.Fprintf(os.Stderr, "Querying whois for %d domains (%d prefixes × %d zones + extras)\n", len(domains), len(prefixes), len(zones))

	responses := make(chan *whois.Response)
	limiter := make(chan struct{}, concurrency) // semaphore to limit concurrency
	for domain, _ := range domains {
		go func(domain string) {
			var res *whois.Response

			limiter <- struct{}{} // acquire semaphore
			defer func() {        // release semaphore
				responses <- res
				<-limiter
			}()

			req, err := whois.Resolve(domain)
			if err != nil {
				return
			}

			if v {
				fmt.Fprintf(os.Stderr, "Fetching %s from %s\n", req.Query, req.Host)
			}
			res, err = req.Fetch()
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error fetching whois for %s: %s\n", req.Query, err)
				return
			}
		}(domain)
	}

	// Collect from goroutines
	var wg sync.WaitGroup
	wg.Add(len(domains))
	for i := 0; i < len(domains); i++ {
		go func() {
			res := <-responses
			defer wg.Done()

			if res == nil {
				return
			}

			if res.Host == "" {
				fmt.Fprintf(os.Stderr, "Response for %q had no host\n", res.Query)
				return
			}

			if len(res.Body) == 0 {
				fmt.Fprintf(os.Stderr, "Response for %q had empty body\n", res.Query)
				return
			}

			dir := filepath.Join(_dir, "data", "responses", res.Host)
			err := os.MkdirAll(dir, os.ModePerm)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error creating response directory for %s: %s\n", res.Host, err)
				return
			}

			fn := filepath.Join(dir, (res.Checksum() + ".mime"))
			f, err := os.Create(fn)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error creating response file for %s: %s\n", res.Query, err)
				return
			}
			defer f.Close()
			res.WriteMIME(f)
		}()
	}
	wg.Wait()

	return nil
}

var whitespaceAndComments = regexp.MustCompile(`\s+|#.+$`)

func readLines(fn string) ([]string, error) {
	fmt.Fprintf(os.Stderr, "Reading %s\n", fn)
	f, err := os.Open(filepath.Join(_dir, "data", fn))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var out []string
	s := bufio.NewScanner(f)
	for s.Scan() {
		line := whitespaceAndComments.ReplaceAllLiteralString(s.Text(), "")
		if line == "" {
			continue
		}
		if line, ierr := idna.ToASCII(line); ierr == nil {
			out = append(out, line)
		}
	}
	return out, s.Err()
}
<|endoftext|>


<commit_before>package commands

import (
	"bufio"
	"io/ioutil"
	"os"
	"strings"

	"github.com/github/git-lfs/lfs"
	"github.com/github/git-lfs/vendor/_nuts/github.com/spf13/cobra"
)

var (
	untrackCmd = &cobra.Command{
		Use:   "untrack",
		Short: "Remove an entry from .gitattributes",
		Run:   untrackCommand,
	}
)

// untrackCommand takes a list of paths as an argument, and removes each path from the
// default attribtues file (.gitattributes), if it exists.
func untrackCommand(cmd *cobra.Command, args []string) {
	if lfs.LocalGitDir == "" {
		Print("Not a git repository.")
		os.Exit(128)
	}
	if lfs.LocalWorkingDir == "" {
		Print("This operation must be run in a work tree.")
		os.Exit(128)
	}

	lfs.InstallHooks(false)

	if len(args) < 1 {
		Print("git lfs untrack <path> [path]*")
		return
	}

	data, err := ioutil.ReadFile(".gitattributes")
	if err != nil {
		return
	}

	attributes := strings.NewReader(string(data))

	attributesFile, err := os.Create(".gitattributes")
	if err != nil {
		Print("Error opening .gitattributes for writing")
		return
	}
	defer attributesFile.Close()

	scanner := bufio.NewScanner(attributes)

	// Iterate through each line of the attributes file and rewrite it,
	// if the path was meant to be untracked, omit it, and print a message instead.
	for scanner.Scan() {
		line := scanner.Text()
		if !strings.Contains(line, "filter=lfs") {
			attributesFile.WriteString(line + "\n")
			continue
		}

		fields := strings.Fields(line)
		removeThisPath := false
		for _, t := range args {
			if t == fields[0] {
				removeThisPath = true
				break
			}
		}

		if !removeThisPath {
			attributesFile.WriteString(line + "\n")
		} else {
			Print("Untracking %s", fields[0])
		}
	}
}

func init() {
	RootCmd.AddCommand(untrackCmd)
}
<commit_msg>Extracted function<commit_after>package commands

import (
	"bufio"
	"io/ioutil"
	"os"
	"strings"

	"github.com/github/git-lfs/lfs"
	"github.com/github/git-lfs/vendor/_nuts/github.com/spf13/cobra"
)

var (
	untrackCmd = &cobra.Command{
		Use:   "untrack",
		Short: "Remove an entry from .gitattributes",
		Run:   untrackCommand,
	}
)

// untrackCommand takes a list of paths as an argument, and removes each path from the
// default attribtues file (.gitattributes), if it exists.
func untrackCommand(cmd *cobra.Command, args []string) {
	if lfs.LocalGitDir == "" {
		Print("Not a git repository.")
		os.Exit(128)
	}
	if lfs.LocalWorkingDir == "" {
		Print("This operation must be run in a work tree.")
		os.Exit(128)
	}

	lfs.InstallHooks(false)

	if len(args) < 1 {
		Print("git lfs untrack <path> [path]*")
		return
	}

	data, err := ioutil.ReadFile(".gitattributes")
	if err != nil {
		return
	}

	attributes := strings.NewReader(string(data))

	attributesFile, err := os.Create(".gitattributes")
	if err != nil {
		Print("Error opening .gitattributes for writing")
		return
	}
	defer attributesFile.Close()

	scanner := bufio.NewScanner(attributes)

	// Iterate through each line of the attributes file and rewrite it,
	// if the path was meant to be untracked, omit it, and print a message instead.
	for scanner.Scan() {
		line := scanner.Text()
		if !strings.Contains(line, "filter=lfs") {
			attributesFile.WriteString(line + "\n")
			continue
		}

		path := strings.Fields(line)[0]
		if removePath(path, args) {
			Print("Untracking %s", path)
		} else {
			attributesFile.WriteString(line + "\n")
		}
	}
}

func removePath(path string, args []string) bool {
	for _, t := range args {
		if path == t {
			return true
		}
	}

	return false
}

func init() {
	RootCmd.AddCommand(untrackCmd)
}
<|endoftext|>


<commit_before>package horizon

import (
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"

	"github.com/PuerkitoBio/throttled"
	"github.com/PuerkitoBio/throttled/store"
	"github.com/rcrowley/go-metrics"
	"github.com/rs/cors"
	"github.com/sebest/xff"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
)

// Web contains the http server related fields for go-horizon: the router,
// rate limiter, etc.
type Web struct {
	router      *web.Mux
	rateLimiter *throttled.Throttler

	requestTimer metrics.Timer
	failureMeter metrics.Meter
	successMeter metrics.Meter
}

// initWeb installed a new Web instance onto the provided app object.
func initWeb(app *App) {
	app.web = &Web{
		router:       web.New(),
		requestTimer: metrics.NewTimer(),
		failureMeter: metrics.NewMeter(),
		successMeter: metrics.NewMeter(),
	}
}

// initWebMiddleware installs the middleware stack used for go-horizon onto the
// provided app.
func initWebMiddleware(app *App) {
	r := app.web.router
	r.Use(middleware.EnvInit)
	r.Use(app.Middleware)
	r.Use(middleware.RequestID)
	r.Use(contextMiddleware(app.ctx))
	r.Use(xff.XFF)
	r.Use(LoggerMiddleware)
	r.Use(requestMetricsMiddleware)
	r.Use(RecoverMiddleware)
	r.Use(middleware.AutomaticOptions)

	c := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
	})
	r.Use(c.Handler)

	r.Use(app.web.RateLimitMiddleware)
}

// initWebActions installs the routing configuration of go-horizon onto the
// provided app.  All route registration should be implemented here.
func initWebActions(app *App) {
	r := app.web.router
	r.Get("/", rootAction)
	r.Get("/metrics", metricsAction)

	// ledger actions
	r.Get("/ledgers", ledgerIndexAction)
	r.Get("/ledgers/:id", ledgerShowAction)
	r.Get("/ledgers/:ledger_id/transactions", transactionIndexAction)
	r.Get("/ledgers/:ledger_id/operations", operationIndexAction)
	r.Get("/ledgers/:ledger_id/payments", paymentsIndexAction)
	r.Get("/ledgers/:ledger_id/effects", notImplementedAction)

	// account actions
	r.Get("/accounts", accountIndexAction)
	r.Get("/accounts/:id", accountShowAction)
	r.Get("/accounts/:account_id/transactions", transactionIndexAction)
	r.Get("/accounts/:account_id/operations", operationIndexAction)
	r.Get("/accounts/:account_id/payments", paymentsIndexAction)
	r.Get("/accounts/:account_id/effects", notImplementedAction)
	r.Get("/accounts/:account_id/offers", offerIndexAction)

	// transaction actions
	r.Get("/transactions", transactionIndexAction)
	r.Get("/transactions/:id", transactionShowAction)
	r.Get("/transactions/:tx_id/operations", operationIndexAction)
	r.Get("/transactions/:tx_id/payments", paymentsIndexAction)
	r.Get("/transactions/:tx_id/effects", notImplementedAction)

	// operation actions
	r.Get("/operations", operationIndexAction)
	r.Get("/operations/:id", operationShowAction)
	r.Get("/operations/:op_id/effects", notImplementedAction)

	r.Get("/payments", paymentsIndexAction)

	r.Get("/offers/:id", notImplementedAction)

	// go-horizon doesn't implement everything horizon did,
	// so we reverse proxy if we can
	if app.config.RubyHorizonUrl != "" {

		u, err := url.Parse(app.config.RubyHorizonUrl)
		if err != nil {
			panic("cannot parse ruby-horizon-url")
		}

		rp := httputil.NewSingleHostReverseProxy(u)
		r.Post("/transactions", rp)
		r.Post("/friendbot", rp)
		r.Get("/friendbot", rp)
	} else {
		r.Post("/transactions", notImplementedAction)
		r.Post("/friendbot", notImplementedAction)
		r.Get("/friendbot", notImplementedAction)
	}

	r.NotFound(notFoundAction)
}

func initWebRateLimiter(app *App) {
	rateLimitStore := store.NewMemStore(1000)

	if app.redis != nil {
		rateLimitStore = store.NewRedisStore(app.redis, "throttle:", 0)
	}

	rateLimiter := throttled.RateLimit(
		app.config.RateLimit,
		&throttled.VaryBy{Custom: remoteAddrIP},
		rateLimitStore,
	)

	rateLimiter.DeniedHandler = http.HandlerFunc(rateLimitExceededAction)
	app.web.rateLimiter = rateLimiter
}

func remoteAddrIP(r *http.Request) string {
	ip := strings.SplitN(r.RemoteAddr, ":", 2)[0]
	return ip
}

func init() {
	appInit.Add(
		"web.init",
		initWeb,

		"app-context",
	)

	appInit.Add(
		"web.rate-limiter",
		initWebRateLimiter,

		"web.init",
	)
	appInit.Add(
		"web.middleware",
		initWebMiddleware,

		"web.init",
		"web.rate-limiter",
		"web.metrics",
	)
	appInit.Add(
		"web.actions",
		initWebActions,

		"web.init",
	)
}
<commit_msg>Fix breakage<commit_after>package horizon

import (
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"

	"github.com/PuerkitoBio/throttled"
	"github.com/PuerkitoBio/throttled/store"
	"github.com/rcrowley/go-metrics"
	"github.com/rs/cors"
	"github.com/sebest/xff"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
)

// Web contains the http server related fields for go-horizon: the router,
// rate limiter, etc.
type Web struct {
	router      *web.Mux
	rateLimiter *throttled.Throttler

	requestTimer metrics.Timer
	failureMeter metrics.Meter
	successMeter metrics.Meter
}

// initWeb installed a new Web instance onto the provided app object.
func initWeb(app *App) {
	app.web = &Web{
		router:       web.New(),
		requestTimer: metrics.NewTimer(),
		failureMeter: metrics.NewMeter(),
		successMeter: metrics.NewMeter(),
	}
}

// initWebMiddleware installs the middleware stack used for go-horizon onto the
// provided app.
func initWebMiddleware(app *App) {
	r := app.web.router
	r.Use(middleware.EnvInit)
	r.Use(app.Middleware)
	r.Use(middleware.RequestID)
	r.Use(contextMiddleware(app.ctx))
	r.Use(xff.Handler)
	r.Use(LoggerMiddleware)
	r.Use(requestMetricsMiddleware)
	r.Use(RecoverMiddleware)
	r.Use(middleware.AutomaticOptions)

	c := cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
	})
	r.Use(c.Handler)

	r.Use(app.web.RateLimitMiddleware)
}

// initWebActions installs the routing configuration of go-horizon onto the
// provided app.  All route registration should be implemented here.
func initWebActions(app *App) {
	r := app.web.router
	r.Get("/", rootAction)
	r.Get("/metrics", metricsAction)

	// ledger actions
	r.Get("/ledgers", ledgerIndexAction)
	r.Get("/ledgers/:id", ledgerShowAction)
	r.Get("/ledgers/:ledger_id/transactions", transactionIndexAction)
	r.Get("/ledgers/:ledger_id/operations", operationIndexAction)
	r.Get("/ledgers/:ledger_id/payments", paymentsIndexAction)
	r.Get("/ledgers/:ledger_id/effects", notImplementedAction)

	// account actions
	r.Get("/accounts", accountIndexAction)
	r.Get("/accounts/:id", accountShowAction)
	r.Get("/accounts/:account_id/transactions", transactionIndexAction)
	r.Get("/accounts/:account_id/operations", operationIndexAction)
	r.Get("/accounts/:account_id/payments", paymentsIndexAction)
	r.Get("/accounts/:account_id/effects", notImplementedAction)
	r.Get("/accounts/:account_id/offers", offerIndexAction)

	// transaction actions
	r.Get("/transactions", transactionIndexAction)
	r.Get("/transactions/:id", transactionShowAction)
	r.Get("/transactions/:tx_id/operations", operationIndexAction)
	r.Get("/transactions/:tx_id/payments", paymentsIndexAction)
	r.Get("/transactions/:tx_id/effects", notImplementedAction)

	// operation actions
	r.Get("/operations", operationIndexAction)
	r.Get("/operations/:id", operationShowAction)
	r.Get("/operations/:op_id/effects", notImplementedAction)

	r.Get("/payments", paymentsIndexAction)

	r.Get("/offers/:id", notImplementedAction)

	// go-horizon doesn't implement everything horizon did,
	// so we reverse proxy if we can
	if app.config.RubyHorizonUrl != "" {

		u, err := url.Parse(app.config.RubyHorizonUrl)
		if err != nil {
			panic("cannot parse ruby-horizon-url")
		}

		rp := httputil.NewSingleHostReverseProxy(u)
		r.Post("/transactions", rp)
		r.Post("/friendbot", rp)
		r.Get("/friendbot", rp)
	} else {
		r.Post("/transactions", notImplementedAction)
		r.Post("/friendbot", notImplementedAction)
		r.Get("/friendbot", notImplementedAction)
	}

	r.NotFound(notFoundAction)
}

func initWebRateLimiter(app *App) {
	rateLimitStore := store.NewMemStore(1000)

	if app.redis != nil {
		rateLimitStore = store.NewRedisStore(app.redis, "throttle:", 0)
	}

	rateLimiter := throttled.RateLimit(
		app.config.RateLimit,
		&throttled.VaryBy{Custom: remoteAddrIP},
		rateLimitStore,
	)

	rateLimiter.DeniedHandler = http.HandlerFunc(rateLimitExceededAction)
	app.web.rateLimiter = rateLimiter
}

func remoteAddrIP(r *http.Request) string {
	ip := strings.SplitN(r.RemoteAddr, ":", 2)[0]
	return ip
}

func init() {
	appInit.Add(
		"web.init",
		initWeb,

		"app-context",
	)

	appInit.Add(
		"web.rate-limiter",
		initWebRateLimiter,

		"web.init",
	)
	appInit.Add(
		"web.middleware",
		initWebMiddleware,

		"web.init",
		"web.rate-limiter",
		"web.metrics",
	)
	appInit.Add(
		"web.actions",
		initWebActions,

		"web.init",
	)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"time"

	icmd "github.com/docker/docker/pkg/integration/cmd"
	"github.com/go-check/check"
)

const attachWait = 5 * time.Second

func (s *DockerSuite) TestAttachMultipleAndRestart(c *check.C) {
	testRequires(c, DaemonIsLinux)

	endGroup := &sync.WaitGroup{}
	startGroup := &sync.WaitGroup{}
	endGroup.Add(3)
	startGroup.Add(3)

	err := waitForContainer("attacher", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 1; echo hello; done")
	c.Assert(err, check.IsNil)

	startDone := make(chan struct{})
	endDone := make(chan struct{})

	go func() {
		endGroup.Wait()
		close(endDone)
	}()

	go func() {
		startGroup.Wait()
		close(startDone)
	}()

	for i := 0; i < 3; i++ {
		go func() {
			cmd := exec.Command(dockerBinary, "attach", "attacher")

			defer func() {
				cmd.Wait()
				endGroup.Done()
			}()

			out, err := cmd.StdoutPipe()
			if err != nil {
				c.Fatal(err)
			}
			defer out.Close()

			if err := cmd.Start(); err != nil {
				c.Fatal(err)
			}

			buf := make([]byte, 1024)

			if _, err := out.Read(buf); err != nil && err != io.EOF {
				c.Fatal(err)
			}

			startGroup.Done()

			if !strings.Contains(string(buf), "hello") {
				c.Fatalf("unexpected output %s expected hello\n", string(buf))
			}
		}()
	}

	select {
	case <-startDone:
	case <-time.After(attachWait):
		c.Fatalf("Attaches did not initialize properly")
	}

	dockerCmd(c, "kill", "attacher")

	select {
	case <-endDone:
	case <-time.After(attachWait):
		c.Fatalf("Attaches did not finish properly")
	}
}

func (s *DockerSuite) TestAttachTTYWithoutStdin(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "-ti", "busybox")

	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), check.IsNil)

	done := make(chan error)
	go func() {
		defer close(done)

		cmd := exec.Command(dockerBinary, "attach", id)
		if _, err := cmd.StdinPipe(); err != nil {
			done <- err
			return
		}

		expected := "the input device is not a TTY"
		if runtime.GOOS == "windows" {
			expected += ".  If you are using mintty, try prefixing the command with 'winpty'"
		}
		if out, _, err := runCommandWithOutput(cmd); err == nil {
			done <- fmt.Errorf("attach should have failed")
			return
		} else if !strings.Contains(out, expected) {
			done <- fmt.Errorf("attach failed with error %q: expected %q", out, expected)
			return
		}
	}()

	select {
	case err := <-done:
		c.Assert(err, check.IsNil)
	case <-time.After(attachWait):
		c.Fatal("attach is running but should have failed")
	}
}

func (s *DockerSuite) TestAttachDisconnect(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-di", "busybox", "/bin/cat")
	id := strings.TrimSpace(out)

	cmd := exec.Command(dockerBinary, "attach", id)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		c.Fatal(err)
	}
	defer stdin.Close()
	stdout, err := cmd.StdoutPipe()
	c.Assert(err, check.IsNil)
	defer stdout.Close()
	c.Assert(cmd.Start(), check.IsNil)
	defer cmd.Process.Kill()

	_, err = stdin.Write([]byte("hello\n"))
	c.Assert(err, check.IsNil)
	out, err = bufio.NewReader(stdout).ReadString('\n')
	c.Assert(err, check.IsNil)
	c.Assert(strings.TrimSpace(out), check.Equals, "hello")

	c.Assert(stdin.Close(), check.IsNil)

	// Expect container to still be running after stdin is closed
	running := inspectField(c, id, "State.Running")
	c.Assert(running, check.Equals, "true")
}

func (s *DockerSuite) TestAttachPausedContainer(c *check.C) {
	testRequires(c, DaemonIsLinux) // Containers cannot be paused on Windows
	defer unpauseAllContainers()
	dockerCmd(c, "run", "-d", "--name=test", "busybox", "top")
	dockerCmd(c, "pause", "test")

	result := dockerCmdWithResult("attach", "test")
	c.Assert(result, icmd.Matches, icmd.Expected{
		Error:    "exit status 1",
		ExitCode: 1,
		Err:      "You cannot attach to a paused container, unpause it first",
	})
}
<commit_msg>Windows: Enable 2 TestAttach* tests<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"os/exec"
	"runtime"
	"strings"
	"sync"
	"time"

	icmd "github.com/docker/docker/pkg/integration/cmd"
	"github.com/go-check/check"
)

const attachWait = 5 * time.Second

func (s *DockerSuite) TestAttachMultipleAndRestart(c *check.C) {
	endGroup := &sync.WaitGroup{}
	startGroup := &sync.WaitGroup{}
	endGroup.Add(3)
	startGroup.Add(3)

	err := waitForContainer("attacher", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 1; echo hello; done")
	c.Assert(err, check.IsNil)

	startDone := make(chan struct{})
	endDone := make(chan struct{})

	go func() {
		endGroup.Wait()
		close(endDone)
	}()

	go func() {
		startGroup.Wait()
		close(startDone)
	}()

	for i := 0; i < 3; i++ {
		go func() {
			cmd := exec.Command(dockerBinary, "attach", "attacher")

			defer func() {
				cmd.Wait()
				endGroup.Done()
			}()

			out, err := cmd.StdoutPipe()
			if err != nil {
				c.Fatal(err)
			}
			defer out.Close()

			if err := cmd.Start(); err != nil {
				c.Fatal(err)
			}

			buf := make([]byte, 1024)

			if _, err := out.Read(buf); err != nil && err != io.EOF {
				c.Fatal(err)
			}

			startGroup.Done()

			if !strings.Contains(string(buf), "hello") {
				c.Fatalf("unexpected output %s expected hello\n", string(buf))
			}
		}()
	}

	select {
	case <-startDone:
	case <-time.After(attachWait):
		c.Fatalf("Attaches did not initialize properly")
	}

	dockerCmd(c, "kill", "attacher")

	select {
	case <-endDone:
	case <-time.After(attachWait):
		c.Fatalf("Attaches did not finish properly")
	}
}

func (s *DockerSuite) TestAttachTTYWithoutStdin(c *check.C) {
	out, _ := dockerCmd(c, "run", "-d", "-ti", "busybox")

	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), check.IsNil)

	done := make(chan error)
	go func() {
		defer close(done)

		cmd := exec.Command(dockerBinary, "attach", id)
		if _, err := cmd.StdinPipe(); err != nil {
			done <- err
			return
		}

		expected := "the input device is not a TTY"
		if runtime.GOOS == "windows" {
			expected += ".  If you are using mintty, try prefixing the command with 'winpty'"
		}
		if out, _, err := runCommandWithOutput(cmd); err == nil {
			done <- fmt.Errorf("attach should have failed")
			return
		} else if !strings.Contains(out, expected) {
			done <- fmt.Errorf("attach failed with error %q: expected %q", out, expected)
			return
		}
	}()

	select {
	case err := <-done:
		c.Assert(err, check.IsNil)
	case <-time.After(attachWait):
		c.Fatal("attach is running but should have failed")
	}
}

func (s *DockerSuite) TestAttachDisconnect(c *check.C) {
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-di", "busybox", "/bin/cat")
	id := strings.TrimSpace(out)

	cmd := exec.Command(dockerBinary, "attach", id)
	stdin, err := cmd.StdinPipe()
	if err != nil {
		c.Fatal(err)
	}
	defer stdin.Close()
	stdout, err := cmd.StdoutPipe()
	c.Assert(err, check.IsNil)
	defer stdout.Close()
	c.Assert(cmd.Start(), check.IsNil)
	defer cmd.Process.Kill()

	_, err = stdin.Write([]byte("hello\n"))
	c.Assert(err, check.IsNil)
	out, err = bufio.NewReader(stdout).ReadString('\n')
	c.Assert(err, check.IsNil)
	c.Assert(strings.TrimSpace(out), check.Equals, "hello")

	c.Assert(stdin.Close(), check.IsNil)

	// Expect container to still be running after stdin is closed
	running := inspectField(c, id, "State.Running")
	c.Assert(running, check.Equals, "true")
}

func (s *DockerSuite) TestAttachPausedContainer(c *check.C) {
	testRequires(c, DaemonIsLinux) // Containers cannot be paused on Windows
	defer unpauseAllContainers()
	dockerCmd(c, "run", "-d", "--name=test", "busybox", "top")
	dockerCmd(c, "pause", "test")

	result := dockerCmdWithResult("attach", "test")
	c.Assert(result, icmd.Matches, icmd.Expected{
		Error:    "exit status 1",
		ExitCode: 1,
		Err:      "You cannot attach to a paused container, unpause it first",
	})
}
<|endoftext|>


<commit_before>package integration_tests

import (
	"fmt"
	"path/filepath"
	"runtime"
	"time"

	. "github.com/onsi/ginkgo"
)

// creates a package repository mirror on the given node.
func createPackageRepositoryMirror(repoNode NodeDeets, distro linuxDistro, sshKey string) error {
	var mirrorScript string
	switch distro {
	case CentOS7:
		mirrorScript = "mirror-rpms.sh"
	case Ubuntu1604LTS:
		mirrorScript = "mirror-debs.sh"
	default:
		return fmt.Errorf("unable to create repo mirror for distro %q", distro)
	}
	start := time.Now()
	err := copyFileToRemote("test-resources/disconnected-installation/"+mirrorScript, "/tmp/"+mirrorScript, repoNode, sshKey, 10*time.Second)
	if err != nil {
		return fmt.Errorf("failed to copy script to remote node: %v", err)
	}
	cmds := []string{"chmod +x /tmp/" + mirrorScript, "sudo /tmp/" + mirrorScript}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 120*time.Minute)
	if err != nil {
		return fmt.Errorf("error running mirroring script: %v", err)
	}
	elapsed := time.Since(start)
	fmt.Println("Creating a package repository took", elapsed)
	return nil
}

// seeds a container image registry using the kismatic seed-registry command
func seedRegistry(repoNode NodeDeets, registryCAFile string, registryPort int, sshKey string) error {
	By("Adding the docker registry self-signed cert to the registry node")
	registry := fmt.Sprintf("%s:%d", repoNode.PublicIP, registryPort)
	err := copyFileToRemote(registryCAFile, "/tmp/docker-registry-ca.crt", repoNode, sshKey, 30*time.Second)
	if err != nil {
		return fmt.Errorf("Failed to copy registry cert to registry node: %v", err)
	}
	cmds := []string{
		fmt.Sprintf("sudo mkdir -p /etc/docker/certs.d/%s", registry),
		fmt.Sprintf("sudo mv /tmp/docker-registry-ca.crt /etc/docker/certs.d/%s/ca.crt", registry),
	}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 10*time.Minute)
	if err != nil {
		return fmt.Errorf("Error adding self-signed cert to registry node: %v", err)
	}

	By("Copying KET to the registry node for seeding")
	err = copyFileToRemote(filepath.Join(currentKismaticDir, "kismatic-"+runtime.GOOS+".tar.gz"), "/tmp/kismatic-"+runtime.GOOS+".tar.gz", repoNode, sshKey, 5*time.Minute)
	if err != nil {
		return fmt.Errorf("Error copying KET to the registry node: %v", err)
	}

	By("Seeding the registry")
	start := time.Now()
	cmds = []string{
		fmt.Sprintf("sudo docker login -u kismaticuser -p kismaticpassword %s", registry),
		"sudo mkdir kismatic",
		"sudo tar -xf /tmp/kismatic-" + runtime.GOOS + ".tar.gz -C kismatic",
		fmt.Sprintf("sudo ./kismatic/kismatic seed-registry --server %s", registry),
	}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 60*time.Minute)
	if err != nil {
		return fmt.Errorf("failed to seed the registry: %v", err)
	}
	elapsed := time.Since(start)
	fmt.Println("Seeding the registry took", elapsed)
	return nil
}
<commit_msg>Increase seed registry command in integration tests<commit_after>package integration_tests

import (
	"fmt"
	"path/filepath"
	"runtime"
	"time"

	. "github.com/onsi/ginkgo"
)

// creates a package repository mirror on the given node.
func createPackageRepositoryMirror(repoNode NodeDeets, distro linuxDistro, sshKey string) error {
	var mirrorScript string
	switch distro {
	case CentOS7:
		mirrorScript = "mirror-rpms.sh"
	case Ubuntu1604LTS:
		mirrorScript = "mirror-debs.sh"
	default:
		return fmt.Errorf("unable to create repo mirror for distro %q", distro)
	}
	start := time.Now()
	err := copyFileToRemote("test-resources/disconnected-installation/"+mirrorScript, "/tmp/"+mirrorScript, repoNode, sshKey, 10*time.Second)
	if err != nil {
		return fmt.Errorf("failed to copy script to remote node: %v", err)
	}
	cmds := []string{"chmod +x /tmp/" + mirrorScript, "sudo /tmp/" + mirrorScript}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 120*time.Minute)
	if err != nil {
		return fmt.Errorf("error running mirroring script: %v", err)
	}
	elapsed := time.Since(start)
	fmt.Println("Creating a package repository took", elapsed)
	return nil
}

// seeds a container image registry using the kismatic seed-registry command
func seedRegistry(repoNode NodeDeets, registryCAFile string, registryPort int, sshKey string) error {
	By("Adding the docker registry self-signed cert to the registry node")
	registry := fmt.Sprintf("%s:%d", repoNode.PublicIP, registryPort)
	err := copyFileToRemote(registryCAFile, "/tmp/docker-registry-ca.crt", repoNode, sshKey, 30*time.Second)
	if err != nil {
		return fmt.Errorf("Failed to copy registry cert to registry node: %v", err)
	}
	cmds := []string{
		fmt.Sprintf("sudo mkdir -p /etc/docker/certs.d/%s", registry),
		fmt.Sprintf("sudo mv /tmp/docker-registry-ca.crt /etc/docker/certs.d/%s/ca.crt", registry),
	}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 10*time.Minute)
	if err != nil {
		return fmt.Errorf("Error adding self-signed cert to registry node: %v", err)
	}

	By("Copying KET to the registry node for seeding")
	err = copyFileToRemote(filepath.Join(currentKismaticDir, "kismatic-"+runtime.GOOS+".tar.gz"), "/tmp/kismatic-"+runtime.GOOS+".tar.gz", repoNode, sshKey, 5*time.Minute)
	if err != nil {
		return fmt.Errorf("Error copying KET to the registry node: %v", err)
	}

	By("Seeding the registry")
	start := time.Now()
	cmds = []string{
		fmt.Sprintf("sudo docker login -u kismaticuser -p kismaticpassword %s", registry),
		"sudo mkdir kismatic",
		"sudo tar -xf /tmp/kismatic-" + runtime.GOOS + ".tar.gz -C kismatic",
		fmt.Sprintf("sudo ./kismatic/kismatic seed-registry --server %s", registry),
	}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 90*time.Minute)
	if err != nil {
		return fmt.Errorf("failed to seed the registry: %v", err)
	}
	elapsed := time.Since(start)
	fmt.Println("Seeding the registry took", elapsed)
	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2013-2016 Pierre Neidhardt <ambrevar@gmail.com>
// Use of this file is governed by the license that can be found in LICENSE.

package main

import (
	"bitbucket.org/ambrevar/demlo/cuesheet"
	"io/ioutil"
	"testing"
)

const (
	SAMPLE_CUESHEET    = "cuesheet/testdata/sample.cue"
	SCRIPT_CASE        = "scripts/case.lua"
	SCRIPT_PUNCTUATION = "scripts/punctuation.lua"
)

func TestFixPunctuation(t *testing.T) {
	input := inputDesc{}
	output := outputDesc{
		Tags: map[string]string{
			"a b": "a_b",
			".a":  ".a",
			"a (": "a(",
			"(a":  "( a",
			"a c": "a 	c",
			"a": "	 a 	",
			"Some i.n.i.t.i.a.l.s.": "Some i.n.i.t.i.a.l.s.",
		},
	}

	buf, err := ioutil.ReadFile(SCRIPT_PUNCTUATION)
	if err != nil {
		t.Fatal("Script is not readable", err)
	}

	// Compile scripts.
	L, err := makeSandbox([]scriptBuffer{{name: "punctuation", buf: string(buf)}})
	if err != nil {
		t.Fatal("Spurious sandbox", err)
	}
	defer L.Close()

	makeSandboxOutput(L, output)
	err = runScript(L, "punctuation", input)
	if err != nil {
		t.Fatalf("script punctuation: %s", err)
	}
	output = scriptOutput(L)

	for want, got := range output.Tags {
		if got != want {
			t.Errorf(`Got "%v", want "%v"`, got, want)
		}
	}
}

func TestTitleCase(t *testing.T) {
	input := inputDesc{}
	output := outputDesc{
		Tags: map[string]string{
			"All Lowercase Words":                     "all lowercase words",
			"All Uppercase Words":                     "ALL UPPERCASE WORDS",
			"All Crazy Case Words":                    "aLl cRaZY cASE WordS",
			"With Common Preps in a CD Into the Box.": "With common preps in a cd INTO the box.",
			"Feat and feat. The Machines.":            "Feat and Feat. the machines.",
			"Unicode Apos´trophe":                     "unicode apos´trophe",
			"...":                                                      "...",
			".'?":                                                      ".'?",
			"I'll Be Ill'":                                             "i'll be ill'",
			"Names Like O'Hara, D’Arcy":                                "Names like o'hara, d’arcy",
			"Names Like McDonald and MacNeil":                          "Names like mcdonald and macneil",
			"Éléanor":                                                  "élÉanor",
			"XIV LIV Xiv Liv. Liv. Xiv.":                               "XIV LIV xiv liv. liv. xiv.",
			"A Start With a Lowercase Constant":                        "a start with a lowercase constant",
			`"A Double Quoted Sentence" and 'One Single Quoted'.`:      `"a double quoted sentence" and 'one single quoted'.`,
			`Another "Double Quoted Sentence", and "A Sentence More".`: `another "double quoted sentence", and "a sentence more".`,
			"Some I.N.I.T.I.A.L.S.":                                    "Some i.n.i.t.i.a.l.s.",
		},
	}

	buf, err := ioutil.ReadFile(SCRIPT_CASE)
	if err != nil {
		t.Fatal("Script is not readable", err)
	}

	// Compile scripts.
	L, err := makeSandbox([]scriptBuffer{{name: "case", buf: string(buf)}})
	if err != nil {
		t.Fatal("Spurious sandbox", err)
	}
	defer L.Close()

	makeSandboxOutput(L, output)
	err = runScript(L, "case", input)
	if err != nil {
		t.Fatalf("script case: %s", err)
	}
	output = scriptOutput(L)

	for want, got := range output.Tags {
		if got != want {
			t.Errorf(`Got "%v", want "%v"`, got, want)
		}
	}
}

func TestSentenceCase(t *testing.T) {
	input := inputDesc{}
	output := outputDesc{
		Tags: map[string]string{
			"Capitalized words":               "capitalized words",
			"Machine":                         "machine",
			"Rise of the machines":            "Rise Of The Machines",
			"Chanson d'avant":                 "Chanson D'Avant",
			"Names like o'hara, d’arcy":       "Names LIKE O'HARA, D’ARCY",
			"Names like McDonald and MacNeil": "Names LIKE MCDONALD AND MACNEIL",
			"XIV LIV xiv liv. Liv. Xiv.":      "XIV LIV xiv liv. liv. xiv.",
		},
	}

	buf, err := ioutil.ReadFile(SCRIPT_CASE)
	if err != nil {
		t.Fatal("Script is not readable", err)
	}

	// Compile scripts.
	L, err := makeSandbox([]scriptBuffer{{name: "case", buf: string(buf)}})
	if err != nil {
		t.Fatal("Spurious sandbox", err)
	}
	defer L.Close()

	// Set setencecase.
	L.PushBoolean(true)
	L.SetGlobal("sentencecase")

	makeSandboxOutput(L, output)
	err = runScript(L, "case", input)
	if err != nil {
		t.Fatalf("script case: %s", err)
	}
	output = scriptOutput(L)

	for want, got := range output.Tags {
		if got != want {
			t.Errorf(`Got "%v", want "%v"`, got, want)
		}
	}
}

func TestStringNorm(t *testing.T) {
	want := []struct {
		s    string
		norm string
	}{
		{s: "A", norm: "a"},
		{s: "0a", norm: "a"},
		{s: "00a", norm: "a"},
		{s: "a0", norm: "a0"},
		{s: "a.0", norm: "a"},
		{s: "a0a", norm: "a0a"},
		{s: "a.0a", norm: "aa"},
		{s: "10", norm: "10"},
		{s: "01", norm: "1"},
		{s: ".a", norm: "a"},
		{s: "..a", norm: "a"},
	}

	for _, v := range want {
		n := stringNorm(v.s)
		if n != v.norm {
			t.Errorf(`Got "%v", want norm("%v")=="%v"`, n, v.s, v.norm)
		}
	}
}

func TestStringRel(t *testing.T) {
	want := []struct {
		a   string
		b   string
		rel float64
	}{
		{a: "foo", b: "bar", rel: 0.0},
		{a: "foo", b: "foo", rel: 1.0},
		{a: "foobar", b: "foobaz", rel: 1 - float64(1)/float64(6)},
		{a: "", b: "b", rel: 0.0},
		{a: "a", b: "", rel: 0.0},
		{a: "", b: "", rel: 1.0},
		{a: "ab", b: "ba", rel: 0.5},
		{a: "abba", b: "aba", rel: 0.75},
		{a: "aba", b: "abba", rel: 0.75},
		{a: "résumé", b: "resume", rel: 1 - float64(2)/float64(6)},
	}

	for _, v := range want {
		r := stringRel(v.a, v.b)
		if r != v.rel {
			t.Errorf(`Got %v, want rel("%v", "%v")==%v`, r, v.a, v.b, v.rel)
		}
	}
}

func TestFFmpegSplitTimes(t *testing.T) {
	// We need to make up last track's duration: 3 minutes.
	totaltime := float64(17*60 + 4 + 3*60)

	want := []struct {
		track    int
		start    string
		duration string
	}{
		{track: 0, start: "00:00:00.000", duration: "00:06:40.360"},
		{track: 1, start: "00:06:40.360", duration: "00:04:13.640"},
		{track: 3, start: "00:17:04.000", duration: "00:03:00.000"},
		{track: 4, start: "", duration: ""},
		{track: 8, start: "", duration: ""},
	}

	buf, err := ioutil.ReadFile(SAMPLE_CUESHEET)
	if err != nil {
		panic(err)
	}
	sheet, err := cuesheet.New(string(buf))
	if err != nil {
		panic(err)
	}

	for _, v := range want {
		start, duration := FFmpegSplitTimes(sheet, "Faithless - Live in Berlin (CD1).mp3", v.track, totaltime)
		if start != v.start || duration != v.duration {
			t.Errorf("Got {start: %v, duration: %v}, want {start: %v, duration: %v}", start, duration, v.start, v.duration)
		}
	}
}
<commit_msg>demlo_test.go: Fix missing 'Slogger' argument to makeSandbox<commit_after>// Copyright © 2013-2016 Pierre Neidhardt <ambrevar@gmail.com>
// Use of this file is governed by the license that can be found in LICENSE.

package main

import (
	"bitbucket.org/ambrevar/demlo/cuesheet"
	"io/ioutil"
	"testing"
)

const (
	SAMPLE_CUESHEET    = "cuesheet/testdata/sample.cue"
	SCRIPT_CASE        = "scripts/case.lua"
	SCRIPT_PUNCTUATION = "scripts/punctuation.lua"
)

func TestFixPunctuation(t *testing.T) {
	input := inputDesc{}
	output := outputDesc{
		Tags: map[string]string{
			"a b": "a_b",
			".a":  ".a",
			"a (": "a(",
			"(a":  "( a",
			"a c": "a 	c",
			"a": "	 a 	",
			"Some i.n.i.t.i.a.l.s.": "Some i.n.i.t.i.a.l.s.",
		},
	}

	buf, err := ioutil.ReadFile(SCRIPT_PUNCTUATION)
	if err != nil {
		t.Fatal("Script is not readable", err)
	}

	// Compile scripts.
	display := newSlogger(false, false)
	L, err := makeSandbox([]scriptBuffer{{name: "punctuation", buf: string(buf)}}, display)
	if err != nil {
		t.Fatal("Spurious sandbox", err)
	}
	defer L.Close()

	makeSandboxOutput(L, output)
	err = runScript(L, "punctuation", input)
	if err != nil {
		t.Fatalf("script punctuation: %s", err)
	}
	output = scriptOutput(L)

	for want, got := range output.Tags {
		if got != want {
			t.Errorf(`Got "%v", want "%v"`, got, want)
		}
	}
}

func TestTitleCase(t *testing.T) {
	input := inputDesc{}
	output := outputDesc{
		Tags: map[string]string{
			"All Lowercase Words":                     "all lowercase words",
			"All Uppercase Words":                     "ALL UPPERCASE WORDS",
			"All Crazy Case Words":                    "aLl cRaZY cASE WordS",
			"With Common Preps in a CD Into the Box.": "With common preps in a cd INTO the box.",
			"Feat and feat. The Machines.":            "Feat and Feat. the machines.",
			"Unicode Apos´trophe":                     "unicode apos´trophe",
			"...":                                                      "...",
			".'?":                                                      ".'?",
			"I'll Be Ill'":                                             "i'll be ill'",
			"Names Like O'Hara, D’Arcy":                                "Names like o'hara, d’arcy",
			"Names Like McDonald and MacNeil":                          "Names like mcdonald and macneil",
			"Éléanor":                                                  "élÉanor",
			"XIV LIV Xiv Liv. Liv. Xiv.":                               "XIV LIV xiv liv. liv. xiv.",
			"A Start With a Lowercase Constant":                        "a start with a lowercase constant",
			`"A Double Quoted Sentence" and 'One Single Quoted'.`:      `"a double quoted sentence" and 'one single quoted'.`,
			`Another "Double Quoted Sentence", and "A Sentence More".`: `another "double quoted sentence", and "a sentence more".`,
			"Some I.N.I.T.I.A.L.S.":                                    "Some i.n.i.t.i.a.l.s.",
		},
	}

	buf, err := ioutil.ReadFile(SCRIPT_CASE)
	if err != nil {
		t.Fatal("Script is not readable", err)
	}

	// Compile scripts.
	display := newSlogger(false, false)
	L, err := makeSandbox([]scriptBuffer{{name: "case", buf: string(buf)}}, display)
	if err != nil {
		t.Fatal("Spurious sandbox", err)
	}
	defer L.Close()

	makeSandboxOutput(L, output)
	err = runScript(L, "case", input)
	if err != nil {
		t.Fatalf("script case: %s", err)
	}
	output = scriptOutput(L)

	for want, got := range output.Tags {
		if got != want {
			t.Errorf(`Got "%v", want "%v"`, got, want)
		}
	}
}

func TestSentenceCase(t *testing.T) {
	input := inputDesc{}
	output := outputDesc{
		Tags: map[string]string{
			"Capitalized words":               "capitalized words",
			"Machine":                         "machine",
			"Rise of the machines":            "Rise Of The Machines",
			"Chanson d'avant":                 "Chanson D'Avant",
			"Names like o'hara, d’arcy":       "Names LIKE O'HARA, D’ARCY",
			"Names like McDonald and MacNeil": "Names LIKE MCDONALD AND MACNEIL",
			"XIV LIV xiv liv. Liv. Xiv.":      "XIV LIV xiv liv. liv. xiv.",
		},
	}

	buf, err := ioutil.ReadFile(SCRIPT_CASE)
	if err != nil {
		t.Fatal("Script is not readable", err)
	}

	// Compile scripts.
	display := newSlogger(false, false)
	L, err := makeSandbox([]scriptBuffer{{name: "case", buf: string(buf)}}, display)
	if err != nil {
		t.Fatal("Spurious sandbox", err)
	}
	defer L.Close()

	// Set setencecase.
	L.PushBoolean(true)
	L.SetGlobal("sentencecase")

	makeSandboxOutput(L, output)
	err = runScript(L, "case", input)
	if err != nil {
		t.Fatalf("script case: %s", err)
	}
	output = scriptOutput(L)

	for want, got := range output.Tags {
		if got != want {
			t.Errorf(`Got "%v", want "%v"`, got, want)
		}
	}
}

func TestStringNorm(t *testing.T) {
	want := []struct {
		s    string
		norm string
	}{
		{s: "A", norm: "a"},
		{s: "0a", norm: "a"},
		{s: "00a", norm: "a"},
		{s: "a0", norm: "a0"},
		{s: "a.0", norm: "a"},
		{s: "a0a", norm: "a0a"},
		{s: "a.0a", norm: "aa"},
		{s: "10", norm: "10"},
		{s: "01", norm: "1"},
		{s: ".a", norm: "a"},
		{s: "..a", norm: "a"},
	}

	for _, v := range want {
		n := stringNorm(v.s)
		if n != v.norm {
			t.Errorf(`Got "%v", want norm("%v")=="%v"`, n, v.s, v.norm)
		}
	}
}

func TestStringRel(t *testing.T) {
	want := []struct {
		a   string
		b   string
		rel float64
	}{
		{a: "foo", b: "bar", rel: 0.0},
		{a: "foo", b: "foo", rel: 1.0},
		{a: "foobar", b: "foobaz", rel: 1 - float64(1)/float64(6)},
		{a: "", b: "b", rel: 0.0},
		{a: "a", b: "", rel: 0.0},
		{a: "", b: "", rel: 1.0},
		{a: "ab", b: "ba", rel: 0.5},
		{a: "abba", b: "aba", rel: 0.75},
		{a: "aba", b: "abba", rel: 0.75},
		{a: "résumé", b: "resume", rel: 1 - float64(2)/float64(6)},
	}

	for _, v := range want {
		r := stringRel(v.a, v.b)
		if r != v.rel {
			t.Errorf(`Got %v, want rel("%v", "%v")==%v`, r, v.a, v.b, v.rel)
		}
	}
}

func TestFFmpegSplitTimes(t *testing.T) {
	// We need to make up last track's duration: 3 minutes.
	totaltime := float64(17*60 + 4 + 3*60)

	want := []struct {
		track    int
		start    string
		duration string
	}{
		{track: 0, start: "00:00:00.000", duration: "00:06:40.360"},
		{track: 1, start: "00:06:40.360", duration: "00:04:13.640"},
		{track: 3, start: "00:17:04.000", duration: "00:03:00.000"},
		{track: 4, start: "", duration: ""},
		{track: 8, start: "", duration: ""},
	}

	buf, err := ioutil.ReadFile(SAMPLE_CUESHEET)
	if err != nil {
		panic(err)
	}
	sheet, err := cuesheet.New(string(buf))
	if err != nil {
		panic(err)
	}

	for _, v := range want {
		start, duration := FFmpegSplitTimes(sheet, "Faithless - Live in Berlin (CD1).mp3", v.track, totaltime)
		if start != v.start || duration != v.duration {
			t.Errorf("Got {start: %v, duration: %v}, want {start: %v, duration: %v}", start, duration, v.start, v.duration)
		}
	}
}
<|endoftext|>