func (rds *RouterDescriptors) Iterate(filter *ObjectFilter) <-chan Object {
	ch := make(chan Object)
	go func() {
		for _, getDesc := range rds.RouterDescriptors {
			desc := getDesc()
			if filter == nil || filter.IsEmpty() || filter.MatchesRouterDescriptor(desc) {
				ch <- desc
			}
		}
		close(ch)
	}()
	return ch
}
Iterate implements the ObjectSet interface.  Using a channel, it iterates
over and returns all router descriptors.  The given object filter can be
used to filter descriptors, e.g., by fingerprint.
package zoossh
import (
	"bytes"
	"fmt"
	"io"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
)
const (
	publishedTimeLayout = "2006-01-02 15:04:05"
)
var descriptorAnnotations = map[Annotation]bool{
	Annotation{"server-descriptor", "1", "0"}:        true,
	Annotation{"bridge-server-descriptor", "1", "2"}: true,
}
type GetDescriptor func() *RouterDescriptor
type ExitPattern struct {
	AddressSpec string
	PortSpec    string
}
type RouterDescriptor struct {
	Nickname  string
	Address   net.IP
	ORPort    uint16
	SOCKSPort uint16
	DirPort   uint16
	BandwidthAvg   uint64
	BandwidthBurst uint64
	BandwidthObs   uint64
	OperatingSystem string
	TorVersion      string
	Published time.Time
	Uptime uint64
	Fingerprint Fingerprint
	Hibernating bool
	Family map[Fingerprint]bool
	Contact string
	HiddenServiceDir bool
	BridgeDistributionRequest string
	OnionKey     string
	NTorOnionKey string
	SigningKey   string
	RawAccept     string
	RawReject     string
	RawExitPolicy string
	Accept []*ExitPattern
	Reject []*ExitPattern
}
type RouterDescriptors struct {
	RouterDescriptors map[Fingerprint]GetDescriptor
}
func (rd *RouterDescriptor) String() string {
	return fmt.Sprintf("%s,%s,%s,%d,%d,%s,%d,%s,%s,%s",
		rd.Fingerprint,
		rd.Nickname,
		rd.Address,
		rd.ORPort,
		rd.DirPort,
		rd.Published.Format(time.RFC3339),
		rd.Uptime,
		strings.Replace(rd.OperatingSystem, ",", "", -1),
		strings.Replace(rd.TorVersion, ",", "", -1),
		strings.Replace(rd.Contact, ",", "", -1))
}
func (rd *RouterDescriptor) GetFingerprint() Fingerprint {
	return rd.Fingerprint
}
func (rd *RouterDescriptor) HasFamily(fingerprint Fingerprint) bool {
	_, ok := rd.Family[SanitiseFingerprint(fingerprint)]
	return ok
}
func (rds *RouterDescriptors) Length() int {
	return len(rds.RouterDescriptors)
}