func (p *PaloAlto) DeleteExternalDynamicList(name string, devicegroup ...string) error {
	var xpath string
	var reqError requestError
	if p.DeviceType == "panos" {
		xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/external-list/entry[@name='%s']", name)
	}
	if p.DeviceType == "panorama" && p.Shared == true {
		xpath = fmt.Sprintf("/config/shared/external-list/entry[@name='%s']", name)
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) > 0 {
		xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/external-list/entry[@name='%s']", devicegroup[0], name)
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) <= 0 {
		return errors.New("you must specify a device-group when deleting a external dynamic list on a Panorama device")
	}
	_, resp, errs := r.Get(p.URI).Query(fmt.Sprintf("type=config&action=delete&xpath=%s&key=%s", xpath, p.Key)).End()
	if errs != nil {
		return errs[0]
	}
	if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
		return err
	}
	if reqError.Status != "success" {
		return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
	}
	return nil
}
DeleteExternalDynamicList removes an external dynamic list from the device. If deleting an EDL on a
Panorama device, specify the device-group as the last parameter.
package panos
import (
	"encoding/xml"
	"errors"
	"fmt"
	"strings"
	"time"
	easycsv "github.com/scottdware/go-easycsv"
)
type URLCategory struct {
	XMLName xml.Name    `xml:"response"`
	Status  string      `xml:"status,attr"`
	Code    string      `xml:"code,attr"`
	URLs    []CustomURL `xml:"result>custom-url-category>entry"`
}
type CustomURL struct {
	Name        string   `xml:"name,attr"`
	Description string   `xml:"description,omitempty"`
	Members     []string `xml:"list>member,omitempty"`
}
type Recurrance struct {
	Method     string
	DayOfWeek  string
	DayOfMonth int
	Hour       string
}
type Tags struct {
	Tags []Tag
}
type Tag struct {
	Name     string
	Color    string
	Comments string
}
type xmlTags struct {
	XMLName xml.Name `xml:"response"`
	Status  string   `xml:"status,attr"`
	Code    string   `xml:"code,attr"`
	Tags    []xmlTag `xml:"result>tag>entry"`
}
type xmlTag struct {
	Name     string `xml:"name,attr"`
	Color    string `xml:"color,omitempty"`
	Comments string `xml:"comments,omitempty"`
}
type SecurityProfiles struct {
	URLFiltering  string
	FileBlocking  string
	AntiVirus     string
	AntiSpyware   string
	Vulnerability string
	Wildfire      string
	Group         string
}
type LogForwarding struct {
	XMLName  xml.Name               `xml:"response"`
	Status   string                 `xml:"status,attr"`
	Code     string                 `xml:"code,attr"`
	Profiles []LogForwardingProfile `xml:"result>profiles>entry"`
}
type LogForwardingProfile struct {
	Name      string                   `xml:"name,attr"`
	MatchList []LogForwardingMatchList `xml:"match-list>entry"`
}
type LogForwardingMatchList struct {
	Name           string `xml:"name,attr"`
	SendToPanorama string `xml:"send-to-panorama"`
	LogType        string `xml:"log-type"`
	Filter         string `xml:"filter"`
}
type SecurityGroups struct {
	XMLName  xml.Name               `xml:"response"`
	Status   string                 `xml:"status,attr"`
	Code     string                 `xml:"code,attr"`
	Profiles []SecurityProfileGroup `xml:"result>profile-group>entry"`
}
type SecurityProfileGroup struct {
	Name          string `xml:"name,attr"`
	URLFiltering  string `xml:"url-filtering>member"`
	FileBlocking  string `xml:"file-blocking>member"`
	AntiVirus     string `xml:"virus>member"`
	AntiSpyware   string `xml:"spyware>member"`
	Vulnerability string `xml:"vulnerability>member"`
	DataFiltering string `xml:"data-filtering>member"`
	Wildfire      string `xml:"wildfire-analysis>member"`
}
var (
	tagColors = map[string]string{
		"Red":         "color1",
		"Green":       "color2",
		"Blue":        "color3",
		"Yellow":      "color4",
		"Copper":      "color5",
		"Orange":      "color6",
		"Purple":      "color7",
		"Gray":        "color8",
		"Light Green": "color9",
		"Cyan":        "color10",
		"Light Gray":  "color11",
		"Blue Gray":   "color12",
		"Lime":        "color13",
		"Black":       "color14",
		"Gold":        "color15",
		"Brown":       "color16",
	}
)
func (p *PaloAlto) URLCategory(devicegroup ...string) (*URLCategory, error) {
	var urls URLCategory
	xpath := "/config/devices/entry//custom-url-category"
	if p.DeviceType != "panorama" && len(devicegroup) > 0 {
		return nil, errors.New("you must be connected to a Panorama device when specifying a device-group")
	}
	if p.DeviceType == "panos" && p.Panorama == true {
		xpath = "/config/panorama//custom-url-category"
	}
	if p.DeviceType == "panos" && p.Panorama == false {
		xpath = "/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/profiles/custom-url-category"
	}
	if p.DeviceType == "panorama" && len(devicegroup) > 0 {
		xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/profiles/custom-url-category", devicegroup[0])
	}
	_, urlData, errs := r.Get(p.URI).Query(fmt.Sprintf("type=config&action=get&xpath=%s&key=%s", xpath, p.Key)).End()
	if errs != nil {
		return nil, errs[0]
	}
	if err := xml.Unmarshal([]byte(urlData), &urls); err != nil {
		return nil, err
	}
	if urls.Status != "success" {
		return nil, fmt.Errorf("error code %s: %s", urls.Code, errorCodes[urls.Code])
	}
	return &urls, nil
}
func (p *PaloAlto) CreateURLCategory(name string, urls []string, description string, devicegroup ...string) error {
	var xpath string
	var reqError requestError
	xmlBody := "<list>"
	for _, m := range urls {
		xmlBody += fmt.Sprintf("<member>%s</member>", strings.TrimSpace(m))
	}
	xmlBody += "</list>"
	if description != "" {
		xmlBody += fmt.Sprintf("<description>%s</description>", description)
	}
	if p.DeviceType == "panos" {
		xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/profiles/custom-url-category/entry[@name='%s']", name)
	}
	if p.DeviceType == "panorama" && p.Shared == true {
		xpath = fmt.Sprintf("/config/shared/profiles/custom-url-category/entry[@name='%s']", name)
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) > 0 {
		xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/profiles/custom-url-category/entry[@name='%s']", devicegroup[0], name)
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) <= 0 {
		return errors.New("you must specify a device-group when creating a URL category on a Panorama device")
	}
	_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=set&xpath=%s&element=%s&key=%s", xpath, xmlBody, p.Key)).End()
	if errs != nil {
		return errs[0]
	}
	if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
		return err
	}
	if reqError.Status != "success" {
		return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
	}
	return nil
}
func (p *PaloAlto) EditURLCategory(action, url, name string, devicegroup ...string) error {
	var xpath string
	var xmlBody string
	var reqError requestError
	query := fmt.Sprintf("type=config&key=%s", p.Key)
	if p.DeviceType == "panos" {
		if action == "add" {
			xmlBody += fmt.Sprintf("<member>%s</member>", url)
			xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/profiles/custom-url-category/entry[@name='%s']/list", name)
			query += fmt.Sprintf("&action=set&xpath=%s&element=%s", xpath, xmlBody)
		}
		if action == "remove" {
			xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/profiles/custom-url-category/entry[@name='%s']/list/member[text()='%s']", name, url)
			query += fmt.Sprintf("&action=delete&xpath=%s", xpath)
		}
	}
	if p.DeviceType == "panorama" && p.Shared == true {
		if action == "add" {
			xmlBody = fmt.Sprintf("<member>%s</member>", url)
			xpath = fmt.Sprintf("/config/shared/profiles/custom-url-category/entry[@name='%s']/list", name)
			query += fmt.Sprintf("&action=set&xpath=%s&element=%s", xpath, xmlBody)
		}
		if action == "remove" {
			xpath = fmt.Sprintf("/config/shared/profiles/custom-url-category/entry[@name='%s']/list/member[text()='%s']", name, url)
			query += fmt.Sprintf("&action=delete&xpath=%s", xpath)
		}
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) > 0 {
		if action == "add" {
			xmlBody = fmt.Sprintf("<member>%s</member>", url)
			xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/profiles/custom-url-category/entry[@name='%s']/list", devicegroup[0], name)
			query += fmt.Sprintf("&action=set&xpath=%s&element=%s", xpath, xmlBody)
		}
		if action == "remove" {
			xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/profiles/custom-url-category/entry[@name='%s']/list/member[text()='%s']", devicegroup[0], name, url)
			query += fmt.Sprintf("&action=delete&xpath=%s", xpath)
		}
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) <= 0 {
		return errors.New("you must specify a device-group when editing a URL category on a Panorama device")
	}
	_, resp, errs := r.Post(p.URI).Query(query).End()
	if errs != nil {
		return errs[0]
	}
	if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
		return err
	}
	if reqError.Status != "success" {
		return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
	}
	return nil
}
func (p *PaloAlto) DeleteURLCategory(name string, devicegroup ...string) error {
	var xpath string
	var reqError requestError
	if p.DeviceType == "panos" {
		xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/profiles/custom-url-category/entry[@name='%s']", name)
	}
	if p.DeviceType == "panorama" && p.Shared == true {
		xpath = fmt.Sprintf("/config/shared/profiles/custom-url-category/entry[@name='%s']", name)
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) > 0 {
		xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/profiles/custom-url-category/entry[@name='%s']", devicegroup[0], name)
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) <= 0 {
		return errors.New("you must specify a device-group when deleting a URL category on a Panorama device")
	}
	_, resp, errs := r.Get(p.URI).Query(fmt.Sprintf("type=config&action=delete&xpath=%s&key=%s", xpath, p.Key)).End()
	if errs != nil {
		return errs[0]
	}
	if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
		return err
	}
	if reqError.Status != "success" {
		return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
	}
	return nil
}
func (p *PaloAlto) EditGroup(objecttype, action, object, group string, devicegroup ...string) error {
	var xmlBody string
	var xpath string
	var reqError requestError
	query := fmt.Sprintf("type=config&key=%s", p.Key)
	if p.DeviceType == "panos" {
		if action == "add" {
			xmlBody = fmt.Sprintf("<member>%s</member>", object)
			xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/address-group/entry[@name='%s']/static", group)
			if objecttype == "service" {
				xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/service-group/entry[@name='%s']/members", group)
			}
			query += fmt.Sprintf("&action=set&xpath=%s&element=%s", xpath, xmlBody)
		}
		if action == "remove" {
			xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/address-group/entry[@name='%s']/static/member[text()='%s']", group, object)
			if objecttype == "service" {
				xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/service-group/entry[@name='%s']/members/member[text()='%s']", group, object)
			}
			query += fmt.Sprintf("&action=delete&xpath=%s", xpath)
		}
	}
	if p.DeviceType == "panorama" && p.Shared == true {
		if action == "add" {
			xmlBody = fmt.Sprintf("<member>%s</member>", object)
			xpath = fmt.Sprintf("/config/shared/address-group/entry[@name='%s']/static", group)
			if objecttype == "service" {
				xpath = fmt.Sprintf("/config/shared/service-group/entry[@name='%s']/members", group)
			}
			query += fmt.Sprintf("&action=set&xpath=%s&element=%s", xpath, xmlBody)
		}
		if action == "remove" {
			xpath = fmt.Sprintf("/config/shared/address-group/entry[@name='%s']/static/member[text()='%s']", group, object)
			if objecttype == "service" {
				xpath = fmt.Sprintf("/config/shared/service-group/entry[@name='%s']/members/member[text()='%s']", group, object)
			}
			query += fmt.Sprintf("&action=delete&xpath=%s", xpath)
		}
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) > 0 {
		if action == "add" {
			xmlBody = fmt.Sprintf("<member>%s</member>", object)
			xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/address-group/entry[@name='%s']/static", devicegroup[0], group)
			if objecttype == "service" {
				xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/service-group/entry[@name='%s']/members", devicegroup[0], group)
			}
			query += fmt.Sprintf("&action=set&xpath=%s&element=%s", xpath, xmlBody)
		}
		if action == "remove" {
			xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/address-group/entry[@name='%s']/static/member[text()='%s']", devicegroup[0], group, object)
			if objecttype == "service" {
				xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/service-group/entry[@name='%s']/members/member[text()='%s']", devicegroup[0], group, object)
			}
			query += fmt.Sprintf("&action=delete&xpath=%s", xpath)
		}
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) <= 0 {
		return errors.New("you must specify a device-group when editing a shared group on a Panorama device")
	}
	_, resp, errs := r.Post(p.URI).Query(query).End()
	if errs != nil {
		return errs[0]
	}
	if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
		return err
	}
	if reqError.Status != "success" {
		return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
	}
	return nil
}
func (p *PaloAlto) RenameObject(oldname, newname string, devicegroup ...string) error {
	var xpath string
	var reqError requestError
	adObj, _ := p.Addresses()
	agObj, _ := p.AddressGroups()
	sObj, _ := p.Services()
	sgObj, _ := p.ServiceGroups()
	tags, _ := p.Tags()
	for _, a := range adObj.Addresses {
		if oldname == a.Name {
			if p.DeviceType == "panos" {
				xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/address/entry[@name='%s']", oldname)
				_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=rename&xpath=%s&newname=%s&key=%s", xpath, newname, p.Key)).End()
				if errs != nil {
					return errs[0]
				}
				if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
					return err
				}
				if reqError.Status != "success" {
					return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
				}
				return nil
			}
			if p.DeviceType == "panorama" {
				if p.Shared == true {
					xpath = fmt.Sprintf("/config/shared/address/entry[@name='%s']", oldname)
				}
				if len(devicegroup) > 0 && devicegroup[0] == "shared" {
					xpath = fmt.Sprintf("/config/shared/address/entry[@name='%s']", oldname)
				}
				if p.Shared == false && len(devicegroup) > 0 && devicegroup[0] != "shared" {
					xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/address/entry[@name='%s']", devicegroup[0], oldname)
				}
				if p.Shared == false && len(devicegroup) <= 0 {
					return errors.New("you must specify a device-group when renaming objects on a Panorama device")
				}
				_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=rename&xpath=%s&newname=%s&key=%s", xpath, newname, p.Key)).End()
				if errs != nil {
					return errs[0]
				}
				if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
					return err
				}
				if reqError.Status != "success" {
					return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
				}
				return nil
			}
		}
	}
	for _, ag := range agObj.Groups {
		if oldname == ag.Name {
			if p.DeviceType == "panos" {
				xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/address-group/entry[@name='%s']", oldname)
				_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=rename&xpath=%s&newname=%s&key=%s", xpath, newname, p.Key)).End()
				if errs != nil {
					return errs[0]
				}
				if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
					return err
				}
				if reqError.Status != "success" {
					return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
				}
				return nil
			}
			if p.DeviceType == "panorama" {
				if p.Shared == true {
					xpath = fmt.Sprintf("/config/shared/address-group/entry[@name='%s']", oldname)
				}
				if len(devicegroup) > 0 && devicegroup[0] == "shared" {
					xpath = fmt.Sprintf("/config/shared/address-group/entry[@name='%s']", oldname)
				}
				if p.Shared == false && len(devicegroup) > 0 && devicegroup[0] != "shared" {
					xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/address-group/entry[@name='%s']", devicegroup[0], oldname)
				}
				if p.Shared == false && len(devicegroup) <= 0 {
					return errors.New("you must specify a device-group when renaming objects on a Panorama device")
				}
				_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=rename&xpath=%s&newname=%s&key=%s", xpath, newname, p.Key)).End()
				if errs != nil {
					return errs[0]
				}
				if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
					return err
				}
				if reqError.Status != "success" {
					return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
				}
				return nil
			}
		}
	}
	for _, s := range sObj.Services {
		if oldname == s.Name {
			if p.DeviceType == "panos" {
				xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/service/entry[@name='%s']", oldname)
				_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=rename&xpath=%s&newname=%s&key=%s", xpath, newname, p.Key)).End()
				if errs != nil {
					return errs[0]
				}
				if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
					return err
				}
				if reqError.Status != "success" {
					return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
				}
				return nil
			}
			if p.DeviceType == "panorama" {
				if p.Shared == true {
					xpath = fmt.Sprintf("/config/shared/service/entry[@name='%s']", oldname)
				}
				if len(devicegroup) > 0 && devicegroup[0] == "shared" {
					xpath = fmt.Sprintf("/config/shared/service/entry[@name='%s']", oldname)
				}
				if p.Shared == false && len(devicegroup) > 0 && devicegroup[0] != "shared" {
					xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/service/entry[@name='%s']", devicegroup[0], oldname)
				}
				if p.Shared == false && len(devicegroup) <= 0 {
					return errors.New("you must specify a device-group when renaming objects on a Panorama device")
				}
				_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=rename&xpath=%s&newname=%s&key=%s", xpath, newname, p.Key)).End()
				if errs != nil {
					return errs[0]
				}
				if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
					return err
				}
				if reqError.Status != "success" {
					return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
				}
				return nil
			}
		}
	}
	for _, sg := range sgObj.Groups {
		if oldname == sg.Name {
			if p.DeviceType == "panos" {
				xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/service-group/entry[@name='%s']", oldname)
				_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=rename&xpath=%s&newname=%s&key=%s", xpath, newname, p.Key)).End()
				if errs != nil {
					return errs[0]
				}
				if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
					return err
				}
				if reqError.Status != "success" {
					return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
				}
				return nil
			}
			if p.DeviceType == "panorama" {
				if p.Shared == true {
					xpath = fmt.Sprintf("/config/shared/service-group/entry[@name='%s']", oldname)
				}
				if len(devicegroup) > 0 && devicegroup[0] == "shared" {
					xpath = fmt.Sprintf("/config/shared/service-group/entry[@name='%s']", oldname)
				}
				if p.Shared == false && len(devicegroup) > 0 && devicegroup[0] != "shared" {
					xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/service-group/entry[@name='%s']", devicegroup[0], oldname)
				}
				if p.Shared == false && len(devicegroup) <= 0 {
					return errors.New("you must specify a device-group when renaming objects on a Panorama device")
				}
				_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=rename&xpath=%s&newname=%s&key=%s", xpath, newname, p.Key)).End()
				if errs != nil {
					return errs[0]
				}
				if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
					return err
				}
				if reqError.Status != "success" {
					return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
				}
				return nil
			}
		}
	}
	for _, t := range tags.Tags {
		if oldname == t.Name {
			if p.DeviceType == "panos" {
				xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/tag/entry[@name='%s']", oldname)
				_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=rename&xpath=%s&newname=%s&key=%s", xpath, newname, p.Key)).End()
				if errs != nil {
					return errs[0]
				}
				if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
					return err
				}
				if reqError.Status != "success" {
					return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
				}
				return nil
			}
			if p.DeviceType == "panorama" {
				if p.Shared == true {
					xpath = fmt.Sprintf("/config/shared/tag/entry[@name='%s']", oldname)
				}
				if len(devicegroup) > 0 && devicegroup[0] == "shared" {
					xpath = fmt.Sprintf("/config/shared/tag/entry[@name='%s']", oldname)
				}
				if p.Shared == false && len(devicegroup) > 0 && devicegroup[0] != "shared" {
					xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/tag/entry[@name='%s']", devicegroup[0], oldname)
				}
				if p.Shared == false && len(devicegroup) <= 0 {
					return errors.New("you must specify a device-group when renaming objects on a Panorama device")
				}
				_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=rename&xpath=%s&newname=%s&key=%s", xpath, newname, p.Key)).End()
				if errs != nil {
					return errs[0]
				}
				if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
					return err
				}
				if reqError.Status != "success" {
					return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
				}
				return nil
			}
		}
	}
	return nil
}
func (p *PaloAlto) CreateExternalDynamicList(listtype string, name string, url string, recurrance *Recurrance, devicegroup ...string) error {
	var xpath string
	var reqError requestError
	var xmlBody string
	var recurring string
	ver := splitSWVersion(p.SoftwareVersion)
	switch recurrance.Method {
	case "hourly":
		recurring = "<hourly/>"
	case "five-minute":
		recurring = "<five-minute/>"
	case "daily":
		recurring = fmt.Sprintf("<daily><at>%s</at></daily>", recurrance.Hour)
	case "weekly":
		recurring = fmt.Sprintf("<weekly><day-of-week>%s</day-of-week><at>%s</at></weekly>", recurrance.DayOfWeek, recurrance.Hour)
	case "monthly":
		recurring = fmt.Sprintf("<monthly><day-of-month>%d</day-of-month><at>%s</at></monthly>", recurrance.DayOfMonth, recurrance.Hour)
	}
	if ver[0] >= 8 {
		xmlBody = fmt.Sprintf("<type><%s><recurring>%s</recurring><url>%s</url></%s></type>", listtype, recurring, url, listtype)
	}
	if ver[0] <= 7 {
		xmlBody = fmt.Sprintf("<recurring>%s</recurring><url>%s</url><type>%s</type>", recurring, url, listtype)
	}
	if p.DeviceType == "panos" {
		xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/vsys/entry[@name='vsys1']/external-list/entry[@name='%s']", name)
	}
	if p.DeviceType == "panorama" && p.Shared == true {
		xpath = fmt.Sprintf("/config/shared/external-list/entry[@name='%s']", name)
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) > 0 {
		xpath = fmt.Sprintf("/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='%s']/external-list/entry[@name='%s']", devicegroup[0], name)
	}
	if p.DeviceType == "panorama" && p.Shared == false && len(devicegroup) <= 0 {
		return errors.New("you must specify a device-group when creating an external dynamic list on a Panorama device")
	}
	_, resp, errs := r.Post(p.URI).Query(fmt.Sprintf("type=config&action=set&xpath=%s&element=%s&key=%s", xpath, xmlBody, p.Key)).End()
	if errs != nil {
		return errs[0]
	}
	if err := xml.Unmarshal([]byte(resp), &reqError); err != nil {
		return err
	}
	if reqError.Status != "success" {
		return fmt.Errorf("error code %s: %s", reqError.Code, errorCodes[reqError.Code])
	}
	return nil
}