func decodeListObjectVersionsResult(result *ListObjectVersionsResult) error {
	var err error
	result.Delimiter, err = url.QueryUnescape(result.Delimiter)
	if err != nil {
		return err
	}
	result.Prefix, err = url.QueryUnescape(result.Prefix)
	if err != nil {
		return err
	}
	result.KeyMarker, err = url.QueryUnescape(result.KeyMarker)
	if err != nil {
		return err
	}
	result.VersionIdMarker, err = url.QueryUnescape(result.VersionIdMarker)
	if err != nil {
		return err
	}
	result.NextKeyMarker, err = url.QueryUnescape(result.NextKeyMarker)
	if err != nil {
		return err
	}
	result.NextVersionIdMarker, err = url.QueryUnescape(result.NextVersionIdMarker)
	if err != nil {
		return err
	}
	for i := 0; i < len(result.CommonPrefixes); i++ {
		result.CommonPrefixes[i], err = url.QueryUnescape(result.CommonPrefixes[i])
		if err != nil {
			return err
		}
	}
	for i := 0; i < len(result.ObjectDeleteMarkers); i++ {
		result.ObjectDeleteMarkers[i].Key, err = url.QueryUnescape(result.ObjectDeleteMarkers[i].Key)
		if err != nil {
			return err
		}
	}
	for i := 0; i < len(result.ObjectVersions); i++ {
		result.ObjectVersions[i].Key, err = url.QueryUnescape(result.ObjectVersions[i].Key)
		if err != nil {
			return err
		}
	}
	return nil
}
decodeListObjectVersionsResult decodes list version objects result in URL encoding
package oss
import (
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"net/url"
	"time"
)
type ListBucketsResult struct {
	XMLName     xml.Name           `xml:"ListAllMyBucketsResult"`
	Prefix      string             `xml:"Prefix"`          
	Marker      string             `xml:"Marker"`          
	MaxKeys     int                `xml:"MaxKeys"`         
	IsTruncated bool               `xml:"IsTruncated"`     
	NextMarker  string             `xml:"NextMarker"`      
	Owner       Owner              `xml:"Owner"`           
	Buckets     []BucketProperties `xml:"Buckets>Bucket"`  
}
type BucketProperties struct {
	XMLName      xml.Name  `xml:"Bucket"`
	Name         string    `xml:"Name"`          
	Location     string    `xml:"Location"`      
	CreationDate time.Time `xml:"CreationDate"`  
	StorageClass string    `xml:"StorageClass"`  
}
type GetBucketACLResult struct {
	XMLName xml.Name `xml:"AccessControlPolicy"`
	ACL     string   `xml:"AccessControlList>Grant"`  
	Owner   Owner    `xml:"Owner"`                    
}
type LifecycleConfiguration struct {
	XMLName xml.Name        `xml:"LifecycleConfiguration"`
	Rules   []LifecycleRule `xml:"Rule"`
}
type LifecycleRule struct {
	XMLName              xml.Name                       `xml:"Rule"`
	ID                   string                         `xml:"ID,omitempty"`                    
	Prefix               string                         `xml:"Prefix"`                          
	Status               string                         `xml:"Status"`                          
	Tags                 []Tag                          `xml:"Tag,omitempty"`                   
	Expiration           *LifecycleExpiration           `xml:"Expiration,omitempty"`            
	Transitions          []LifecycleTransition          `xml:"Transition,omitempty"`            
	AbortMultipartUpload *LifecycleAbortMultipartUpload `xml:"AbortMultipartUpload,omitempty"`  
	NonVersionExpiration *LifecycleVersionExpiration    `xml:"NoncurrentVersionExpiration,omitempty"`
	NonVersionTransition *LifecycleVersionTransition    `xml:"NoncurrentVersionTransition,omitempty"`
}
type LifecycleExpiration struct {
	XMLName                   xml.Name `xml:"Expiration"`
	Days                      int      `xml:"Days,omitempty"`                       
	Date                      string   `xml:"Date,omitempty"`                       
	CreatedBeforeDate         string   `xml:"CreatedBeforeDate,omitempty"`          
	ExpiredObjectDeleteMarker *bool    `xml:"ExpiredObjectDeleteMarker,omitempty"`  
}
type LifecycleTransition struct {
	XMLName           xml.Name         `xml:"Transition"`
	Days              int              `xml:"Days,omitempty"`               
	CreatedBeforeDate string           `xml:"CreatedBeforeDate,omitempty"`  
	StorageClass      StorageClassType `xml:"StorageClass,omitempty"`       
}
type LifecycleAbortMultipartUpload struct {
	XMLName           xml.Name `xml:"AbortMultipartUpload"`
	Days              int      `xml:"Days,omitempty"`               
	CreatedBeforeDate string   `xml:"CreatedBeforeDate,omitempty"`  
}
type LifecycleVersionExpiration struct {
	XMLName        xml.Name `xml:"NoncurrentVersionExpiration"`
	NoncurrentDays int      `xml:"NoncurrentDays,omitempty"`  
}
type LifecycleVersionTransition struct {
	XMLName        xml.Name         `xml:"NoncurrentVersionTransition"`
	NoncurrentDays int              `xml:"NoncurrentDays,omitempty"`  
	StorageClass   StorageClassType `xml:"StorageClass,omitempty"`
}
const iso8601DateFormat = "2006-01-02T15:04:05.000Z"
func BuildLifecycleRuleByDays(id, prefix string, status bool, days int) LifecycleRule {
	var statusStr = "Enabled"
	if !status {
		statusStr = "Disabled"
	}
	return LifecycleRule{ID: id, Prefix: prefix, Status: statusStr,
		Expiration: &LifecycleExpiration{Days: days}}
}
func BuildLifecycleRuleByDate(id, prefix string, status bool, year, month, day int) LifecycleRule {
	var statusStr = "Enabled"
	if !status {
		statusStr = "Disabled"
	}
	date := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC).Format(iso8601DateFormat)
	return LifecycleRule{ID: id, Prefix: prefix, Status: statusStr,
		Expiration: &LifecycleExpiration{Date: date}}
}
func verifyLifecycleRules(rules []LifecycleRule) error {
	if len(rules) == 0 {
		return fmt.Errorf("invalid rules, the length of rules is zero")
	}
	for _, rule := range rules {
		if rule.Status != "Enabled" && rule.Status != "Disabled" {
			return fmt.Errorf("invalid rule, the value of status must be Enabled or Disabled")
		}
		abortMPU := rule.AbortMultipartUpload
		if abortMPU != nil {
			if (abortMPU.Days != 0 && abortMPU.CreatedBeforeDate != "") || (abortMPU.Days == 0 && abortMPU.CreatedBeforeDate == "") {
				return fmt.Errorf("invalid abort multipart upload lifecycle, must be set one of CreatedBeforeDate and Days")
			}
		}
		transitions := rule.Transitions
		if len(transitions) > 0 {
			if len(transitions) > 2 {
				return fmt.Errorf("invalid count of transition lifecycles, the count must than less than 3")
			}
			for _, transition := range transitions {
				if (transition.Days != 0 && transition.CreatedBeforeDate != "") || (transition.Days == 0 && transition.CreatedBeforeDate == "") {
					return fmt.Errorf("invalid transition lifecycle, must be set one of CreatedBeforeDate and Days")
				}
				if transition.StorageClass != StorageIA && transition.StorageClass != StorageArchive {
					return fmt.Errorf("invalid transition lifecylce, the value of storage class must be IA or Archive")
				}
			}
		} else if rule.Expiration == nil && abortMPU == nil && rule.NonVersionExpiration == nil && rule.NonVersionTransition == nil {
			return fmt.Errorf("invalid rule, must set one of Expiration, AbortMultipartUplaod, NonVersionExpiration, NonVersionTransition and Transitions")
		}
	}
	return nil
}
type GetBucketLifecycleResult LifecycleConfiguration
type RefererXML struct {
	XMLName           xml.Name `xml:"RefererConfiguration"`
	AllowEmptyReferer bool     `xml:"AllowEmptyReferer"`    
	RefererList       []string `xml:"RefererList>Referer"`  
}
type GetBucketRefererResult RefererXML
type LoggingXML struct {
	XMLName        xml.Name       `xml:"BucketLoggingStatus"`
	LoggingEnabled LoggingEnabled `xml:"LoggingEnabled"`  
}
type loggingXMLEmpty struct {
	XMLName xml.Name `xml:"BucketLoggingStatus"`
}
type LoggingEnabled struct {
	XMLName      xml.Name `xml:"LoggingEnabled"`
	TargetBucket string   `xml:"TargetBucket"`  
	TargetPrefix string   `xml:"TargetPrefix"`  
}
type GetBucketLoggingResult LoggingXML
type WebsiteXML struct {
	XMLName       xml.Name      `xml:"WebsiteConfiguration"`
	IndexDocument IndexDocument `xml:"IndexDocument,omitempty"`             
	ErrorDocument ErrorDocument `xml:"ErrorDocument,omitempty"`             
	RoutingRules  []RoutingRule `xml:"RoutingRules>RoutingRule,omitempty"`  
}
type IndexDocument struct {
	XMLName xml.Name `xml:"IndexDocument"`
	Suffix  string   `xml:"Suffix"`  
}
type ErrorDocument struct {
	XMLName xml.Name `xml:"ErrorDocument"`
	Key     string   `xml:"Key"`  
}
type RoutingRule struct {
	XMLName    xml.Name  `xml:"RoutingRule"`
	RuleNumber int       `xml:"RuleNumber,omitempty"`  
	Condition  Condition `xml:"Condition,omitempty"`   
	Redirect   Redirect  `xml:"Redirect,omitempty"`    
}
type Condition struct {
	XMLName                     xml.Name        `xml:"Condition"`
	KeyPrefixEquals             string          `xml:"KeyPrefixEquals,omitempty"`              
	HTTPErrorCodeReturnedEquals int             `xml:"HttpErrorCodeReturnedEquals,omitempty"`  
	IncludeHeader               []IncludeHeader `xml:"IncludeHeader"`                          
}
type IncludeHeader struct {
	XMLName xml.Name `xml:"IncludeHeader"`
	Key     string   `xml:"Key,omitempty"`     
	Equals  string   `xml:"Equals,omitempty"`  
}
type Redirect struct {
	XMLName               xml.Name      `xml:"Redirect"`
	RedirectType          string        `xml:"RedirectType,omitempty"`          
	PassQueryString       *bool         `xml:"PassQueryString"`                 
	MirrorURL             string        `xml:"MirrorURL,omitempty"`             
	MirrorPassQueryString *bool         `xml:"MirrorPassQueryString"`           
	MirrorFollowRedirect  *bool         `xml:"MirrorFollowRedirect"`            
	MirrorCheckMd5        *bool         `xml:"MirrorCheckMd5"`                  
	MirrorHeaders         MirrorHeaders `xml:"MirrorHeaders,omitempty"`         
	Protocol              string        `xml:"Protocol,omitempty"`              
	HostName              string        `xml:"HostName,omitempty"`              
	ReplaceKeyPrefixWith  string        `xml:"ReplaceKeyPrefixWith,omitempty"`  
	HttpRedirectCode      int           `xml:"HttpRedirectCode,omitempty"`      
	ReplaceKeyWith        string        `xml:"ReplaceKeyWith,omitempty"`        
}
type MirrorHeaders struct {
	XMLName xml.Name          `xml:"MirrorHeaders"`
	PassAll *bool             `xml:"PassAll"`  
	Pass    []string          `xml:"Pass"`     
	Remove  []string          `xml:"Remove"`   
	Set     []MirrorHeaderSet `xml:"Set"`      
}
type MirrorHeaderSet struct {
	XMLName xml.Name `xml:"Set"`
	Key     string   `xml:"Key,omitempty"`    
	Value   string   `xml:"Value,omitempty"`  
}
type GetBucketWebsiteResult WebsiteXML
type CORSXML struct {
	XMLName   xml.Name   `xml:"CORSConfiguration"`
	CORSRules []CORSRule `xml:"CORSRule"`  
}
type CORSRule struct {
	XMLName       xml.Name `xml:"CORSRule"`
	AllowedOrigin []string `xml:"AllowedOrigin"`  
	AllowedMethod []string `xml:"AllowedMethod"`  
	AllowedHeader []string `xml:"AllowedHeader"`  
	ExposeHeader  []string `xml:"ExposeHeader"`   
	MaxAgeSeconds int      `xml:"MaxAgeSeconds"`  
}
type GetBucketCORSResult CORSXML
type GetBucketInfoResult struct {
	XMLName    xml.Name   `xml:"BucketInfo"`
	BucketInfo BucketInfo `xml:"Bucket"`
}
type BucketInfo struct {
	XMLName          xml.Name  `xml:"Bucket"`
	Name             string    `xml:"Name"`                      
	Location         string    `xml:"Location"`                  
	CreationDate     time.Time `xml:"CreationDate"`              
	ExtranetEndpoint string    `xml:"ExtranetEndpoint"`          
	IntranetEndpoint string    `xml:"IntranetEndpoint"`          
	ACL              string    `xml:"AccessControlList>Grant"`   
	RedundancyType   string    `xml:"DataRedundancyType"`        
	Owner            Owner     `xml:"Owner"`                     
	StorageClass     string    `xml:"StorageClass"`              
	SseRule          SSERule   `xml:"ServerSideEncryptionRule"`  
	Versioning       string    `xml:"Versioning"`                
}
type SSERule struct {
	XMLName        xml.Name `xml:"ServerSideEncryptionRule"`  
	KMSMasterKeyID string   `xml:"KMSMasterKeyID"`            
	SSEAlgorithm   string   `xml:"SSEAlgorithm"`              
}
type ListObjectsResult struct {
	XMLName        xml.Name           `xml:"ListBucketResult"`
	Prefix         string             `xml:"Prefix"`                 
	Marker         string             `xml:"Marker"`                 
	MaxKeys        int                `xml:"MaxKeys"`                
	Delimiter      string             `xml:"Delimiter"`              
	IsTruncated    bool               `xml:"IsTruncated"`            
	NextMarker     string             `xml:"NextMarker"`             
	Objects        []ObjectProperties `xml:"Contents"`               
	CommonPrefixes []string           `xml:"CommonPrefixes>Prefix"`  
}
type ObjectProperties struct {
	XMLName      xml.Name  `xml:"Contents"`
	Key          string    `xml:"Key"`           
	Type         string    `xml:"Type"`          
	Size         int64     `xml:"Size"`          
	ETag         string    `xml:"ETag"`          
	Owner        Owner     `xml:"Owner"`         
	LastModified time.Time `xml:"LastModified"`  
	StorageClass string    `xml:"StorageClass"`  
}
type ListObjectVersionsResult struct {
	XMLName             xml.Name                       `xml:"ListVersionsResult"`
	Name                string                         `xml:"Name"`                   
	Owner               Owner                          `xml:"Owner"`                  
	Prefix              string                         `xml:"Prefix"`                 
	KeyMarker           string                         `xml:"KeyMarker"`              
	VersionIdMarker     string                         `xml:"VersionIdMarker"`        
	MaxKeys             int                            `xml:"MaxKeys"`                
	Delimiter           string                         `xml:"Delimiter"`              
	IsTruncated         bool                           `xml:"IsTruncated"`            
	NextKeyMarker       string                         `xml:"NextKeyMarker"`          
	NextVersionIdMarker string                         `xml:"NextVersionIdMarker"`    
	CommonPrefixes      []string                       `xml:"CommonPrefixes>Prefix"`  
	ObjectDeleteMarkers []ObjectDeleteMarkerProperties `xml:"DeleteMarker"`           
	ObjectVersions      []ObjectVersionProperties      `xml:"Version"`                
}
type ObjectDeleteMarkerProperties struct {
	XMLName      xml.Name  `xml:"DeleteMarker"`
	Key          string    `xml:"Key"`           
	VersionId    string    `xml:"VersionId"`     
	IsLatest     bool      `xml:"IsLatest"`      
	LastModified time.Time `xml:"LastModified"`  
	Owner        Owner     `xml:"Owner"`         
}
type ObjectVersionProperties struct {
	XMLName      xml.Name  `xml:"Version"`
	Key          string    `xml:"Key"`           
	VersionId    string    `xml:"VersionId"`     
	IsLatest     bool      `xml:"IsLatest"`      
	LastModified time.Time `xml:"LastModified"`  
	Type         string    `xml:"Type"`          
	Size         int64     `xml:"Size"`          
	ETag         string    `xml:"ETag"`          
	StorageClass string    `xml:"StorageClass"`  
	Owner        Owner     `xml:"Owner"`         
}
type Owner struct {
	XMLName     xml.Name `xml:"Owner"`
	ID          string   `xml:"ID"`           
	DisplayName string   `xml:"DisplayName"`  
}
type CopyObjectResult struct {
	XMLName      xml.Name  `xml:"CopyObjectResult"`
	LastModified time.Time `xml:"LastModified"`  
	ETag         string    `xml:"ETag"`          
}
type GetObjectACLResult GetBucketACLResult
type deleteXML struct {
	XMLName xml.Name       `xml:"Delete"`
	Objects []DeleteObject `xml:"Object"`  
	Quiet   bool           `xml:"Quiet"`   
}
type DeleteObject struct {
	XMLName   xml.Name `xml:"Object"`
	Key       string   `xml:"Key"`                  
	VersionId string   `xml:"VersionId,omitempty"`  
}
type DeleteObjectsResult struct {
	XMLName        xml.Name
	DeletedObjects []string  
}
type DeleteObjectVersionsResult struct {
	XMLName              xml.Name         `xml:"DeleteResult"`
	DeletedObjectsDetail []DeletedKeyInfo `xml:"Deleted"`  
}
type DeletedKeyInfo struct {
	XMLName               xml.Name `xml:"Deleted"`
	Key                   string   `xml:"Key"`                    
	VersionId             string   `xml:"VersionId"`              
	DeleteMarker          bool     `xml:"DeleteMarker"`           
	DeleteMarkerVersionId string   `xml:"DeleteMarkerVersionId"`  
}
type InitiateMultipartUploadResult struct {
	XMLName  xml.Name `xml:"InitiateMultipartUploadResult"`
	Bucket   string   `xml:"Bucket"`    
	Key      string   `xml:"Key"`       
	UploadID string   `xml:"UploadId"`  
}
type UploadPart struct {
	XMLName    xml.Name `xml:"Part"`
	PartNumber int      `xml:"PartNumber"`  
	ETag       string   `xml:"ETag"`        
}
type uploadParts []UploadPart
func (slice uploadParts) Len() int {
	return len(slice)
}
func (slice uploadParts) Less(i, j int) bool {
	return slice[i].PartNumber < slice[j].PartNumber
}
func (slice uploadParts) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}
type UploadPartCopyResult struct {
	XMLName      xml.Name  `xml:"CopyPartResult"`
	LastModified time.Time `xml:"LastModified"`  
	ETag         string    `xml:"ETag"`          
}
type completeMultipartUploadXML struct {
	XMLName xml.Name     `xml:"CompleteMultipartUpload"`
	Part    []UploadPart `xml:"Part"`
}
type CompleteMultipartUploadResult struct {
	XMLName  xml.Name `xml:"CompleteMultipartUploadResult"`
	Location string   `xml:"Location"`  
	Bucket   string   `xml:"Bucket"`    
	ETag     string   `xml:"ETag"`      
	Key      string   `xml:"Key"`       
}
type ListUploadedPartsResult struct {
	XMLName              xml.Name       `xml:"ListPartsResult"`
	Bucket               string         `xml:"Bucket"`                
	Key                  string         `xml:"Key"`                   
	UploadID             string         `xml:"UploadId"`              
	NextPartNumberMarker string         `xml:"NextPartNumberMarker"`  
	MaxParts             int            `xml:"MaxParts"`              
	IsTruncated          bool           `xml:"IsTruncated"`           
	UploadedParts        []UploadedPart `xml:"Part"`                  
}
type UploadedPart struct {
	XMLName      xml.Name  `xml:"Part"`
	PartNumber   int       `xml:"PartNumber"`    
	LastModified time.Time `xml:"LastModified"`  
	ETag         string    `xml:"ETag"`          
	Size         int       `xml:"Size"`          
}
type ListMultipartUploadResult struct {
	XMLName            xml.Name            `xml:"ListMultipartUploadsResult"`
	Bucket             string              `xml:"Bucket"`                 
	Delimiter          string              `xml:"Delimiter"`              
	Prefix             string              `xml:"Prefix"`                 
	KeyMarker          string              `xml:"KeyMarker"`              
	UploadIDMarker     string              `xml:"UploadIdMarker"`         
	NextKeyMarker      string              `xml:"NextKeyMarker"`          
	NextUploadIDMarker string              `xml:"NextUploadIdMarker"`     
	MaxUploads         int                 `xml:"MaxUploads"`             
	IsTruncated        bool                `xml:"IsTruncated"`            
	Uploads            []UncompletedUpload `xml:"Upload"`                 
	CommonPrefixes     []string            `xml:"CommonPrefixes>Prefix"`  
}
type UncompletedUpload struct {
	XMLName   xml.Name  `xml:"Upload"`
	Key       string    `xml:"Key"`        
	UploadID  string    `xml:"UploadId"`   
	Initiated time.Time `xml:"Initiated"`  
}
type ProcessObjectResult struct {
	Bucket   string `json:"bucket"`
	FileSize int    `json:"fileSize"`
	Object   string `json:"object"`
	Status   string `json:"status"`
}
func decodeDeleteObjectsResult(result *DeleteObjectVersionsResult) error {
	var err error
	for i := 0; i < len(result.DeletedObjectsDetail); i++ {
		result.DeletedObjectsDetail[i].Key, err = url.QueryUnescape(result.DeletedObjectsDetail[i].Key)
		if err != nil {
			return err
		}
	}
	return nil
}
func decodeListObjectsResult(result *ListObjectsResult) error {
	var err error
	result.Prefix, err = url.QueryUnescape(result.Prefix)
	if err != nil {
		return err
	}
	result.Marker, err = url.QueryUnescape(result.Marker)
	if err != nil {
		return err
	}
	result.Delimiter, err = url.QueryUnescape(result.Delimiter)
	if err != nil {
		return err
	}
	result.NextMarker, err = url.QueryUnescape(result.NextMarker)
	if err != nil {
		return err
	}
	for i := 0; i < len(result.Objects); i++ {
		result.Objects[i].Key, err = url.QueryUnescape(result.Objects[i].Key)
		if err != nil {
			return err
		}
	}
	for i := 0; i < len(result.CommonPrefixes); i++ {
		result.CommonPrefixes[i], err = url.QueryUnescape(result.CommonPrefixes[i])
		if err != nil {
			return err
		}
	}
	return nil
}