func chainStarted(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	if mixin.Started != nil {
		svcHook := service.Started
		mixinHook := mixin.Started
		service.Started = func(ctx moleculer.BrokerContext, svc moleculer.ServiceSchema) {
			mixinHook(ctx, svc)
			if svcHook != nil {
				svcHook(ctx, svc)
			}
		}
	}
	return service
}
chainStarted chain the Started hook of services and mixins
the service.Started handler is called after all of the mixins Started
handlers are called. so all initialization that your service need and is done by plugins
will be done by the time your service Started is called.
package service
import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"github.com/moleculer-go/moleculer"
	"github.com/moleculer-go/moleculer/payload"
	log "github.com/sirupsen/logrus"
)
type Action struct {
	name     string
	fullname string
	handler  moleculer.ActionHandler
	params   moleculer.ActionSchema
}
type Event struct {
	name        string
	serviceName string
	group       string
	handler     moleculer.EventHandler
}
func (event *Event) Handler() moleculer.EventHandler {
	return event.handler
}
func (event *Event) Name() string {
	return event.name
}
func (event *Event) ServiceName() string {
	return event.serviceName
}
func (event *Event) Group() string {
	return event.group
}
type HasName interface {
	Name() string
}
type HasVersion interface {
	Version() string
}
type HasDependencies interface {
	Dependencies() []string
}
type HasSettings interface {
	Settings() map[string]interface{}
}
type HasMetadata interface {
	Metadata() map[string]interface{}
}
type HasMixins interface {
	Mixins() []moleculer.Mixin
}
type HasEvents interface {
	Events() []moleculer.Event
}
func ParseVersion(iver interface{}) string {
	v, ok := iver.(string)
	if ok {
		return v
	}
	f, ok := iver.(float64)
	if ok {
		return fmt.Sprintf("%g", f)
	}
	i, ok := iver.(int64)
	if ok {
		return fmt.Sprintf("%d", i)
	}
	return fmt.Sprintf("%v", iver)
}
type Service struct {
	nodeID       string
	fullname     string
	name         string
	version      string
	dependencies []string
	settings     map[string]interface{}
	metadata     map[string]interface{}
	actions      []Action
	events       []Event
	created      moleculer.CreatedFunc
	started      moleculer.LifecycleFunc
	stopped      moleculer.LifecycleFunc
	schema       *moleculer.ServiceSchema
	logger       *log.Entry
}
func (service *Service) Schema() *moleculer.ServiceSchema {
	return service.schema
}
func (service *Service) NodeID() string {
	return service.nodeID
}
func (service *Service) Settings() map[string]interface{} {
	return service.settings
}
func (service *Service) SetNodeID(nodeID string) {
	service.nodeID = nodeID
}
func (service *Service) Dependencies() []string {
	return service.dependencies
}
func (serviceAction *Action) Handler() moleculer.ActionHandler {
	return serviceAction.handler
}
func (serviceAction *Action) Name() string {
	return serviceAction.name
}
func (serviceAction *Action) FullName() string {
	return serviceAction.fullname
}
func (service *Service) Name() string {
	return service.name
}
func (service *Service) FullName() string {
	return service.fullname
}
func (service *Service) Version() string {
	return service.version
}
func (service *Service) Actions() []Action {
	return service.actions
}
func (service *Service) Summary() map[string]string {
	return map[string]string{
		"name":    service.name,
		"version": service.version,
		"nodeID":  service.nodeID,
	}
}
func (service *Service) Events() []Event {
	return service.events
}
func findAction(name string, actions []moleculer.Action) bool {
	for _, a := range actions {
		if a.Name == name {
			return true
		}
	}
	return false
}
func extendActions(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	for _, ma := range mixin.Actions {
		if !findAction(ma.Name, service.Actions) {
			service.Actions = append(service.Actions, ma)
		}
	}
	return service
}
func mergeDependencies(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	list := []string{}
	for _, item := range mixin.Dependencies {
		list = append(list, item)
	}
	for _, item := range service.Dependencies {
		list = append(list, item)
	}
	service.Dependencies = list
	return service
}
func concatenateEvents(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	for _, mixinEvent := range mixin.Events {
		for _, serviceEvent := range service.Events {
			if serviceEvent.Name != mixinEvent.Name {
				service.Events = append(service.Events, mixinEvent)
			}
		}
	}
	return service
}
func MergeSettings(settings ...map[string]interface{}) map[string]interface{} {
	result := map[string]interface{}{}
	for _, set := range settings {
		if set != nil {
			for key, value := range set {
				result[key] = value
			}
		}
	}
	return result
}
func extendSettings(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	service.Settings = MergeSettings(mixin.Settings, service.Settings)
	return service
}
func extendMetadata(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	service.Metadata = MergeSettings(mixin.Metadata, service.Metadata)
	return service
}
func extendHooks(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	service.Hooks = MergeSettings(mixin.Hooks, service.Hooks)
	return service
}
func chainCreated(service moleculer.ServiceSchema, mixin *moleculer.Mixin) moleculer.ServiceSchema {
	if mixin.Created != nil {
		svcHook := service.Created
		mixinHook := mixin.Created
		service.Created = func(svc moleculer.ServiceSchema, log *log.Entry) {
			mixinHook(svc, log)
			if svcHook != nil {
				svcHook(svc, log)
			}
		}
	}
	return service
}