You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: udm.go
    path of file: ./repos/unpoller/pkg/datadogunifi
    
    the code of the file until where you have to start completion: package datadogunifi

import (
	"regexp"
	"strings"

	"github.com/unpoller/unifi"
)

// udmT is used as a name for printed/logged counters.
const udmT = item("UDM")

// Combine concatenates N maps. This will delete things if not used with caution.
func Combine(in ...map[string]any) map[string]any {
	out := make(map[string]any)

	for i := range in {
		for k := range in[i] {
			out[k] = in[i][k]
		}
	}

	return out
}

// CombineFloat64 concatenates N maps. This will delete things if not used with caution.
func CombineFloat64(in ...map[string]float64) map[string]float64 {
	out := make(map[string]float64)

	for i := range in {
		for k := range in[i] {
			out[k] = in[i][k]
		}
	}

	return out
}

var statNameRe = regexp.MustCompile("[^a-zA-Z0-9_]")

func safeStatsName(s string) string {
	return statNameRe.ReplaceAllString(strings.ToLower(s), "_")
}

// batchSysStats is used by all device types.
func (u *DatadogUnifi) batchSysStats(s unifi.SysStats, ss unifi.SystemStats) map[string]float64 {
	m := map[string]float64{
		"loadavg_1":     s.Loadavg1.Val,
		"loadavg_5":     s.Loadavg5.Val,
		"loadavg_15":    s.Loadavg15.Val,
		"mem_used":      s.MemUsed.Val,
		"mem_buffer":    s.MemBuffer.Val,
		"mem_total":     s.MemTotal.Val,
		"cpu":           ss.CPU.Val,
		"mem":           ss.Mem.Val,
		"system_uptime": ss.Uptime.Val,
	}

	for k, v := range ss.Temps {
		temp := v.Celsius()
		k = safeStatsName(k)

		if temp != 0 && k != "" {
			m[k] = float64(temp)
		}
	}

	return m
}

func (u *DatadogUnifi) batchUDMtemps(temps []unifi.Temperature) map[string]float64 {
	output := make(map[string]float64)

	for _, t := range temps {
		if t.Name == "" {
			continue
		}

		output[safeStatsName("temp_"+t.Name)] = t.Value
	}

	return output
}

func (u *DatadogUnifi) batchUDMstorage(storage []*unifi.Storage) map[string]float64 {
	output := make(map[string]float64)

	for _, t := range storage {
		if t.Name == "" {
			continue
		}

		output[safeStatsName("storage_"+t.Name+"_size")] = t.Size.Val
		output[safeStatsName("storage_"+t.Name+"_used")] = t.Used.Val

		if t.Size.Val != 0 && t.Used.Val != 
    
func (u *DatadogUnifi) batchUDM(r report, s *unifi.UDM) { // nolint: funlen
	if !s.Adopted.Val || s.Locating.Val {
		return
	}

	tags := cleanTags(map[string]string{
		"source":        s.SourceName,
		"mac":           s.Mac,
		"site_name":     s.SiteName,
		"name":          s.Name,
		"version":       s.Version,
		"model":         s.Model,
		"serial":        s.Serial,
		"type":          s.Type,
		"ip":            s.IP,
		"license_state": s.LicenseState,
	})
	data := CombineFloat64(
		u.batchUDMstorage(s.Storage),
		u.batchUDMtemps(s.Temperatures),
		u.batchUSGstats(s.SpeedtestStatus, s.Stat.Gw, s.Uplink),
		u.batchSysStats(s.SysStats, s.SystemStats),
		map[string]float64{
			"bytes":         s.Bytes.Val,
			"last_seen":     s.LastSeen.Val,
			"guest_num_sta": s.GuestNumSta.Val,
			"rx_bytes":      s.RxBytes.Val,
			"tx_bytes":      s.TxBytes.Val,
			"uptime":        s.Uptime.Val,
			"state":         s.State.Val,
			"user_num_sta":  s.UserNumSta.Val,
			"num_desktop":   s.NumDesktop.Val,
			"num_handheld":  s.NumHandheld.Val,
			"num_mobile":    s.NumMobile.Val,
			"upgradeable":   boolToFloat64(s.Upgradeable.Val),
		},
	)

	r.addCount(udmT)

	metricName := metricNamespace("usg")

	reportGaugeForFloat64Map(r, metricName, data, tags)

	u.batchNetTable(r, tags, s.NetworkTable)
	u.batchUSGwans(r, tags, s.Wan1, s.Wan2)

	tags = cleanTags(map[string]string{
		"mac":       s.Mac,
		"site_name": s.SiteName,
		"source":    s.SourceName,
		"name":      s.Name,
		"version":   s.Version,
		"model":     s.Model,
		"serial":    s.Serial,
		"type":      s.Type,
		"ip":        s.IP,
	})
	data = CombineFloat64(
		u.batchUSWstat(s.Stat.Sw),
		map[string]float64{
			"guest_num_sta": s.GuestNumSta.Val,
			"bytes":         s.Bytes.Val,
			"last_seen":     s.LastSeen.Val,
			"rx_bytes":      s.RxBytes.Val,
			"tx_bytes":      s.TxBytes.Val,
			"uptime":        s.Uptime.Val,
			"upgradeable":   boolToFloat64(s.Upgradeable.Val),
		})

	metricName = metricNamespace("usw")
	reportGaugeForFloat64Map(r, metricName, data, tags)

	u.batchPortTable(r, tags, s.PortTable) // udm has a usw in it.

	if s.Stat.Ap == nil {
		return // we're done now. the following code process UDM (non-pro) UAP data.
	}

	tags = cleanTags(map[string]string{
		"mac":       s.Mac,
		"site_name": s.SiteName,
		"source":    s.SourceName,
		"name":      s.Name,
		"version":   s.Version,
		"model":     s.Model,
		"serial":    s.Serial,
		"type":      s.Type,
		"ip":        s.IP,
	})
	data = u.processUAPstats(s.Stat.Ap)
	data["bytes"] = s.Bytes.Val
	data["last_seen"] = s.LastSeen.Val
	data["rx_bytes"] = s.RxBytes.Val
	data["tx_bytes"] = s.TxBytes.Val
	data["uptime"] = s.Uptime.Val
	data["state"] = s.State.Val
	data["user_num_sta"] = s.UserNumSta.Val
	data["guest_num_sta"] = s.GuestNumSta.Val
	data["num_sta"] = s.NumSta.Val

	metricName = metricNamespace("uap")
	reportGaugeForFloat64Map(r, metricName, data, tags)

	u.processRadTable(r, tags, *s.RadioTable, *s.RadioTableStats)
	u.processVAPTable(r, tags, *s.VapTable)
}