func TellUpdate(datfile string, stamp int64, id string, n *node.Node) {
	const updateNodes = 10
	tellstr := node.Me(true).Toxstring()
	if n != nil {
		tellstr = n.Toxstring()
	}
	msg := strings.Join([]string{"/update", datfile, strconv.FormatInt(stamp, 10), id, tellstr}, "/")
	ns := Get(datfile, nil)
	ns = ns.Extend(Get(list, nil))
	ns = ns.Extend(Random(ns, updateNodes))
	log.Println("telling #", len(ns))
	for _, n := range ns {
		_, err := n.Talk(msg, nil)
		if err != nil {
			log.Println(err)
		}
	}
}
TellUpdate makes mynode info from node or dnsname or ip addr,
and broadcast the updates of record id=id in cache c.datfile with stamp.
package manager
import (
	"errors"
	"log"
	"math/rand"
	"strconv"
	"strings"
	"sync"
	"github.com/boltdb/bolt"
	"github.com/shingetsu-gou/shingetsu-gou/cfg"
	"github.com/shingetsu-gou/shingetsu-gou/db"
	"github.com/shingetsu-gou/shingetsu-gou/myself"
	"github.com/shingetsu-gou/shingetsu-gou/node"
)
const (
	defaultNodes = 100  
	shareNodes   = 100  
)
var list = string([]byte{0x01})
func getFromList() *node.Node {
	var rs map[string]struct{}
	err := db.DB.View(func(tx *bolt.Tx) error {
		var err error
		rs, err = db.GetMap(tx, "lookupT", []byte(list))
		return err
	})
	if err != nil {
		log.Print(err)
		return nil
	}
	if len(rs) == 0 {
		log.Println("node not found")
		return nil
	}
	var r string
	for rr := range rs {
		r = rr
		break
	}
	n, err := node.New(r)
	if err != nil {
		log.Println(err)
		return nil
	}
	return n
}
func NodeLen() int {
	ns := getAllNodes()
	return ns.Len()
}
func ListLen() int {
	return listLen(list)
}
func listLen(datfile string) int {
	var rs map[string]struct{}
	err := db.DB.View(func(tx *bolt.Tx) error {
		var err error
		rs, err = db.GetMap(tx, "lookupT", []byte(datfile))
		return err
	})
	if err != nil {
		log.Print(err, datfile)
		return 0
	}
	return len(rs)
}
func GetNodestrSlice() []string {
	return getAllNodes().GetNodestrSlice()
}
func getAllNodes() node.Slice {
	var r []string
	err := db.DB.View(func(tx *bolt.Tx) error {
		var err error
		r, err = db.KeyStrings(tx, "lookupA")
		return err
	})
	if err != nil {
		log.Print(err)
		return nil
	}
	return node.NewSlice(r)
}
func Get(datfile string, def node.Slice) node.Slice {
	str := GetNodestrSliceInTable(datfile)
	if str == nil {
		return def
	}
	return node.NewSlice(str)
}
func GetNodestrSliceInList() []string {
	return GetNodestrSliceInTable(list)
}
func GetNodestrSliceInTable(datfile string) []string {
	var r []string
	err := db.DB.View(func(tx *bolt.Tx) error {
		var err error
		r, err = db.MapKeys(tx, "lookupT", []byte(datfile))
		return err
	})
	if err != nil {
		log.Print(err, datfile)
		return nil
	}
	return r
}
func Random(exclude node.Slice, num int) []*node.Node {
	all := getAllNodes()
	if exclude != nil {
		cand := make([]*node.Node, 0, len(all))
		m := exclude.ToMap()
		for _, n := range all {
			if _, exist := m[n.Nodestr]; !exist {
				cand = append(cand, n)
			}
		}
		all = cand
	}
	n := all.Len()
	if num < n && num != 0 {
		n = num
	}
	r := make([]*node.Node, n)
	rs := rand.Perm(all.Len())
	for i := 0; i < n; i++ {
		r[i] = all[rs[i]]
	}
	return r
}
func appendable(datfile string, n *node.Node) bool {
	l := listLen(datfile)
	return ((datfile != "" && l < shareNodes) ||
		(datfile == "" && l < defaultNodes)) &&
		n != nil && n.IsAllowed() && !hasNodeInTable(datfile, n)
}
func AppendToTable(datfile string, n *node.Node) {
	err := db.DB.Update(func(tx *bolt.Tx) error {
		AppendToTableTX(tx, datfile, n)
		return nil
	})
	if err != nil {
		log.Println(err)
	}
}
func AppendToTableTX(tx *bolt.Tx, datfile string, n *node.Node) {
	if !appendable(datfile, n) {
		return
	}
	err := db.PutMap(tx, "lookupT", []byte(datfile), n.Nodestr)
	if err != nil {
		log.Print(err)
	}
	err = db.PutMap(tx, "lookupA", []byte(n.Nodestr), datfile)
	if err != nil {
		log.Print(err)
	}
}
func AppendToList(n *node.Node) {
	AppendToTable(list, n)
}
func appendToList(tx *bolt.Tx, n *node.Node) {
	AppendToTableTX(tx, list, n)
}
func ReplaceNodeInList(n *node.Node) *node.Node {
	l := ListLen()
	if !n.IsAllowed() || hasNodeInTable(list, n) {
		return nil
	}
	var old *node.Node
	if l >= defaultNodes {
		old = getFromList()
		RemoveFromList(old)
		old.Bye()
	}
	err := db.DB.Update(func(tx *bolt.Tx) error {
		appendToList(tx, n)
		return nil
	})
	if err != nil {
		log.Println(err)
	}
	return old
}
func hasNodeInTable(datfile string, n *node.Node) bool {
	var r bool
	err := db.DB.View(func(tx *bolt.Tx) error {
		r = db.HasVal(tx, "lookupT", []byte(datfile), n.Nodestr)
		return nil
	})
	if err != nil {
		log.Println(err)
	}
	return r
}
func removeFromTable(tx *bolt.Tx, datfile string, n *node.Node) error {
	if n == nil {
		err := errors.New("n is nil")
		log.Println(err)
		return err
	}
	if !db.HasVal(tx, "lookupT", []byte(datfile), n.Nodestr) {
		return errors.New("no node")
	}
	err := db.DelMap(tx, "lookupT", []byte(datfile), n.Nodestr)
	if err != nil {
		return err
	}
	return db.DelMap(tx, "lookupA", []byte(n.Nodestr), datfile)
}
func RemoveFromTable(datfile string, n *node.Node) bool {
	err := db.DB.Update(func(tx *bolt.Tx) error {
		return removeFromTable(tx, datfile, n)
	})
	if err != nil {
		log.Println(err)
		return false
	}
	return true
}
func RemoveFromList(n *node.Node) bool {
	return RemoveFromTable(list, n)
}
func RemoveFromAllTable(n *node.Node) bool {
	err := db.DB.Update(func(tx *bolt.Tx) error {
		threads, err := db.GetMap(tx, "lookupA", []byte(n.Nodestr))
		if err != nil {
			return err
		}
		err = db.Del(tx, "lookupA", []byte(n.Nodestr))
		if err != nil {
			return err
		}
		for t := range threads {
			err := db.DelMap(tx, "lookupT", []byte(t), n.Nodestr)
			if err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		log.Println(err)
		return false
	}
	return true
}
func Initialize(allnodes node.Slice) {
	inodes := allnodes
	if len(allnodes) > defaultNodes {
		inodes = inodes[:defaultNodes]
	}
	var wg sync.WaitGroup
	var mutex sync.Mutex
	port0 := true
	for i := 0; i < len(inodes) && ListLen() < defaultNodes; i++ {
		wg.Add(1)
		go func(inode *node.Node) {
			if _, err := inode.Ping(); err != nil {
				wg.Done()
				return
			}
			go func(inode *node.Node) {
				if Join(inode) {
					mutex.Lock()
					port0 = false
					mutex.Unlock()
				}
				AppendToList(inode)
				wg.Done()
			}(inode)
		}(inodes[i])
	}
	wg.Wait()
	log.Println("# of nodelist:", ListLen())
	if port0 {
		log.Println("port0")
		myself.SetStatus(cfg.Port0)
	} else {
		log.Println("opened")
	}
}
func Join(n *node.Node) bool {
	const retryJoin = 2  
	if n == nil {
		return false
	}
	if hasNodeInTable(list, n) || node.Me(false).Nodestr == n.Nodestr {
		return false
	}
	flag := false
	for count := 0; count < retryJoin && ListLen() < defaultNodes; count++ {
		extnode, err := n.Join()
		if err != nil {
			RemoveFromTable(list, n)
			return false
		}
		AppendToList(n)
		flag = true
		if extnode == nil {
			return true
		}
		n = extnode
	}
	return flag
}