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 get(begin int64, wg *sync.WaitGroup, n *node.Node) {
	defer wg.Done()
	var res []string
	var err error
	res, err = n.Talk("/recent/"+strconv.FormatInt(begin, 10)+"-", nil)
	if err != nil {
		manager.RemoveFromAllTable(n)
		log.Println(err)
		return
	}
	err = db.DB.Update(func(tx *bolt.Tx) error {
		for _, line := range res {
			rec, errr := record.Make(line)
			if errr != nil {
				continue
			}
			appendHead(tx, rec.Head)
			tags := strings.Fields(strings.TrimSpace(rec.GetBodyValue("tag", "")))
			if len(tags) > 0 {
				suggest.AddString(tx, rec.Datfile, tags)
				manager.AppendToTableTX(tx, rec.Datfile, n)
			}
		}
		return nil
	})
	if err != nil {
		log.Println(err)
	}
	log.Println("added", len(res), "recent records from", n.Nodestr)
}
//getWithRange gets records with range using node n and adds to cache after checking them.
//if no records exist in cache, uses head
//return true if gotten records>0
func getWithRange(n *node.Node, c *thread.Cache, dm *Manager) bool {
	got := false
	for {
		from, to := dm.Get(n)
		if from <= 0 {
			return got
		}

		var okcount int
		ress, err := n.Talk(fmt.Sprintf("/get/%s/%d-%d", c.Datfile, from, to), nil)
		if err != nil {
			dm.Finished(n, false)
			return false
		}
		err = db.DB.Update(func(tx *bolt.Tx) error {
			for _, res := range ress {
				errf := c.CheckData(tx, res, -1, "", from, to)
				if errf == nil {
					okcount++
				}
			}
			return nil
		})
		if err != nil {
			log.Println(err)
		}
		dm.Finished(n, true)
		log.Println(c.Datfile, okcount, "records were saved from", n.Nodestr)
		got = okcount > 0
	}
}
//headWithRange checks node n has records with range and adds records which should be downloaded to downloadmanager.
func headWithRange(n *node.Node, c *thread.Cache, dm *Manager) bool {
	begin := time.Now().Unix() - cfg.GetRange
	if rec, err := recentlist.Newest(c.Datfile); err == nil {
		begin = rec.Stamp - cfg.GetRange
	}
	if cfg.GetRange == 0 || begin < 0 {
		begin = 0
	}
	res, err := n.Talk(fmt.Sprintf("/head/%s/%d-", c.Datfile, begin), nil)
	if err != nil {
		return false
	}
	if len(res) == 0 {
		ress, errr := n.Talk(fmt.Sprintf("/have/%s", c.Datfile), nil)
		if errr != nil || len(ress) == 0 || ress[0] != "YES" {
			manager.RemoveFromTable(c.Datfile, n)
		} else {
			manager.AppendToTable(c.Datfile, n)
		}
		return false
	}
	manager.AppendToTable(c.Datfile, n)
	dm.Set(res, n)
	return true
}
//GetData gets records from node n and checks its is same as stamp and id in args.
//save recs if success. returns errSpam or errGet.
func (r *Record) GetData(n *node.Node) error {
	res, err := n.Talk(fmt.Sprintf("/get/%s/%d/%s", r.Datfile, r.Stamp, r.ID), nil)
	if len(res) == 0 {
		err = errors.New("no response")
	}
	if err != nil {
		log.Println(err)
		return cfg.ErrGet
	}
	if err = r.Parse(res[0]); err != nil {
		return cfg.ErrGet
	}
	r.Sync()
	return r.CheckData(-1, -1)
}
//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.
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)
		}
	}
}
//ReplaceNodeInList removes one node and say bye to the node and add n in nodelist.
//if len(node)>defaultnode
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
}
//Join tells n to join and adds n to nodelist if welcomed.
//if n returns another nodes, repeats it and return true..
//removes fron nodelist if not welcomed and return false.
func Join(n *node.Node) bool {
	const retryJoin = 2 // Times; Join network
	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
}