func AddGenericCancelNode(s *core.Spec) error {
	if _, have := s.Nodes["cancel"]; have {
		return NodeExists
	}
	var n core.Node
	if err := yaml.Unmarshal([]byte(CancelNodeYAML), &n); err != nil {
		return err
	}
	if s.Nodes == nil {
		s.Nodes = make(map[string]*core.Node, 32)
	}
	s.Nodes["cancel"] = &n
	return nil
}
AddGenericCancelNode adds a 'cancel' node as given by
CancelNodeYAML.
package main
import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"os"
	"time"
	"github.com/Comcast/sheens/core"
	"github.com/Comcast/sheens/tools"
	"github.com/jsccast/yaml"
)
var Mods = map[string]Mod{
	"addMessageBranches":    &AddMessageBranchesMod{},
	"addGenericCancelNode":  &AddGenericCancelNodeMod{},
	"addOrderedOutMessages": &AddOrderedOutMessagesMod{},
	"analyze":               &Analyzer{},
	"dot":                   &Grapher{},
	"graph":                 &Grapher{},
	"mermaid":               &Mermaid{},
}
var (
	NoTargetNode = errors.New("no target node")
	NodeExists   = errors.New("node exists")
)
type Mod interface {
	F(*core.Spec) error
	Doc() string
	Flags() *flag.FlagSet
}
func AddMessageBranches(s *core.Spec, pattern interface{}, target string) error {
	if _, have := s.Nodes[target]; !have {
		return NoTargetNode
	}
	for name, node := range s.Nodes {
		if node == nil {
			node = &core.Node{}
			s.Nodes[name] = node
		}
		if node.Branches == nil {
			continue
		}
		if node.Branches.Type != "message" {
			continue
		}
		branch := &core.Branch{
			Pattern: pattern,
			Target:  target,
		}
		node.Branches.Branches = append(node.Branches.Branches, branch)
	}
	s.Doc = s.Doc + fmt.Sprintf(`
This spec was processed by AddMessageBranches with target "%s".
`, target)
	return nil
}
type AddMessageBranchesMod struct {
	PatternJS    string
	Target       string
	ParsePattern bool
}
func (c *AddMessageBranchesMod) Doc() string {
	return `
Adds an additional branch to every message node. The branch has the specified 
pattern and target.
`
}
func (c *AddMessageBranchesMod) Flags() *flag.FlagSet {
	flags := flag.NewFlagSet("addMessageBranches", flag.PanicOnError)
	flags.StringVar(&c.PatternJS, "p", `{"ctl":"cancel"}`, "pattern")
	flags.StringVar(&c.Target, "t", "cancel", "target")
	flags.BoolVar(&c.ParsePattern, "P", false, "parse the pattern as JSON")
	return flags
}
func (c *AddMessageBranchesMod) F(s *core.Spec) error {
	var pattern interface{}
	if c.ParsePattern {
		if err := json.Unmarshal([]byte(c.PatternJS), &pattern); err != nil {
			return err
		}
	} else {
		pattern = c.PatternJS
	}
	return AddMessageBranches(s, pattern, c.Target)
}
var CancelNodeYAML = `
action:
  doc: Emit any clean-up messages.
  interpreter: ecmascript
  source: |-
    for (var i = 0; i < _.bindings.cleanupMessages.length; i++) {
       _.out(_.bindings.cleanupMessages[i]);
    }
    _.bindings.cleanupMessages = [];
    _.bindings;
branching:
  branches:
  - target: listenForEnable
`