func (s *scene) WaitFlagLimitedAndFetch(topic string, timeout time.Duration) (interface{}, error) {
	err := s.WaitFlagLimited(topic, timeout)
	if err != nil {
		return nil, err
	}
	return s.Fetch(topic)
}
WaitFlagLimitedAndFetch is specified on the Scene interface.
package scene
import (
	"time"
	"github.com/tideland/golib/errors"
	"github.com/tideland/golib/identifier"
	"github.com/tideland/golib/loop"
)
const (
	Active    = loop.Running
	Finishing = loop.Stopping
	Over      = loop.Stopped
)
type CleanupFunc func(key string, prop interface{}) error
type box struct {
	key     string
	prop    interface{}
	cleanup CleanupFunc
}
type signaling struct {
	topic      string
	signalChan chan struct{}
}
const (
	storeProp = iota
	fetchProp
	disposeProp
	flag
	unflag
	wait
)
type envelope struct {
	kind      int
	box       *box
	signaling *signaling
	err       error
	respChan  chan *envelope
}
type Scene interface {
	ID() identifier.UUID
	Stop() error
	Abort(err error)
	Wait() error
	Status() (int, error)
	Store(key string, prop interface{}) error
	StoreAndFlag(key string, prop interface{}) error
	StoreClean(key string, prop interface{}, cleanup CleanupFunc) error
	StoreCleanAndFlag(key string, prop interface{}, cleanup CleanupFunc) error
	Fetch(key string) (interface{}, error)
	Dispose(key string) (interface{}, error)
	Flag(topic string) error
	Unflag(topic string) error
	WaitFlag(topic string) error
	WaitFlagAndFetch(topic string) (interface{}, error)
	WaitFlagLimited(topic string, timeout time.Duration) error
	WaitFlagLimitedAndFetch(topic string, timeout time.Duration) (interface{}, error)
}
type scene struct {
	id          identifier.UUID
	props       map[string]*box
	flags       map[string]bool
	signalings  map[string][]chan struct{}
	inactivity  time.Duration
	absolute    time.Duration
	commandChan chan *envelope
	backend     loop.Loop
}
func Start() Scene {
	return StartLimited(0, 0)
}
func StartLimited(inactivity, absolute time.Duration) Scene {
	s := &scene{
		id:          identifier.NewUUID(),
		props:       make(map[string]*box),
		flags:       make(map[string]bool),
		signalings:  make(map[string][]chan struct{}),
		inactivity:  inactivity,
		absolute:    absolute,
		commandChan: make(chan *envelope, 1),
	}
	s.backend = loop.Go(s.backendLoop, "scene", s.id.String())
	return s
}
func (s *scene) ID() identifier.UUID {
	return s.id.Copy()
}
func (s *scene) Stop() error {
	return s.backend.Stop()
}
func (s *scene) Abort(err error) {
	s.backend.Kill(err)
}
func (s *scene) Wait() error {
	return s.backend.Wait()
}
func (s *scene) Status() (int, error) {
	return s.backend.Error()
}
func (s *scene) Store(key string, prop interface{}) error {
	return s.StoreClean(key, prop, nil)
}
func (s *scene) StoreAndFlag(key string, prop interface{}) error {
	err := s.StoreClean(key, prop, nil)
	if err != nil {
		return err
	}
	return s.Flag(key)
}
func (s *scene) StoreClean(key string, prop interface{}, cleanup CleanupFunc) error {
	command := &envelope{
		kind: storeProp,
		box: &box{
			key:     key,
			prop:    prop,
			cleanup: cleanup,
		},
		respChan: make(chan *envelope, 1),
	}
	_, err := s.command(command)
	return err
}
func (s *scene) StoreCleanAndFlag(key string, prop interface{}, cleanup CleanupFunc) error {
	err := s.StoreClean(key, prop, cleanup)
	if err != nil {
		return err
	}
	return s.Flag(key)
}
func (s *scene) Fetch(key string) (interface{}, error) {
	command := &envelope{
		kind: fetchProp,
		box: &box{
			key: key,
		},
		respChan: make(chan *envelope, 1),
	}
	resp, err := s.command(command)
	if err != nil {
		return nil, err
	}
	return resp.box.prop, nil
}
func (s *scene) Dispose(key string) (interface{}, error) {
	command := &envelope{
		kind: disposeProp,
		box: &box{
			key: key,
		},
		respChan: make(chan *envelope, 1),
	}
	resp, err := s.command(command)
	if err != nil {
		return nil, err
	}
	return resp.box.prop, nil
}
func (s *scene) Flag(topic string) error {
	command := &envelope{
		kind: flag,
		signaling: &signaling{
			topic: topic,
		},
		respChan: make(chan *envelope, 1),
	}
	_, err := s.command(command)
	return err
}
func (s *scene) Unflag(topic string) error {
	command := &envelope{
		kind: unflag,
		signaling: &signaling{
			topic: topic,
		},
		respChan: make(chan *envelope, 1),
	}
	_, err := s.command(command)
	return err
}
func (s *scene) WaitFlag(topic string) error {
	return s.WaitFlagLimited(topic, 0)
}
func (s *scene) WaitFlagAndFetch(topic string) (interface{}, error) {
	err := s.WaitFlag(topic)
	if err != nil {
		return nil, err
	}
	return s.Fetch(topic)
}
func (s *scene) WaitFlagLimited(topic string, timeout time.Duration) error {
	command := &envelope{
		kind: wait,
		signaling: &signaling{
			topic:      topic,
			signalChan: make(chan struct{}, 1),
		},
		respChan: make(chan *envelope, 1),
	}
	_, err := s.command(command)
	if err != nil {
		return err
	}
	var timeoutChan <-chan time.Time
	if timeout > 0 {
		timeoutChan = time.After(timeout)
	}
	select {
	case <-s.backend.IsStopping():
		err = s.Wait()
		if err == nil {
			err = errors.New(ErrSceneEnded, errorMessages)
		}
		return err
	case <-command.signaling.signalChan:
		return nil
	case <-timeoutChan:
		return errors.New(ErrWaitedTooLong, errorMessages, topic)
	}
}