<commit_before>package ncp

import (
	"regexp"
	"strconv"
	"strings"
)

func (t *Topic) getRating() float64 {
	var (
		reRating = regexp.MustCompile(`>(\d,\d|\d)<\/span>.+?\(Голосов:`)
		rating   float64
	)
	if reRating.Match(t.Body) == true {
		str := string(reRating.FindSubmatch(t.Body)[1])
		str = strings.Replace(str, ",", ".", -1)
		rating, _ = strconv.ParseFloat(str, 64)
	}
	return rating
}

func (t *Topic) getSize() int64 {
	var (
		reSize = regexp.MustCompile(`Размер блока: \d.+?B"> (\d{1,2},\d{1,2}|\d{3,4}|\d{1,2})\s`)
		size   int64
	)
	if reSize.Match(t.Body) == true {
		str := string(reSize.FindSubmatch(t.Body)[1])
		str = strings.Replace(str, ",", ".", -1)
		if s64, err := strconv.ParseFloat(str, 64); err == nil {
			if s64 < 100 {
				s64 = s64 * 1000
			}
			size = int64(s64)
		}
	}
	return size
}

func (t *Topic) getTorrent() string {
	var (
		reTor   = regexp.MustCompile(`<a href="download\.php\?id=(\d{5,7})" rel="nofollow">Скачать<`)
		torrent string
	)
	if reTor.Match(t.Body) == true {
		findTor := reTor.FindSubmatch(t.Body)
		torrent = "http://nnm-club.me/forum/download.php?id=" + string(findTor[1])
	}
	return torrent
}

func (t *Topic) getPoster() string {
	var (
		rePos = regexp.MustCompile(`"postImg postImgAligned img-right" title="http:\/\/assets\.nnm-club\.ws\/forum\/image\.php\?link=(.+?jpe{0,1}g)`)
		image string
	)
	if rePos.Match(t.Body) == true {
		image = string(rePos.FindSubmatch(t.Body)[1])
	}
	return image
}

func (t *Topic) getDate() string {
	var (
		reDate = regexp.MustCompile(`> (\d{1,2} .{3} \d{4}).{9}<`)
		date   string
	)
	if reDate.Match(t.Body) == true {
		date = replaceDate(string(reDate.FindSubmatch(t.Body)[1]))
	}
	return date
}

func (t *Topic) getSeeds() int64 {
	var (
		reSs  = regexp.MustCompile(`<span class="seed">\[ <b>(\d{1,5})\s`)
		seeds int64
	)
	if reSs.Match(t.Body) == true {
		ss := reSs.FindSubmatch(t.Body)
		seeds, _ = strconv.ParseInt(string(ss[1]), 10, 64)
	}
	return seeds
}

func (t *Topic) getLeechs() int64 {
	var (
		reLs   = regexp.MustCompile(`<span class="leech">\[ <b>(\d{1,5})\s`)
		leechs int64
	)
	if reLs.Match(t.Body) == true {
		ls := reLs.FindSubmatch(t.Body)
		leechs, _ = strconv.ParseInt(string(ls[1]), 10, 64)
	}
	return leechs
}

func getResolution(str string) string {
	var (
		reRes      = regexp.MustCompile(`(\d{3,4}x\d{3,4}|\d{3,4}X\d{3,4}|\d{3,4}х\d{3,4}|\d{3,4}Х\d{3,4})`)
		resolution string
	)
	if reRes.MatchString(str) == true {
		resolution = reRes.FindString(str)
	}
	return resolution
}

func (t *Topic) getCountry() string {
	var (
		reCountry = regexp.MustCompile(`<span style="font-weight: bold">Производство:\s*<\/span>(.+?)<`)
		country   string
	)
	if reCountry.Match(t.Body) == true {
		country = string(reCountry.FindSubmatch(t.Body)[1])
		country = cleanStr(country)
	}
	return country
}

func (t *Topic) getGenre() string {
	var (
		reGenre = regexp.MustCompile(`<span style="font-weight: bold">Жанр:\s*<\/span>(.+?)<`)
		genre   string
	)
	if reGenre.Match(t.Body) == true {
		genre = string(reGenre.FindSubmatch(t.Body)[1])
		genre = strings.ToLower(cleanStr(genre))
	}
	return genre
}

func (t *Topic) getDirector() string {
	var (
		reDirector = regexp.MustCompile(`<span style="font-weight: bold">Режиссер:\s*<\/span>(.+?)<`)
		director   string
	)
	if reDirector.Match(t.Body) == true {
		director = string(reDirector.FindSubmatch(t.Body)[1])
		director = cleanStr(director)
	}
	return director
}

func (t *Topic) getProducer() string {
	var (
		reProducer = regexp.MustCompile(`<span style="font-weight: bold">Продюсер:\s*<\/span>(.+?)<`)
		producer   string
	)
	if reProducer.Match(t.Body) == true {
		producer = string(reProducer.FindSubmatch(t.Body)[1])
		producer = cleanStr(producer)
	}
	return producer
}

func (t *Topic) getActors() string {
	var (
		reActors = regexp.MustCompile(`<span style="font-weight: bold">Актеры:\s*<\/span>(.+?)<`)
		actors   string
	)
	if reActors.Match(t.Body) == true {
		actors = string(reActors.FindSubmatch(t.Body)[1])
		actors = cleanStr(actors)
	}
	return actors
}

func (t *Topic) getDescription() string {
	var (
		reDescription = regexp.MustCompile(`<span style="font-weight: bold">(?:Описание фильма|Описание):\s*<\/span>(.+?)<`)
		description   string
	)
	if reDescription.Match(t.Body) == true {
		description = string(reDescription.FindSubmatch(t.Body)[1])
		description = cleanStr(description)
	}
	return description
}

func (t *Topic) getAge() string {
	var (
		reAge = regexp.MustCompile(`<span style="font-weight: bold">Возраст:\s*<\/span>(.+?)<`)
		age   string
	)
	if reAge.Match(t.Body) == true {
		age = string(reAge.FindSubmatch(t.Body)[1])
		age = cleanStr(age)
	}
	return age
}

func (t *Topic) getReleaseDate() string {
	var (
		reReleaseDate = regexp.MustCompile(`<span style="font-weight: bold">Дата мировой премьеры:\s*<\/span>(.+?)<`)
		releaseDate   string
	)
	if reReleaseDate.Match(t.Body) == true {
		releaseDate = string(reReleaseDate.FindSubmatch(t.Body)[1])
		releaseDate = cleanStr(releaseDate)
		releaseDate = replaceDate(releaseDate)
	}
	return releaseDate
}

func (t *Topic) getRussianDate() string {
	var (
		reRussianDate = regexp.MustCompile(`<span style="font-weight: bold">(?:Дата премьеры в России|Дата Российской премьеры|Дата российской премьеры):\s*<\/span>(.+?)<`)
		russianDate   string
	)
	if reRussianDate.Match(t.Body) == true {
		russianDate = string(reRussianDate.FindSubmatch(t.Body)[1])
		russianDate = cleanStr(russianDate)
		russianDate = replaceDate(russianDate)
	}
	return russianDate
}

func (t *Topic) getDuration() string {
	var (
		reDuration = regexp.MustCompile(`<span style="font-weight: bold">Продолжительность:\s*<\/span>(.+?)<`)
		duration   string
	)
	if reDuration.Match(t.Body) == true {
		duration = string(reDuration.FindSubmatch(t.Body)[1])
		duration = cleanStr(duration)
	}
	return duration
}

func (t *Topic) getQuality() string {
	var (
		reQuality = regexp.MustCompile(`<span style="font-weight: bold">(?:Качество видео|Качество):\s*<\/span>(.+?)<`)
		quality   string
	)
	if reQuality.Match(t.Body) == true {
		quality = string(reQuality.FindSubmatch(t.Body)[1])
		quality = cleanStr(quality)
	}
	return quality
}

func (t *Topic) getTranslation() string {
	var (
		reTranslation = regexp.MustCompile(`<span style="font-weight: bold">Перевод:\s*<\/span>(.+?)<`)
		translation   string
	)
	if reTranslation.Match(t.Body) == true {
		translation = string(reTranslation.FindSubmatch(t.Body)[1])
		translation = cleanStr(translation)
		if caseInsensitiveContains(translation, "не требуется") == true {
			translation = "Не требуется"
		}
	}
	return translation
}

func (t *Topic) getSubtitlesType() string {
	var (
		reSubtitlesType = regexp.MustCompile(`<span style="font-weight: bold">Вид субтитров:\s*<\/span>(.+?)<`)
		subtitlesType   string
	)
	if reSubtitlesType.Match(t.Body) == true {
		subtitlesType = string(reSubtitlesType.FindSubmatch(t.Body)[1])
		subtitlesType = cleanStr(subtitlesType)
	}
	return subtitlesType
}

func (t *Topic) getSubtitles() string {
	var (
		reSubtitles = regexp.MustCompile(`<span style="font-weight: bold">Субтитры:\s*<\/span>(.+?)<`)
		subtitles   string
	)
	if reSubtitles.Match(t.Body) == true {
		subtitles = string(reSubtitles.FindSubmatch(t.Body)[1])
		subtitles = cleanStr(subtitles)
	}
	return subtitles
}

func (t *Topic) getVideo() string {
	var (
		reVideo = regexp.MustCompile(`<span style="font-weight: bold">Видео:\s*<\/span>(.+?)<`)
		video   string
	)
	if reVideo.Match(t.Body) == true {
		video = string(reVideo.FindSubmatch(t.Body)[1])
		video = cleanStr(video)
	}
	return video
}

func (t *Topic) getAudio1() string {
	var (
		reAudio = regexp.MustCompile(`<span style="font-weight: bold">(?:Аудио\s?:\s*|Аудио\s?.?1.?:\s*)<\/span>(.+?)<`)
		audio   string
	)
	if reAudio.Match(t.Body) == true {
		audio = string(reAudio.FindSubmatch(t.Body)[1])
		audio = cleanStr(audio)
	}
	return audio
}

func (t *Topic) getAudio2() string {
	var (
		reAudio = regexp.MustCompile(`<span style="font-weight: bold">Аудио\s?.?2.?:\s*<\/span>(.+?)<`)
		audio   string
	)
	if reAudio.Match(t.Body) == true {
		audio = string(reAudio.FindSubmatch(t.Body)[1])
		audio = cleanStr(audio)
	}
	return audio
}

func (t *Topic) getAudio3() string {
	var (
		reAudio = regexp.MustCompile(`<span style="font-weight: bold">Аудио\s?.?3.?:\s*<\/span>(.+?)<`)
		audio   string
	)
	if reAudio.Match(t.Body) == true {
		audio = string(reAudio.FindSubmatch(t.Body)[1])
		audio = cleanStr(audio)
	}
	return audio
}
<commit_msg>fix translation<commit_after>package ncp

import (
	"regexp"
	"strconv"
	"strings"
)

func (t *Topic) getRating() float64 {
	var (
		reRating = regexp.MustCompile(`>(\d,\d|\d)<\/span>.+?\(Голосов:`)
		rating   float64
	)
	if reRating.Match(t.Body) == true {
		str := string(reRating.FindSubmatch(t.Body)[1])
		str = strings.Replace(str, ",", ".", -1)
		rating, _ = strconv.ParseFloat(str, 64)
	}
	return rating
}

func (t *Topic) getSize() int64 {
	var (
		reSize = regexp.MustCompile(`Размер блока: \d.+?B"> (\d{1,2},\d{1,2}|\d{3,4}|\d{1,2})\s`)
		size   int64
	)
	if reSize.Match(t.Body) == true {
		str := string(reSize.FindSubmatch(t.Body)[1])
		str = strings.Replace(str, ",", ".", -1)
		if s64, err := strconv.ParseFloat(str, 64); err == nil {
			if s64 < 100 {
				s64 = s64 * 1000
			}
			size = int64(s64)
		}
	}
	return size
}

func (t *Topic) getTorrent() string {
	var (
		reTor   = regexp.MustCompile(`<a href="download\.php\?id=(\d{5,7})" rel="nofollow">Скачать<`)
		torrent string
	)
	if reTor.Match(t.Body) == true {
		findTor := reTor.FindSubmatch(t.Body)
		torrent = "http://nnm-club.me/forum/download.php?id=" + string(findTor[1])
	}
	return torrent
}

func (t *Topic) getPoster() string {
	var (
		rePos = regexp.MustCompile(`"postImg postImgAligned img-right" title="http:\/\/assets\.nnm-club\.ws\/forum\/image\.php\?link=(.+?jpe{0,1}g)`)
		image string
	)
	if rePos.Match(t.Body) == true {
		image = string(rePos.FindSubmatch(t.Body)[1])
	}
	return image
}

func (t *Topic) getDate() string {
	var (
		reDate = regexp.MustCompile(`> (\d{1,2} .{3} \d{4}).{9}<`)
		date   string
	)
	if reDate.Match(t.Body) == true {
		date = replaceDate(string(reDate.FindSubmatch(t.Body)[1]))
	}
	return date
}

func (t *Topic) getSeeds() int64 {
	var (
		reSs  = regexp.MustCompile(`<span class="seed">\[ <b>(\d{1,5})\s`)
		seeds int64
	)
	if reSs.Match(t.Body) == true {
		ss := reSs.FindSubmatch(t.Body)
		seeds, _ = strconv.ParseInt(string(ss[1]), 10, 64)
	}
	return seeds
}

func (t *Topic) getLeechs() int64 {
	var (
		reLs   = regexp.MustCompile(`<span class="leech">\[ <b>(\d{1,5})\s`)
		leechs int64
	)
	if reLs.Match(t.Body) == true {
		ls := reLs.FindSubmatch(t.Body)
		leechs, _ = strconv.ParseInt(string(ls[1]), 10, 64)
	}
	return leechs
}

func getResolution(str string) string {
	var (
		reRes      = regexp.MustCompile(`(\d{3,4}x\d{3,4}|\d{3,4}X\d{3,4}|\d{3,4}х\d{3,4}|\d{3,4}Х\d{3,4})`)
		resolution string
	)
	if reRes.MatchString(str) == true {
		resolution = reRes.FindString(str)
	}
	return resolution
}

func (t *Topic) getCountry() string {
	var (
		reCountry = regexp.MustCompile(`<span style="font-weight: bold">Производство:\s*<\/span>(.+?)<`)
		country   string
	)
	if reCountry.Match(t.Body) == true {
		country = string(reCountry.FindSubmatch(t.Body)[1])
		country = cleanStr(country)
	}
	return country
}

func (t *Topic) getGenre() string {
	var (
		reGenre = regexp.MustCompile(`<span style="font-weight: bold">Жанр:\s*<\/span>(.+?)<`)
		genre   string
	)
	if reGenre.Match(t.Body) == true {
		genre = string(reGenre.FindSubmatch(t.Body)[1])
		genre = strings.ToLower(cleanStr(genre))
	}
	return genre
}

func (t *Topic) getDirector() string {
	var (
		reDirector = regexp.MustCompile(`<span style="font-weight: bold">Режиссер:\s*<\/span>(.+?)<`)
		director   string
	)
	if reDirector.Match(t.Body) == true {
		director = string(reDirector.FindSubmatch(t.Body)[1])
		director = cleanStr(director)
	}
	return director
}

func (t *Topic) getProducer() string {
	var (
		reProducer = regexp.MustCompile(`<span style="font-weight: bold">Продюсер:\s*<\/span>(.+?)<`)
		producer   string
	)
	if reProducer.Match(t.Body) == true {
		producer = string(reProducer.FindSubmatch(t.Body)[1])
		producer = cleanStr(producer)
	}
	return producer
}

func (t *Topic) getActors() string {
	var (
		reActors = regexp.MustCompile(`<span style="font-weight: bold">Актеры:\s*<\/span>(.+?)<`)
		actors   string
	)
	if reActors.Match(t.Body) == true {
		actors = string(reActors.FindSubmatch(t.Body)[1])
		actors = cleanStr(actors)
	}
	return actors
}

func (t *Topic) getDescription() string {
	var (
		reDescription = regexp.MustCompile(`<span style="font-weight: bold">(?:Описание фильма|Описание):\s*<\/span>(.+?)<`)
		description   string
	)
	if reDescription.Match(t.Body) == true {
		description = string(reDescription.FindSubmatch(t.Body)[1])
		description = cleanStr(description)
	}
	return description
}

func (t *Topic) getAge() string {
	var (
		reAge = regexp.MustCompile(`<span style="font-weight: bold">Возраст:\s*<\/span>(.+?)<`)
		age   string
	)
	if reAge.Match(t.Body) == true {
		age = string(reAge.FindSubmatch(t.Body)[1])
		age = cleanStr(age)
	}
	return age
}

func (t *Topic) getReleaseDate() string {
	var (
		reReleaseDate = regexp.MustCompile(`<span style="font-weight: bold">Дата мировой премьеры:\s*<\/span>(.+?)<`)
		releaseDate   string
	)
	if reReleaseDate.Match(t.Body) == true {
		releaseDate = string(reReleaseDate.FindSubmatch(t.Body)[1])
		releaseDate = cleanStr(releaseDate)
		releaseDate = replaceDate(releaseDate)
	}
	return releaseDate
}

func (t *Topic) getRussianDate() string {
	var (
		reRussianDate = regexp.MustCompile(`<span style="font-weight: bold">(?:Дата премьеры в России|Дата Российской премьеры|Дата российской премьеры):\s*<\/span>(.+?)<`)
		russianDate   string
	)
	if reRussianDate.Match(t.Body) == true {
		russianDate = string(reRussianDate.FindSubmatch(t.Body)[1])
		russianDate = cleanStr(russianDate)
		russianDate = replaceDate(russianDate)
	}
	return russianDate
}

func (t *Topic) getDuration() string {
	var (
		reDuration = regexp.MustCompile(`<span style="font-weight: bold">Продолжительность:\s*<\/span>(.+?)<`)
		duration   string
	)
	if reDuration.Match(t.Body) == true {
		duration = string(reDuration.FindSubmatch(t.Body)[1])
		duration = cleanStr(duration)
	}
	return duration
}

func (t *Topic) getQuality() string {
	var (
		reQuality = regexp.MustCompile(`<span style="font-weight: bold">(?:Качество видео|Качество):\s*<\/span>(.+?)<`)
		quality   string
	)
	if reQuality.Match(t.Body) == true {
		quality = string(reQuality.FindSubmatch(t.Body)[1])
		quality = cleanStr(quality)
	}
	return quality
}

func (t *Topic) getTranslation() string {
	var (
		reTranslation = regexp.MustCompile(`<span style="font-weight: bold">Перевод:\s*<\/span>(.+?)<`)
		translation   string
	)
	if reTranslation.Match(t.Body) == true {
		translation = string(reTranslation.FindSubmatch(t.Body)[1])
		translation = cleanStr(translation)
		// if caseInsensitiveContains(translation, "не требуется") == true {
		// 	translation = "Не требуется"
		// }
	}
	return translation
}

func (t *Topic) getSubtitlesType() string {
	var (
		reSubtitlesType = regexp.MustCompile(`<span style="font-weight: bold">Вид субтитров:\s*<\/span>(.+?)<`)
		subtitlesType   string
	)
	if reSubtitlesType.Match(t.Body) == true {
		subtitlesType = string(reSubtitlesType.FindSubmatch(t.Body)[1])
		subtitlesType = cleanStr(subtitlesType)
	}
	return subtitlesType
}

func (t *Topic) getSubtitles() string {
	var (
		reSubtitles = regexp.MustCompile(`<span style="font-weight: bold">Субтитры:\s*<\/span>(.+?)<`)
		subtitles   string
	)
	if reSubtitles.Match(t.Body) == true {
		subtitles = string(reSubtitles.FindSubmatch(t.Body)[1])
		subtitles = cleanStr(subtitles)
	}
	return subtitles
}

func (t *Topic) getVideo() string {
	var (
		reVideo = regexp.MustCompile(`<span style="font-weight: bold">Видео:\s*<\/span>(.+?)<`)
		video   string
	)
	if reVideo.Match(t.Body) == true {
		video = string(reVideo.FindSubmatch(t.Body)[1])
		video = cleanStr(video)
	}
	return video
}

func (t *Topic) getAudio1() string {
	var (
		reAudio = regexp.MustCompile(`<span style="font-weight: bold">(?:Аудио\s?:\s*|Аудио\s?.?1.?:\s*)<\/span>(.+?)<`)
		audio   string
	)
	if reAudio.Match(t.Body) == true {
		audio = string(reAudio.FindSubmatch(t.Body)[1])
		audio = cleanStr(audio)
	}
	return audio
}

func (t *Topic) getAudio2() string {
	var (
		reAudio = regexp.MustCompile(`<span style="font-weight: bold">Аудио\s?.?2.?:\s*<\/span>(.+?)<`)
		audio   string
	)
	if reAudio.Match(t.Body) == true {
		audio = string(reAudio.FindSubmatch(t.Body)[1])
		audio = cleanStr(audio)
	}
	return audio
}

func (t *Topic) getAudio3() string {
	var (
		reAudio = regexp.MustCompile(`<span style="font-weight: bold">Аудио\s?.?3.?:\s*<\/span>(.+?)<`)
		audio   string
	)
	if reAudio.Match(t.Body) == true {
		audio = string(reAudio.FindSubmatch(t.Body)[1])
		audio = cleanStr(audio)
	}
	return audio
}
<|endoftext|>


<commit_before>package idols

import (
	"bytes"
	"fmt"
	"image/png"
	"strings"

	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/bwmarrin/discordgo"
	"github.com/nfnt/resize"
)

// GetImgBytes will get the bytes for the image with a default size of 150x150
func (i IdolImage) GetImgBytes() []byte {
	return i.GetResizeImgBytes(150)
}

// GetImageBytesWithResize will get the bytes to the correctly sized image bytes
func (i IdolImage) GetResizeImgBytes(resizeHeight int) []byte {

	// image bytes is sometimes loaded if the object needs to be deleted
	if i.ImageBytes != nil {
		return i.ImageBytes
	}

	// get image bytes
	imgBytes, err := helpers.RetrieveFileWithoutLogging(i.ObjectName)
	helpers.Relax(err)

	img, _, err := helpers.DecodeImageBytes(imgBytes)
	helpers.Relax(err)

	// check if the image is already the correct size, otherwise resize it
	if img.Bounds().Dx() == resizeHeight && img.Bounds().Dy() == resizeHeight {
		return imgBytes
	} else {

		// resize image to the correct size
		img = resize.Resize(0, uint(resizeHeight), img, resize.Lanczos3)

		// AFTER resizing, re-encode the bytes
		resizedImgBytes := new(bytes.Buffer)
		encoder := new(png.Encoder)
		encoder.CompressionLevel = -2
		encoder.Encode(resizedImgBytes, img)

		return resizedImgBytes.Bytes()
	}
}

// validateImages will read the idols table to retrieve all image object names. then it will make a call to retrieve all images
//  Note: to avoid spam, missing images object names are logged to console, not displayed in discord
func validateImages(msg *discordgo.Message, content string) {

	contentArgs, err := helpers.ToArgv(content)
	if err != nil {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("bot.arguments.invalid"))
		return
	}

	// options
	listObjectName := false

	// check for options
	for _, option := range contentArgs {
		if option == "list" {
			listObjectName = true
		}
	}

	helpers.SendMessage(msg.ChannelID, "Checking idol images..")

	// loop through idol images and check if object exists
	var missingImages []string
	for _, idol := range GetActiveIdols() {
		for _, image := range idol.Images {
			if !helpers.ObjectExists(image.ObjectName) {
				missingImages = append(missingImages, image.ObjectName)
				log().Infoln("Idol image does not exist in minio: ", image.ObjectName)
			}
		}
	}

	helpers.SendMessage(msg.ChannelID, fmt.Sprintf("Done.\nMissing Images: %d", len(missingImages)))

	// list out object names if wanted
	if listObjectName {
		printableObjectNames := strings.Join(missingImages, "\n")
		helpers.SendMessage(msg.ChannelID, fmt.Sprintf("Missing Image Object Names: \n%s", printableObjectNames))
	}
}
<commit_msg>[idol] adds "clean" option to remove images from idol records that no longer exist<commit_after>package idols

import (
	"bytes"
	"fmt"
	"image/png"
	"strings"

	"github.com/Seklfreak/Robyul2/helpers"
	"github.com/Seklfreak/Robyul2/models"
	"github.com/bwmarrin/discordgo"
	"github.com/globalsign/mgo/bson"
	"github.com/nfnt/resize"
)

// GetImgBytes will get the bytes for the image with a default size of 150x150
func (i IdolImage) GetImgBytes() []byte {
	return i.GetResizeImgBytes(150)
}

// GetImageBytesWithResize will get the bytes to the correctly sized image bytes
func (i IdolImage) GetResizeImgBytes(resizeHeight int) []byte {

	// image bytes is sometimes loaded if the object needs to be deleted
	if i.ImageBytes != nil {
		return i.ImageBytes
	}

	// get image bytes
	imgBytes, err := helpers.RetrieveFileWithoutLogging(i.ObjectName)
	helpers.Relax(err)

	img, _, err := helpers.DecodeImageBytes(imgBytes)
	helpers.Relax(err)

	// check if the image is already the correct size, otherwise resize it
	if img.Bounds().Dx() == resizeHeight && img.Bounds().Dy() == resizeHeight {
		return imgBytes
	} else {

		// resize image to the correct size
		img = resize.Resize(0, uint(resizeHeight), img, resize.Lanczos3)

		// AFTER resizing, re-encode the bytes
		resizedImgBytes := new(bytes.Buffer)
		encoder := new(png.Encoder)
		encoder.CompressionLevel = -2
		encoder.Encode(resizedImgBytes, img)

		return resizedImgBytes.Bytes()
	}
}

// validateImages will read the idols table to retrieve all image object names. then it will make a call to retrieve all images
//  Note: to avoid spam, missing images object names are logged to console, not displayed in discord
func validateImages(msg *discordgo.Message, content string) {

	contentArgs, err := helpers.ToArgv(content)
	if err != nil {
		helpers.SendMessage(msg.ChannelID, helpers.GetText("bot.arguments.invalid"))
		return
	}

	// options
	cleanImages := false
	listObjectName := false

	// check for options
	for _, option := range contentArgs {
		if option == "list" {
			listObjectName = true
		}

		if option == "clean" {
			cleanImages = true
		}
	}

	helpers.SendMessage(msg.ChannelID, "Checking idol images..")

	find := helpers.MdbCollection(models.IdolTable).Find(bson.M{})
	idols := find.Iter()

	var missingImages []string
	idol := models.IdolEntry{}

	// loop through idol images and check if object exists
	for idols.Next(&idol) {
		imagesDelete := false

		for i := len(idol.Images) - 1; i >= 0; i-- {
			image := idol.Images[i]

			// log().Infoln("Checking image: ", image.ObjectName)

			if !helpers.ObjectExists(image.ObjectName) {
				missingImages = append(missingImages, image.ObjectName)
				log().Infoln("Idol image does not exist in minio: ", image.ObjectName)

				if cleanImages {
					imagesDelete = true
					idol.Images = append(idol.Images[:i], idol.Images[i+1:]...)
				}
			}
		}

		if cleanImages && imagesDelete {
			if len(idol.Images) == 0 {
				idol.Deleted = true
			}

			helpers.MDbUpsertID(models.IdolTable, idol.ID, idol)
		}
	}

	helpers.SendMessage(msg.ChannelID, fmt.Sprintf("Done.\nMissing Images: %d", len(missingImages)))

	// list out object names if wanted
	if listObjectName {
		printableObjectNames := strings.Join(missingImages, "\n")
		helpers.SendMessage(msg.ChannelID, fmt.Sprintf("Missing Image Object Names: \n%s", printableObjectNames))
	}

	if cleanImages {
		helpers.SendMessage(msg.ChannelID, "Missing images were deleted from idol records, please refresh idols.")
	}
}
<|endoftext|>


<commit_before>package trace

import (
	"fmt"
	"path/filepath"
	"runtime"
)

var debug bool

func EnableDebug() {
	debug = true
}

// Wrap takes the original error and wraps it into the Trace struct
// memorizing the context of the error.
func Wrap(err error, args ...interface{}) Error {
	t := newTrace(runtime.Caller(1))
	t.error = err
	if len(args) != 0 {
		t.Message = fmt.Sprintf(fmt.Sprintf("%v", args[0]), args[1:]...)
	}
	return t
}

// Errorf is similar to fmt.Errorf except that it captures
// more information about the origin of error, such as
// callee, line number and function that simplifies debugging
func Errorf(format string, args ...interface{}) error {
	t := newTrace(runtime.Caller(1))
	t.error = fmt.Errorf(format, args...)
	return t
}

// Fatalf. If debug is false Fatalf calls Errorf. If debug is
// true Fatalf calls panic
func Fatalf(format string, args ...interface{}) error {
	if debug {
		panic(fmt.Sprintf(format, args))
	} else {
		return Errorf(format, args)
	}
}

func newTrace(pc uintptr, filePath string, line int, ok bool) *TraceErr {
	if !ok {
		return &TraceErr{
			File: "unknown_file",
			Path: "unknown_path",
			Func: "unknown_func",
			Line: 0,
		}
	}
	return &TraceErr{
		File: filepath.Base(filePath),
		Path: filePath,
		Func: runtime.FuncForPC(pc).Name(),
		Line: line,
	}
}

// TraceErr contains error message and some additional
// information about the error origin
type TraceErr struct {
	error
	Message string
	File    string
	Path    string
	Func    string
	Line    int
}

func (e *TraceErr) Error() string {
	return fmt.Sprintf("[%v:%v] %v %v", e.File, e.Line, e.Message, e.error)
}

func (e *TraceErr) OrigError() error {
	return e.error
}

// Error is an interface that helps to adapt usage of trace in the code
// When applications define new error types, they can implement the interface
// So error handlers can use OrigError() to retrieve error from the wrapper
type Error interface {
	OrigError() error
}
<commit_msg>make sure trace.Error is compatible with errors<commit_after>package trace

import (
	"fmt"
	"path/filepath"
	"runtime"
)

var debug bool

func EnableDebug() {
	debug = true
}

// Wrap takes the original error and wraps it into the Trace struct
// memorizing the context of the error.
func Wrap(err error, args ...interface{}) Error {
	t := newTrace(runtime.Caller(1))
	t.error = err
	if len(args) != 0 {
		t.Message = fmt.Sprintf(fmt.Sprintf("%v", args[0]), args[1:]...)
	}
	return t
}

// Errorf is similar to fmt.Errorf except that it captures
// more information about the origin of error, such as
// callee, line number and function that simplifies debugging
func Errorf(format string, args ...interface{}) error {
	t := newTrace(runtime.Caller(1))
	t.error = fmt.Errorf(format, args...)
	return t
}

// Fatalf. If debug is false Fatalf calls Errorf. If debug is
// true Fatalf calls panic
func Fatalf(format string, args ...interface{}) error {
	if debug {
		panic(fmt.Sprintf(format, args))
	} else {
		return Errorf(format, args)
	}
}

func newTrace(pc uintptr, filePath string, line int, ok bool) *TraceErr {
	if !ok {
		return &TraceErr{
			File: "unknown_file",
			Path: "unknown_path",
			Func: "unknown_func",
			Line: 0,
		}
	}
	return &TraceErr{
		File: filepath.Base(filePath),
		Path: filePath,
		Func: runtime.FuncForPC(pc).Name(),
		Line: line,
	}
}

// TraceErr contains error message and some additional
// information about the error origin
type TraceErr struct {
	error
	Message string
	File    string
	Path    string
	Func    string
	Line    int
}

func (e *TraceErr) Error() string {
	return fmt.Sprintf("[%v:%v] %v %v", e.File, e.Line, e.Message, e.error)
}

func (e *TraceErr) OrigError() error {
	return e.error
}

// Error is an interface that helps to adapt usage of trace in the code
// When applications define new error types, they can implement the interface
// So error handlers can use OrigError() to retrieve error from the wrapper
type Error interface {
	error
	OrigError() error
}
<|endoftext|>


<commit_before>package hostdb

import (
	"net"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// TestDecrementReliability tests the decrementReliability method.
func TestDecrementReliability(t *testing.T) {
	hdb := bareHostDB()

	// Decrementing a non-existent host should be a no-op.
	// NOTE: can't check any post-conditions here; only indication of correct
	// behavior is that the test doesn't panic.
	hdb.decrementReliability("foo", types.NewCurrency64(0))

	// Add a host to allHosts and activeHosts. Decrementing it should remove it
	// from activeHosts.
	h := new(hostEntry)
	h.NetAddress = "foo"
	h.reliability = types.NewCurrency64(1)
	hdb.allHosts[h.NetAddress] = h
	hdb.activeHosts[h.NetAddress] = &hostNode{hostEntry: h}
	hdb.decrementReliability(h.NetAddress, types.NewCurrency64(0))
	if _, ok := hdb.activeHosts[h.NetAddress]; ok {
		t.Error("decrementing did not remove host from activeHosts")
	}

	// Decrement reliability to 0. This should remove the host from allHosts.
	hdb.decrementReliability(h.NetAddress, h.reliability)
	if _, ok := hdb.allHosts[h.NetAddress]; ok {
		t.Error("decrementing did not remove host from allHosts")
	}
}

// probeDialer is used to test the threadedProbeHosts method. A simple type
// alias is used so that it can easily be redefined during testing, allowing
// multiple behaviors to be tested.
type probeDialer func(modules.NetAddress, time.Duration) (net.Conn, error)

func (dial probeDialer) DialTimeout(addr modules.NetAddress, timeout time.Duration) (net.Conn, error) {
	return dial(addr, timeout)
}

// TestThreadedProbeHosts tests the threadedProbeHosts method.
func TestThreadedProbeHosts(t *testing.T) {
	hdb := bareHostDB()

	// create a host to send to threadedProbeHosts
	h := new(hostEntry)
	h.NetAddress = "foo"
	h.reliability = baseWeight // enough to withstand a few failures

	// define a helper function for running threadedProbeHosts. We send the
	// hostEntry, close the channel, and then call threadedProbeHosts.
	// threadedProbeHosts will receive the host, loop once, and return after
	// seeing the channel has closed.
	runProbe := func(h *hostEntry) {
		hdb.scanPool <- h
		close(hdb.scanPool)
		hdb.threadedProbeHosts()
		// reset hdb.scanPool
		hdb.scanPool = make(chan *hostEntry, 1)
	}

	// make the dial fail
	hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) {
		return nil, net.UnknownNetworkError("fail")
	})
	runProbe(h)
	if _, ok := hdb.activeHosts[h.NetAddress]; ok {
		t.Error("unresponsive host was added")
	}

	// make the RPC fail
	hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) {
		ourPipe, theirPipe := net.Pipe()
		ourPipe.Close()
		return theirPipe, nil
	})
	runProbe(h)
	if _, ok := hdb.activeHosts[h.NetAddress]; ok {
		t.Error("unresponsive host was added")
	}

	// normal host
	hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) {
		// create an in-memory conn and spawn a goroutine to handle our half
		ourConn, theirConn := net.Pipe()
		go func() {
			// read the RPC
			encoding.ReadObject(ourConn, new(types.Specifier), types.SpecifierLen)
			// write old host settings
			encoding.WriteObject(ourConn, oldHostSettings{
				NetAddress: "probed",
			})
			ourConn.Close()
		}()
		return theirConn, nil
	})
	runProbe(h)
	if _, ok := hdb.activeHosts[h.NetAddress]; !ok {
		t.Error("host was not added")
	}

	// TODO: respond with old host settings
}

// TestThreadedScan tests the threadedScan method.
func TestThreadedScan(t *testing.T) {
	hdb := bareHostDB()
	// use a real sleeper; this will prevent threadedScan from looping too
	// quickly.
	hdb.sleeper = stdSleeper{}
	// use a dummy dialer that always fails
	hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) {
		return nil, net.UnknownNetworkError("fail")
	})

	// create a host to be scanned
	h := new(hostEntry)
	h.NetAddress = "foo"
	h.reliability = types.NewCurrency64(1)
	hdb.activeHosts[h.NetAddress] = &hostNode{hostEntry: h}

	// perform one scan
	go hdb.threadedScan()

	// host should be sent down scanPool
	select {
	case <-hdb.scanPool:
	case <-time.After(time.Second):
		t.Error("host was not scanned")
	}

	// remove the host from activeHosts and add it to allHosts
	hdb.mu.Lock()
	delete(hdb.activeHosts, h.NetAddress)
	hdb.allHosts[h.NetAddress] = h
	hdb.mu.Unlock()

	// perform one scan
	go hdb.threadedScan()

	// host should be sent down scanPool
	select {
	case <-hdb.scanPool:
	case <-time.After(time.Second):
		t.Error("host was not scanned")
	}
}
<commit_msg>prefer checking behavior via exported functions<commit_after>package hostdb

import (
	"net"
	"testing"
	"time"

	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// TestDecrementReliability tests the decrementReliability method.
func TestDecrementReliability(t *testing.T) {
	hdb := bareHostDB()

	// Decrementing a non-existent host should be a no-op.
	// NOTE: can't check any post-conditions here; only indication of correct
	// behavior is that the test doesn't panic.
	hdb.decrementReliability("foo", types.NewCurrency64(0))

	// Add a host to allHosts and activeHosts. Decrementing it should remove it
	// from activeHosts.
	h := new(hostEntry)
	h.NetAddress = "foo"
	h.reliability = types.NewCurrency64(1)
	hdb.allHosts[h.NetAddress] = h
	hdb.activeHosts[h.NetAddress] = &hostNode{hostEntry: h}
	hdb.decrementReliability(h.NetAddress, types.NewCurrency64(0))
	if len(hdb.ActiveHosts()) != 0 {
		t.Error("decrementing did not remove host from activeHosts")
	}

	// Decrement reliability to 0. This should remove the host from allHosts.
	hdb.decrementReliability(h.NetAddress, h.reliability)
	if len(hdb.AllHosts()) != 0 {
		t.Error("decrementing did not remove host from allHosts")
	}
}

// probeDialer is used to test the threadedProbeHosts method. A simple type
// alias is used so that it can easily be redefined during testing, allowing
// multiple behaviors to be tested.
type probeDialer func(modules.NetAddress, time.Duration) (net.Conn, error)

func (dial probeDialer) DialTimeout(addr modules.NetAddress, timeout time.Duration) (net.Conn, error) {
	return dial(addr, timeout)
}

// TestThreadedProbeHosts tests the threadedProbeHosts method.
func TestThreadedProbeHosts(t *testing.T) {
	hdb := bareHostDB()

	// create a host to send to threadedProbeHosts
	h := new(hostEntry)
	h.NetAddress = "foo"
	h.reliability = baseWeight // enough to withstand a few failures

	// define a helper function for running threadedProbeHosts. We send the
	// hostEntry, close the channel, and then call threadedProbeHosts.
	// threadedProbeHosts will receive the host, loop once, and return after
	// seeing the channel has closed.
	runProbe := func(h *hostEntry) {
		hdb.scanPool <- h
		close(hdb.scanPool)
		hdb.threadedProbeHosts()
		// reset hdb.scanPool
		hdb.scanPool = make(chan *hostEntry, 1)
	}

	// make the dial fail
	hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) {
		return nil, net.UnknownNetworkError("fail")
	})
	runProbe(h)
	if len(hdb.ActiveHosts()) != 0 {
		t.Error("unresponsive host was added")
	}

	// make the RPC fail
	hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) {
		ourPipe, theirPipe := net.Pipe()
		ourPipe.Close()
		return theirPipe, nil
	})
	runProbe(h)
	if len(hdb.ActiveHosts()) != 0 {
		t.Error("unresponsive host was added")
	}

	// normal host
	hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) {
		// create an in-memory conn and spawn a goroutine to handle our half
		ourConn, theirConn := net.Pipe()
		go func() {
			// read the RPC
			encoding.ReadObject(ourConn, new(types.Specifier), types.SpecifierLen)
			// write old host settings
			encoding.WriteObject(ourConn, oldHostSettings{
				NetAddress: "probed",
			})
			ourConn.Close()
		}()
		return theirConn, nil
	})
	runProbe(h)
	if len(hdb.ActiveHosts()) != 1 {
		t.Error("host was not added")
	}

	// TODO: respond with old host settings
}

// TestThreadedScan tests the threadedScan method.
func TestThreadedScan(t *testing.T) {
	hdb := bareHostDB()
	// use a real sleeper; this will prevent threadedScan from looping too
	// quickly.
	hdb.sleeper = stdSleeper{}
	// use a dummy dialer that always fails
	hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) {
		return nil, net.UnknownNetworkError("fail")
	})

	// create a host to be scanned
	h := new(hostEntry)
	h.NetAddress = "foo"
	h.reliability = types.NewCurrency64(1)
	hdb.activeHosts[h.NetAddress] = &hostNode{hostEntry: h}

	// perform one scan
	go hdb.threadedScan()

	// host should be sent down scanPool
	select {
	case <-hdb.scanPool:
	case <-time.After(time.Second):
		t.Error("host was not scanned")
	}

	// remove the host from activeHosts and add it to allHosts
	hdb.mu.Lock()
	delete(hdb.activeHosts, h.NetAddress)
	hdb.allHosts[h.NetAddress] = h
	hdb.mu.Unlock()

	// perform one scan
	go hdb.threadedScan()

	// host should be sent down scanPool
	select {
	case <-hdb.scanPool:
	case <-time.After(time.Second):
		t.Error("host was not scanned")
	}
}
<|endoftext|>


<commit_before>package trace

import (
	"fmt"
	"path/filepath"
	"runtime"
)

// Errorf is similar to fmt.Errorf except that it captures
// more information about the origin of error, such as
// callee, line number and function that simplifies debugging
func Errorf(format string, args ...interface{}) error {
	msg := fmt.Sprintf(format, args...)
	pc, filePath, lineNo, ok := runtime.Caller(1)
	if !ok {
		return &TraceErr{
			Message: msg,
			File:    "unknown_file",
			Path:    "unknown_path",
			Func:    "unknown_func",
			Line:    0,
		}
	}
	return &TraceErr{
		Message: msg,
		File:    filepath.Base(filePath),
		Path:    filePath,
		Func:    runtime.FuncForPC(pc).Name(),
		Line:    lineNo,
	}
}

// TraceErr contains error message and some additional
// information about the error origin
type TraceErr struct {
	Message string
	File    string
	Path    string
	Func    string
	Line    int
}

func (e *TraceErr) Error() string {
	return fmt.Sprintf("[%v:%v] %v", e.File, e.Line, e.Message)
}
<commit_msg>add wrap function<commit_after>package trace

import (
	"fmt"
	"path/filepath"
	"runtime"
)

// Wrap takes the original error and wraps it into the Trace struct
// memorizing the context of the error.
func Wrap(err error) error {
	t := newTrace(runtime.Caller(1))
	t.error = err
	return t
}

// Errorf is similar to fmt.Errorf except that it captures
// more information about the origin of error, such as
// callee, line number and function that simplifies debugging
func Errorf(format string, args ...interface{}) error {
	t := newTrace(runtime.Caller(1))
	t.error = fmt.Errorf(format, args...)
	return t
}

func newTrace(pc uintptr, filePath string, line int, ok bool) *TraceErr {
	if !ok {
		return &TraceErr{
			File: "unknown_file",
			Path: "unknown_path",
			Func: "unknown_func",
			Line: 0,
		}
	}
	return &TraceErr{
		File: filepath.Base(filePath),
		Path: filePath,
		Func: runtime.FuncForPC(pc).Name(),
		Line: line,
	}
}

// TraceErr contains error message and some additional
// information about the error origin
type TraceErr struct {
	error
	File string
	Path string
	Func string
	Line int
}

func (e *TraceErr) Error() string {
	return fmt.Sprintf("[%v:%v] %v", e.File, e.Line, e.error)
}
<|endoftext|>


<commit_before>// Package trace defines common-use Dapper-style tracing APIs for the Go programming language.
//
// Package trace provides a backend-agnostic APIs and various tracing providers
// can be used with the package by importing various implementations of the Client interface.
package trace

import (
	"context"
	"net/http"
	"time"

	"github.com/rakyll/trace/minitrace"
)

var client Client

// TODO(jbd): how to propagate a subset of labels?

// TODO(jbd): should we support a span to have multiple parents?

// TODO(jbd): set error/state on finish.

// TODO(jbd): Avoid things if client = nil.

// TODO(jbd): A big TODO, we probably don't want to set a global client.
func Configure(c Client) {
	client = c
}

// Span represents a work.
type Span struct {
	ID          []byte            // represents the global identifier of the span.
	Annotations map[string][]byte // annotations set on this span.
}

// Annotate allows you to attach data to a span. Key-value pairs are
// arbitary information you want to collect in the lifetime of a span.
func (s *Span) Annotate(key string, val []byte) {
	if s == nil {
		return
	}
	s.Annotations[key] = val
}

// Child creates a child span from s with the given name.
// Created child span needs to be finished by calling
// the finishing function.
func (s *Span) Child(name string, linked ...*Span) (*Span, FinishFunc) {
	if s == nil {
		return nil, noop
	}
	child := &Span{
		ID:          client.NewSpan(s.ID),
		Annotations: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(child.ID, name, spanIDs(linked), child.Annotations, start, time.Now())
	}
	return child, fn
}

// ToHTTPReq injects the span information in the given request
// and returns the modified request.
//
// If the current client is not supporting HTTP propagation,
// an error is returned.
func (s *Span) ToHTTPReq(req *http.Request) (*http.Request, error) {
	if s == nil {
		return req, nil
	}
	hc, ok := client.(minitrace.HTTPCarrier)
	if !ok {
		return req, nil
	}
	return hc.SpanToReq(req, &sspan{id: s.ID})
}

type sspan struct {
	id []byte
}

func (s *sspan) ID() []byte {
	return s.id
}

func (s *sspan) Annotations() []byte {
	return nil
}

// FromHTTPReq creates a *Span from an incoming request.
//
// An error will be returned if the current tracing client is
// not supporting propagation via HTTP.
func FromHTTPReq(req *http.Request) (*Span, error) {
	hc, ok := client.(minitrace.HTTPCarrier)
	if !ok {
		return nil, nil
	}
	span, err := hc.SpanFromReq(req)
	if err != nil {
		return nil, err
	}
	return &Span{ID: span.ID()}, nil
}

// Client represents a client communicates with a tracing backend.
// Tracing backends are supposed to implement the interface in order to
// provide Go support.
//
// A Client is an HTTPCarrier if it can propagate the tracing
// information via an HTTP request.
//
// If you are not a tracing provider, you will never have to interact with
// this interface directly.
type Client interface {
	NewSpan(parent []byte) (id []byte)
	Finish(id []byte, name string, linked [][]byte, annotations map[string][]byte, start, end time.Time) error
}

// NewSpan creates a new root-level span.
//
// The span must be finished when the job it represents it is finished.
func NewSpan(name string, linked ...*Span) (*Span, FinishFunc) {
	span := &Span{
		ID:          client.NewSpan(nil),
		Annotations: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(span.ID, name, spanIDs(linked), span.Annotations, start, time.Now())
	}
	return span, fn
}

// NewContext returns a context with the span in.
func NewContext(ctx context.Context, span *Span) context.Context {
	return context.WithValue(ctx, spanKey, span)
}

// FromContext returns a span from the given context.
func FromContext(ctx context.Context) *Span {
	return ctx.Value(spanKey).(*Span)
}

func spanIDs(spans []*Span) [][]byte {
	var ids [][]byte
	for _, s := range spans {
		ids = append(ids, s.ID)
	}
	return ids
}

// FinishFunc finalizes its span.
type FinishFunc func() error

type contextKey struct{}

var spanKey = contextKey{}

func noop() error { return nil }
<commit_msg>fix the broken build<commit_after>// Package trace defines common-use Dapper-style tracing APIs for the Go programming language.
//
// Package trace provides a backend-agnostic APIs and various tracing providers
// can be used with the package by importing various implementations of the Client interface.
package trace

import (
	"context"
	"net/http"
	"time"

	"github.com/rakyll/trace/minitrace"
)

var client Client

// TODO(jbd): how to propagate a subset of labels?

// TODO(jbd): should we support a span to have multiple parents?

// TODO(jbd): set error/state on finish.

// TODO(jbd): Avoid things if client = nil.

// TODO(jbd): A big TODO, we probably don't want to set a global client.
func Configure(c Client) {
	client = c
}

// Span represents a work.
type Span struct {
	ID          []byte            // represents the global identifier of the span.
	Annotations map[string][]byte // annotations set on this span.
}

// Annotate allows you to attach data to a span. Key-value pairs are
// arbitary information you want to collect in the lifetime of a span.
func (s *Span) Annotate(key string, val []byte) {
	if s == nil {
		return
	}
	s.Annotations[key] = val
}

// Child creates a child span from s with the given name.
// Created child span needs to be finished by calling
// the finishing function.
func (s *Span) Child(name string, linked ...*Span) (*Span, FinishFunc) {
	if s == nil {
		return nil, noop
	}
	child := &Span{
		ID:          client.NewSpan(s.ID),
		Annotations: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(child.ID, name, spanIDs(linked), child.Annotations, start, time.Now())
	}
	return child, fn
}

// ToHTTPReq injects the span information in the given request
// and returns the modified request.
//
// If the current client is not supporting HTTP propagation,
// an error is returned.
func (s *Span) ToHTTPReq(req *http.Request) (*http.Request, error) {
	if s == nil {
		return req, nil
	}
	hc, ok := client.(minitrace.HTTPInjector)
	if !ok {
		return req, nil
	}
	return hc.SpanToReq(req, &sspan{id: s.ID})
}

type sspan struct {
	id []byte
}

func (s *sspan) ID() []byte {
	return s.id
}

func (s *sspan) Annotations() []byte {
	return nil
}

// FromHTTPReq creates a *Span from an incoming request.
//
// An error will be returned if the current tracing client is
// not supporting propagation via HTTP.
func FromHTTPReq(req *http.Request) (*Span, error) {
	hc, ok := client.(minitrace.HTTPExtractor)
	if !ok {
		return nil, nil
	}
	span, err := hc.SpanFromReq(req)
	if err != nil {
		return nil, err
	}
	return &Span{ID: span.ID()}, nil
}

// Client represents a client communicates with a tracing backend.
// Tracing backends are supposed to implement the interface in order to
// provide Go support.
//
// A Client is an HTTPExtractor if it can extract spans from an incoming HTTP request.
// A Client in an HTTPInjector if it can inject span info into an outgoing HTTP request.
//
// If you are not a tracing provider, you will never have to interact with
// this interface directly.
type Client interface {
	NewSpan(parent []byte) (id []byte)
	Finish(id []byte, name string, linked [][]byte, annotations map[string][]byte, start, end time.Time) error
}

// NewSpan creates a new root-level span.
//
// The span must be finished when the job it represents it is finished.
func NewSpan(name string, linked ...*Span) (*Span, FinishFunc) {
	span := &Span{
		ID:          client.NewSpan(nil),
		Annotations: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(span.ID, name, spanIDs(linked), span.Annotations, start, time.Now())
	}
	return span, fn
}

// NewContext returns a context with the span in.
func NewContext(ctx context.Context, span *Span) context.Context {
	return context.WithValue(ctx, spanKey, span)
}

// FromContext returns a span from the given context.
func FromContext(ctx context.Context) *Span {
	return ctx.Value(spanKey).(*Span)
}

func spanIDs(spans []*Span) [][]byte {
	var ids [][]byte
	for _, s := range spans {
		ids = append(ids, s.ID)
	}
	return ids
}

// FinishFunc finalizes its span.
type FinishFunc func() error

type contextKey struct{}

var spanKey = contextKey{}

func noop() error { return nil }
<|endoftext|>


<commit_before>package varis

type Dataset []struct {
	input    []float64
	expected []float64
}

type Trainer struct {
	Network   *Network
	TrainFunc func(*Network, []float64, []float64, int)
}

func (t *Trainer) TrainByDataset(dataset Dataset, times int) {
	for times > 0 {
		for _, f := range dataset {
			t.TrainFunc(t.Network, f.input, f.expected, 1)
		}
		times--
	}
}

func BackPropagation(network *Network, inputs []float64, expected []float64, speed int) {
	results := network.Calculate(inputs...)

	layerDelta := 0.0
	for i, n := range network.GetOutputLayer().getNeurons() {
		neuronDelta := (expected[i] - results[i]) * n.deactivation()
		neuronDelta *= float64(speed)
		layerDelta += neuronDelta
		n.changeWeight(neuronDelta)
	}

	for i := len(network.Layers) - 2; i > 0; i-- {
		nextLayerDelta := 0.00
		for _, n := range network.Layers[i].getNeurons() {
			neuronDelta := layerDelta * n.deactivation()
			nextLayerDelta += neuronDelta
			n.changeWeight(neuronDelta)
		}
		layerDelta = nextLayerDelta
	}
}
<commit_msg>Rewrite Train function<commit_after>package varis

type Dataset []struct {
	input    []float64
	expected []float64
}

type Trainer struct {
	Network   *Network
	TrainFunc func(*Network, []float64, []float64, int)
}

func (t *Trainer) TrainByDataset(dataset Dataset, times int) {
	for times > 0 {
		for _, f := range dataset {
			t.TrainFunc(t.Network, f.input, f.expected, 1)
		}
		times--
	}
}

func BackPropagation(network *Network, inputs []float64, expected []float64, speed int) {
	results := network.Calculate(inputs...)

	layerDelta := 0.0
	for l := len(network.Layers) - 1; l > 0; l-- {
		nextLayerDelta := 0.00
		for i, n := range network.Layers[l].getNeurons() {
			var neuronDelta float64
			if l == len(network.Layers)-1 {
				neuronDelta = (expected[i] - results[i]) * n.deactivation()
			} else {
				neuronDelta = layerDelta * n.deactivation()
			}
			neuronDelta *= float64(speed)
			nextLayerDelta += neuronDelta
			n.changeWeight(neuronDelta)
		}
		layerDelta = nextLayerDelta
	}

}
<|endoftext|>


<commit_before>package treap

type Treap struct {
	compare    Compare
	count      int
	root       *node
}

// Compare returns an integer comparing the two items
// lexicographically. The result will be 0 if a==b, -1 if a < b, and
// +1 if a > b.
type Compare func(a, b Item) int

// Key and Item can be anything.
type Key interface{}
type Item interface{}

type node struct {
	key      Key
	item     Item
	priority int
	left     *node
	right    *node
}

func NewTreap(c Compare) *Treap {
	return &Treap{compare: c, root: nil}
}

func (t *Treap) Count() int {
	return t.count
}

func (t *Treap) Get(key Key) Item {
	if t.root == nil {
		return nil
	}
	return t.root.get(key)
}

func (n *node) get(key Key) Item {
	return nil
}<commit_msg>Iterative node get().<commit_after>package treap

type Treap struct {
	compare Compare
	count   int
	root    *node
}

// Compare returns an integer comparing the two items
// lexicographically. The result will be 0 if a==b, -1 if a < b, and
// +1 if a > b.
type Compare func(a, b Item) int

// Key and Item can be anything.
type Item interface{}

type node struct {
	item     Item
	priority int
	left     *node
	right    *node
}

func NewTreap(c Compare) *Treap {
	return &Treap{compare: c, count: 0, root: nil}
}

func (t *Treap) Count() int {
	return t.count
}

func (t *Treap) Get(target Item) Item {
	if t.root == nil {
		return nil
	}
	return t.get(t.root, target)
}

func (t *Treap) get(n *node, target Item) Item {
	for {
		if n == nil {
			break
		}
		c := t.compare(target, n.item)
		if c < 0 {
			n = n.left
		} else if c > 0 {
			n = n.right
		} else {
			return n.item
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "os"
    "strings"
    "flag"

    "github.com/fsouza/go-dockerclient"
)

func main() {
    var compTag string
    flag.StringVar(&compTag, "tag", "latest", "Tag to compare the current ($GO_PIPELINE_COUNTER) tag against")
    flag.Parse()

    endpoint := os.Getenv("DOCKER_HOST")
    if endpoint == "" {
        endpoint = "unix:///var/run/docker.sock"
    }
    client, _ := docker.NewClient(endpoint)
    imgs, _ := client.ListImages(docker.ListImagesOptions{All: false})
    imgName := fmt.Sprintf("qnib/%s", os.Getenv("GO_PIPELINE_NAME"))
    imgTag := os.Getenv("GO_PIPELINE_COUNTER")
    var latest string
    var current string
    for _, img := range imgs {
        for _, repotag := range img.RepoTags {
            if strings.HasPrefix(repotag, imgName) {
                arr := strings.Split(repotag, ":")
                repo := arr[0]
                tag := arr[1]
                if repo == imgName {
                    if tag == compTag {
                        latest = img.ID
                    } else if tag == imgTag {
                        current = img.ID
                    }
                    fmt.Println("> RepoTag: ", repotag)
                    fmt.Println("ID: ", img.ID)
                    fmt.Println("Size: ", img.Size)
                }
            }
        }
    }
    if latest == current {
        fmt.Printf("FAIL > '%s' :  '%s'==%s !! Therefore we do not need to go on...\n", imgName, imgTag, compTag)
        os.Exit(1)
    } else {
        fmt.Printf("PASS > '%s' :  '%s'!=%s\n", imgName, imgTag, compTag)
        os.Exit(0)
    }
}<commit_msg>adjust imgcheck to underscore in tag-name<commit_after>package main

import (
    "fmt"
    "os"
    "strings"
    "flag"

    "github.com/fsouza/go-dockerclient"
)

func main() {
    var compTag string
    flag.StringVar(&compTag, "tag", "latest", "Tag to compare the current ($GO_PIPELINE_COUNTER) tag against")
    flag.Parse()

    endpoint := os.Getenv("DOCKER_HOST")
    if endpoint == "" {
        endpoint = "unix:///var/run/docker.sock"
    }
    client, _ := docker.NewClient(endpoint)
    imgs, _ := client.ListImages(docker.ListImagesOptions{All: false})
    imgName := fmt.Sprintf("qnib/%s", os.Getenv("GO_PIPELINE_NAME"))
    nameArr := strings.Split(os.Getenv("GO_PIPELINE_NAME"), "_")
    if len(nameArr) == 2 {
        imgName = fmt.Sprintf("qnib/%s", nameArr[0])
    } else if len(nameArr) > 2 {
        fmt.Printf("Weird image name '%s'", os.Getenv("GO_PIPELINE_NAME"))
        os.Exit(1)
    }
    imgTag := fmt.Sprintf("%s_%s", compTag, os.Getenv("GO_PIPELINE_COUNTER"))
    var latest string
    var current string
    for _, img := range imgs {
        for _, repotag := range img.RepoTags {
            if strings.HasPrefix(repotag, imgName) {
                arr := strings.Split(repotag, ":")
                repo := arr[0]
                tag := arr[1]
                if repo == imgName {
                    if tag == compTag {
                        latest = img.ID
                    } else if tag == imgTag {
                        current = img.ID
                    }
                    fmt.Println("> RepoTag: ", repotag)
                    fmt.Println("ID: ", img.ID)
                    fmt.Println("Size: ", img.Size)
                }
            }
        }
    }
    if latest == current {
        fmt.Printf("FAIL > '%s' :  '%s'==%s !! Therefore we do not need to go on...\n", imgName, imgTag, compTag)
        os.Exit(1)
    } else {
        fmt.Printf("PASS > '%s' :  (%s)'%s'!=%s(%s)\n", imgName, latest, imgTag, compTag, current)
        os.Exit(0)
    }
}
<|endoftext|>


<commit_before>package validate

import (
	"fmt"
	"log"
	"net/url"
	"os/exec"
	"strings"
	"sync"

	"golang.org/x/crypto/ssh"

	"github.com/codegangsta/cli"
	"github.com/marcosnils/cmt/cmd"
)

var Command = cli.Command{
	Name:  "validate",
	Usage: "Validate host migration capabilities",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "src",
			Usage: "Source host URL [user@host:port]",
		},
		cli.StringFlag{
			Name:  "dst",
			Usage: "Destination host URL [user@host:port]",
		},
	},
	Action: func(c *cli.Context) {
		srcURL := ParseURL(c.String("src"))
		dstURL := ParseURL(c.String("dst"))

		Validate(srcURL, dstURL)
		println("Validation succeded")

	},
}

func ParseURL(rawurl string) *url.URL {
	if rawurl == "" {
		return nil
	}
	// We do this hack beacuse url.Parse require a schema to do the right thing
	schemaUrl := rawurl
	if !strings.HasPrefix(rawurl, "ssh://") {
		schemaUrl = fmt.Sprintf("ssh://%s", rawurl)
	}

	u, err := url.Parse(schemaUrl)
	if err != nil {
		log.Fatal("Error parsing host: ", rawurl)
	}

	return u

}

func Validate(src, dst *url.URL) (srcCmd, dstCmd cmd.Cmd) {
	if src == nil || dst == nil {
		log.Fatal("Both src and dst must be specified")
	}

	srcCmd = GetCommand(src)
	dstCmd = GetCommand(dst)

	if e := checkVersion(srcCmd, dstCmd, "criu"); e != nil {
		log.Fatal(e)
	}
	if e := checkVersion(srcCmd, dstCmd, "runc"); e != nil {
		log.Fatal(e)
	}

	if e := checkKernelCap(srcCmd); e != nil {
		log.Fatal(e)
	}

	if e := checkKernelCap(dstCmd); e != nil {
		log.Fatal(e)
	}

	if e := checkCPUCompat(srcCmd, dstCmd); e != nil {
		log.Fatal(e)
	}

	return
}

func checkCPUCompat(srcCmd, dstCmd cmd.Cmd) error {
	// Dump
	_, _, err := srcCmd.Run("sudo", "criu", "cpuinfo", "dump")
	if _, ok := err.(*ssh.ExitError); ok {
		return fmt.Errorf("Error dumping CPU info")
	} else if _, ok := err.(*exec.ExitError); ok {
		return fmt.Errorf("Error dumping CPU info")
	} else if err != nil {
		return fmt.Errorf("Connection error: %s ", err)
	}

	// Copy

	err = cmd.Scp(srcCmd.URL("./cpuinfo.img"), dstCmd.URL("."))
	if _, ok := err.(*ssh.ExitError); ok {
		return fmt.Errorf("Error copying dump image")
	} else if _, ok := err.(*exec.ExitError); ok {
		return fmt.Errorf("Error copying dump image")
	} else if err != nil {
		return fmt.Errorf("Connection error: %s ", err)
	}

	// Check
	_, _, err = srcCmd.Run("sudo", "criu", "cpuinfo", "check")
	if _, ok := err.(*ssh.ExitError); ok {
		return fmt.Errorf("Error checking CPU info")
	} else if _, ok := err.(*exec.ExitError); ok {
		return fmt.Errorf("Error checking CPU info")
	} else if err != nil {
		return fmt.Errorf("Connection error: %s ", err)
	}
	return nil
}

func checkKernelCap(c cmd.Cmd) error {
	_, _, err := c.Run("sudo", "criu", "check", "--ms")
	if _, ok := err.(*ssh.ExitError); ok {
		return fmt.Errorf("Error criu checks do not pass")
	} else if _, ok := err.(*exec.ExitError); ok {
		return fmt.Errorf("Error criu checks do not pass")
	} else if err != nil {
		return fmt.Errorf("Connection error: %s ", err)
	}
	return err
}

func GetCommand(hostURL *url.URL) cmd.Cmd {
	if hostURL.Host != "" {
		rc := cmd.NewSSH(hostURL.User.Username(), hostURL.Host)
		if err := rc.UseAgent(); err != nil {
			log.Fatal("Unable to use SSH agent for host: ", hostURL.String())
		}
		return rc

	}

	return cmd.NewLocal()

}

func checkVersion(sCmd, dCmd cmd.Cmd, name string) error {
	var wg sync.WaitGroup
	wg.Add(2)
	var sourceVersion, destVersion string
	var sourceError, destError error
	go func() {
		sourceVersion, sourceError = getVersion(sCmd, name)
		wg.Done()
	}()
	go func() {
		destVersion, destError = getVersion(dCmd, name)
		wg.Done()
	}()

	wg.Wait()

	if sourceError != nil {
		return fmt.Errorf("%s in src", sourceError)
	}
	if destError != nil {
		return fmt.Errorf("%s in dst", destError)
	}

	if sourceVersion != destVersion {
		return fmt.Errorf("ERROR: Source and destination versions of %s do not match", name)
	}

	return nil
}

func getVersion(command cmd.Cmd, name string) (string, error) {
	version, _, err := command.Run("sudo", name, "--version")
	if _, ok := err.(*ssh.ExitError); ok {
		return "", fmt.Errorf("Error %s does not exist", name)
	} else if _, ok := err.(*exec.ExitError); ok {
		return "", fmt.Errorf("Error %s does not exist", name)
	} else if err != nil {
		return "", fmt.Errorf("Connection error: %s ", err)
	}
	return version, nil
}
<commit_msg>Remove sudo to cpuinfo as it's not necessary and produced permission errors<commit_after>package validate

import (
	"fmt"
	"log"
	"net/url"
	"os/exec"
	"strings"
	"sync"

	"golang.org/x/crypto/ssh"

	"github.com/codegangsta/cli"
	"github.com/marcosnils/cmt/cmd"
)

var Command = cli.Command{
	Name:  "validate",
	Usage: "Validate host migration capabilities",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "src",
			Usage: "Source host URL [user@host:port]",
		},
		cli.StringFlag{
			Name:  "dst",
			Usage: "Destination host URL [user@host:port]",
		},
	},
	Action: func(c *cli.Context) {
		srcURL := ParseURL(c.String("src"))
		dstURL := ParseURL(c.String("dst"))

		Validate(srcURL, dstURL)
		println("Validation succeded")

	},
}

func ParseURL(rawurl string) *url.URL {
	if rawurl == "" {
		return nil
	}
	// We do this hack beacuse url.Parse require a schema to do the right thing
	schemaUrl := rawurl
	if !strings.HasPrefix(rawurl, "ssh://") {
		schemaUrl = fmt.Sprintf("ssh://%s", rawurl)
	}

	u, err := url.Parse(schemaUrl)
	if err != nil {
		log.Fatal("Error parsing host: ", rawurl)
	}

	return u

}

func Validate(src, dst *url.URL) (srcCmd, dstCmd cmd.Cmd) {
	if src == nil || dst == nil {
		log.Fatal("Both src and dst must be specified")
	}

	srcCmd = GetCommand(src)
	dstCmd = GetCommand(dst)

	if e := checkVersion(srcCmd, dstCmd, "criu"); e != nil {
		log.Fatal(e)
	}
	if e := checkVersion(srcCmd, dstCmd, "runc"); e != nil {
		log.Fatal(e)
	}

	if e := checkKernelCap(srcCmd); e != nil {
		log.Fatal(e)
	}

	if e := checkKernelCap(dstCmd); e != nil {
		log.Fatal(e)
	}

	if e := checkCPUCompat(srcCmd, dstCmd); e != nil {
		log.Fatal(e)
	}

	return
}

func checkCPUCompat(srcCmd, dstCmd cmd.Cmd) error {
	// Dump
	_, _, err := srcCmd.Run("criu", "cpuinfo", "dump")
	if _, ok := err.(*ssh.ExitError); ok {
		return fmt.Errorf("Error dumping CPU info")
	} else if _, ok := err.(*exec.ExitError); ok {
		return fmt.Errorf("Error dumping CPU info")
	} else if err != nil {
		return fmt.Errorf("Connection error: %s ", err)
	}

	// Copy

	err = cmd.Scp(srcCmd.URL("./cpuinfo.img"), dstCmd.URL("."))
	if _, ok := err.(*ssh.ExitError); ok {
		return fmt.Errorf("Error copying dump image")
	} else if _, ok := err.(*exec.ExitError); ok {
		return fmt.Errorf("Error copying dump image")
	} else if err != nil {
		return fmt.Errorf("Connection error: %s ", err)
	}

	// Check
	_, _, err = srcCmd.Run("criu", "cpuinfo", "check")
	if _, ok := err.(*ssh.ExitError); ok {
		return fmt.Errorf("Error checking CPU info")
	} else if _, ok := err.(*exec.ExitError); ok {
		return fmt.Errorf("Error checking CPU info")
	} else if err != nil {
		return fmt.Errorf("Connection error: %s ", err)
	}
	return nil
}

func checkKernelCap(c cmd.Cmd) error {
	_, _, err := c.Run("sudo", "criu", "check", "--ms")
	if _, ok := err.(*ssh.ExitError); ok {
		return fmt.Errorf("Error criu checks do not pass")
	} else if _, ok := err.(*exec.ExitError); ok {
		return fmt.Errorf("Error criu checks do not pass")
	} else if err != nil {
		return fmt.Errorf("Connection error: %s ", err)
	}
	return err
}

func GetCommand(hostURL *url.URL) cmd.Cmd {
	if hostURL.Host != "" {
		rc := cmd.NewSSH(hostURL.User.Username(), hostURL.Host)
		if err := rc.UseAgent(); err != nil {
			log.Fatal("Unable to use SSH agent for host: ", hostURL.String())
		}
		return rc

	}

	return cmd.NewLocal()

}

func checkVersion(sCmd, dCmd cmd.Cmd, name string) error {
	var wg sync.WaitGroup
	wg.Add(2)
	var sourceVersion, destVersion string
	var sourceError, destError error
	go func() {
		sourceVersion, sourceError = getVersion(sCmd, name)
		wg.Done()
	}()
	go func() {
		destVersion, destError = getVersion(dCmd, name)
		wg.Done()
	}()

	wg.Wait()

	if sourceError != nil {
		return fmt.Errorf("%s in src", sourceError)
	}
	if destError != nil {
		return fmt.Errorf("%s in dst", destError)
	}

	if sourceVersion != destVersion {
		return fmt.Errorf("ERROR: Source and destination versions of %s do not match", name)
	}

	return nil
}

func getVersion(command cmd.Cmd, name string) (string, error) {
	version, _, err := command.Run("sudo", name, "--version")
	if _, ok := err.(*ssh.ExitError); ok {
		return "", fmt.Errorf("Error %s does not exist", name)
	} else if _, ok := err.(*exec.ExitError); ok {
		return "", fmt.Errorf("Error %s does not exist", name)
	} else if err != nil {
		return "", fmt.Errorf("Connection error: %s ", err)
	}
	return version, nil
}
<|endoftext|>


<commit_before>// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package version

import (
	"time"

	"github.com/ava-labs/avalanchego/utils/constants"
)

// These are globals that describe network upgrades and node versions
var (
	Current                      = NewDefaultVersion(1, 7, 5)
	CurrentApp                   = NewDefaultApplication(constants.PlatformName, Current.Major(), Current.Minor(), Current.Patch())
	MinimumCompatibleVersion     = NewDefaultApplication(constants.PlatformName, 1, 7, 0)
	PrevMinimumCompatibleVersion = NewDefaultApplication(constants.PlatformName, 1, 6, 0)
	MinimumUnmaskedVersion       = NewDefaultApplication(constants.PlatformName, 1, 1, 0)
	PrevMinimumUnmaskedVersion   = NewDefaultApplication(constants.PlatformName, 1, 0, 0)
	VersionParser                = NewDefaultApplicationParser()

	CurrentDatabase = DatabaseVersion1_4_5
	PrevDatabase    = DatabaseVersion1_0_0

	DatabaseVersion1_4_5 = NewDefaultVersion(1, 4, 5)
	DatabaseVersion1_0_0 = NewDefaultVersion(1, 0, 0)

	ApricotPhase0Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2020, time.December, 8, 3, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC),
	}
	ApricotPhase0DefaultTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)

	ApricotPhase1Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2021, time.March, 31, 14, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2021, time.March, 26, 14, 0, 0, 0, time.UTC),
	}
	ApricotPhase1DefaultTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)

	ApricotPhase2Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2021, time.May, 10, 11, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2021, time.May, 5, 14, 0, 0, 0, time.UTC),
	}
	ApricotPhase2DefaultTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)

	ApricotPhase3Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2021, time.August, 24, 14, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2021, time.August, 16, 19, 0, 0, 0, time.UTC),
	}
	ApricotPhase3DefaultTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)

	ApricotPhase4Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2021, time.September, 22, 21, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2021, time.September, 16, 21, 0, 0, 0, time.UTC),
	}
	ApricotPhase4DefaultTime     = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)
	ApricotPhase4MinPChainHeight = map[uint32]uint64{
		constants.MainnetID: 793005,
		constants.FujiID:    47437,
	}
	ApricotPhase4DefaultMinPChainHeight uint64

	ApricotPhase5Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2021, time.December, 2, 18, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2021, time.November, 24, 15, 0, 0, 0, time.UTC),
	}
	ApricotPhase5DefaultTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)

	// FIXME: update this before release
	XChainMigrationTimes = map[uint32]time.Time{
		constants.MainnetID: time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC),
	}
	XChainMigrationDefaultTime = time.Date(2022, time.January, 1, 1, 0, 0, 0, time.UTC)
)

func GetApricotPhase0Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase0Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase0DefaultTime
}

func GetApricotPhase1Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase1Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase1DefaultTime
}

func GetApricotPhase2Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase2Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase2DefaultTime
}

func GetApricotPhase3Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase3Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase3DefaultTime
}

func GetApricotPhase4Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase4Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase4DefaultTime
}

func GetApricotPhase4MinPChainHeight(networkID uint32) uint64 {
	if minHeight, exists := ApricotPhase4MinPChainHeight[networkID]; exists {
		return minHeight
	}
	return ApricotPhase4DefaultMinPChainHeight
}

func GetApricotPhase5Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase5Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase5DefaultTime
}

func GetXChainMigrationTime(networkID uint32) time.Time {
	if upgradeTime, exists := XChainMigrationTimes[networkID]; exists {
		return upgradeTime
	}
	return XChainMigrationDefaultTime
}

func GetCompatibility(networkID uint32) Compatibility {
	return NewCompatibility(
		CurrentApp,
		MinimumCompatibleVersion,
		GetApricotPhase5Time(networkID),
		PrevMinimumCompatibleVersion,
		MinimumUnmaskedVersion,
		GetApricotPhase0Time(networkID),
		PrevMinimumUnmaskedVersion,
	)
}
<commit_msg>Version bump to v1.7.6 (#1218)<commit_after>// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package version

import (
	"time"

	"github.com/ava-labs/avalanchego/utils/constants"
)

// These are globals that describe network upgrades and node versions
var (
	Current                      = NewDefaultVersion(1, 7, 6)
	CurrentApp                   = NewDefaultApplication(constants.PlatformName, Current.Major(), Current.Minor(), Current.Patch())
	MinimumCompatibleVersion     = NewDefaultApplication(constants.PlatformName, 1, 7, 0)
	PrevMinimumCompatibleVersion = NewDefaultApplication(constants.PlatformName, 1, 6, 0)
	MinimumUnmaskedVersion       = NewDefaultApplication(constants.PlatformName, 1, 1, 0)
	PrevMinimumUnmaskedVersion   = NewDefaultApplication(constants.PlatformName, 1, 0, 0)
	VersionParser                = NewDefaultApplicationParser()

	CurrentDatabase = DatabaseVersion1_4_5
	PrevDatabase    = DatabaseVersion1_0_0

	DatabaseVersion1_4_5 = NewDefaultVersion(1, 4, 5)
	DatabaseVersion1_0_0 = NewDefaultVersion(1, 0, 0)

	ApricotPhase0Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2020, time.December, 8, 3, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC),
	}
	ApricotPhase0DefaultTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)

	ApricotPhase1Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2021, time.March, 31, 14, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2021, time.March, 26, 14, 0, 0, 0, time.UTC),
	}
	ApricotPhase1DefaultTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)

	ApricotPhase2Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2021, time.May, 10, 11, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2021, time.May, 5, 14, 0, 0, 0, time.UTC),
	}
	ApricotPhase2DefaultTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)

	ApricotPhase3Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2021, time.August, 24, 14, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2021, time.August, 16, 19, 0, 0, 0, time.UTC),
	}
	ApricotPhase3DefaultTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)

	ApricotPhase4Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2021, time.September, 22, 21, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2021, time.September, 16, 21, 0, 0, 0, time.UTC),
	}
	ApricotPhase4DefaultTime     = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)
	ApricotPhase4MinPChainHeight = map[uint32]uint64{
		constants.MainnetID: 793005,
		constants.FujiID:    47437,
	}
	ApricotPhase4DefaultMinPChainHeight uint64

	ApricotPhase5Times = map[uint32]time.Time{
		constants.MainnetID: time.Date(2021, time.December, 2, 18, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(2021, time.November, 24, 15, 0, 0, 0, time.UTC),
	}
	ApricotPhase5DefaultTime = time.Date(2020, time.December, 5, 5, 0, 0, 0, time.UTC)

	// FIXME: update this before release
	XChainMigrationTimes = map[uint32]time.Time{
		constants.MainnetID: time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC),
		constants.FujiID:    time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC),
	}
	XChainMigrationDefaultTime = time.Date(2022, time.January, 1, 1, 0, 0, 0, time.UTC)
)

func GetApricotPhase0Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase0Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase0DefaultTime
}

func GetApricotPhase1Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase1Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase1DefaultTime
}

func GetApricotPhase2Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase2Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase2DefaultTime
}

func GetApricotPhase3Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase3Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase3DefaultTime
}

func GetApricotPhase4Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase4Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase4DefaultTime
}

func GetApricotPhase4MinPChainHeight(networkID uint32) uint64 {
	if minHeight, exists := ApricotPhase4MinPChainHeight[networkID]; exists {
		return minHeight
	}
	return ApricotPhase4DefaultMinPChainHeight
}

func GetApricotPhase5Time(networkID uint32) time.Time {
	if upgradeTime, exists := ApricotPhase5Times[networkID]; exists {
		return upgradeTime
	}
	return ApricotPhase5DefaultTime
}

func GetXChainMigrationTime(networkID uint32) time.Time {
	if upgradeTime, exists := XChainMigrationTimes[networkID]; exists {
		return upgradeTime
	}
	return XChainMigrationDefaultTime
}

func GetCompatibility(networkID uint32) Compatibility {
	return NewCompatibility(
		CurrentApp,
		MinimumCompatibleVersion,
		GetApricotPhase5Time(networkID),
		PrevMinimumCompatibleVersion,
		MinimumUnmaskedVersion,
		GetApricotPhase0Time(networkID),
		PrevMinimumUnmaskedVersion,
	)
}
<|endoftext|>


<commit_before>package message

import (
	"encoding/xml"

	"github.com/silenceper/wechat/v2/officialaccount/device"
)

// MsgType 基本消息类型
type MsgType string

// EventType 事件类型
type EventType string

// InfoType 第三方平台授权事件类型
type InfoType string

const (
	// MsgTypeText 表示文本消息
	MsgTypeText MsgType = "text"
	// MsgTypeImage 表示图片消息
	MsgTypeImage = "image"
	// MsgTypeVoice 表示语音消息
	MsgTypeVoice = "voice"
	// MsgTypeVideo 表示视频消息
	MsgTypeVideo = "video"
	// MsgTypeMiniprogrampage 表示小程序卡片消息
	MsgTypeMiniprogrampage = "miniprogrampage"
	// MsgTypeShortVideo 表示短视频消息[限接收]
	MsgTypeShortVideo = "shortvideo"
	// MsgTypeLocation 表示坐标消息[限接收]
	MsgTypeLocation = "location"
	// MsgTypeLink 表示链接消息[限接收]
	MsgTypeLink = "link"
	// MsgTypeMusic 表示音乐消息[限回复]
	MsgTypeMusic = "music"
	// MsgTypeNews 表示图文消息[限回复]
	MsgTypeNews = "news"
	// MsgTypeTransfer 表示消息消息转发到客服
	MsgTypeTransfer = "transfer_customer_service"
	// MsgTypeEvent 表示事件推送消息
	MsgTypeEvent = "event"
)

const (
	// EventSubscribe 订阅
	EventSubscribe EventType = "subscribe"
	// EventUnsubscribe 取消订阅
	EventUnsubscribe = "unsubscribe"
	// EventScan 用户已经关注公众号，则微信会将带场景值扫描事件推送给开发者
	EventScan = "SCAN"
	// EventLocation 上报地理位置事件
	EventLocation = "LOCATION"
	// EventClick 点击菜单拉取消息时的事件推送
	EventClick = "CLICK"
	// EventView 点击菜单跳转链接时的事件推送
	EventView = "VIEW"
	// EventScancodePush 扫码推事件的事件推送
	EventScancodePush = "scancode_push"
	// EventScancodeWaitmsg 扫码推事件且弹出“消息接收中”提示框的事件推送
	EventScancodeWaitmsg = "scancode_waitmsg"
	// EventPicSysphoto 弹出系统拍照发图的事件推送
	EventPicSysphoto = "pic_sysphoto"
	// EventPicPhotoOrAlbum 弹出拍照或者相册发图的事件推送
	EventPicPhotoOrAlbum = "pic_photo_or_album"
	// EventPicWeixin 弹出微信相册发图器的事件推送
	EventPicWeixin = "pic_weixin"
	// EventLocationSelect 弹出地理位置选择器的事件推送
	EventLocationSelect = "location_select"
	// EventTemplateSendJobFinish 发送模板消息推送通知
	EventTemplateSendJobFinish = "TEMPLATESENDJOBFINISH"
	// EventMassSendJobFinish 群发消息推送通知
	EventMassSendJobFinish = "MASSSENDJOBFINISH"
	// EventWxaMediaCheck 异步校验图片/音频是否含有违法违规内容推送事件
	EventWxaMediaCheck = "wxa_media_check"
)

const (
	// 微信开放平台需要用到

	// InfoTypeVerifyTicket 返回ticket
	InfoTypeVerifyTicket InfoType = "component_verify_ticket"
	// InfoTypeAuthorized 授权
	InfoTypeAuthorized = "authorized"
	// InfoTypeUnauthorized 取消授权
	InfoTypeUnauthorized = "unauthorized"
	// InfoTypeUpdateAuthorized 更新授权
	InfoTypeUpdateAuthorized = "updateauthorized"
	// InfoTypeNotifyThirdFasterRegister 注册审核事件推送
	InfoTypeNotifyThirdFasterRegister = "notify_third_fasteregister"
)

// MixMessage 存放所有微信发送过来的消息和事件
type MixMessage struct {
	CommonToken

	// 基本消息
	MsgID         int64   `xml:"MsgId"` // 其他消息推送过来是MsgId
	TemplateMsgID int64   `xml:"MsgID"` // 模板消息推送成功的消息是MsgID
	Content       string  `xml:"Content"`
	Recognition   string  `xml:"Recognition"`
	PicURL        string  `xml:"PicUrl"`
	MediaID       string  `xml:"MediaId"`
	Format        string  `xml:"Format"`
	ThumbMediaID  string  `xml:"ThumbMediaId"`
	LocationX     float64 `xml:"Location_X"`
	LocationY     float64 `xml:"Location_Y"`
	Scale         float64 `xml:"Scale"`
	Label         string  `xml:"Label"`
	Title         string  `xml:"Title"`
	Description   string  `xml:"Description"`
	URL           string  `xml:"Url"`

	// 事件相关
	Event       EventType `xml:"Event"`
	EventKey    string    `xml:"EventKey"`
	Ticket      string    `xml:"Ticket"`
	Latitude    string    `xml:"Latitude"`
	Longitude   string    `xml:"Longitude"`
	Precision   string    `xml:"Precision"`
	MenuID      string    `xml:"MenuId"`
	Status      string    `xml:"Status"`
	SessionFrom string    `xml:"SessionFrom"`
	TotalCount  int64     `xml:"TotalCount"`
	FilterCount int64     `xml:"FilterCount"`
	SentCount   int64     `xml:"SentCount"`
	ErrorCount  int64     `xml:"ErrorCount"`

	ScanCodeInfo struct {
		ScanType   string `xml:"ScanType"`
		ScanResult string `xml:"ScanResult"`
	} `xml:"ScanCodeInfo"`

	SendPicsInfo struct {
		Count   int32      `xml:"Count"`
		PicList []EventPic `xml:"PicList>item"`
	} `xml:"SendPicsInfo"`

	SendLocationInfo struct {
		LocationX float64 `xml:"Location_X"`
		LocationY float64 `xml:"Location_Y"`
		Scale     float64 `xml:"Scale"`
		Label     string  `xml:"Label"`
		Poiname   string  `xml:"Poiname"`
	}

	// 第三方平台相关
	InfoType                     InfoType `xml:"InfoType"`
	AppID                        string   `xml:"AppId"`
	ComponentVerifyTicket        string   `xml:"ComponentVerifyTicket"`
	AuthorizerAppid              string   `xml:"AuthorizerAppid"`
	AuthorizationCode            string   `xml:"AuthorizationCode"`
	AuthorizationCodeExpiredTime int64    `xml:"AuthorizationCodeExpiredTime"`
	PreAuthCode                  string   `xml:"PreAuthCode"`
	AuthCode                     string   `xml:"auth_code"`
	Info                         struct {
		Name               string `xml:"name"`
		Code               string `xml:"code"`
		CodeType           int    `xml:"code_type"`
		LegalPersonaWechat string `xml:"legal_persona_wechat"`
		LegalPersonaName   string `xml:"legal_persona_name"`
		ComponentPhone     string `xml:"component_phone"`
	} `xml:"info"`

	// 卡券相关
	CardID              string `xml:"CardId"`
	RefuseReason        string `xml:"RefuseReason"`
	IsGiveByFriend      int32  `xml:"IsGiveByFriend"`
	FriendUserName      string `xml:"FriendUserName"`
	UserCardCode        string `xml:"UserCardCode"`
	OldUserCardCode     string `xml:"OldUserCardCode"`
	OuterStr            string `xml:"OuterStr"`
	IsRestoreMemberCard int32  `xml:"IsRestoreMemberCard"`
	UnionID             string `xml:"UnionId"`

	// 内容审核相关
	IsRisky       bool   `xml:"isrisky"`
	ExtraInfoJSON string `xml:"extra_info_json"`
	TraceID       string `xml:"trace_id"`
	StatusCode    int    `xml:"status_code"`

	// 设备相关
	device.MsgDevice
}

// EventPic 发图事件推送
type EventPic struct {
	PicMd5Sum string `xml:"PicMd5Sum"`
}

// EncryptedXMLMsg 安全模式下的消息体
type EncryptedXMLMsg struct {
	XMLName      struct{} `xml:"xml" json:"-"`
	ToUserName   string   `xml:"ToUserName" json:"ToUserName"`
	EncryptedMsg string   `xml:"Encrypt"    json:"Encrypt"`
}

// ResponseEncryptedXMLMsg 需要返回的消息体
type ResponseEncryptedXMLMsg struct {
	XMLName      struct{} `xml:"xml" json:"-"`
	EncryptedMsg string   `xml:"Encrypt"      json:"Encrypt"`
	MsgSignature string   `xml:"MsgSignature" json:"MsgSignature"`
	Timestamp    int64    `xml:"TimeStamp"    json:"TimeStamp"`
	Nonce        string   `xml:"Nonce"        json:"Nonce"`
}

// CDATA  使用该类型,在序列化为 xml 文本时文本会被解析器忽略
type CDATA string

// MarshalXML 实现自己的序列化方法
func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	return e.EncodeElement(struct {
		string `xml:",cdata"`
	}{string(c)}, start)
}

// CommonToken 消息中通用的结构
type CommonToken struct {
	XMLName      xml.Name `xml:"xml"`
	ToUserName   CDATA    `xml:"ToUserName"`
	FromUserName CDATA    `xml:"FromUserName"`
	CreateTime   int64    `xml:"CreateTime"`
	MsgType      MsgType  `xml:"MsgType"`
}

// SetToUserName set ToUserName
func (msg *CommonToken) SetToUserName(toUserName CDATA) {
	msg.ToUserName = toUserName
}

// SetFromUserName set FromUserName
func (msg *CommonToken) SetFromUserName(fromUserName CDATA) {
	msg.FromUserName = fromUserName
}

// SetCreateTime set createTime
func (msg *CommonToken) SetCreateTime(createTime int64) {
	msg.CreateTime = createTime
}

// SetMsgType set MsgType
func (msg *CommonToken) SetMsgType(msgType MsgType) {
	msg.MsgType = msgType
}

// GetOpenID get the FromUserName value
func (msg *CommonToken) GetOpenID() string {
	return string(msg.FromUserName)
}
<commit_msg>增加订阅通知事件 (#509)<commit_after>package message

import (
	"encoding/xml"

	"github.com/silenceper/wechat/v2/officialaccount/device"
)

// MsgType 基本消息类型
type MsgType string

// EventType 事件类型
type EventType string

// InfoType 第三方平台授权事件类型
type InfoType string

const (
	// MsgTypeText 表示文本消息
	MsgTypeText MsgType = "text"
	// MsgTypeImage 表示图片消息
	MsgTypeImage = "image"
	// MsgTypeVoice 表示语音消息
	MsgTypeVoice = "voice"
	// MsgTypeVideo 表示视频消息
	MsgTypeVideo = "video"
	// MsgTypeMiniprogrampage 表示小程序卡片消息
	MsgTypeMiniprogrampage = "miniprogrampage"
	// MsgTypeShortVideo 表示短视频消息[限接收]
	MsgTypeShortVideo = "shortvideo"
	// MsgTypeLocation 表示坐标消息[限接收]
	MsgTypeLocation = "location"
	// MsgTypeLink 表示链接消息[限接收]
	MsgTypeLink = "link"
	// MsgTypeMusic 表示音乐消息[限回复]
	MsgTypeMusic = "music"
	// MsgTypeNews 表示图文消息[限回复]
	MsgTypeNews = "news"
	// MsgTypeTransfer 表示消息消息转发到客服
	MsgTypeTransfer = "transfer_customer_service"
	// MsgTypeEvent 表示事件推送消息
	MsgTypeEvent = "event"
)

const (
	// EventSubscribe 订阅
	EventSubscribe EventType = "subscribe"
	// EventUnsubscribe 取消订阅
	EventUnsubscribe = "unsubscribe"
	// EventScan 用户已经关注公众号，则微信会将带场景值扫描事件推送给开发者
	EventScan = "SCAN"
	// EventLocation 上报地理位置事件
	EventLocation = "LOCATION"
	// EventClick 点击菜单拉取消息时的事件推送
	EventClick = "CLICK"
	// EventView 点击菜单跳转链接时的事件推送
	EventView = "VIEW"
	// EventScancodePush 扫码推事件的事件推送
	EventScancodePush = "scancode_push"
	// EventScancodeWaitmsg 扫码推事件且弹出“消息接收中”提示框的事件推送
	EventScancodeWaitmsg = "scancode_waitmsg"
	// EventPicSysphoto 弹出系统拍照发图的事件推送
	EventPicSysphoto = "pic_sysphoto"
	// EventPicPhotoOrAlbum 弹出拍照或者相册发图的事件推送
	EventPicPhotoOrAlbum = "pic_photo_or_album"
	// EventPicWeixin 弹出微信相册发图器的事件推送
	EventPicWeixin = "pic_weixin"
	// EventLocationSelect 弹出地理位置选择器的事件推送
	EventLocationSelect = "location_select"
	// EventTemplateSendJobFinish 发送模板消息推送通知
	EventTemplateSendJobFinish = "TEMPLATESENDJOBFINISH"
	// EventMassSendJobFinish 群发消息推送通知
	EventMassSendJobFinish = "MASSSENDJOBFINISH"
	// EventWxaMediaCheck 异步校验图片/音频是否含有违法违规内容推送事件
	EventWxaMediaCheck = "wxa_media_check"
	// EventSubscribeMsgPopupEvent 订阅通知事件推送
	EventSubscribeMsgPopupEvent = "subscribe_msg_popup_event"
)

const (
	// 微信开放平台需要用到

	// InfoTypeVerifyTicket 返回ticket
	InfoTypeVerifyTicket InfoType = "component_verify_ticket"
	// InfoTypeAuthorized 授权
	InfoTypeAuthorized = "authorized"
	// InfoTypeUnauthorized 取消授权
	InfoTypeUnauthorized = "unauthorized"
	// InfoTypeUpdateAuthorized 更新授权
	InfoTypeUpdateAuthorized = "updateauthorized"
	// InfoTypeNotifyThirdFasterRegister 注册审核事件推送
	InfoTypeNotifyThirdFasterRegister = "notify_third_fasteregister"
)

// MixMessage 存放所有微信发送过来的消息和事件
type MixMessage struct {
	CommonToken

	// 基本消息
	MsgID         int64   `xml:"MsgId"` // 其他消息推送过来是MsgId
	TemplateMsgID int64   `xml:"MsgID"` // 模板消息推送成功的消息是MsgID
	Content       string  `xml:"Content"`
	Recognition   string  `xml:"Recognition"`
	PicURL        string  `xml:"PicUrl"`
	MediaID       string  `xml:"MediaId"`
	Format        string  `xml:"Format"`
	ThumbMediaID  string  `xml:"ThumbMediaId"`
	LocationX     float64 `xml:"Location_X"`
	LocationY     float64 `xml:"Location_Y"`
	Scale         float64 `xml:"Scale"`
	Label         string  `xml:"Label"`
	Title         string  `xml:"Title"`
	Description   string  `xml:"Description"`
	URL           string  `xml:"Url"`

	// 事件相关
	Event       EventType `xml:"Event"`
	EventKey    string    `xml:"EventKey"`
	Ticket      string    `xml:"Ticket"`
	Latitude    string    `xml:"Latitude"`
	Longitude   string    `xml:"Longitude"`
	Precision   string    `xml:"Precision"`
	MenuID      string    `xml:"MenuId"`
	Status      string    `xml:"Status"`
	SessionFrom string    `xml:"SessionFrom"`
	TotalCount  int64     `xml:"TotalCount"`
	FilterCount int64     `xml:"FilterCount"`
	SentCount   int64     `xml:"SentCount"`
	ErrorCount  int64     `xml:"ErrorCount"`

	ScanCodeInfo struct {
		ScanType   string `xml:"ScanType"`
		ScanResult string `xml:"ScanResult"`
	} `xml:"ScanCodeInfo"`

	SendPicsInfo struct {
		Count   int32      `xml:"Count"`
		PicList []EventPic `xml:"PicList>item"`
	} `xml:"SendPicsInfo"`

	SendLocationInfo struct {
		LocationX float64 `xml:"Location_X"`
		LocationY float64 `xml:"Location_Y"`
		Scale     float64 `xml:"Scale"`
		Label     string  `xml:"Label"`
		Poiname   string  `xml:"Poiname"`
	}

	SubscribeMsgPopupEvent []struct {
		List SubscribeMsgPopupEvent `xml:"List"`
	} `xml:"SubscribeMsgPopupEvent"`

	// 第三方平台相关
	InfoType                     InfoType `xml:"InfoType"`
	AppID                        string   `xml:"AppId"`
	ComponentVerifyTicket        string   `xml:"ComponentVerifyTicket"`
	AuthorizerAppid              string   `xml:"AuthorizerAppid"`
	AuthorizationCode            string   `xml:"AuthorizationCode"`
	AuthorizationCodeExpiredTime int64    `xml:"AuthorizationCodeExpiredTime"`
	PreAuthCode                  string   `xml:"PreAuthCode"`
	AuthCode                     string   `xml:"auth_code"`
	Info                         struct {
		Name               string `xml:"name"`
		Code               string `xml:"code"`
		CodeType           int    `xml:"code_type"`
		LegalPersonaWechat string `xml:"legal_persona_wechat"`
		LegalPersonaName   string `xml:"legal_persona_name"`
		ComponentPhone     string `xml:"component_phone"`
	} `xml:"info"`

	// 卡券相关
	CardID              string `xml:"CardId"`
	RefuseReason        string `xml:"RefuseReason"`
	IsGiveByFriend      int32  `xml:"IsGiveByFriend"`
	FriendUserName      string `xml:"FriendUserName"`
	UserCardCode        string `xml:"UserCardCode"`
	OldUserCardCode     string `xml:"OldUserCardCode"`
	OuterStr            string `xml:"OuterStr"`
	IsRestoreMemberCard int32  `xml:"IsRestoreMemberCard"`
	UnionID             string `xml:"UnionId"`

	// 内容审核相关
	IsRisky       bool   `xml:"isrisky"`
	ExtraInfoJSON string `xml:"extra_info_json"`
	TraceID       string `xml:"trace_id"`
	StatusCode    int    `xml:"status_code"`

	// 设备相关
	device.MsgDevice
}

// SubscribeMsgPopupEvent 订阅通知事件推送的消息体
type SubscribeMsgPopupEvent struct {
	TemplateID            string `xml:"TemplateId"`
	SubscribeStatusString string `xml:"SubscribeStatusString"`
	PopupScene            int    `xml:"PopupScene"`
}

// EventPic 发图事件推送
type EventPic struct {
	PicMd5Sum string `xml:"PicMd5Sum"`
}

// EncryptedXMLMsg 安全模式下的消息体
type EncryptedXMLMsg struct {
	XMLName      struct{} `xml:"xml" json:"-"`
	ToUserName   string   `xml:"ToUserName" json:"ToUserName"`
	EncryptedMsg string   `xml:"Encrypt"    json:"Encrypt"`
}

// ResponseEncryptedXMLMsg 需要返回的消息体
type ResponseEncryptedXMLMsg struct {
	XMLName      struct{} `xml:"xml" json:"-"`
	EncryptedMsg string   `xml:"Encrypt"      json:"Encrypt"`
	MsgSignature string   `xml:"MsgSignature" json:"MsgSignature"`
	Timestamp    int64    `xml:"TimeStamp"    json:"TimeStamp"`
	Nonce        string   `xml:"Nonce"        json:"Nonce"`
}

// CDATA  使用该类型,在序列化为 xml 文本时文本会被解析器忽略
type CDATA string

// MarshalXML 实现自己的序列化方法
func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	return e.EncodeElement(struct {
		string `xml:",cdata"`
	}{string(c)}, start)
}

// CommonToken 消息中通用的结构
type CommonToken struct {
	XMLName      xml.Name `xml:"xml"`
	ToUserName   CDATA    `xml:"ToUserName"`
	FromUserName CDATA    `xml:"FromUserName"`
	CreateTime   int64    `xml:"CreateTime"`
	MsgType      MsgType  `xml:"MsgType"`
}

// SetToUserName set ToUserName
func (msg *CommonToken) SetToUserName(toUserName CDATA) {
	msg.ToUserName = toUserName
}

// SetFromUserName set FromUserName
func (msg *CommonToken) SetFromUserName(fromUserName CDATA) {
	msg.FromUserName = fromUserName
}

// SetCreateTime set createTime
func (msg *CommonToken) SetCreateTime(createTime int64) {
	msg.CreateTime = createTime
}

// SetMsgType set MsgType
func (msg *CommonToken) SetMsgType(msgType MsgType) {
	msg.MsgType = msgType
}

// GetOpenID get the FromUserName value
func (msg *CommonToken) GetOpenID() string {
	return string(msg.FromUserName)
}
<|endoftext|>