func (c *lineImp) makeRelays() {
	var setExists = struct{}{}  
	c.mutex.Lock()
	defer c.mutex.Unlock()
	logger := dot.Logger()
	liveIDToType := make(map[dot.LiveID]dot.TypeID)
	typeIDToLiveIds := make(map[dot.TypeID]map[dot.LiveID]struct{}, len(c.lives.LiveIDMap))
	for _, live := range c.lives.LiveIDMap {
		liveIDToType[live.LiveID] = live.TypeID
		if _, ok := typeIDToLiveIds[live.TypeID]; !ok {
			typeIDToLiveIds[live.TypeID] = make(map[dot.LiveID]struct{})
		}
		typeIDToLiveIds[live.TypeID][live.LiveID] = setExists
	}
	typeToTypeID := make(map[reflect.Type]dot.TypeID)
	for _, meta := range c.metas.metas {
		if meta.RefType != nil {
			typeToTypeID[meta.RefType] = meta.TypeID
		}
	}
	for _, meta := range c.metas.metas {  
		dotFields := make(map[string]dot.LiveID)
		if meta.RefType != nil {
			relayTypeIDs := make(map[dot.TypeID]struct{})
			for i := 0; i < meta.RefType.NumField(); i++ {  
				tField := meta.RefType.Field(i)
				liveID, ok := tField.Tag.Lookup(dot.TagDot)
				if !ok || liveID == dot.CanNull {  
					continue
				}
				dotFields[tField.Name] = dot.LiveID(liveID)
				if len(liveID) < 1 {
					if typeID, ok := typeToTypeID[tField.Type]; ok {
						relayTypeIDs[typeID] = setExists
					} else {
					}
				} else {
					if typeID, ok := liveIDToType[dot.LiveID(liveID)]; ok {
						relayTypeIDs[typeID] = setExists
					}
				}
			}
			if lives, ok := typeIDToLiveIds[meta.TypeID]; ok {
				for liveID := range lives {
					if live, ok := c.lives.LiveIDMap[liveID]; ok {
						for name := range live.RelyLives {
							if _, ok := dotFields[name]; !ok {
								if logger != nil {
									logger.Warn(func() string {
										return fmt.Sprintf("make relay of dot, meta: %v\n live: %v", meta, live)
									})
								}
							}
						}
						for name, nameLiveID := range dotFields {
							if _, ok := live.RelyLives[name]; !ok {
								if len(nameLiveID.String()) > 0 {
									live.RelyLives[name] = nameLiveID
								} else {
								}
							}
						}
					}
				}
			}
			if len(relayTypeIDs) > 0 {
				for _, typeID := range meta.RelyTypeIDs {  
					relayTypeIDs[typeID] = setExists
				}
				meta.RelyTypeIDs = make([]dot.TypeID, 0, len(relayTypeIDs))
				for typeID := range relayTypeIDs {
					meta.RelyTypeIDs = append(meta.RelyTypeIDs, typeID)
				}
			}
		}
	}
}
get relay from the tag
merge type relay
merge live relay
verify the key of relay lives(the name have to eq the field name)
package line
import (
	"fmt"
	"github.com/pkg/errors"
	"log"
	"reflect"
	"strings"
	"sync"
	"go.uber.org/zap"
	"github.com/scryinfo/dot/dot"
	"github.com/scryinfo/dot/dots/sconfig"
	"github.com/scryinfo/dot/dots/slog"
	"github.com/scryinfo/scryg/sutils/skit"
)
var (
	_ dot.Lifer    = (*lineImp)(nil)
	_ dot.Line     = (*lineImp)(nil)
	_ dot.Injecter = (*lineImp)(nil)
)
type lineImp struct {
	logger     dot.SLogger
	sConfig    dot.SConfig  
	config     dot.Config   
	metas      *Metas       
	lives      *Lives       
	types      map[reflect.Type]dot.Dot
	newerLives map[dot.LiveID]dot.Newer
	newerTypes map[dot.TypeID]dot.Newer
	parent dot.Injecter
	mutex  sync.Mutex
	lineBuilder *dot.Builder
	dotEvent dotEventerImp
}
func newLine(builder *dot.Builder) *lineImp {
	a := &lineImp{metas: NewMetas(),
		lives: NewLives(), types: make(map[reflect.Type]dot.Dot),
		newerLives:  make(map[dot.LiveID]dot.Newer),
		newerTypes:  make(map[dot.TypeID]dot.Newer),
		lineBuilder: builder,
	}
	a.dotEvent.Init()
	if dot.GetDefaultLine() == nil {
		dot.SetDefaultLine(a)
	}
	return a
}
func (c *lineImp) ID() string {
	return c.lineBuilder.LineLiveID
}
func (c *lineImp) AddNewerByLiveID(liveID dot.LiveID, newDot dot.Newer) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	if _, ok := c.newerLives[liveID]; ok {
		return dot.SError.Existed.AddNewError(liveID.String())
	}
	c.newerLives[liveID] = newDot
	return nil
}
func (c *lineImp) AddNewerByTypeID(typeID dot.TypeID, newDot dot.Newer) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	if _, ok := c.newerTypes[typeID]; ok {
		return dot.SError.Existed.AddNewError(typeID.String())
	}
	c.newerTypes[typeID] = newDot
	return nil
}
func (c *lineImp) RemoveNewerByLiveID(liveID dot.LiveID) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	delete(c.newerLives, liveID)
}
func (c *lineImp) RemoveNewerByTypeID(typeID dot.TypeID) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	delete(c.newerTypes, typeID)
}
func (c *lineImp) PreAdd(typeLives ...*dot.TypeLives) error {
	logger := dot.Logger()
	c.mutex.Lock()
	defer c.mutex.Unlock()
	var err error
	for _, typeLive := range typeLives {
		err2 := c.metas.UpdateOrAdd(&typeLive.Meta)
		if err2 == nil {
			if len(typeLive.Lives) > 0 {
				for i := range typeLive.Lives {
					it := &typeLive.Lives[i]
					if len(it.TypeID.String()) < 1 {
						it.TypeID = typeLive.Meta.TypeID
					}
					err2 = c.lives.UpdateOrAdd(it)
					if err2 != nil {
						if err != nil {
							logger.Debugln(fmt.Sprintf("lineImp - meta: %v", typeLive.Meta))
							logger.Errorln("lineImp", zap.Error(err))  
						}
						err = err2
					}
				}
			}
		} else {
			if err != nil {
				logger.Debugln(fmt.Sprintf("lineImp - meta: %v", typeLive.Meta))
				logger.Errorln("lineImp", zap.Error(err))  
			}
			err = err2
		}
	}
	return err
}
func (c *lineImp) relyOrder() ([]*dot.Live, []*dot.Live) {
	var cloneLives map[dot.LiveID]*dot.Live
	var cloneMetas map[dot.TypeID]*dot.Metadata
	logger := dot.Logger()
	{  
		c.mutex.Lock()
		cloneLives = make(map[dot.LiveID]*dot.Live, len(c.lives.LiveIDMap))
		for k, v := range c.lives.LiveIDMap {
			cloneLives[k] = v
		}
		cloneMetas = make(map[dot.TypeID]*dot.Metadata, len(c.metas.metas))
		for k, v := range c.metas.metas {
			cloneMetas[k] = v
		}
		c.mutex.Unlock()
	}
	order := make([]*dot.Live, 0, len(cloneLives))
	var circle []*dot.Live
	{
		relyed := make(map[dot.LiveID][]dot.LiveID, len(cloneLives))
		for _, it := range cloneLives {
			if _, ok := relyed[it.LiveID]; !ok {
				relyed[it.LiveID] = []dot.LiveID{}
			}
			for _, liveID := range it.RelyLives {
				r, ok := relyed[liveID]
				if !ok {
					r = []dot.LiveID{it.LiveID}
				} else {
					r = append(r, it.LiveID)
				}
				relyed[liveID] = r
			}
		}
		done := make(map[dot.LiveID]bool, len(relyed))           
		remain := make(map[dot.LiveID]bool, len(relyed))         
		levels := make([]map[dot.LiveID]bool, 0, len(relyed)/3)  
		{
			for liveID := range relyed {
				remain[liveID] = true
			}
			level0 := make(map[dot.LiveID]bool)
			for liveID, live := range cloneLives {  
				if len(live.RelyLives) < 1 {
					level0[liveID] = true
					delete(remain, liveID)
					done[liveID] = true
				}
			}
			levels = append(levels, level0)
			levelCurrent := level0
			for curFor := 0; curFor <= len(relyed); curFor++ {  
				levelNext := make(map[dot.LiveID]bool, len(remain))
				for liveID := range levelCurrent {
					des := relyed[liveID]
					if len(des) < 1 {
						delete(remain, liveID)
						done[liveID] = true
					} else {
						for _, liveID2 := range des {
							allDone := true
							for _, liveID3 := range cloneLives[liveID2].RelyLives {  
								if _, ok := done[liveID3]; !ok {
									allDone = false
									break
								}
							}
							if allDone {
								if _, ok := done[liveID2]; !ok {  
									levelNext[liveID2] = true
									done[liveID2] = true
								}
								delete(remain, liveID2)
							} else {
							}
						}
					}
				}
				levels = append(levels, levelNext)
				if len(remain) < 1 || len(levelNext) < 1 {
					break
				}
				levelCurrent = levelNext
			}
		}
		{
			for i, lev := range levels {
				logger.Debugln(fmt.Sprintf("level : %d", i))
				for liveID := range lev {
					logger.Debugln(cloneLives[liveID].LiveID.String())
					live, ok := cloneLives[liveID]
					if ok {
						order = append(order, live)
					} else {
						logger.Warnln("", zap.String("", "dot not find the dot live id: "+liveID.String()))
					}
				}
			}
			if len(remain) > 0 {
				circle = make([]*dot.Live, 0, len(remain))
				for liveID := range remain {  
					live, ok := cloneLives[liveID]
					if ok {
						order = append(order, live)
						circle = append(circle, live)
					} else {
						logger.Warnln("", zap.String("", "dot not find the dot live id: "+liveID.String()))
					}
				}
			}
		}
	}
	return order, circle
}
func (c *lineImp) CreateDots(orderedDots []*dot.Live) error {
	logger := dot.Logger()
	createDotFun := func(it *dot.Live) error {
		{  
			if nl, ok := it.Dot.(dot.SetterLine); ok {
				nl.SetLine(c)
			}
			if nl, ok := it.Dot.(dot.SetterTypeAndLiveID); ok {
				nl.SetTypeID(it.TypeID, it.LiveID)
			}
		}
		if b := c.dotEvent.TypeEvents(it.TypeID); len(b) > 0 {  
			for i := range b {
				e := &b[i]
				if e.BeforeCreate != nil {
					e.BeforeCreate(it, c)
				}
			}
		}
		if b := c.dotEvent.LiveEvents(it.LiveID); len(b) > 0 {  
			for i := range b {
				e := &b[i]
				if e.BeforeCreate != nil {
					e.BeforeCreate(it, c)
				}
			}
		}
		if creator, ok := it.Dot.(dot.Creator); ok {  
			if err := creator.Create(c); err != nil {
				return err
			}
		}
		if a := c.dotEvent.LiveEvents(it.LiveID); len(a) > 0 {  
			for i := range a {
				e := &a[i]
				if e.AfterCreate != nil {
					e.AfterCreate(it, c)
				}
			}
		}
		if a := c.dotEvent.TypeEvents(it.TypeID); len(a) > 0 {  
			for i := range a {
				e := &a[i]
				if e.AfterCreate != nil {
					e.AfterCreate(it, c)
				}
			}
		}
		return nil
	}
	var err error
	var dotLive *dot.Live  
CreateLives:
	for _, dotLive = range orderedDots {
		logger.Debug(func() string {
			m, _ := c.metas.Get(dotLive.TypeID)
			if m != nil {
				return fmt.Sprintf("Create dot, type id: %s, live id: %s, name: %s", dotLive.TypeID, dotLive.LiveID, m.Name)
			}
			return fmt.Sprintf("Create dot, type id: %s, live id: %s", dotLive.TypeID, dotLive.LiveID)
		})
		if skit.IsNil(&dotLive.Dot) {
			var bytesConfig []byte
			var config *dot.LiveConfig
			{
				config = c.config.FindConfig(dotLive.TypeID, dotLive.LiveID)
				bytesConfig, err = dot.MarshalConfig(config)
				if err != nil {
					break CreateLives
				}
			}
			{
				if newer, ok := c.newerLives[dotLive.LiveID]; ok {
					dotLive.Dot, err = newer(bytesConfig)
					if err != nil {
						break CreateLives
					} else {
						if err = createDotFun(dotLive); err != nil {
							break CreateLives
						}
						continue CreateLives
					}
				}
			}
			{
				if newer, ok := c.newerTypes[dotLive.TypeID]; ok {
					dotLive.Dot, err = newer(bytesConfig)
					if err != nil {
						break CreateLives
					} else {
						if err = createDotFun(dotLive); err != nil {
							break CreateLives
						}
						continue CreateLives
					}
				}
			}
			{
				var m *dot.Metadata
				m, err = c.metas.Get(dotLive.TypeID)
				if err != nil {
					break CreateLives
				}
				if m.NewDoter == nil && m.RefType == nil {
					err = dot.SError.NoDotNewer.AddNewError(m.TypeID.String())
					break CreateLives
				}
				dotLive.Dot, err = m.NewDot(bytesConfig)
				if err == nil {
					if err = createDotFun(dotLive); err != nil {
						break CreateLives
					}
					continue CreateLives
				} else {
					break CreateLives
				}
			}
		}
	}
	if err != nil {
		logger.Debug(func() string {
			m, _ := c.metas.Get(dotLive.TypeID)
			if m != nil {
				return fmt.Sprintf("Create dot, meta: %v\n live: %v", m, dotLive)
			}
			return fmt.Sprintf("Create dot, live: %v", dotLive)
		})
		logger.Errorln("lineImp", zap.Error(err))
		return err
	}
	{
		c.mutex.Lock()
		c.types[reflect.TypeOf(c.logger)] = c.logger
		{
			t := reflect.TypeOf((*dot.SLogger)(nil)).Elem()
			c.types[t] = c.logger
		}
		c.types[reflect.TypeOf(c.config)] = c.config
		{
			t := reflect.TypeOf((*dot.SConfig)(nil)).Elem()
			c.types[t] = c.sConfig
		}
		c.mutex.Unlock()
	}
	for _, it := range orderedDots {
		if !skit.IsNil(&it.Dot) && ((string)(it.TypeID) == (string)(it.LiveID)) {
			t := reflect.TypeOf(it.Dot)
			c.mutex.Lock()
			c.types[t] = it.Dot
			if getter, ok := it.Dot.(dot.GetInterfaceType); ok {
				c.types[getter.GetInterfaceType()] = it.Dot
			}
			c.mutex.Unlock()
		}
	}
	{
		afterInjects := make([]dot.AfterAllInjecter, 0, 20)
		err = nil
		for _, it := range orderedDots {
			if it.Dot != nil {  
				err = c.injectInLine(it.Dot, it)
				if err != nil {
					break
				}
				if ed, ok := it.Dot.(dot.Injected); ok {
					err = ed.Injected(c)
					if err != nil {
						logger.Debug(func() string {
							m, _ := c.metas.Get(it.TypeID)
							if m != nil {
								return fmt.Sprintf("Create dot, meta: %v\n live: %v", m, it)
							}
							return fmt.Sprintf("Create dot, live: %v", it)
						})
						logger.Errorln("lineImp", zap.Error(err))
						break
					}
				}
				if s, ok := it.Dot.(dot.AfterAllInjecter); ok {
					afterInjects = append(afterInjects, s)
				}
			}
		}
		if err == nil {
			for _, v := range afterInjects {
				v.AfterAllInject(c)
			}
		}
	}
	return err
}
func (c *lineImp) Config() *dot.Config {
	return &c.config
}
func (c *lineImp) SLogger() dot.SLogger {
	return c.logger
}
func (c *lineImp) SConfig() dot.SConfig {
	return c.sConfig
}
func (c *lineImp) ToLifer() dot.Lifer {
	return c
}
func (c *lineImp) ToInjecter() dot.Injecter {
	return c
}
func (c *lineImp) ToDotEventer() dot.Eventer {
	return &c.dotEvent
}
func (c *lineImp) GetDotConfig(liveID dot.LiveID) *dot.LiveConfig {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	co := c.config.FindConfig("", liveID)
	return co
}
func (c *lineImp) Inject(obj interface{}) error {
	logger := dot.Logger()
	var err error
	if skit.IsNil(obj) {
		return dot.SError.NilParameter
	}
	value := reflect.ValueOf(obj)
	for value.Kind() == reflect.Ptr {
		value = value.Elem()
	}
	if value.Kind() != reflect.Struct {
		return dot.SError.NotStruct
	}
	rType := value.Type()
	for i := 0; i < value.NumField(); i++ {
		var err2 error
		valueField := value.Field(i)
		if !valueField.CanSet() {
			continue
		}
		typeField := rType.Field(i)
		tagName, ok := typeField.Tag.Lookup(dot.TagDot)
		if !ok {
			continue
		}
		if typeField.Type.Kind() != reflect.Ptr && typeField.Type.Kind() != reflect.Interface {
			err2 = errors.New("the field with dot tag must be point or interface")
			logger.Debug(func() string {
				return fmt.Sprintf("error: %s\ninstance: %v", err2.Error(), obj)
			})
			multiErr(&err, err2)
		}
		var d dot.Dot
		{
			if len(tagName) < 1 || tagName == dot.CanNull {  
				d, err2 = c.GetByType(valueField.Type())
			} else {  
				liveID := strings.TrimPrefix(tagName, dot.CanNull)  
				d, err2 = c.GetByLiveID(dot.LiveID(liveID))
			}
			if err2 != nil {
				if tagName == dot.CanNull {  
					if dotError, ok := err2.(dot.Errorer); !ok || dotError.Code() != dot.SError.NotExisted.Code() {  
						logger.Debugln(fmt.Sprintf("lineImp, find dot error, field: %s, err: %value", typeField.Name, err2))
						multiErr(&err, err2)
					}
				} else {
					logger.Debugln(fmt.Sprintf("lineImp, find dot error, field: %s, err: %value", typeField.Name, err2))
					multiErr(&err, err2)
				}
			}
			if d == nil {
				logger.Debugln(fmt.Sprintf("lineImp, can not find dot error, field: %s", typeField.Name))
				continue
			}
		}
		if err2 == nil {
			valueDot := reflect.ValueOf(d)
			if valueDot.IsValid() && valueDot.Type().AssignableTo(valueField.Type()) {
				valueField.Set(valueDot)
			} else {
				multiErr(&err, dot.SError.DotInvalid.AddNewError(typeField.Type.String()+"  "+tagName))
			}
		}
	}
	return err
}
func (c *lineImp) injectInLine(obj interface{}, live *dot.Live) error {
	logger := dot.Logger()
	var err error
	if skit.IsNil(obj) {
		return dot.SError.NilParameter
	}
	value := reflect.ValueOf(obj)
	for value.Kind() == reflect.Ptr {
		value = value.Elem()
	}
	if value.Kind() != reflect.Struct {
		return dot.SError.NotStruct
	}
	rType := value.Type()
	for i := 0; i < value.NumField(); i++ {
		var err2 error = nil
		valueField := value.Field(i)
		if !valueField.CanSet() {
			continue
		}
		tField := rType.Field(i)
		tagName, ok := tField.Tag.Lookup(dot.TagDot)
		if !ok {
			continue
		}
		if tField.Type.Kind() != reflect.Ptr && tField.Type.Kind() != reflect.Interface {
			err2 = errors.New("the field with dot tag must be point or interface")
			logger.Debug(func() string {
				return fmt.Sprintf("error: %s\nlive: %v", err2.Error(), live)
			})
			multiErr(&err, err2)
		}
		var d dot.Dot
		{
			if len(live.RelyLives) > 0 {  
				if liveID, ok := live.RelyLives[tField.Name]; ok {
					d, err2 = c.GetByLiveID(liveID)
				}
			}
			if d == nil {
				if len(tagName) < 1 || tagName == dot.CanNull {  
					d, err2 = c.GetByType(valueField.Type())
				} else {  
					liveID := strings.TrimPrefix(tagName, dot.CanNull)  
					d, err2 = c.GetByLiveID(dot.LiveID(liveID))
				}
			}
			if err2 != nil {
				if tagName == dot.CanNull {  
					if dotError, ok := err2.(dot.Errorer); !ok || dotError.Code() != dot.SError.NotExisted.Code() {  
						logger.Debugln(fmt.Sprintf("lineImp, find dot error, field: %s, err: %value", tField.Name, err2))
						multiErr(&err, err2)
					}
				} else {
					logger.Debugln(fmt.Sprintf("lineImp, find dot error, field: %s, err: %value", tField.Name, err2))
					multiErr(&err, err2)
				}
			}
			if d == nil {
				logger.Debugln(fmt.Sprintf("lineImp, can not find dot error, field: %s, live: %value", tField.Name, live))
				continue
			}
		}
		if err2 == nil {
			valueDot := reflect.ValueOf(d)
			if valueDot.IsValid() && valueDot.Type().AssignableTo(valueField.Type()) {
				valueField.Set(valueDot)
			} else if err == nil {
				multiErr(&err, dot.SError.DotInvalid.AddNewError(tField.Type.String()+"  "+tagName))
			}
		}
	}
	return err
}
func (c *lineImp) GetByType(t reflect.Type) (d dot.Dot, err error) {
	d = nil
	err = nil
	c.mutex.Lock()
	d, ok := c.types[t]
	c.mutex.Unlock()
	if !ok {
		if c.parent != nil {
			d, err = c.parent.GetByType(t)
		} else {
			err = dot.SError.NotExisted.AddNewError(t.String())
		}
	}
	return
}
func (c *lineImp) GetByLiveID(liveID dot.LiveID) (d dot.Dot, err error) {
	d = nil
	err = nil
	c.mutex.Lock()
	var l *dot.Live
	l, err = c.lives.Get(liveID)
	c.mutex.Unlock()
	if err != nil {
		if c.parent != nil {
			d, err = c.parent.GetByLiveID(liveID)
		}
	} else {
		d = l.Dot
	}
	return
}
func (c *lineImp) ReplaceOrAddByType(d dot.Dot) error {
	var err error
	typeDot := reflect.TypeOf(d)
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.types[typeDot] = d
	return err
}
func (c *lineImp) ReplaceOrAddByParamType(d dot.Dot, rType reflect.Type) error {
	var err error
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.types[rType] = d
	return err
}
func (c *lineImp) ReplaceOrAddByLiveID(d dot.Dot, liveID dot.LiveID) error {
	var err error
	c.mutex.Lock()
	defer c.mutex.Unlock()
	l := dot.Live{LiveID: liveID, TypeID: "", Dot: d, RelyLives: nil}
	err = c.lives.UpdateOrAdd(&l)
	return err
}
func (c *lineImp) RemoveByType(rType reflect.Type) error {
	var err error
	c.mutex.Lock()
	defer c.mutex.Unlock()
	delete(c.types, rType)
	return err
}
func (c *lineImp) RemoveByLiveID(liveID dot.LiveID) error {
	var err error
	c.mutex.Lock()
	defer c.mutex.Unlock()
	err = c.lives.RemoveByID(liveID)
	return err
}
func (c *lineImp) SetParent(parent dot.Injecter) {
	c.parent = parent
}
func (c *lineImp) GetParent() dot.Injecter {
	return c.parent
}
func (c *lineImp) Create(l dot.Line) error {
	var err error
	c.sConfig = sconfig.NewConfig()
	c.sConfig.RootPath()
	if s, ok := c.sConfig.(dot.Creator); ok {
		if err = s.Create(l); err != nil {
			createLog(c)
			return err
		} else if len(c.sConfig.ConfigFile()) < 1 {  
			createLog(c)
			return err
		}
	}
	if err = c.sConfig.Unmarshal(&c.config); err != nil {
		createLog(c)
		return err
	}
	if len(c.config.Dots) < 1 {  
		createLog(c)
		return err
	}
	createLog(c)
	return err
}
func (c *lineImp) makeDotMetaFromConfig() error {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	var err error
	var dotConfig *dot.MetaLivesConfig
ForConfigDots:  
	for i := range c.config.Dots {
		dotConfig = &c.config.Dots[i]
		if len(dotConfig.MetaData.TypeID.String()) < 1 {
			err = dot.SError.Config.AddNewError("type id is null")
			break ForConfigDots
		}
		if err = c.metas.UpdateOrAdd(&dotConfig.MetaData); err != nil {
			break ForConfigDots
		}
		if len(dotConfig.Lives) < 1 {  
			live := dot.Live{TypeID: dotConfig.MetaData.TypeID, LiveID: dot.LiveID(dotConfig.MetaData.TypeID), Dot: nil}
			if len(dotConfig.MetaData.RelyTypeIDs) > 0 {
				live.RelyLives = make(map[string]dot.LiveID, len(dotConfig.MetaData.RelyTypeIDs))
				for i := range dotConfig.MetaData.RelyTypeIDs {
					li := &dotConfig.MetaData.RelyTypeIDs[i]
					live.RelyLives[li.String()] = dot.LiveID(*li)
				}
			}
			if err = c.lives.UpdateOrAdd(&live); err != nil {
				break ForConfigDots
			}
		} else {
			for _, li := range dotConfig.Lives {
				if len(li.LiveID.String()) < 1 {
					li.LiveID = dot.LiveID(dotConfig.MetaData.TypeID)
				}
				live := dot.Live{TypeID: dotConfig.MetaData.TypeID, LiveID: li.LiveID, RelyLives: li.RelyLives, Dot: nil}
				if err = c.lives.UpdateOrAdd(&live); err != nil {
					break ForConfigDots
				}
			}
		}
	}
	if err != nil {
		dot.Logger().Debugln(fmt.Sprintf("lineImp, %v", dotConfig))
	}
	return err
}
func (c *lineImp) autoMakeLiveID() {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	hasType := make(map[dot.TypeID]bool, len(c.lives.LiveIDMap))
	for _, v := range c.lives.LiveIDMap {
		hasType[v.TypeID] = true
	}
	for typeID := range c.metas.metas {
		if _, ok := hasType[typeID]; !ok {
			liveID := (dot.LiveID)(typeID)
			live := dot.Live{TypeID: typeID, LiveID: liveID, Dot: nil, RelyLives: nil}
			err2 := c.lives.UpdateOrAdd(&live)
			if err2 != nil && c.logger != nil {
				c.logger.Debugln(fmt.Sprintf("err: %v, live: %v", err2, live))
			}
		}
	}
}