func (pt *InParamPort) Failf(msg string, parts ...interface{}) {
	pt.Fail(fmt.Sprintf(msg, parts...))
}
Failf fails with a message that includes the process name
package scipipe
import (
	"fmt"
	"strconv"
	"sync"
)
type InPort struct {
	Chan        chan *FileIP
	name        string
	process     WorkflowProcess
	RemotePorts map[string]*OutPort
	ready       bool
	closeLock   sync.Mutex
}
func NewInPort(name string) *InPort {
	inp := &InPort{
		name:        name,
		RemotePorts: map[string]*OutPort{},
		Chan:        make(chan *FileIP, getBufsize()),  
		ready:       false,
	}
	return inp
}
func (pt *InPort) Name() string {
	return pt.Process().Name() + "." + pt.name
}
func (pt *InPort) Process() WorkflowProcess {
	if pt.process == nil {
		pt.Fail("No connected process!")
	}
	return pt.process
}
func (pt *InPort) SetProcess(p WorkflowProcess) {
	pt.process = p
}
func (pt *InPort) AddRemotePort(rpt *OutPort) {
	if pt.RemotePorts[rpt.Name()] != nil {
		pt.Failf("A remote port with name (%s) already exists", rpt.Name())
	}
	pt.RemotePorts[rpt.Name()] = rpt
}
func (pt *InPort) From(rpt *OutPort) {
	pt.AddRemotePort(rpt)
	rpt.AddRemotePort(pt)
	pt.SetReady(true)
	rpt.SetReady(true)
}
func (pt *InPort) Disconnect(rptName string) {
	pt.removeRemotePort(rptName)
	if len(pt.RemotePorts) == 0 {
		pt.SetReady(false)
	}
}
func (pt *InPort) removeRemotePort(rptName string) {
	if _, ok := pt.RemotePorts[rptName]; !ok {
		pt.Failf("No remote port with name (%s) exists", rptName)
	}
	delete(pt.RemotePorts, rptName)
}
func (pt *InPort) SetReady(ready bool) {
	pt.ready = ready
}
func (pt *InPort) Ready() bool {
	return pt.ready
}
func (pt *InPort) Send(ip *FileIP) {
	pt.Chan <- ip
}
func (pt *InPort) Recv() *FileIP {
	return <-pt.Chan
}
func (pt *InPort) CloseConnection(rptName string) {
	pt.closeLock.Lock()
	delete(pt.RemotePorts, rptName)
	if len(pt.RemotePorts) == 0 {
		close(pt.Chan)
	}
	pt.closeLock.Unlock()
}
func (pt *InPort) Failf(msg string, parts ...interface{}) {
	pt.Fail(fmt.Sprintf(msg, parts...))
}
func (pt *InPort) Fail(msg interface{}) {
	Failf("[In-Port:%s] %s", pt.Name(), msg)
}
type OutPort struct {
	name        string
	process     WorkflowProcess
	RemotePorts map[string]*InPort
	ready       bool
}
func NewOutPort(name string) *OutPort {
	outp := &OutPort{
		name:        name,
		RemotePorts: map[string]*InPort{},
		ready:       false,
	}
	return outp
}
func (pt *OutPort) Name() string {
	return pt.Process().Name() + "." + pt.name
}
func (pt *OutPort) Process() WorkflowProcess {
	if pt.process == nil {
		pt.Fail("No connected process!")
	}
	return pt.process
}
func (pt *OutPort) SetProcess(p WorkflowProcess) {
	pt.process = p
}
func (pt *OutPort) AddRemotePort(rpt *InPort) {
	if _, ok := pt.RemotePorts[rpt.Name()]; ok {
		pt.Failf("A remote port with name (%s) already exists", rpt.Name())
	}
	pt.RemotePorts[rpt.Name()] = rpt
}
func (pt *OutPort) removeRemotePort(rptName string) {
	if _, ok := pt.RemotePorts[rptName]; !ok {
		pt.Failf("No remote port with name (%s) exists", rptName)
	}
	delete(pt.RemotePorts, rptName)
}
func (pt *OutPort) To(rpt *InPort) {
	pt.AddRemotePort(rpt)
	rpt.AddRemotePort(pt)
	pt.SetReady(true)
	rpt.SetReady(true)
}
func (pt *OutPort) Disconnect(rptName string) {
	pt.removeRemotePort(rptName)
	if len(pt.RemotePorts) == 0 {
		pt.SetReady(false)
	}
}
func (pt *OutPort) SetReady(ready bool) {
	pt.ready = ready
}
func (pt *OutPort) Ready() bool {
	return pt.ready
}
func (pt *OutPort) Send(ip *FileIP) {
	for _, rpt := range pt.RemotePorts {
		Debug.Printf("Sending on out-port (%s) connected to in-port (%s)", pt.Name(), rpt.Name())
		rpt.Send(ip)
	}
}
func (pt *OutPort) Close() {
	for _, rpt := range pt.RemotePorts {
		Debug.Printf("Closing out-port (%s) connected to in-port (%s)", pt.Name(), rpt.Name())
		rpt.CloseConnection(pt.Name())
		pt.removeRemotePort(rpt.Name())
	}
}
func (pt *OutPort) Failf(msg string, parts ...interface{}) {
	pt.Fail(fmt.Sprintf(msg, parts...))
}
func (pt *OutPort) Fail(msg interface{}) {
	Failf("[Out-Port:%s] %s", pt.Name(), msg)
}
type InParamPort struct {
	Chan        chan string
	name        string
	process     WorkflowProcess
	RemotePorts map[string]*OutParamPort
	ready       bool
	closeLock   sync.Mutex
}
func NewInParamPort(name string) *InParamPort {
	return &InParamPort{
		name:        name,
		Chan:        make(chan string, getBufsize()),
		RemotePorts: map[string]*OutParamPort{},
	}
}
func (pip *InParamPort) Name() string {
	return pip.Process().Name() + "." + pip.name
}
func (pip *InParamPort) Process() WorkflowProcess {
	if pip.process == nil {
		pip.Failf("No connected process!")
	}
	return pip.process
}
func (pip *InParamPort) SetProcess(p WorkflowProcess) {
	pip.process = p
}
func (pip *InParamPort) AddRemotePort(pop *OutParamPort) {
	if pip.RemotePorts[pop.Name()] != nil {
		pip.Failf("A remote param port with name (%s) already exists", pop.Name())
	}
	pip.RemotePorts[pop.Name()] = pop
}
func (pip *InParamPort) From(pop *OutParamPort) {
	pip.AddRemotePort(pop)
	pop.AddRemotePort(pip)
	pip.SetReady(true)
	pop.SetReady(true)
}
func (pip *InParamPort) FromStr(strings ...string) {
	pop := NewOutParamPort("string_feeder")
	pop.process = pip.Process()
	pip.From(pop)
	go func() {
		defer pop.Close()
		for _, str := range strings {
			pop.Send(str)
		}
	}()
}
func (pip *InParamPort) FromInt(ints ...int) {
	params := []string{}
	for _, i := range ints {
		params = append(params, strconv.Itoa(i))
	}
	pip.FromStr(params...)
}
func (pip *InParamPort) FromFloat(floats ...float64) {
	params := []string{}
	for _, f := range floats {
		params = append(params, strconv.FormatFloat(f, 'f', -1, 64))
	}
	pip.FromStr(params...)
}
func (pip *InParamPort) SetReady(ready bool) {
	pip.ready = ready
}
func (pip *InParamPort) Ready() bool {
	return pip.ready
}
func (pip *InParamPort) Send(param string) {
	pip.Chan <- param
}
func (pip *InParamPort) Recv() string {
	return <-pip.Chan
}
func (pip *InParamPort) CloseConnection(popName string) {
	pip.closeLock.Lock()
	delete(pip.RemotePorts, popName)
	if len(pip.RemotePorts) == 0 {
		close(pip.Chan)
	}
	pip.closeLock.Unlock()
}