소스 검색

first commit

lijiali 2 년 전
커밋
ed77fc597d
100개의 변경된 파일13873개의 추가작업 그리고 0개의 파일을 삭제
  1. 5 0
      BuildAllGames.bat
  2. 4 0
      BuildAllMainServers.bat
  3. 21 0
      BuildAllServices.bat
  4. 46 0
      awscdn/awscdn.go
  5. 38 0
      awscdn/config.go
  6. 92 0
      awscdn/invalidate.go
  7. 191 0
      awscdn/upload.go
  8. 238 0
      creatorversion/creatorversion.go
  9. 122 0
      creatorversion/file.go
  10. 122 0
      creatorversion/xxtea.go
  11. 40 0
      database/database.go
  12. 185 0
      database/sqlserver.go
  13. 147 0
      database/statement.go
  14. 20 0
      database/trans_base.go
  15. 190 0
      event/event_chan.go
  16. 299 0
      go.mod
  17. 1674 0
      go.sum
  18. 30 0
      log/example_test.go
  19. 254 0
      log/log.go
  20. 33 0
      log/panic_handler.go
  21. 6 0
      network/agent.go
  22. 102 0
      network/datalink.go
  23. 372 0
      network/encrypt_datalink.go
  24. 114 0
      network/protobuf.go
  25. 163 0
      network/ws_conn.go
  26. 165 0
      network/ws_server.go
  27. 181 0
      profile/profile.go
  28. 330 0
      public/ByteArray.go
  29. 153 0
      public/IdNumber.go
  30. 709 0
      public/Public.go
  31. 220 0
      public/citizen.go
  32. 113 0
      public/httpReq.go
  33. 96 0
      public/rsa.go
  34. 355 0
      public/rsa_ext.go
  35. 55 0
      public/tagClientInfo.go
  36. 31 0
      public/tagConnectInfo.go
  37. 27 0
      public/tagVersionInfo.go
  38. 58 0
      public/timeTool.go
  39. 38 0
      public/zip.go
  40. 50 0
      redis/channel_client.go
  41. 43 0
      redis/channel_msg.go
  42. 95 0
      redis/keyOperate.go
  43. 55 0
      redis/pool.go
  44. 42 0
      redis/setOperate.go
  45. 153 0
      redis/stringOperate.go
  46. 133 0
      redis/zsetOperate.go
  47. BIN
      servers/adminserver/adminserver
  48. 46 0
      servers/adminserver/adminserver.go
  49. 60 0
      servers/adminserver/agent/agentmgr.go
  50. 157 0
      servers/adminserver/agent/controller.go
  51. 129 0
      servers/adminserver/agent/data.go
  52. 400 0
      servers/adminserver/agent/transaction.go
  53. 44 0
      servers/adminserver/announce/announcemgr.go
  54. 63 0
      servers/adminserver/announce/controller.go
  55. 22 0
      servers/adminserver/announce/data.go
  56. 87 0
      servers/adminserver/announce/transaction.go
  57. 150 0
      servers/adminserver/audioroom/controllger.go
  58. 215 0
      servers/adminserver/audioroom/data.go
  59. 160 0
      servers/adminserver/audioroom/manager.go
  60. 396 0
      servers/adminserver/audioroom/transaction.go
  61. 46 0
      servers/adminserver/badge/badge.go
  62. 5 0
      servers/adminserver/badge/badge_main.go
  63. 55 0
      servers/adminserver/card/cardmgr.go
  64. 126 0
      servers/adminserver/card/controller.go
  65. 82 0
      servers/adminserver/card/data.go
  66. 281 0
      servers/adminserver/card/transaction.go
  67. 20 0
      servers/adminserver/character/character.go
  68. 88 0
      servers/adminserver/chat/controller.go
  69. 10 0
      servers/adminserver/chat/data.go
  70. 24 0
      servers/adminserver/config/conf.go
  71. 146 0
      servers/adminserver/config/json.go
  72. 300 0
      servers/adminserver/controller/alluser.go
  73. 183 0
      servers/adminserver/controller/cash.go
  74. 227 0
      servers/adminserver/controller/chip.go
  75. 212 0
      servers/adminserver/controller/exchange.go
  76. 31 0
      servers/adminserver/controller/feedback.go
  77. 219 0
      servers/adminserver/controller/game.go
  78. 48 0
      servers/adminserver/controller/giftcard.go
  79. 107 0
      servers/adminserver/controller/item.go
  80. 48 0
      servers/adminserver/controller/job.go
  81. 115 0
      servers/adminserver/controller/log.go
  82. 266 0
      servers/adminserver/controller/mail.go
  83. 38 0
      servers/adminserver/controller/notfound.go
  84. 56 0
      servers/adminserver/controller/partner.go
  85. 248 0
      servers/adminserver/controller/pay.go
  86. 53 0
      servers/adminserver/controller/platformInfo.go
  87. 33 0
      servers/adminserver/controller/rank.go
  88. 77 0
      servers/adminserver/controller/role.go
  89. 41 0
      servers/adminserver/controller/shop.go
  90. 21 0
      servers/adminserver/controller/sign.go
  91. 346 0
      servers/adminserver/controller/stat.go
  92. 257 0
      servers/adminserver/controller/track.go
  93. 187 0
      servers/adminserver/controller/user.go
  94. 21 0
      servers/adminserver/controller/utm.go
  95. 48 0
      servers/adminserver/controller/white.go
  96. 74 0
      servers/adminserver/controller/withdraw.go
  97. 27 0
      servers/adminserver/controller/xwuserinfo.go
  98. 65 0
      servers/adminserver/coupon/controller.go
  99. 87 0
      servers/adminserver/coupon/couponmgr.go
  100. 16 0
      servers/adminserver/coupon/data.go

+ 5 - 0
BuildAllGames.bat

@@ -0,0 +1,5 @@
+go install bet24.com/servers/games/baloot
+go install bet24.com/servers/games/luckyfruit_table
+go install bet24.com/servers/games/masharie_table
+go install bet24.com/servers/games/quickludo
+go install bet24.com/servers/games/spinplay

+ 4 - 0
BuildAllMainServers.bat

@@ -0,0 +1,4 @@
+go install bet24.com/servers/adminserver
+go install bet24.com/servers/coreservice
+go install bet24.com/servers/fishhall
+go install bet24.com/servers/payment

+ 21 - 0
BuildAllServices.bat

@@ -0,0 +1,21 @@
+go install bet24.com/servers/micros/activityservice
+go install bet24.com/servers/micros/badge
+go install bet24.com/servers/micros/cardlibrary
+go install bet24.com/servers/micros/dbengine
+go install bet24.com/servers/micros/dotservice
+go install bet24.com/servers/micros/game
+go install bet24.com/servers/micros/giftservice
+go install bet24.com/servers/micros/guess
+go install bet24.com/servers/micros/highly_profitable
+go install bet24.com/servers/micros/item_inventory
+go install bet24.com/servers/micros/ladderservice
+go install bet24.com/servers/micros/matches
+go install bet24.com/servers/micros/money
+go install bet24.com/servers/micros/notification
+go install bet24.com/servers/micros/platformconfig
+go install bet24.com/servers/micros/privateroom
+go install bet24.com/servers/micros/slotsservice
+go install bet24.com/servers/micros/task
+go install bet24.com/servers/micros/userlabel
+go install bet24.com/servers/micros/userservices
+go install bet24.com/servers/micros/waterpool

+ 46 - 0
awscdn/awscdn.go

@@ -0,0 +1,46 @@
+package main
+
+import (
+	"fmt"
+	"os"
+)
+
+func main() {
+	defer func() {
+		fmt.Println("结束,按任意键退出")
+		var endInput string
+		fmt.Scanln(&endInput)
+	}()
+
+	if !loadConfig() {
+		fmt.Println("加载配置文件失败,青检查awscdn.json文件")
+		return
+	}
+
+	if len(os.Args) > 1 {
+		if os.Args[1] == "invalidate" {
+			if !doInvalidate() {
+				fmt.Println("刷新cdn失败,请重新尝试")
+				return
+			}
+			return
+		}
+
+		if os.Args[1] == "show" {
+			doViewList()
+			return
+		}
+	}
+
+	if !doUpload() {
+		fmt.Println("上传失败,请重新尝试")
+		return
+	}
+
+	//自动刷新cdn,暂时屏蔽(由于接入的cdn部署aws的)
+	// if !doInvalidate() {
+	// 	fmt.Println("刷新cdn失败,请重新尝试")
+	// 	return
+	// }
+	flushCdn()
+}

+ 38 - 0
awscdn/config.go

@@ -0,0 +1,38 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+)
+
+var config struct {
+	Key    string
+	Secret string
+	DistId string
+
+	Ftp_url      string
+	Ftp_user     string
+	Ftp_password string
+	Delta_path   string
+	Version_file string
+
+	Pattern string
+}
+
+func loadConfig() bool {
+	data, err := os.ReadFile("awscdn.json")
+	if err != nil {
+		fmt.Println("awscdn.loadConfig.loadData read awscdn failed")
+		return false
+	}
+
+	err = json.Unmarshal(data, &config)
+	if err != nil {
+		fmt.Println("awscdn.loadConfig.loadData Unmarshal failed", err)
+		return false
+	}
+
+	fmt.Println("awscdn.loadConfig success")
+	return true
+}

+ 92 - 0
awscdn/invalidate.go

@@ -0,0 +1,92 @@
+package main
+
+import (
+	"fmt"
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/session"
+	"github.com/aws/aws-sdk-go/service/cloudfront"
+	"time"
+)
+
+func createSession() *cloudfront.CloudFront {
+	customCreds := credentials.NewStaticCredentials(config.Key, config.Secret, "")
+	s := session.New(&aws.Config{Credentials: customCreds})
+
+	if e, a := customCreds, s.Config.Credentials; e != a {
+		fmt.Printf("expect %v, got %v\n", e, a)
+		return nil
+	}
+	return cloudfront.New(s)
+}
+
+func doViewList() {
+	svc := createSession()
+	if svc == nil {
+		fmt.Println("doViewList createSession failed")
+		return
+	}
+	if err := viewListInvalidations(svc); err != nil {
+		fmt.Println(err)
+	}
+}
+
+func doInvalidate() bool {
+	svc := createSession()
+	if svc == nil {
+		return false
+	}
+	if err := viewListInvalidations(svc); err != nil {
+		fmt.Println(err)
+	}
+
+	pattern := "/hotfix_asset*"
+	if config.Pattern != "" {
+		pattern = config.Pattern
+	}
+	if err := createInvalidationRequest(svc, pattern); err != nil {
+		fmt.Println(err)
+		return false
+	}
+
+	if err := viewListInvalidations(svc); err != nil {
+		fmt.Println(err)
+	}
+	return true
+}
+
+func viewListInvalidations(svc *cloudfront.CloudFront) error {
+	resp, err := svc.ListInvalidations(&cloudfront.ListInvalidationsInput{
+		DistributionId: aws.String(config.DistId),
+	})
+	if err != nil {
+		return fmt.Errorf("list.inval. err:%v", err.Error())
+	}
+
+	fmt.Printf("invs:%v\n", resp)
+	return nil
+}
+
+func createInvalidationRequest(svc *cloudfront.CloudFront, pattern string) error {
+	now := time.Now()
+	resp, err := svc.CreateInvalidation(&cloudfront.CreateInvalidationInput{
+		DistributionId: aws.String(config.DistId),
+		InvalidationBatch: &cloudfront.InvalidationBatch{
+			CallerReference: aws.String(
+				fmt.Sprintf("goinvali%s", now.Format("2006/01/02,15:04:05"))),
+			Paths: &cloudfront.Paths{
+				Quantity: aws.Int64(1),
+				Items: []*string{
+					aws.String(pattern),
+				},
+			},
+		},
+	})
+
+	if err != nil {
+		return fmt.Errorf("create.inval. err:%v", err.Error())
+	}
+
+	fmt.Printf("invs:%v\n", resp)
+	return nil
+}

+ 191 - 0
awscdn/upload.go

@@ -0,0 +1,191 @@
+package main
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/jlaffaye/ftp"
+)
+
+type version struct {
+	Version string
+	Cdn_dir string
+}
+
+type fileInfo struct {
+	fullPath string
+	relPath  string
+}
+
+const PthSep = string(os.PathSeparator)
+
+var totalFileUploaded int
+
+var failList []fileInfo
+
+var delta_root_path string
+var cdn_dir string
+
+func loadVersion() string {
+	d, err := os.ReadFile(config.Version_file)
+	if err != nil {
+		fmt.Printf("loadVersion failed %v\n", err)
+		return ""
+	}
+	var v version
+	err = json.Unmarshal(d, &v)
+	if err != nil {
+		fmt.Printf("loadVersion Unmarshal failed %v\n", err)
+		return ""
+	}
+	cdn_dir = v.Cdn_dir
+	vs := strings.Split(v.Version, ".")
+	if len(vs) != 3 {
+		fmt.Printf("loadVersion split version failed %s\n", v.Version)
+		return ""
+	}
+	lv, _ := strconv.ParseInt(vs[len(vs)-1], 10, 32)
+	lv--
+	vs[len(vs)-1] = fmt.Sprintf("%d", lv)
+	lastVersion := fmt.Sprintf("%v", vs[0])
+	for i := 1; i < len(vs); i++ {
+		lastVersion = fmt.Sprintf("%v.%v", lastVersion, vs[i])
+	}
+
+	fmt.Printf("loadVersion lastVersion = %s\n", lastVersion)
+	return lastVersion
+}
+
+func doUpload() bool {
+	totalFileUploaded = 0
+	c, err := ftp.Dial(config.Ftp_url, ftp.DialWithTimeout(5*time.Second))
+	if err != nil {
+		fmt.Printf("doUpload 连接ftp服务器失败 %v\n", err)
+		return false
+	}
+
+	err = c.Login(config.Ftp_user, config.Ftp_password)
+	if err != nil {
+		fmt.Printf("doUpload 登录ftp服务器失败 %v\n", err)
+		return false
+	}
+
+	fmt.Printf("登录ftp完成\n")
+
+	lastVersion := loadVersion()
+
+	root_path := config.Delta_path + PthSep + lastVersion
+	delta_root_path = root_path
+
+	fmt.Printf("开始遍历delta目录 %s\n", root_path)
+	uploadDir(root_path, "", c)
+
+	loopCount := 0
+	for {
+		if len(failList) == 0 {
+			break
+		}
+		loopCount++
+		if loopCount > 10 {
+			fmt.Printf("尝试上传失败文件达10次,退出 \n")
+			return false
+		}
+		tmpFailed := make([]fileInfo, len(failList))
+		copy(tmpFailed, failList)
+		failList = []fileInfo{}
+		fmt.Printf("正在上传失败文件 总共失败 %d \n", len(tmpFailed))
+		for _, v := range tmpFailed {
+			uploadFile(v.fullPath, v.relPath, c)
+		}
+	}
+
+	fmt.Printf("上传完成,总共上传 %d 个文件 \n", totalFileUploaded)
+	return totalFileUploaded > 0
+}
+
+func uploadDir(fullPath string, relPath string, c *ftp.ServerConn) {
+	dir, err := os.ReadDir(fullPath)
+	if err != nil {
+		return
+	}
+	if relPath != "" {
+		err := c.MakeDir(relPath)
+		if err != nil && !strings.Contains(err.Error(), "exists") {
+			fmt.Printf("uploadDir make dir failed %v  path = %s\n", err, relPath)
+		}
+	}
+	for _, fi := range dir {
+		if fi.IsDir() { // 忽略目录
+			uploadDir(fullPath+PthSep+fi.Name(), relPath+PthSep+fi.Name(), c)
+		} else {
+			uploadFile(fullPath+PthSep+fi.Name(), relPath+PthSep+fi.Name(), c)
+		}
+	}
+}
+
+func uploadFile(fullPath string, relPath string, c *ftp.ServerConn) {
+	dat1, err1 := os.ReadFile(fullPath)
+	if err1 != nil {
+		fmt.Printf("uploadFile read file %s failed\n", fullPath)
+		return
+	}
+	err := c.Stor(relPath, bytes.NewReader(dat1))
+	if err != nil {
+		fmt.Printf("uploadFile store failed %v relPath=%s\n", err, relPath)
+		failList = append(failList, fileInfo{fullPath: fullPath, relPath: relPath})
+
+	} else {
+		fmt.Printf("    %s 已上传\n", relPath)
+		totalFileUploaded++
+	}
+}
+
+func flushCdn() {
+	if cdn_dir == "" {
+		return
+	}
+	fmt.Printf("正在覆盖cdn目录,%s -> %s \n", delta_root_path, cdn_dir)
+	copyDir(delta_root_path, cdn_dir)
+}
+
+func copyFile(dstName, srcName string) (written int64, err error) {
+	src, err := os.Open(srcName)
+	if err != nil {
+		fmt.Println("copy file " + srcName + " error")
+		return
+	}
+	defer src.Close()
+	os.Remove(dstName)
+	dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
+	if err != nil {
+		fmt.Println("open file " + dstName + " error")
+		return
+	}
+	defer dst.Close()
+	//fmt.Println("copy file " + srcName + " to " + dstName)
+	return io.Copy(dst, src)
+}
+
+func copyDir(srcPath string, destPath string) {
+	os.MkdirAll(destPath, 0777)
+	dir, err := os.ReadDir(srcPath)
+	if err != nil {
+		return
+	}
+	for _, fi := range dir {
+		if fi.IsDir() { // 忽略目录
+			outPath := destPath + PthSep + fi.Name()
+			copyDir(srcPath+PthSep+fi.Name(), outPath)
+		} else {
+			srcFile := srcPath + PthSep + fi.Name()
+			destFile := destPath + PthSep + fi.Name()
+			copyFile(destFile, srcFile)
+		}
+	}
+}

+ 238 - 0
creatorversion/creatorversion.go

@@ -0,0 +1,238 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+)
+
+/*
+说明:
+	大厅部分的project.manifest需要拷贝回resources/version,打包需要重新编译一次
+*/
+
+const PthSep = string(os.PathSeparator)
+
+type VersionInfo struct {
+	Url         string
+	Version     string
+	PubDir      string
+	OutDir      string
+	PrePubDir   string
+	Modules     []string
+	Cdn_dir     string
+	MetaVersion string
+	XXTeaSign   string
+	XXTeaKey    string
+	EncodeSufix []string
+}
+
+func Marshal(v VersionInfo) []byte {
+	data, err := json.Marshal(v)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return data
+}
+
+func Unmarshal(data []byte) VersionInfo {
+	var user VersionInfo
+	err := json.Unmarshal(data, &user)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return user
+}
+
+func Read() []byte {
+	fp, err := os.OpenFile("./creatorversion.json", os.O_RDONLY, 0755)
+	defer fp.Close()
+	if err != nil {
+		log.Fatal(err)
+	}
+	data := make([]byte, 1024)
+	n, err := fp.Read(data)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return data[:n]
+}
+
+func Write(data []byte) {
+	fp, err := os.OpenFile("./creatorversion.json", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer fp.Close()
+	_, err = fp.Write(data)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func removeManifest(srcPath string) {
+	dir, err := os.ReadDir(srcPath)
+	if err != nil {
+		return
+	}
+	for _, fi := range dir {
+		if fi.IsDir() { // 忽略目录
+			removeManifest(srcPath + PthSep + fi.Name())
+		} else {
+			if fi.Name() == "project.manifest" || fi.Name() == "version.manifest" {
+				os.Remove(srcPath + PthSep + fi.Name())
+			}
+		}
+	}
+}
+
+func makeManifest(version, url, dir, out_dir, name string) {
+	fmt.Println("makeManifest ", version, url, dir, out_dir, name)
+	cmd := exec.Command("node", "version_generator.js", "-v", version, "-u", url,
+		"-s", dir, "-d", out_dir, "-n", name)
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		log.Fatal(err)
+	}
+	// 保证关闭输出流
+	defer stdout.Close()
+	// 运行命令
+	if err := cmd.Start(); err != nil {
+		log.Fatal(err)
+	}
+	// 读取输出结果
+	opBytes, err := io.ReadAll(stdout)
+	if err != nil {
+		log.Fatal(err)
+	}
+	log.Println(string(opBytes))
+	cmd.Start()
+	cmd.Wait()
+}
+
+func isNeedEncode(file string, postFixes []string) bool {
+	for _, v := range postFixes {
+		if strings.HasSuffix(file, v) {
+			return true
+		}
+	}
+	return false
+}
+
+func main() {
+	defer func() {
+		fmt.Println("结束,按任意键退出")
+		var endInput string
+		fmt.Scanln(&endInput)
+	}()
+
+	versionInfo := Unmarshal(Read())
+	fmt.Println(versionInfo)
+
+	if len(os.Args) >= 2 && os.Args[1] == "decode" {
+		fmt.Println("开始还原加密")
+		StartDecodeDir(versionInfo.PubDir+PthSep+"assets", versionInfo.PubDir+PthSep+"assets",
+			versionInfo.XXTeaKey, versionInfo.XXTeaSign, versionInfo.EncodeSufix)
+		return
+	}
+
+	v := strings.Split(versionInfo.Version, ".")
+	if len(v) <= 0 {
+		return
+	}
+
+	if versionInfo.XXTeaKey != "" {
+		fmt.Println("xxtea 加密")
+		StartEncodeDir(versionInfo.PubDir+PthSep+"assets", versionInfo.PubDir+PthSep+"assets",
+			versionInfo.XXTeaKey, versionInfo.XXTeaSign, versionInfo.EncodeSufix)
+	}
+
+	// 拷贝预发布
+	fmt.Println("正在拷贝预发布")
+	os.RemoveAll(versionInfo.PrePubDir)
+	copyDir(versionInfo.PubDir+PthSep+"src", versionInfo.PrePubDir+PthSep+"src")
+	copyDir(versionInfo.PubDir+PthSep+"assets", versionInfo.PrePubDir+PthSep+"assets")
+
+	outputVersion := versionInfo.Version
+
+	outputDir := fmt.Sprintf("release%v%v", PthSep, outputVersion)
+	os.RemoveAll(outputDir)
+	os.MkdirAll(outputDir+PthSep+"assets", 0777)
+	subModule := "assets" // subpackages
+	// 子模块编译到assets目录中去了,先把子模块代码抽出来
+	for _, v := range versionInfo.Modules {
+		fmt.Println("正在生成manifest", v)
+		//moduleDest := outputDir + PthSep + subModule + PthSep + v
+
+		//os.MkdirAll(moduleDest, 0777)
+
+		makeManifest(versionInfo.Version, versionInfo.Url+"assets/"+v+"/",
+			versionInfo.PrePubDir+PthSep+subModule+PthSep+v,
+			versionInfo.PrePubDir+PthSep+subModule+PthSep+v, "")
+		CopyFile(versionInfo.PubDir+subModule+PthSep+v+"/project.manifest", versionInfo.PrePubDir+PthSep+subModule+PthSep+v+"/project.manifest")
+		src := versionInfo.PrePubDir + PthSep + subModule + PthSep + v
+		dst := outputDir + PthSep + subModule + PthSep + v
+		fmt.Printf("转移模块 %v -> %v\n", src, dst)
+		err := os.Rename(src, dst)
+		if err != nil {
+			fmt.Printf("%v\n", err)
+		}
+	}
+
+	/**outputDir = fmt.Sprintf("release%v%v", PthSep, outputVersion)
+	fmt.Println("正在copy src目录")
+	copyDir(versionInfo.PubDir+"/src", fmt.Sprintf("%v/src", outputDir))
+	fmt.Println("正在copy assets")
+	copyDir(versionInfo.PubDir+"/assets", fmt.Sprintf("%v/assets", outputDir))*/
+
+	fmt.Println("正在制作大厅 manifest")
+	makeManifest(versionInfo.Version, versionInfo.Url, versionInfo.PrePubDir, versionInfo.PrePubDir, "")
+
+	CopyFile(versionInfo.OutDir+"/project.manifest", versionInfo.PrePubDir+PthSep+"project.manifest")
+	CopyFile(outputDir+PthSep+"/project.manifest", versionInfo.PrePubDir+PthSep+"project.manifest")
+	CopyFile(outputDir+PthSep+"/version.manifest", versionInfo.PrePubDir+PthSep+"version.manifest")
+	copyDir(versionInfo.PrePubDir+PthSep+"src", outputDir+PthSep+"src")
+	copyDir(versionInfo.PrePubDir+PthSep+"assets", outputDir+PthSep+"assets")
+
+	// 把大厅的manifest拷贝到build目录下
+	fmt.Println("正在拷贝大厅 manifest")
+	CopyFile(versionInfo.PubDir+subModule+PthSep+versionInfo.MetaVersion, versionInfo.PrePubDir+PthSep+"project.manifest")
+
+	// 通过比较,生成delta文件
+	if versionInfo.Cdn_dir != "" {
+		fmt.Println("正在生成delta 文件 ", versionInfo.Cdn_dir)
+		deltaDir := fmt.Sprintf("delta%v%v", PthSep, outputVersion)
+		compareFolder(outputDir, versionInfo.Cdn_dir, deltaDir)
+	}
+
+	// 删除无用部分
+	fmt.Println("正在删除无更新游戏目录")
+	for _, v := range versionInfo.Modules {
+		dir := fmt.Sprintf("delta%v%v/assets/%s", PthSep, outputVersion, v)
+		if isDeltaEmpty(dir) {
+			fmt.Printf(" %s\n", dir)
+			os.RemoveAll(dir)
+		}
+	}
+
+	// 版本维护
+	lastVersion, _ := strconv.ParseInt(v[len(v)-1], 10, 32)
+	lastVersion++
+	v[len(v)-1] = fmt.Sprintf("%d", lastVersion)
+	newVersion := fmt.Sprintf("%v", v[0])
+	for i := 1; i < len(v); i++ {
+		newVersion = fmt.Sprintf("%v.%v", newVersion, v[i])
+	}
+
+	versionInfo.Version = newVersion
+	fmt.Println("正在更新版本号 为 ", versionInfo.Version)
+
+	data := Marshal(versionInfo)
+	Write(data)
+
+}

+ 122 - 0
creatorversion/file.go

@@ -0,0 +1,122 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"os"
+)
+
+func CopyFile(dstName, srcName string) (written int64, err error) {
+	if dstName == srcName {
+		return
+	}
+	src, err := os.Open(srcName)
+	if err != nil {
+		fmt.Println("copy file " + srcName + " error")
+		return
+	}
+	defer src.Close()
+	os.Remove(dstName)
+	dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
+	if err != nil {
+		fmt.Println("open file " + dstName + " error")
+		return
+	}
+	defer dst.Close()
+	return io.Copy(dst, src)
+}
+
+func copyDir(srcPath string, destPath string) {
+	os.MkdirAll(destPath, 0777)
+	dir, err := os.ReadDir(srcPath)
+	if err != nil {
+		return
+	}
+	for _, fi := range dir {
+		if fi.IsDir() { // 忽略目录
+			outPath := destPath + PthSep + fi.Name()
+			copyDir(srcPath+PthSep+fi.Name(), outPath)
+		} else {
+			srcFile := srcPath + PthSep + fi.Name()
+			destFile := destPath + PthSep + fi.Name()
+			CopyFile(destFile, srcFile)
+		}
+	}
+}
+
+func isFileEqual(file1 string, file2 string) bool {
+	// 打开文件
+	dat1, err1 := os.ReadFile(file1)
+	if err1 != nil {
+		return false
+	}
+	dat2, err2 := os.ReadFile(file2)
+	if err2 != nil {
+		return false
+	}
+	byteData1 := []byte(dat1)
+	dataLen1 := len(byteData1)
+	byteData2 := []byte(dat2)
+	dataLen2 := len(byteData2)
+	if dataLen1 != dataLen2 {
+		return false
+	}
+	//fmt.Println(fmt.Errorf("EncodePicFile %s len = %d", srcFile, dataLen))
+	for i := 0; i < dataLen1; i++ {
+		if byteData1[i] != byteData2[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func doCompareFolder(srcPath string, destPath string, outputPath string) int {
+	diffCount := 0
+	dir, err := os.ReadDir(srcPath)
+	if err != nil {
+		return diffCount
+	}
+	for _, fi := range dir {
+		if fi.IsDir() { // 忽略目录
+			diffCount += doCompareFolder(srcPath+PthSep+fi.Name(), destPath+PthSep+fi.Name(), outputPath+PthSep+fi.Name())
+		} else {
+			//fmt.Println(dirPth + PthSep + fi.Name())
+			srcFile := srcPath + PthSep + fi.Name()
+			destFile := destPath + PthSep + fi.Name()
+			outFile := outputPath + PthSep + fi.Name()
+			//func(src, dest, outName, outPath string) {
+			if !isFileEqual(srcFile, destFile) {
+				os.MkdirAll(outputPath, 0777)
+				CopyFile(outFile, srcFile)
+				diffCount++
+			}
+			//}(srcFile, destFile, outFile, outputPath)
+		}
+	}
+	return diffCount
+}
+
+func isDeltaEmpty(srcPath string) bool {
+	dir, err := os.ReadDir(srcPath)
+	if err != nil {
+		return true
+	}
+	fileCount := 0
+	for _, fi := range dir {
+		if fi.IsDir() { // 忽略目录
+			return false
+		} else {
+			fileCount++
+		}
+	}
+	return fileCount <= 2
+}
+
+func compareFolder(srcPath string, destPath string, outputPath string) {
+	fmt.Printf("compareFolder %v:%v to %v\n", srcPath, destPath, outputPath)
+	if doCompareFolder(srcPath, destPath, outputPath) <= 2 {
+		// 只有版本文件不一样,删除目录
+		fmt.Printf("Removing delta folder %v\n", outputPath)
+		os.RemoveAll(outputPath)
+	}
+}

+ 122 - 0
creatorversion/xxtea.go

@@ -0,0 +1,122 @@
+package main
+
+import (
+	"bytes"
+	"os"
+	"strings"
+	"sync"
+
+	"github.com/xxtea/xxtea-go/xxtea"
+)
+
+func EncodeFile(srcFile string, destFile string, password string, sign string, sufixes []string) bool {
+	//fmt.Println("EncodeFile " + srcFile)
+	// 是否要加密的文件
+	if isNeedEncode(srcFile, sufixes) {
+		// 打开文件
+		dat, err := os.ReadFile(srcFile)
+		if err != nil {
+			return false
+		}
+		// 已经加密过
+		if strings.HasPrefix(string(dat), sign) {
+			return false
+		}
+		encrypt_data := xxtea.Encrypt([]byte(dat), []byte(password))
+		s := make([][]byte, 2)
+		s[0] = []byte(sign)
+		s[1] = encrypt_data
+		sep := []byte("")
+		os.WriteFile(destFile, bytes.Join(s, sep), 0777)
+		return true
+	}
+	return false
+}
+
+func DecodeFile(srcFile string, destFile string, password string, sign string, sufixes []string) bool {
+	// 是否要加密的文件
+	if isNeedEncode(srcFile, sufixes) {
+		// 打开文件
+		dat, err := os.ReadFile(srcFile)
+		if err != nil {
+			return false
+		}
+		// 没有加密过
+		if !strings.HasPrefix(string(dat), sign) {
+			return false
+		}
+
+		decrypt_data := xxtea.Decrypt(([]byte(dat))[len(sign):], []byte(password))
+		os.WriteFile(destFile, decrypt_data, 0777)
+		return true
+	}
+	return false
+}
+
+func DoEncodeFile(srcFile string, destFile string, password string, sign string, wg *sync.WaitGroup, sufixes []string) {
+	defer wg.Done()
+	if !EncodeFile(srcFile, destFile, password, sign, sufixes) {
+		CopyFile(destFile, srcFile)
+	}
+}
+
+func DoDecodeFile(srcFile string, destFile string, password string, sign string, wg *sync.WaitGroup, sufixes []string) {
+	defer wg.Done()
+	if !DecodeFile(srcFile, destFile, password, sign, sufixes) {
+		CopyFile(destFile, srcFile)
+	}
+}
+
+func EncodeDir(srcPath string, destPath string, password string, sign string, wg *sync.WaitGroup, sufixes []string) {
+	dir, err := os.ReadDir(srcPath)
+	if err != nil {
+		return
+	}
+	// 创建文件夹
+	os.MkdirAll(destPath, 0777)
+
+	for _, fi := range dir {
+		if fi.IsDir() { // 忽略目录
+			EncodeDir(srcPath+PthSep+fi.Name(), destPath+PthSep+fi.Name(), password, sign, wg, sufixes)
+		} else {
+			//fmt.Println(dirPth + PthSep + fi.Name())
+			srcFile := srcPath + PthSep + fi.Name()
+			destFile := destPath + PthSep + fi.Name()
+			wg.Add(1)
+			go DoEncodeFile(srcFile, destFile, password, sign, wg, sufixes)
+		}
+	}
+}
+
+func DecodeDir(srcPath string, destPath string, password string, sign string, wg *sync.WaitGroup, sufixes []string) {
+	dir, err := os.ReadDir(srcPath)
+	if err != nil {
+		return
+	}
+	// 创建文件夹
+	os.MkdirAll(destPath, 0777)
+
+	for _, fi := range dir {
+		if fi.IsDir() { // 忽略目录
+			DecodeDir(srcPath+PthSep+fi.Name(), destPath+PthSep+fi.Name(), password, sign, wg, sufixes)
+		} else {
+			//fmt.Println(dirPth + PthSep + fi.Name())
+			srcFile := srcPath + PthSep + fi.Name()
+			destFile := destPath + PthSep + fi.Name()
+			wg.Add(1)
+			go DoDecodeFile(srcFile, destFile, password, sign, wg, sufixes)
+		}
+	}
+}
+
+func StartEncodeDir(srcPath string, destPath string, password string, sign string, sufixes []string) {
+	var wg sync.WaitGroup
+	EncodeDir(srcPath, destPath, password, sign, &wg, sufixes)
+	wg.Wait()
+}
+
+func StartDecodeDir(srcPath string, destPath string, password string, sign string, sufixes []string) {
+	var wg sync.WaitGroup
+	DecodeDir(srcPath, destPath, password, sign, &wg, sufixes)
+	wg.Wait()
+}

+ 40 - 0
database/database.go

@@ -0,0 +1,40 @@
+package database
+
+import (
+	"bet24.com/log"
+	_ "github.com/denisenkom/go-mssqldb"
+)
+
+type DataBase struct {
+	sqlServer *SqlServer
+}
+
+func NewDataBase(datasource, database, login, password string) *DataBase {
+	db := new(DataBase)
+	db.start(datasource, database, login, password)
+	return db
+}
+
+func (this *DataBase) start(datasource, database, login, password string) bool {
+	this.sqlServer = NewSqlServer(datasource, database, login, password)
+	if this.sqlServer == nil {
+		log.Error("连接到数据库[%s : %s]失败\n", datasource, database)
+		return false
+	}
+
+	log.Debug("datasource=%s database=%s 连接到数据成功...", datasource, database)
+	return true
+}
+
+func (this *DataBase) ExecSql(sql string) [][]interface{} {
+	return this.sqlServer.execSql(sql)
+}
+
+func (this *DataBase) ExecSqlJson(sql string) string {
+	ret, err := this.sqlServer.execSqlJson(sql)
+	if err != nil {
+		log.Release("DataBase.ExecSqlJson error = %v", err)
+		return ""
+	}
+	return ret
+}

+ 185 - 0
database/sqlserver.go

@@ -0,0 +1,185 @@
+package database
+
+//import _ "github.com/denisenkom/go-mssqldb"
+import (
+	"bet24.com/log"
+	"database/sql"
+	"encoding/json"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type SqlServer struct {
+	m_db          *sql.DB
+	goroutine_cnt chan int
+}
+
+func NewSqlServer(datasource, database, user, password string) *SqlServer {
+	this := new(SqlServer)
+	if !this.OpenDB(datasource, database, user, password) {
+		return nil
+	}
+	this.goroutine_cnt = make(chan int, 30)
+	return this
+}
+
+func (this *SqlServer) OpenDB(ds string, database string, user string, password string) bool {
+	connString := fmt.Sprintf("server=%s;database=%s;user id=%s;password=%s;port=1433;encrypt=disable",
+		ds, database, user, password)
+
+	fmt.Printf(" connString:%s\n", connString)
+
+	db, err := sql.Open("mssql", connString)
+	if err != nil {
+		log.Error("Open connection failed: %v", err.Error())
+		return false
+	}
+	db.SetMaxIdleConns(64)
+	db.SetMaxOpenConns(64)
+	err = db.Ping()
+	if err != nil {
+		log.Error("PING:%s\n", err)
+		return false
+	}
+	this.m_db = db
+	return true
+}
+
+func (this *SqlServer) execSqlJson(sqlString string) (string, error) {
+	this.goroutine_cnt <- 1
+	db := this.m_db
+
+	defer func() {
+		//c <- ret
+		<-this.goroutine_cnt
+	}()
+
+	rows, err := db.Query(sqlString)
+	
+	if err != nil {
+		return "", err
+	}
+	defer rows.Close()
+	columns, err := rows.Columns()
+	if err != nil {
+		return "", err
+	}
+	count := len(columns)
+	tableData := make([]map[string]interface{}, 0)
+	values := make([]interface{}, count)
+	valuePtrs := make([]interface{}, count)
+	for rows.Next() {
+		for i := 0; i < count; i++ {
+			valuePtrs[i] = &values[i]
+		}
+		rows.Scan(valuePtrs...)
+		entry := make(map[string]interface{})
+		for i, col := range columns {
+			var v interface{}
+			val := values[i]
+			b, ok := val.([]byte)
+			if ok {
+				str := string(b)
+				// 可能是float
+				if strings.Contains(str, ".") {
+					f, err := strconv.ParseFloat(str, 64)
+					if err == nil {
+						v = f
+					}
+				}
+				if v == nil {
+					v = str
+				}
+			} else {
+				v = val
+			}
+			entry[col] = v
+		}
+		tableData = append(tableData, entry)
+	}
+	jsonData, err := json.Marshal(tableData)
+	if err != nil {
+		return "", err
+	}
+	// fmt.Println(string(jsonData))
+	return string(jsonData), nil
+}
+
+func (this *SqlServer) execSql(sqlstring string) [][]interface{} {
+	this.goroutine_cnt <- 1
+	db := this.m_db
+
+	var ret [][]interface{}
+	defer func() {
+		//c <- ret
+		<-this.goroutine_cnt
+	}()
+
+	rows, err := db.Query(sqlstring)
+	if err != nil {
+		log.Error("db.Query %v %s\n", err.Error(), sqlstring)
+		return ret
+	}
+	defer rows.Close()
+
+	for {
+		cols, err := rows.Columns()
+		if err != nil {
+			log.Error("rows.Columns() %v", err.Error())
+			return ret
+		}
+		if cols == nil {
+			log.Error("cols == nil %v", err.Error())
+			return ret
+		}
+		for rows.Next() {
+			vals := make([]interface{}, len(cols))
+			for i := 0; i < len(cols); i++ {
+				vals[i] = new(interface{})
+			}
+			err = rows.Scan(vals...)
+			if err != nil {
+				fmt.Println(err)
+				continue
+			}
+
+			//log
+			//for i := 0; i < len(vals); i++ {
+			//	if i != 0 {
+			//		log.Debug("\t")
+			//	}
+			//	printValue(vals[i].(*interface{}))
+			//}
+
+			//fmt.Println()
+
+			ret = append(ret, vals)
+		}
+		if !rows.NextResultSet() {
+			break
+		}
+	}
+
+	return ret
+}
+
+func printValue(pval *interface{}) {
+	switch v := (*pval).(type) {
+	case nil:
+		log.Debug("nil NULL")
+	case bool:
+		if v {
+			log.Debug("bool 1")
+		} else {
+			log.Debug("bool 0")
+		}
+	case []byte:
+		log.Debug("[]byte %s", v)
+	case time.Time:
+		log.Debug("time.Time %s", v.Format("2006-01-02 15:04:05.999"))
+	default:
+		log.Debug("default %v", v)
+	}
+}

+ 147 - 0
database/statement.go

@@ -0,0 +1,147 @@
+// Statement.go
+package database
+
+import (
+	"fmt"
+
+	"bet24.com/log"
+)
+
+const (
+	AdParamInput = iota
+	AdParamOutput
+	AdParamInputOutput
+)
+
+const (
+	AdTinyInt = iota
+	AdSmallInt
+	AdInteger
+	AdBigint
+	AdChar
+	AdVarChar
+	AdBinary
+	AdFloat
+	AdNVarChar
+)
+
+type Parameter struct {
+	IO      int
+	Name    string
+	Type    int
+	Data    interface{}
+	DataLen int
+}
+
+type Statement struct {
+	Params          []Parameter
+	NeedReturnValue bool
+	IsOpenRecordSet bool
+	ProcName        string
+}
+
+func NewStatement() *Statement {
+	this := new(Statement)
+	return this
+}
+
+func (this *Statement) AddParamter(name string, io, t int, dataLen int, value interface{}) {
+	p := Parameter{io, name, t, value, dataLen}
+	this.Params = append(this.Params, p)
+}
+
+func (this *Statement) SetProcName(name string) {
+	this.ProcName = name
+}
+
+func (this *Statement) SetNeedReturnValue(b bool) {
+	this.NeedReturnValue = b
+}
+
+func (this *Statement) SetOpenRecordSet(b bool) {
+	this.IsOpenRecordSet = b
+}
+
+func (this *Statement) GenSql() string {
+	if len(this.ProcName) == 0 {
+		log.Error("Statement.GenSql faile no procname")
+		return ""
+	}
+	if len(this.Params) == 0 {
+		return fmt.Sprintf("exec %s", this.ProcName)
+	}
+
+	ret := "declare "
+	if this.NeedReturnValue {
+		ret = fmt.Sprintf("%v @RETURN_VALUE int", ret)
+		if len(this.Params) > 0 {
+			ret = fmt.Sprintf("%v; declare ", ret)
+		}
+	}
+	// 声明所有参数
+	for k, v := range this.Params {
+		if k != 0 {
+			ret = fmt.Sprintf("%v; declare ", ret)
+		}
+		switch v.Type {
+		case AdTinyInt:
+			ret = fmt.Sprintf("%v%s TINYINT; set %s=%v", ret, v.Name, v.Name, v.Data)
+		case AdSmallInt:
+			ret = fmt.Sprintf("%v%s SMALLINT; set %s=%v", ret, v.Name, v.Name, v.Data)
+		case AdInteger:
+			ret = fmt.Sprintf("%v%s INT; set %s=%v", ret, v.Name, v.Name, v.Data)
+		case AdFloat:
+			ret = fmt.Sprintf("%v%s DECIMAL(18, 4); set %s=%v", ret, v.Name, v.Name, v.Data)
+		case AdBigint:
+			ret = fmt.Sprintf("%v%s BIGINT; set %s=%v", ret, v.Name, v.Name, v.Data)
+		case AdChar:
+			ret = fmt.Sprintf("%v%s CHAR(%d); set %s='%v'", ret, v.Name, v.DataLen, v.Name, v.Data)
+		case AdVarChar:
+			ret = fmt.Sprintf("%v%s VARCHAR(%d); set %s='%v'", ret, v.Name, v.DataLen, v.Name, v.Data)
+		case AdBinary:
+			ret = fmt.Sprintf("%v%s VARBINARY(%d); set %s =0x%s", ret, v.Name, v.DataLen, v.Name, v.Data)
+		case AdNVarChar:
+			ret = fmt.Sprintf("%v%s NVARCHAR(%d); set %s=N'%v'", ret, v.Name, v.DataLen, v.Name, v.Data)
+		}
+	}
+	// 声明结束
+	ret = fmt.Sprintf("%v;", ret)
+	if !this.NeedReturnValue {
+		ret = fmt.Sprintf("%v exec %s ", ret, this.ProcName)
+	} else {
+		ret = fmt.Sprintf("%v exec @RETURN_VALUE = %s ", ret, this.ProcName)
+	}
+	// 执行参数
+	comma := ""
+	for _, v := range this.Params {
+		if v.IO == AdParamOutput || v.IO == AdParamInputOutput {
+			ret = fmt.Sprintf("%v%s%v OUTPUT", ret, comma, v.Name)
+		} else {
+			ret = fmt.Sprintf("%v%s%v", ret, comma, v.Name)
+		}
+		comma = ","
+	}
+	// 如果返回结果集
+	/*if this.IsOpenRecordSet {
+		return ret
+	}*/
+
+	outStr := ""
+	comma = ""
+	for _, v := range this.Params {
+		if v.IO == AdParamOutput || v.IO == AdParamInputOutput {
+			outStr = fmt.Sprintf("%v%s%s", outStr, comma, v.Name)
+			comma = ","
+		}
+	}
+	if this.NeedReturnValue || len(outStr) > 0 {
+		ret = fmt.Sprintf("%v ;select ", ret)
+	}
+
+	if this.NeedReturnValue {
+		ret = fmt.Sprintf("%v @RETURN_VALUE%s%s", ret, comma, outStr)
+	} else {
+		ret = fmt.Sprintf("%v%v", ret, outStr)
+	}
+	return ret
+}

+ 20 - 0
database/trans_base.go

@@ -0,0 +1,20 @@
+package database
+
+// 未保证线程同步,当数据库操作需要输出的时候,对应的transaction需要继承ITransaction及trans_base
+// 对应的DoAction也通过channel异步返回
+// 如果该数据库操作无须返回,则不需要继承
+type ITransaction interface {
+	OnRet()
+	DoAction(ch chan<- interface{})
+}
+
+type Trans_base struct {
+	RetFunc func(state bool)
+	State   bool
+}
+
+func (this *Trans_base) OnRet() {
+	if this.RetFunc != nil {
+		this.RetFunc(this.State)
+	}
+}

+ 190 - 0
event/event_chan.go

@@ -0,0 +1,190 @@
+package event
+
+import (
+	"context"
+	"fmt"
+	"runtime/debug"
+	"sync"
+	"time"
+
+	"bet24.com/log"
+)
+
+type IEventChan interface {
+	OnEvent()
+	//Dispatch(ch chan<- interface{})
+}
+
+type EventChan_base struct {
+	EventFunc func(arg string)
+	Arg       string
+	obj       chan interface{}
+}
+
+func (e *EventChan_base) OnEvent() {
+	if e.EventFunc != nil {
+		e.EventFunc(e.Arg)
+	}
+}
+
+func (ei *EventChan_base) isSame(ei2 *EventChan_base) bool {
+	if ei2 == nil {
+		return false
+	}
+
+	if fmt.Sprintf("%p", ei.obj) != fmt.Sprintf("%p", ei2.obj) {
+		return false
+	}
+	return fmt.Sprintf("%p", ei.EventFunc) == fmt.Sprintf("%p", ei2.EventFunc)
+}
+
+func (ei *EventChan_base) isSameObject(obj interface{}) bool {
+	if obj == nil {
+		return false
+	}
+
+	return fmt.Sprintf("%p", ei.obj) == fmt.Sprintf("%p", obj)
+}
+
+type event_chan struct {
+	sync.RWMutex
+	events map[string][]EventChan_base
+}
+
+var g = newEvent()
+
+func newEvent() *event_chan {
+	return &event_chan{
+		events: make(map[string][]EventChan_base),
+	}
+}
+
+func hasFunc(name string, ei *EventChan_base) bool {
+	evt, ok := g.events[name]
+	if !ok {
+		return false
+	}
+
+	for _, f := range evt {
+		if f.isSame(ei) {
+			return true
+		}
+	}
+	return false
+}
+
+func AddEvent(name string, obj chan interface{}, fn func(arg string)) {
+	g.Lock()
+	defer g.Unlock()
+	if obj == nil || fn == nil {
+		log.Release("AddEvent no obj or f %v", name)
+		return
+	}
+	ei := EventChan_base{obj: obj, EventFunc: fn}
+	if hasFunc(name, &ei) {
+		log.Release("AddEvent same event %v", name)
+		return
+	}
+	g.events[name] = append(g.events[name], ei)
+}
+
+func RemoveEvent(name string, obj chan interface{}, fn func(arg string)) {
+	g.Lock()
+	defer g.Unlock()
+	if obj == nil || fn == nil {
+		log.Release("RemoveEvent no obj or fn %v", name)
+		return
+	}
+
+	evt, ok := g.events[name]
+	if !ok {
+		log.Release("RemoveEvent event name not found: %s", name)
+		return
+	}
+	ei := EventChan_base{obj: obj, EventFunc: fn}
+
+	//for k, f := range evt {
+	for i := 0; i < len(evt); {
+		if evt[i].isSame(&ei) {
+			log.Debug("Removing Event %v,%v", name, evt[i])
+			evt = append(evt[:i], evt[i+1:]...)
+		} else {
+			i++
+		}
+	}
+	g.events[name] = evt
+	//}
+	if len(g.events[name]) == 0 {
+		log.Debug("Remove name: %s", name)
+		delete(g.events, name)
+	}
+}
+
+// 删除对象所有事件
+func RemoveAllEvent(obj interface{}) {
+	if obj == nil {
+		log.Release("RemoveAllEvent no obj")
+		return
+	}
+	g.Lock()
+	for name, evt := range g.events {
+		for i := 0; i < len(evt); {
+			if evt[i].isSameObject(obj) {
+				evt = append(evt[:i], evt[i+1:]...)
+			} else {
+				i++
+			}
+		}
+		if len(evt) > 0 {
+			g.events[name] = evt
+		} else {
+			delete(g.events, name)
+		}
+	}
+	g.Unlock()
+}
+
+func DispatchEvent(eventName, eventArg string) {
+	go func(n, a string) {
+		g.RLock()
+		fns := g.events[n]
+		g.RUnlock()
+		if len(fns) == 0 {
+			return
+		}
+		defer func() {
+			if err := recover(); err != nil {
+				log.Release("DispatchEvent recover err %v", err)
+				log.Release("%s", debug.Stack())
+			}
+		}()
+		for i := len(fns) - 1; i >= 0; i-- {
+			obj := fns[i]
+			obj.Arg = a
+			//log.Debug("Dispatching event %v:%v", eventName, obj)
+			ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*500)
+			select {
+			case <-ctx.Done():
+				//log.Release("Dispatch event timeout %v:%v", eventName, obj)
+				//RemoveEvent(n, fns[i].obj, fns[i].EventFunc)
+				break
+			case fns[i].obj <- &(obj):
+				break
+			}
+			cancel()
+		}
+	}(eventName, eventArg)
+}
+
+func Dump() {
+	go func() {
+		g.RLock()
+		defer g.RUnlock()
+		for name, fns := range g.events {
+			log.Release("event name[%v],count[%d]", name, len(fns))
+			for _, v := range fns {
+				log.Release("event func %v", v)
+			}
+		}
+	}()
+}

+ 299 - 0
go.mod

@@ -0,0 +1,299 @@
+module bet24.com
+
+go 1.21.4
+
+require (
+	cloud.google.com/go/translate v1.9.3
+	firebase.google.com/go v3.13.0+incompatible
+	github.com/360EntSecGroup-Skylar/excelize v1.4.1
+	github.com/alexmullins/zip v0.0.0-20180717182244-4affb64b04d0
+	github.com/aws/aws-sdk-go v1.48.4
+	github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
+	github.com/denisenkom/go-mssqldb v0.12.3
+	github.com/gin-gonic/gin v1.9.1
+	github.com/go-sql-driver/mysql v1.7.1
+	github.com/golang/protobuf v1.5.3
+	github.com/gomodule/redigo v1.8.9
+	github.com/google/uuid v1.4.0
+	github.com/gorilla/websocket v1.5.1
+	github.com/hashicorp/consul/api v1.26.1
+	github.com/huandu/facebook v2.3.1+incompatible
+	github.com/jlaffaye/ftp v0.2.0
+	github.com/mattn/go-colorable v0.1.13
+	github.com/pkg/errors v0.9.1
+	github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
+	github.com/robfig/cron v1.2.0
+	github.com/rpcxio/rpcx-consul v0.0.0-20230904043151-f6175fbe2f72
+	github.com/satori/go.uuid v1.2.0
+	github.com/sideshow/apns2 v0.23.0
+	github.com/smallnest/rpcx v1.8.21
+	github.com/unrolled/secure v1.13.0
+	github.com/xuri/excelize/v2 v2.8.0
+	github.com/xxtea/xxtea-go v1.0.0
+	golang.org/x/crypto v0.15.0
+	golang.org/x/net v0.18.0
+	golang.org/x/oauth2 v0.14.0
+	golang.org/x/text v0.14.0
+	google.golang.org/api v0.151.0
+)
+
+require (
+	github.com/DataDog/datadog-go v4.8.2+incompatible // indirect
+	github.com/Microsoft/go-winio v0.6.1 // indirect
+	github.com/aliyun/alibaba-cloud-sdk-go v1.62.156 // indirect
+	github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e // indirect
+	github.com/armon/go-radix v1.0.0 // indirect
+	github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
+	github.com/benbjohnson/immutable v0.4.0 // indirect
+	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/boltdb/bolt v1.3.1 // indirect
+	github.com/cenkalti/backoff/v3 v3.0.0 // indirect
+	github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
+	github.com/cespare/xxhash/v2 v2.2.0 // indirect
+	github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible // indirect
+	github.com/circonus-labs/circonusllhist v0.1.3 // indirect
+	github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect
+	github.com/coreos/etcd v3.3.27+incompatible // indirect
+	github.com/coreos/go-oidc v2.1.0+incompatible // indirect
+	github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
+	github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf // indirect
+	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+	github.com/docker/go-connections v0.4.0 // indirect
+	github.com/emicklei/go-restful/v3 v3.10.1 // indirect
+	github.com/envoyproxy/go-control-plane v0.11.1 // indirect
+	github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect
+	github.com/fsnotify/fsnotify v1.6.0 // indirect
+	github.com/go-logr/logr v1.2.4 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/go-openapi/analysis v0.21.4 // indirect
+	github.com/go-openapi/errors v0.20.3 // indirect
+	github.com/go-openapi/jsonpointer v0.19.5 // indirect
+	github.com/go-openapi/jsonreference v0.20.0 // indirect
+	github.com/go-openapi/loads v0.21.2 // indirect
+	github.com/go-openapi/runtime v0.25.0 // indirect
+	github.com/go-openapi/spec v0.20.8 // indirect
+	github.com/go-openapi/strfmt v0.21.3 // indirect
+	github.com/go-openapi/swag v0.22.3 // indirect
+	github.com/go-openapi/validate v0.22.1 // indirect
+	github.com/go-ozzo/ozzo-validation v3.6.0+incompatible // indirect
+	github.com/google/btree v1.0.1 // indirect
+	github.com/google/gnostic v0.5.7-v3refs // indirect
+	github.com/google/go-cmp v0.6.0 // indirect
+	github.com/google/gofuzz v1.2.0 // indirect
+	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
+	github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
+	github.com/hashicorp/consul-awsauth v0.0.0-20220713182709-05ac1c5c2706 // indirect
+	github.com/hashicorp/consul-net-rpc v0.0.0-20221205195236-156cfab66a69 // indirect
+	github.com/hashicorp/consul/envoyextensions v0.5.1 // indirect
+	github.com/hashicorp/consul/proto-public v0.5.1 // indirect
+	github.com/hashicorp/consul/sdk v0.15.0 // indirect
+	github.com/hashicorp/go-bexpr v0.1.2 // indirect
+	github.com/hashicorp/go-connlimit v0.3.0 // indirect
+	github.com/hashicorp/go-memdb v1.3.4 // indirect
+	github.com/hashicorp/go-msgpack v1.1.5 // indirect
+	github.com/hashicorp/go-msgpack/v2 v2.0.0 // indirect
+	github.com/hashicorp/go-plugin v1.4.5 // indirect
+	github.com/hashicorp/go-raftchunking v0.7.0 // indirect
+	github.com/hashicorp/go-retryablehttp v0.6.7 // indirect
+	github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6 // indirect
+	github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect
+	github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect
+	github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
+	github.com/hashicorp/go-sockaddr v1.0.2 // indirect
+	github.com/hashicorp/go-syslog v1.0.0 // indirect
+	github.com/hashicorp/go-uuid v1.0.3 // indirect
+	github.com/hashicorp/go-version v1.2.1 // indirect
+	github.com/hashicorp/hcl v1.0.0 // indirect
+	github.com/hashicorp/hcp-scada-provider v0.2.3 // indirect
+	github.com/hashicorp/hcp-sdk-go v0.61.0 // indirect
+	github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038 // indirect
+	github.com/hashicorp/memberlist v0.5.0 // indirect
+	github.com/hashicorp/net-rpc-msgpackrpc/v2 v2.0.0 // indirect
+	github.com/hashicorp/raft v1.5.0 // indirect
+	github.com/hashicorp/raft-autopilot v0.1.6 // indirect
+	github.com/hashicorp/raft-boltdb/v2 v2.2.2 // indirect
+	github.com/hashicorp/raft-wal v0.4.1 // indirect
+	github.com/hashicorp/vault-plugin-auth-alicloud v0.14.0 // indirect
+	github.com/hashicorp/vault/api v1.8.3 // indirect
+	github.com/hashicorp/vault/api/auth/gcp v0.3.0 // indirect
+	github.com/hashicorp/vault/sdk v0.7.0 // indirect
+	github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect
+	github.com/imdario/mergo v0.3.15 // indirect
+	github.com/josharian/intern v1.0.0 // indirect
+	github.com/mailru/easyjson v0.7.7 // indirect
+	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
+	github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
+	github.com/mitchellh/copystructure v1.2.0 // indirect
+	github.com/mitchellh/go-testing-interface v1.14.0 // indirect
+	github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452 // indirect
+	github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
+	github.com/mitchellh/pointerstructure v1.2.1 // indirect
+	github.com/mitchellh/reflectwalk v1.0.2 // indirect
+	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+	github.com/oklog/run v1.0.0 // indirect
+	github.com/oklog/ulid v1.3.1 // indirect
+	github.com/oklog/ulid/v2 v2.1.0 // indirect
+	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
+	github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
+	github.com/pierrec/lz4 v2.6.1+incompatible // indirect
+	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+	github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
+	github.com/prometheus/client_golang v1.14.0 // indirect
+	github.com/prometheus/client_model v0.4.0 // indirect
+	github.com/prometheus/common v0.39.0 // indirect
+	github.com/prometheus/procfs v0.8.0 // indirect
+	github.com/ryanuber/go-glob v1.0.0 // indirect
+	github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
+	github.com/segmentio/fasthash v1.0.3 // indirect
+	github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
+	github.com/stretchr/objx v0.5.0 // indirect
+	github.com/stretchr/testify v1.8.3 // indirect
+	github.com/syndtr/goleveldb v1.0.0 // indirect
+	github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect
+	github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
+	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
+	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+	go.etcd.io/bbolt v1.3.7 // indirect
+	go.mongodb.org/mongo-driver v1.11.0 // indirect
+	go.opentelemetry.io/otel v1.16.0 // indirect
+	go.opentelemetry.io/otel/metric v1.16.0 // indirect
+	go.opentelemetry.io/otel/sdk v1.16.0 // indirect
+	go.opentelemetry.io/otel/sdk/metric v0.39.0 // indirect
+	go.opentelemetry.io/otel/trace v1.16.0 // indirect
+	go.opentelemetry.io/proto/otlp v0.19.0 // indirect
+	go.uber.org/atomic v1.9.0 // indirect
+	golang.org/x/term v0.14.0 // indirect
+	gopkg.in/inf.v0 v0.9.1 // indirect
+	gopkg.in/ini.v1 v1.66.2 // indirect
+	gopkg.in/square/go-jose.v2 v2.5.1 // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
+	k8s.io/api v0.26.2 // indirect
+	k8s.io/apimachinery v0.26.2 // indirect
+	k8s.io/client-go v0.26.2 // indirect
+	k8s.io/klog/v2 v2.90.1 // indirect
+	k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
+	k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect
+	sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
+	sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
+	sigs.k8s.io/yaml v1.3.0 // indirect
+	xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 // indirect
+)
+
+require (
+	cloud.google.com/go v0.110.8 // indirect
+	cloud.google.com/go/compute v1.23.1 // indirect
+	cloud.google.com/go/compute/metadata v0.2.3 // indirect
+	cloud.google.com/go/firestore v1.13.0 // indirect
+	cloud.google.com/go/iam v1.1.3 // indirect
+	cloud.google.com/go/longrunning v0.5.2 // indirect
+	cloud.google.com/go/storage v1.30.1 // indirect
+	github.com/akutz/memconn v0.1.0 // indirect
+	github.com/alitto/pond v1.8.3 // indirect
+	github.com/apache/thrift v0.18.1 // indirect
+	github.com/armon/go-metrics v0.4.1 // indirect
+	github.com/bytedance/sonic v1.9.1 // indirect
+	github.com/cenk/backoff v2.2.1+incompatible // indirect
+	github.com/cenkalti/backoff v2.2.1+incompatible // indirect
+	github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
+	github.com/dgryski/go-jump v0.0.0-20211018200510-ba001c3ffce0 // indirect
+	github.com/edwingeng/doublejump v1.0.1 // indirect
+	github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
+	github.com/fatih/color v1.14.1 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.2 // indirect
+	github.com/gin-contrib/sse v0.1.0 // indirect
+	github.com/go-echarts/go-echarts/v2 v2.3.2 // indirect
+	github.com/go-ping/ping v1.1.0 // indirect
+	github.com/go-playground/locales v0.14.1 // indirect
+	github.com/go-playground/universal-translator v0.18.1 // indirect
+	github.com/go-playground/validator/v10 v10.14.0 // indirect
+	github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
+	github.com/goccy/go-json v0.10.2 // indirect
+	github.com/godzie44/go-uring v0.0.0-20220926161041-69611e8b13d5 // indirect
+	github.com/gogo/protobuf v1.3.2 // indirect
+	github.com/golang-jwt/jwt/v4 v4.4.1 // indirect
+	github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
+	github.com/golang-sql/sqlexp v0.1.0 // indirect
+	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+	github.com/golang/mock v1.6.0 // indirect
+	github.com/golang/snappy v0.0.4 // indirect
+	github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect
+	github.com/google/s2a-go v0.1.7 // indirect
+	github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
+	github.com/googleapis/gax-go/v2 v2.12.0 // indirect
+	github.com/grandcat/zeroconf v1.0.0 // indirect
+	github.com/hashicorp/consul v1.17.0
+	github.com/hashicorp/errwrap v1.1.0 // indirect
+	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+	github.com/hashicorp/go-hclog v1.5.0 // indirect
+	github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
+	github.com/hashicorp/go-multierror v1.1.1 // indirect
+	github.com/hashicorp/go-rootcerts v1.0.2 // indirect
+	github.com/hashicorp/golang-lru v0.5.4 // indirect
+	github.com/hashicorp/serf v0.10.1 // indirect
+	github.com/jamiealquiza/tachymeter v2.0.0+incompatible // indirect
+	github.com/jmespath/go-jmespath v0.4.0 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/juju/ratelimit v1.0.2 // indirect
+	github.com/julienschmidt/httprouter v1.3.0 // indirect
+	github.com/kavu/go_reuseport v1.5.0 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.4 // indirect
+	github.com/klauspost/reedsolomon v1.11.7 // indirect
+	github.com/leodido/go-urn v1.2.4 // indirect
+	github.com/libp2p/go-sockaddr v0.1.1 // indirect
+	github.com/mattn/go-isatty v0.0.19 // indirect
+	github.com/miekg/dns v1.1.51 // indirect
+	github.com/mitchellh/go-homedir v1.1.0 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
+	github.com/onsi/ginkgo/v2 v2.9.0 // indirect
+	github.com/pelletier/go-toml/v2 v2.0.8 // indirect
+	github.com/philhofer/fwd v1.1.2 // indirect
+	github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
+	github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
+	github.com/quic-go/quic-go v0.34.0 // indirect
+	github.com/richardlehane/mscfb v1.0.4 // indirect
+	github.com/richardlehane/msoleps v1.0.3 // indirect
+	github.com/rpcxio/libkv v0.5.1 // indirect
+	github.com/rs/cors v1.8.3 // indirect
+	github.com/rubyist/circuitbreaker v2.2.1+incompatible // indirect
+	github.com/smallnest/quick v0.1.0 // indirect
+	github.com/smallnest/statsview v0.0.0-20231119085602-10700f9abec4 // indirect
+	github.com/soheilhy/cmux v0.1.5 // indirect
+	github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
+	github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
+	github.com/tinylib/msgp v1.1.8 // indirect
+	github.com/tjfoc/gmsm v1.4.1 // indirect
+	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
+	github.com/ugorji/go/codec v1.2.11 // indirect
+	github.com/valyala/fastrand v1.1.0 // indirect
+	github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
+	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+	github.com/xtaci/kcp-go v5.4.20+incompatible // indirect
+	github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect
+	github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect
+	go.opencensus.io v0.24.0 // indirect
+	golang.org/x/arch v0.3.0 // indirect
+	golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
+	golang.org/x/mod v0.12.0 // indirect
+	golang.org/x/sync v0.5.0 // indirect
+	golang.org/x/sys v0.14.0 // indirect
+	golang.org/x/time v0.3.0 // indirect
+	golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
+	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
+	google.golang.org/appengine v1.6.7 // indirect
+	google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
+	google.golang.org/grpc v1.59.0 // indirect
+	google.golang.org/protobuf v1.31.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+	xorm.io/xorm v1.3.4
+
+)
+
+replace (
+	github.com/gorilla/websocket => ../github.com/gorilla/websocket
+	github.com/satori/go.uuid => ../github.com/satori/go.uuid
+)

+ 1674 - 0
go.sum

@@ -0,0 +1,1674 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
+cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
+cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
+cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
+cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
+cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
+cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
+cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
+cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
+cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
+cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
+cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
+cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME=
+cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/compute v1.23.1 h1:V97tBoDaZHb6leicZ1G6DLK2BAaZLJ/7+9BB/En3hR0=
+cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78=
+cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
+cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/firestore v1.13.0 h1:/3S4RssUV4GO/kvgJZB+tayjhOfyAHs+KcpJgRVu/Qk=
+cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8=
+cloud.google.com/go/iam v1.1.3 h1:18tKG7DzydKWUnLjonWcJO6wjSCAtzh4GcRKlH/Hrzc=
+cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE=
+cloud.google.com/go/longrunning v0.5.2 h1:u+oFqfEwwU7F9dIELigxbe0XVnBAo9wqMuQLA50CZ5k=
+cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUzqv2YttZiveCs=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
+cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
+cloud.google.com/go/translate v1.9.3 h1:t5WXTqlrk8VVJu/i3WrYQACjzYJiff5szARHiyqqPzI=
+cloud.google.com/go/translate v1.9.3/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4=
+firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs=
+gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
+gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
+github.com/360EntSecGroup-Skylar/excelize v1.4.1 h1:l55mJb6rkkaUzOpSsgEeKYtS6/0gHwBYyfo5Jcjv/Ks=
+github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
+github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
+github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
+github.com/DataDog/datadog-go v4.8.2+incompatible h1:qbcKSx29aBLD+5QLvlQZlGmRMF/FfGqFLFev/1TDzRo=
+github.com/DataDog/datadog-go v4.8.2+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
+github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
+github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
+github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20201120081800-1786d5ef83d4/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
+github.com/alexmullins/zip v0.0.0-20180717182244-4affb64b04d0 h1:BVts5dexXf4i+JX8tXlKT0aKoi38JwTXSe+3WUneX0k=
+github.com/alexmullins/zip v0.0.0-20180717182244-4affb64b04d0/go.mod h1:FDIQmoMNJJl5/k7upZEnGvgWVZfFeE6qHeN7iCMbCsA=
+github.com/alitto/pond v1.8.3 h1:ydIqygCLVPqIX/USe5EaV/aSRXTRXDEI9JwuDdu+/xs=
+github.com/alitto/pond v1.8.3/go.mod h1:CmvIIGd5jKLasGI3D87qDkQxjzChdKMmnXMg3fG6M6Q=
+github.com/aliyun/alibaba-cloud-sdk-go v1.62.156 h1:K4N91T1+RlSlx+t2dujeDviy4ehSGVjEltluDgmeHS4=
+github.com/aliyun/alibaba-cloud-sdk-go v1.62.156/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/apache/thrift v0.18.1 h1:lNhK/1nqjbwbiOPDBPFJVKxgDEGSepKuTh6OLiXW8kg=
+github.com/apache/thrift v0.18.1/go.mod h1:rdQn/dCcDKEWjjylUeueum4vQEjG2v8v2PqriUnbr+I=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
+github.com/armon/go-metrics v0.3.6/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
+github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
+github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
+github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
+github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
+github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
+github.com/aws/aws-sdk-go v1.48.4 h1:HS2L7ynVhkcRrQRro9CLJZ/xLRb4UOzDEfPzgevZwXM=
+github.com/aws/aws-sdk-go v1.48.4/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
+github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
+github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
+github.com/benbjohnson/immutable v0.4.0 h1:CTqXbEerYso8YzVPxmWxh2gnoRQbbB9X1quUC8+vGZA=
+github.com/benbjohnson/immutable v0.4.0/go.mod h1:iAr8OjJGLnLmVUr9MZ/rz4PWUy6Ouc2JLYuMArmvAJM=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
+github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
+github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
+github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
+github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
+github.com/cenk/backoff v2.2.1+incompatible h1:djdFT7f4gF2ttuzRKPbMOWgZajgesItGLwG5FTQKmmE=
+github.com/cenk/backoff v2.2.1+incompatible/go.mod h1:7FtoeaSnHoZnmZzz47cM35Y9nSW7tNyaidugnHTaFDE=
+github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c=
+github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
+github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
+github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
+github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY=
+github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
+github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA=
+github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
+github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/coreos/etcd v3.3.27+incompatible h1:QIudLb9KeBsE5zyYxd1mjzRSkzLg9Wf9QlRwFgd6oTA=
+github.com/coreos/etcd v3.3.27+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM=
+github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
+github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf h1:GOPo6vn/vTN+3IwZBvXX0y5doJfSC7My0cdzelyOCsQ=
+github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
+github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
+github.com/dgryski/go-jump v0.0.0-20170409065014-e1f439676b57/go.mod h1:4hKCXuwrJoYvHZxJ86+bRVTOMyJ0Ej+RqfSm8mHi6KA=
+github.com/dgryski/go-jump v0.0.0-20211018200510-ba001c3ffce0 h1:0wH6nO9QEa02Qx8sIQGw6ieKdz+BXjpccSOo9vXNl4U=
+github.com/dgryski/go-jump v0.0.0-20211018200510-ba001c3ffce0/go.mod h1:4hKCXuwrJoYvHZxJ86+bRVTOMyJ0Ej+RqfSm8mHi6KA=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/edwingeng/doublejump v1.0.1 h1:wJ6QgNyyF23Of9vw+ThbwJ/obe9KdxaWEg/Brpv5S1o=
+github.com/edwingeng/doublejump v1.0.1/go.mod h1:ykMWX8JWePtMtk2OGjNE9kwtgpI+SF2FNIyXV4gS36k=
+github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
+github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
+github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
+github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM=
+github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
+github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
+github.com/evanphx/json-patch/v5 v5.5.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
+github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw=
+github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
+github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
+github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
+github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
+github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
+github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
+github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
+github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
+github.com/go-echarts/go-echarts/v2 v2.3.2 h1:imRxqF5sLtEPBsv5HGwz9KklNuwCo0fTITZ31mrgfzo=
+github.com/go-echarts/go-echarts/v2 v2.3.2/go.mod h1:56YlvzhW/a+du15f3S2qUGNDfKnFOeJSThBIrVFHDtI=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
+github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY=
+github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc=
+github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo=
+github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
+github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
+github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
+github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc=
+github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
+github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
+github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
+github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g=
+github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro=
+github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw=
+github.com/go-openapi/runtime v0.25.0 h1:7yQTCdRbWhX8vnIjdzU8S00tBYf7Sg71EBeorlPHvhc=
+github.com/go-openapi/runtime v0.25.0/go.mod h1:Ux6fikcHXyyob6LNWxtE96hWwjBPYF0DXgVFuMTneOs=
+github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
+github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
+github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU=
+github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
+github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
+github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
+github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o=
+github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
+github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU=
+github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
+github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE=
+github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
+github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
+github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
+github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/go-redis/redis/v8 v8.8.2/go.mod h1:F7resOH5Kdug49Otu24RjHWwgK7u9AmtqWMnCV1iP5Y=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
+github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
+github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
+github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
+github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
+github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
+github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
+github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
+github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
+github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
+github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
+github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
+github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
+github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
+github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
+github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
+github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
+github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
+github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
+github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
+github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/godzie44/go-uring v0.0.0-20220926161041-69611e8b13d5 h1:5zELAgnSz0gqmr4Q5DWCoOzNHoeBAxVUXB7LS1eG+sw=
+github.com/godzie44/go-uring v0.0.0-20220926161041-69611e8b13d5/go.mod h1:ermjEDUoT/fS+3Ona5Vd6t6mZkw1eHp99ILO5jGRBkM=
+github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
+github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ=
+github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
+github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
+github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
+github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
+github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
+github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
+github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
+github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
+github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso=
+github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
+github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
+github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
+github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
+github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
+github.com/grandcat/zeroconf v1.0.0 h1:uHhahLBKqwWBV6WZUDAT71044vwOTL+McW0mBJvo6kE=
+github.com/grandcat/zeroconf v1.0.0/go.mod h1:lTKmG1zh86XyCoUeIHSA4FJMBwCJiQmGfcP2PdzytEs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
+github.com/hashicorp/consul v1.17.0 h1:djvpA44p6E7sLdgTNUCtvGktEHlFEPw1a3tquT1hWqQ=
+github.com/hashicorp/consul v1.17.0/go.mod h1:W5Ea0mjHs9c2jeAQR3ajbgmcDU6LnZDRdo53JGhnbFE=
+github.com/hashicorp/consul-awsauth v0.0.0-20220713182709-05ac1c5c2706 h1:1ZEjnveDe20yFa6lSkfdQZm5BR/b271n0MsB5R2L3us=
+github.com/hashicorp/consul-awsauth v0.0.0-20220713182709-05ac1c5c2706/go.mod h1:1Cs8FlmD1BfSQXJGcFLSV5FuIx1AbJP+EJGdxosoS2g=
+github.com/hashicorp/consul-net-rpc v0.0.0-20221205195236-156cfab66a69 h1:wzWurXrxfSyG1PHskIZlfuXlTSCj1Tsyatp9DtaasuY=
+github.com/hashicorp/consul-net-rpc v0.0.0-20221205195236-156cfab66a69/go.mod h1:svUZZDvotY8zTODknUePc6mZ9pX8nN0ViGwWcUSOBEA=
+github.com/hashicorp/consul/api v1.8.1/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk=
+github.com/hashicorp/consul/api v1.26.1 h1:5oSXOO5fboPZeW5SN+TdGFP/BILDgBm19OrPZ/pICIM=
+github.com/hashicorp/consul/api v1.26.1/go.mod h1:B4sQTeaSO16NtynqrAdwOlahJ7IUDZM9cj2420xYL8A=
+github.com/hashicorp/consul/envoyextensions v0.5.1 h1:W5vkAKr60r3NUa7JjGZU6obTYms9PWgtEKB+MB+90YI=
+github.com/hashicorp/consul/envoyextensions v0.5.1/go.mod h1:M/VMPmhwjksu66pxQ6RBKkQEI7Qn6RM8hSnIoJUgskI=
+github.com/hashicorp/consul/proto-public v0.5.1 h1:g4xHZ7rJ56iktDi1uThKp+IbvHrP6nveZeGVt2Qw5x0=
+github.com/hashicorp/consul/proto-public v0.5.1/go.mod h1:SayEhfXS3DQDnW/vKSZXvkwDObg7XK60KTfrJcp0wrg=
+github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM=
+github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU=
+github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-bexpr v0.1.2 h1:ijMXI4qERbzxbCnkxmfUtwMyjrrk3y+Vt0MxojNCbBs=
+github.com/hashicorp/go-bexpr v0.1.2/go.mod h1:ANbpTX1oAql27TZkKVeW8p1w8NTdnyzPe/0qqPCKohU=
+github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-connlimit v0.3.0 h1:oAojHGjFxUTTTA8c5XXnDqWJ2HLuWbDiBPTpWvNzvqM=
+github.com/hashicorp/go-connlimit v0.3.0/go.mod h1:OUj9FGL1tPIhl/2RCfzYHrIiWj+VVPGNyVPnUX8AqS0=
+github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v0.16.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
+github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
+github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk=
+github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c=
+github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
+github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs=
+github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4=
+github.com/hashicorp/go-msgpack/v2 v2.0.0 h1:c1fiLq1LNghmLOry1ipGhvLDi+/zEoaEP2JrE1oFJ9s=
+github.com/hashicorp/go-msgpack/v2 v2.0.0/go.mod h1:JIxYkkFJRDDRSoWQBSh7s9QAVThq+82iWmUpmE4jKak=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
+github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo=
+github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
+github.com/hashicorp/go-raftchunking v0.7.0 h1:APNMnCXmTOhumkFv/GpJIbq7HteWF7EnGZ3875lRN0Y=
+github.com/hashicorp/go-raftchunking v0.7.0/go.mod h1:Dg/eBOaJzE0jYKNwNLs5IA5j0OSmL5HoCUiMy3mDmrI=
+github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
+github.com/hashicorp/go-retryablehttp v0.6.7 h1:8/CAEZt/+F7kR7GevNHulKkUjLht3CPmn7egmhieNKo=
+github.com/hashicorp/go-retryablehttp v0.6.7/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
+github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
+github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
+github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6 h1:W9WN8p6moV1fjKLkeqEgkAMu5rauy9QeYDAmIaPuuiA=
+github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6/go.mod h1:MpCPSPGLDILGb4JMm94/mMi3YysIqsXzGCzkEZjcjXg=
+github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw=
+github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc=
+github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I=
+github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
+github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ=
+github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
+github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo=
+github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
+github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
+github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
+github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
+github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
+github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
+github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
+github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/hcp-scada-provider v0.2.3 h1:AarYR+/Pcv+cMvPdAlb92uOBmZfEH6ny4+DT+4NY2VQ=
+github.com/hashicorp/hcp-scada-provider v0.2.3/go.mod h1:ZFTgGwkzNv99PLQjTsulzaCplCzOTBh0IUQsPKzrQFo=
+github.com/hashicorp/hcp-sdk-go v0.61.0 h1:x4hJ8SlLI5WCE8Uzcu4q5jfdOEz/hFxfUkhAdoFdzSg=
+github.com/hashicorp/hcp-sdk-go v0.61.0/go.mod h1:xP7wmWAmdMxs/7+ovH3jZn+MCDhHRj50Rn+m7JIY3Ck=
+github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038 h1:n9J0rwVWXDpNd5iZnwY7w4WZyq53/rROeI7OVvLW8Ok=
+github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
+github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
+github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
+github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
+github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
+github.com/hashicorp/net-rpc-msgpackrpc/v2 v2.0.0 h1:kBpVVl1sl3MaSrs97e0+pDQhSrqJv9gVbSUrPpVfl1w=
+github.com/hashicorp/net-rpc-msgpackrpc/v2 v2.0.0/go.mod h1:6pdNz0vo0mF0GvhwDG56O3N18qBrAz/XRIcfINfTbwo=
+github.com/hashicorp/raft v1.1.0/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM=
+github.com/hashicorp/raft v1.2.0/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
+github.com/hashicorp/raft v1.3.11/go.mod h1:J8naEwc6XaaCfts7+28whSeRvCqTd6e20BlCU3LtEO4=
+github.com/hashicorp/raft v1.5.0 h1:uNs9EfJ4FwiArZRxxfd/dQ5d33nV31/CdCHArH89hT8=
+github.com/hashicorp/raft v1.5.0/go.mod h1:pKHB2mf/Y25u3AHNSXVRv+yT+WAnmeTX0BwVppVQV+M=
+github.com/hashicorp/raft-autopilot v0.1.6 h1:C1q3RNF2FfXNZfHWbvVAu0QixaQK8K5pX4O5lh+9z4I=
+github.com/hashicorp/raft-autopilot v0.1.6/go.mod h1:Af4jZBwaNOI+tXfIqIdbcAnh/UyyqIMj/pOISIfhArw=
+github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk=
+github.com/hashicorp/raft-boltdb v0.0.0-20210409134258-03c10cc3d4ea/go.mod h1:qRd6nFJYYS6Iqnc/8HcUmko2/2Gw8qTFEmxDLii6W5I=
+github.com/hashicorp/raft-boltdb/v2 v2.2.2 h1:rlkPtOllgIcKLxVT4nutqlTH2NRFn+tO1wwZk/4Dxqw=
+github.com/hashicorp/raft-boltdb/v2 v2.2.2/go.mod h1:N8YgaZgNJLpZC+h+by7vDu5rzsRgONThTEeUS3zWbfY=
+github.com/hashicorp/raft-wal v0.4.1 h1:aU8XZ6x8R9BAIB/83Z1dTDtXvDVmv9YVYeXxd/1QBSA=
+github.com/hashicorp/raft-wal v0.4.1/go.mod h1:A6vP5o8hGOs1LHfC1Okh9xPwWDcmb6Vvuz/QyqUXlOE=
+github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
+github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
+github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
+github.com/hashicorp/vault-plugin-auth-alicloud v0.14.0 h1:O6tNk0s/arubLUbLeCyaRs5xGo9VwmbQazISY/BfPK4=
+github.com/hashicorp/vault-plugin-auth-alicloud v0.14.0/go.mod h1:We3fJplmALwK1VpjwrLuXr/4QCQHYMdnXLHmLUU6Ntg=
+github.com/hashicorp/vault/api v1.8.0/go.mod h1:uJrw6D3y9Rv7hhmS17JQC50jbPDAZdjZoTtrCCxxs7E=
+github.com/hashicorp/vault/api v1.8.3 h1:cHQOLcMhBR+aVI0HzhPxO62w2+gJhIrKguQNONPzu6o=
+github.com/hashicorp/vault/api v1.8.3/go.mod h1:4g/9lj9lmuJQMtT6CmVMHC5FW1yENaVv+Nv4ZfG8fAg=
+github.com/hashicorp/vault/api/auth/gcp v0.3.0 h1:taum+3pCmOXnNgEKHlQbmgXmKw5daWHk7YJrLPP/w8g=
+github.com/hashicorp/vault/api/auth/gcp v0.3.0/go.mod h1:gnNBFOASYUaFunedTHOzdir7vKcHL3skWBUzEn263bo=
+github.com/hashicorp/vault/sdk v0.6.0/go.mod h1:+DRpzoXIdMvKc88R4qxr+edwy/RvH5QK8itmxLiDHLc=
+github.com/hashicorp/vault/sdk v0.7.0 h1:2pQRO40R1etpKkia5fb4kjrdYMx3BHklPxl1pxpxDHg=
+github.com/hashicorp/vault/sdk v0.7.0/go.mod h1:KyfArJkhooyba7gYCKSq8v66QdqJmnbAxtV/OX1+JTs=
+github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I=
+github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/huandu/facebook v2.3.1+incompatible h1:+F6kUqKx5TifzMg2fXYZFdA/3VVNphdNK8G4PF2ui74=
+github.com/huandu/facebook v2.3.1+incompatible/go.mod h1:wJogp9rhXUUjDuhx6ZaR5Eylx3dsJmy0zyFRaPYUq5g=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
+github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
+github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
+github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
+github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
+github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
+github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
+github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
+github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E=
+github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
+github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
+github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
+github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
+github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
+github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
+github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
+github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
+github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
+github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
+github.com/jackc/pgx/v4 v4.18.0/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
+github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jamiealquiza/tachymeter v2.0.0+incompatible h1:mGiF1DGo8l6vnGT8FXNNcIXht/YmjzfraiUprXYwJ6g=
+github.com/jamiealquiza/tachymeter v2.0.0+incompatible/go.mod h1:Ayf6zPZKEnLsc3winWEXJRkTBhdHo58HODAu1oFJkYU=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
+github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
+github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI=
+github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
+github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
+github.com/kavu/go_reuseport v1.5.0 h1:UNuiY2OblcqAtVDE8Gsg1kZz8zbBWg907sP1ceBV+bk=
+github.com/kavu/go_reuseport v1.5.0/go.mod h1:CG8Ee7ceMFSMnx/xr25Vm0qXaj2Z4i5PWoUx+JZ5/CU=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
+github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/klauspost/reedsolomon v1.11.7 h1:9uaHU0slncktTEEg4+7Vl7q7XUNMBUOK4R9gnKhMjAU=
+github.com/klauspost/reedsolomon v1.11.7/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
+github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/libp2p/go-sockaddr v0.1.1 h1:yD80l2ZOdGksnOyHrhxDdTDFrf7Oy+v3FMVArIRgZxQ=
+github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
+github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
+github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
+github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
+github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
+github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
+github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo=
+github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
+github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
+github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/go-testing-interface v1.14.0 h1:/x0XQ6h+3U3nAyk1yx+bHPURrKa9sVVvYbuqZ7pIAtI=
+github.com/mitchellh/go-testing-interface v1.14.0/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
+github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
+github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452 h1:hOY53G+kBFhbYFpRVxHl5eS7laP6B1+Cq+Z9Dry1iMU=
+github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
+github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
+github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/pointerstructure v1.2.1 h1:ZhBBeX8tSlRpu/FFhXH4RC4OJzFlqsQhoHZAz4x7TIw=
+github.com/mitchellh/pointerstructure v1.2.1/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
+github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
+github.com/onsi/ginkgo/v2 v2.9.0 h1:Tugw2BKlNHTMfG+CheOITkYvk4LAh6MFOvikhGVnhE8=
+github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
+github.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754=
+github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
+github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
+github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
+github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
+github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
+github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
+github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
+github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
+github.com/peterbourgon/g2s v0.0.0-20140925154142-ec76db4c1ac1 h1:5Dl+ADmsGerAqHwWzyLqkNaUBQ+48DQwfDCaW1gHAQM=
+github.com/peterbourgon/g2s v0.0.0-20140925154142-ec76db4c1ac1/go.mod h1:1VcHEd3ro4QMoHfiNl/j7Jkln9+KQuorp0PItHMJYNg=
+github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
+github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
+github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
+github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
+github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
+github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
+github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
+github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
+github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
+github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
+github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI=
+github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
+github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
+github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
+github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
+github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
+github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
+github.com/quic-go/quic-go v0.34.0 h1:OvOJ9LFjTySgwOTYUZmNoq0FzVicP8YujpV0kB7m2lU=
+github.com/quic-go/quic-go v0.34.0/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
+github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
+github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
+github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
+github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
+github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
+github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
+github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rpcxio/libkv v0.5.1 h1:M0/QqwTcdXz7us0NB+2i8Kq5+wikTm7zZ4Hyb/jNgME=
+github.com/rpcxio/libkv v0.5.1/go.mod h1:zHGgtLr3cFhGtbalum0BrMPOjhFZFJXCKiws/25ewls=
+github.com/rpcxio/rpcx-consul v0.0.0-20230904043151-f6175fbe2f72 h1:Egzag//iWWxCEaOIDLdGz3HqAGmpWyFGt/1r1lZQM3M=
+github.com/rpcxio/rpcx-consul v0.0.0-20230904043151-f6175fbe2f72/go.mod h1:N4SjBS0M9HpVdq3CIIXm/MwWv6euXQ39ybhfH2iTh1c=
+github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo=
+github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
+github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/rubyist/circuitbreaker v2.2.1+incompatible h1:KUKd/pV8Geg77+8LNDwdow6rVCAYOp8+kHUyFvL6Mhk=
+github.com/rubyist/circuitbreaker v2.2.1+incompatible/go.mod h1:Ycs3JgJADPuzJDwffe12k6BZT8hxVi6lFK+gWYJLN4A=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
+github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
+github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
+github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/sideshow/apns2 v0.23.0 h1:lpkikaZ995GIcKk6AFsYzHyezCrsrfEDvUWcWkEGErY=
+github.com/sideshow/apns2 v0.23.0/go.mod h1:7Fceu+sL0XscxrfLSkAoH6UtvKefq3Kq1n4W3ayQZqE=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
+github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
+github.com/smallnest/quick v0.1.0 h1:7/a3mvWjBNSKpcwmuiizTi5Alcn7xRkHNNuKgRda1V8=
+github.com/smallnest/quick v0.1.0/go.mod h1:mjmFVnOUd/Ruq8Gb7wxFjweGsrVILFsKrcwLz4QyX3g=
+github.com/smallnest/rpcx v1.8.21 h1:Z9QtEb6X3F0uG+7HGAkYFJx6EPXAKrJmS3G9yI9gAeQ=
+github.com/smallnest/rpcx v1.8.21/go.mod h1:l66lz8alcl0ayK+56ydFUEGFeGxSs6rU5oo7rsUolMc=
+github.com/smallnest/statsview v0.0.0-20231119085602-10700f9abec4 h1:jLb5bc8CWY/7WrZuir9Xd/RJCgPC5H/V7FO5PFS9ojA=
+github.com/smallnest/statsview v0.0.0-20231119085602-10700f9abec4/go.mod h1:BMgxQ/U/wQ/mJY8WyPxIG+e3cx7HKbKSZL+DniC2tvc=
+github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
+github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
+github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
+github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
+github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
+github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
+github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
+github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
+github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
+github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
+github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
+github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=
+github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
+github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
+github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
+github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
+github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
+github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
+github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFsk=
+github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
+github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8=
+github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ=
+github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
+github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
+github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
+github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
+github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
+github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
+github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
+github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
+github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
+github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
+github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca h1:uvPMDVyP7PXMMioYdyPH+0O+Ta/UO1WFfNYMO3Wz0eg=
+github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
+github.com/xuri/excelize/v2 v2.8.0 h1:Vd4Qy809fupgp1v7X+nCS/MioeQmYVVzi495UCTqB7U=
+github.com/xuri/excelize/v2 v2.8.0/go.mod h1:6iA2edBTKxKbZAa7X5bDhcCg51xdOn1Ar5sfoXRGrQg=
+github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a h1:Mw2VNrNNNjDtw68VsEj2+st+oCSn4Uz7vZw6TbhcV1o=
+github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
+github.com/xxtea/xxtea-go v1.0.0 h1:HUeElH97FsZS/+l+iroj0lhosKe47VMtdIL2Lz3MeFg=
+github.com/xxtea/xxtea-go v1.0.0/go.mod h1:2uvuCBt0VXxijrX5ieiAeeNT2+2MIsrs1DI9iXz7OOQ=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
+github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
+go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
+go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
+go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
+go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
+go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
+go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE=
+go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/otel v0.19.0/go.mod h1:j9bF567N9EfomkSidSfmMwIwIBuP37AMAIzVW85OxSg=
+go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
+go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
+go.opentelemetry.io/otel/metric v0.19.0/go.mod h1:8f9fglJPRnXuskQmKpnad31lcLJ2VmNNqIsx/uIwBSc=
+go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
+go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
+go.opentelemetry.io/otel/oteltest v0.19.0/go.mod h1:tI4yxwh8U21v7JD6R3BcA/2+RBoTKFexE/PJ/nSO7IA=
+go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
+go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
+go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI=
+go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI=
+go.opentelemetry.io/otel/trace v0.19.0/go.mod h1:4IXiNextNOpPnRlI4ryK69mn5iC84bjBWZQA5DXz/qg=
+go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
+go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
+go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
+golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/crypto v0.0.0-20170512130425-ab89591268e0/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
+golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
+golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
+golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
+golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
+golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
+golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
+golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
+golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
+golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
+golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
+golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
+golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
+golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
+golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
+golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
+golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
+golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
+golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
+golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
+google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
+google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
+google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
+google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
+google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
+google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
+google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
+google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
+google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
+google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
+google.golang.org/api v0.151.0 h1:FhfXLO/NFdJIzQtCqjpysWwqKk8AzGWBUhMIx67cVDU=
+google.golang.org/api v0.151.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
+google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
+google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
+google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
+google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
+google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA=
+google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI=
+google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k=
+google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE=
+google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
+google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
+google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
+google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
+google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
+gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
+gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.26.2 h1:dM3cinp3PGB6asOySalOZxEG4CZ0IAdJsrYZXE/ovGQ=
+k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU=
+k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ=
+k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I=
+k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI=
+k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU=
+k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
+k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
+k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
+k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk=
+k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
+lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
+modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
+modernc.org/cc/v3 v3.38.1/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20=
+modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
+modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI=
+modernc.org/ccgo/v3 v3.0.0-20220910160915-348f15de615a/go.mod h1:8p47QxPkdugex9J4n9P2tLZ9bK01yngIVp00g4nomW0=
+modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g=
+modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
+modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
+modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
+modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA=
+modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0=
+modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
+modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
+modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
+modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug=
+modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
+modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
+modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
+modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
+modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
+modernc.org/sqlite v1.20.4/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A=
+modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
+modernc.org/tcl v1.15.0/go.mod h1:xRoGotBZ6dU+Zo2tca+2EqVEeMmOUBzHnhIwq4YrVnE=
+modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
+modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
+sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
+xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 h1:bvLlAPW1ZMTWA32LuZMBEGHAUOcATZjzHcotf3SWweM=
+xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
+xorm.io/xorm v1.3.4 h1:vWFKzR3DhGUDl5b4srhUjhDwjxkZAc4C7BFszpu0swI=
+xorm.io/xorm v1.3.4/go.mod h1:qFJGFoVYbbIdnz2vaL5OxSQ2raleMpyRRalnq3n9OJo=

+ 30 - 0
log/example_test.go

@@ -0,0 +1,30 @@
+package log_test
+
+import (
+	l "log"
+
+	"bet24.com/log"
+)
+
+func Example() {
+	name := "Leaf"
+
+	log.Debug("My name is %v", name)
+	log.Release("My name is %v", name)
+	log.Error("My name is %v", name)
+	log.Fatal("My name is %v", name)
+
+	logger, err := log.New("release", "", "", l.LstdFlags)
+	if err != nil {
+		return
+	}
+	defer logger.Close()
+
+	logger.Debug("will not print")
+	logger.Release("My name is %v", name)
+
+	log.Export(logger)
+
+	log.Debug("will not print")
+	log.Release("My name is %v", name)
+}

+ 254 - 0
log/log.go

@@ -0,0 +1,254 @@
+package log
+
+import (
+	_ "errors"
+	"fmt"
+	"github.com/mattn/go-colorable"
+	"log"
+	"os"
+	"path"
+	"strings"
+	"time"
+)
+
+// levels
+const (
+	debugLevel   = 0
+	releaseLevel = 1
+	errorLevel   = 2
+	fatalLevel   = 3
+)
+
+const (
+	printDebugLevel   = "[D]"
+	printReleaseLevel = "[R]"
+	printErrorLevel   = "[E]"
+	printFatalLevel   = "[F]"
+)
+
+const (
+	Green   = "\033[97;42m"
+	White   = "\033[90;47m"
+	Yellow  = "\033[90;43m"
+	Red     = "\033[97;41m"
+	Blue    = "\033[97;44m"
+	Magenta = "\033[97;45m"
+	Cyan    = "\033[97;46m"
+	Reset   = "\033[0m"
+)
+
+type Logger struct {
+	console_level  int
+	console_Logger *log.Logger
+
+	file_level  int
+	file_Logger *log.Logger
+	file        *os.File
+
+	error_logger *log.Logger
+	file_error   *os.File
+}
+
+func createFileLogger(pathName string, flag int, level int) (*log.Logger, *os.File) {
+	if pathName == "" {
+		return nil, nil
+	}
+
+	// 如果文件夹不存在则创建
+	os.MkdirAll(pathName, 0777)
+
+	now := time.Now()
+
+	var filename string
+
+	// debug 分时间段写日志文件,以免文件过大
+	if level == debugLevel {
+		filename = fmt.Sprintf("%d%02d%02d%02d.log",
+			now.Year(), now.Month(), now.Day(), now.Hour())
+	} else { // 写一个日志文件
+		filename = fmt.Sprintf("%d%02d%02d.log",
+			now.Year(), now.Month(), now.Day())
+	}
+
+	fmt.Printf("createFileLogger pathName=%s fileName=%s level=%d\n", pathName, filename, level)
+
+	file, err := os.OpenFile(path.Join(pathName, filename), os.O_APPEND|os.O_CREATE, 0644)
+	if err != nil {
+		return nil, nil
+	}
+
+	return log.New(file, "", flag), file
+}
+
+func getColor(level int) string {
+	switch level {
+	case releaseLevel:
+		return Cyan
+	case errorLevel:
+		return Red
+	case fatalLevel:
+		return Magenta
+	}
+	return Reset
+}
+
+func getLevelByString(strLevel string) int {
+	var level int
+	switch strings.ToLower(strLevel) {
+	case "debug":
+		level = debugLevel
+	case "release":
+		level = releaseLevel
+	case "error":
+		level = errorLevel
+	case "fatal":
+		level = fatalLevel
+	default:
+		return debugLevel
+	}
+	return level
+}
+
+func New(consoleLevel string, fileLevel string, pathname string, flag int) (*Logger, error) {
+	flag = log.Lmsgprefix
+	// level
+	cLevel := getLevelByString(consoleLevel)
+	fLevel := getLevelByString(fileLevel)
+	consoleLogger := log.New(colorable.NewColorableStdout(), "", flag)
+	fileLogger, file := createFileLogger(pathname, flag, fLevel)
+	// new
+	logger := new(Logger)
+	logger.console_level = cLevel
+	logger.file_level = fLevel
+	logger.console_Logger = consoleLogger
+	logger.file_Logger = fileLogger
+	logger.file = file
+	return logger, nil
+}
+
+func NewWithError(consoleLevel string, fileLevel string, pathname string, flag int, errorFile string) (*Logger, error) {
+	flag = log.Lmsgprefix
+	// level
+	cLevel := getLevelByString(consoleLevel)
+	fLevel := getLevelByString(fileLevel)
+	consoleLogger := log.New(colorable.NewColorableStdout(), "", flag)
+	fileLogger, file := createFileLogger(pathname, flag, fLevel)
+	// new
+	logger := new(Logger)
+	logger.console_level = cLevel
+	logger.file_level = fLevel
+	logger.console_Logger = consoleLogger
+	logger.file_Logger = fileLogger
+	logger.file = file
+
+	errorLogger, errfile := createFileLogger(errorFile, flag, errorLevel)
+	logger.error_logger = errorLogger
+	logger.file_error = errfile
+	return logger, nil
+}
+
+func RecreateFileLog(pathname string, flag int) {
+	flag = log.Lmsgprefix
+	logger, file := createFileLogger(pathname, flag, gLogger.file_level)
+	if gLogger.file != nil {
+		gLogger.file.Close()
+	}
+	gLogger.file_Logger = logger
+	gLogger.file = file
+	//gLogger.file_Logger, gLogger.file = createFileLogger(pathname, flag, gLogger.file_level)
+}
+
+// It's dangerous to call the method on logging
+func (logger *Logger) Close() {
+	if logger.file != nil {
+		logger.file.Close()
+	}
+
+	logger.console_Logger = nil
+	logger.file_Logger = nil
+	logger.file = nil
+}
+
+func getTimeHeaser() string {
+	t := time.Now()
+	_, month, day := t.Date()
+	hour, min, sec := t.Clock()
+	return fmt.Sprintf("%02d-%02d %02d:%02d:%02d", month, day, hour, min, sec)
+}
+
+func (logger *Logger) doPrintf(color string, level int, printLevel string, format string, a ...interface{}) {
+	if level >= errorLevel && logger.error_logger != nil {
+		logger.error_logger.Output(3, getTimeHeaser()+fmt.Sprintf(format, a...))
+	} else {
+
+		if (level >= logger.console_level) && (logger.console_Logger != nil) {
+			f := fmt.Sprintf("%s %s %v %s %v", getTimeHeaser(), color, printLevel, Reset, format)
+			logger.console_Logger.Output(3, fmt.Sprintf(f, a...))
+		}
+		format = getTimeHeaser() + printLevel + format
+		if (level >= logger.file_level) && (logger.file_Logger != nil) {
+			logger.file_Logger.Output(3, fmt.Sprintf(format, a...))
+		}
+	}
+
+	if level == fatalLevel {
+		os.Exit(1)
+	}
+}
+
+func (logger *Logger) Debug(format string, a ...interface{}) {
+	logger.doPrintf(getColor(debugLevel), debugLevel, printDebugLevel, format, a...)
+}
+
+func (logger *Logger) Release(format string, a ...interface{}) {
+	logger.doPrintf(getColor(releaseLevel), releaseLevel, printReleaseLevel, format, a...)
+}
+
+func (logger *Logger) Error(format string, a ...interface{}) {
+	logger.doPrintf(getColor(errorLevel), errorLevel, printErrorLevel, format, a...)
+}
+
+func (logger *Logger) Fatal(format string, a ...interface{}) {
+	logger.doPrintf(getColor(fatalLevel), fatalLevel, printFatalLevel, format, a...)
+}
+
+func (logger *Logger) Color(color string, format string, a ...interface{}) {
+	logger.doPrintf(color, debugLevel, printDebugLevel, format, a...)
+}
+
+var gLogger, _ = New("debug", "debug", "", log.Lmsgprefix)
+
+// It's dangerous to call the method on logging
+func Export(logger *Logger) {
+	if logger != nil {
+		gLogger = logger
+	}
+}
+
+func Debug(format string, a ...interface{}) {
+	gLogger.Debug(format, a...)
+}
+
+func Color(color, format string, a ...interface{}) {
+	gLogger.Color(color, format, a...)
+}
+
+func Release(format string, a ...interface{}) {
+	gLogger.Release(format, a...)
+}
+
+func Error(format string, a ...interface{}) {
+	gLogger.Error(format, a...)
+}
+
+func Fatal(format string, a ...interface{}) {
+	gLogger.Fatal(format, a...)
+}
+
+func Close() {
+	gLogger.Close()
+}
+
+func GetDebugLogger() *log.Logger {
+	return gLogger.console_Logger
+}

+ 33 - 0
log/panic_handler.go

@@ -0,0 +1,33 @@
+package log
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"runtime/debug"
+	"time"
+)
+
+//捕获panic信息,输出到log文件
+func PanicHandler(exeName string) {
+	if err := recover(); err != nil {
+		now := time.Now()  //获取当前时间
+		pid := os.Getpid() //获取进程ID
+
+		time_str := now.Format("200601021504")                            //设定时间格式
+		fname := fmt.Sprintf("%s-%d-%s-dump.log", exeName, pid, time_str) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
+
+		path := "./panicLog"
+		os.MkdirAll(path, 0777)
+		fn := filepath.Join(path, fname)
+		f, osErr := os.Create(fn)
+		if osErr != nil {
+			return
+		}
+		defer f.Close()
+
+		f.WriteString(fmt.Sprintf("%v\r\n", err)) //输出panic信息
+		f.WriteString("========\r\n")
+		f.WriteString(string(debug.Stack())) //输出堆栈信息
+	}
+}

+ 6 - 0
network/agent.go

@@ -0,0 +1,6 @@
+package network
+
+type Agent interface {
+	Run()
+	OnClose()
+}

+ 102 - 0
network/datalink.go

@@ -0,0 +1,102 @@
+package network
+
+import (
+	"net"
+	"bet24.com/log"
+	"bet24.com/public"
+)
+
+const (
+	HEADER          uint8 = 0xAA
+	CMD_PING        uint8 = 5
+	MAX_BUFFER_SIZE int   = 4096
+)
+
+type DataLink struct {
+	recvBuffer []byte
+}
+
+func NewDataLink() *DataLink {
+	var obj = new(DataLink)
+	obj.recvBuffer = nil
+	return obj
+}
+
+func (this *DataLink) OnDataArrive(buffer []byte, onCommand func([]byte)) bool {
+	if buffer == nil {
+		return true
+	}
+	if this.recvBuffer != nil {
+		if buffer != nil {
+			buffer = append(this.recvBuffer, buffer...)
+		} else {
+			buffer = this.recvBuffer
+		}
+		this.recvBuffer = nil
+	}
+	totalLen := len(buffer)
+	if totalLen == 0 {
+		return true
+	}
+	// 不够包头
+	if totalLen < 4 {
+		this.appendTemBuffer(buffer)
+		return true
+	}
+	// 解析长度
+	var ba *public.ByteArray = public.CreateByteArray(buffer)
+	ph, _ := ba.ReadUInt8()
+	if ph != HEADER {
+		log.Debug("handleData 第一个字节不是%d %d\n", HEADER, ph)
+		return false
+	}
+	cmdID, _ := ba.ReadUInt8()
+	cmdLen, _ := ba.ReadUInt16()
+
+	if ba.Available() < int(cmdLen) {
+		// 粘包
+		this.appendTemBuffer(buffer)
+		return true
+	}
+	log.Debug("handleData cmdID = %d,cmdLen = %d,totalLen = %d", cmdID, cmdLen, totalLen)
+	// 是否第一个包
+	cmdBuffer := make([]byte, cmdLen+1)
+	cmdBuffer[0] = cmdID
+	ba.ReadBytes(cmdBuffer, int(cmdLen), 1)
+
+	onCommand(cmdBuffer)
+
+	nAvailable := ba.Available()
+	if nAvailable > 0 {
+		available := make([]byte, nAvailable)
+		ba.ReadBytes(available, nAvailable, 0)
+		this.appendTemBuffer(available)
+		return this.OnDataArrive([]byte{}, onCommand)
+	}
+	return true
+}
+
+func (this *DataLink) appendTemBuffer(buffer []byte) {
+	if this.recvBuffer == nil {
+		this.recvBuffer = buffer[:]
+		return
+	}
+	this.recvBuffer = append(this.recvBuffer, buffer...)
+}
+
+func SendData(data []byte, conn net.Conn) {
+	log.Debug("datalink SendData len = %d", len(data))
+	var buf []byte
+	var ba *public.ByteArray = public.CreateByteArray(buf)
+	dataLen := 0
+	if data != nil {
+		dataLen = len(data)
+	}
+	ba.WriteUInt8(HEADER)
+	ba.WriteUInt8(0)
+	ba.WriteInt16(int16(dataLen))
+	if data != nil {
+		ba.WriteBytes(data)
+	}
+	conn.Write(ba.Bytes())
+}

+ 372 - 0
network/encrypt_datalink.go

@@ -0,0 +1,372 @@
+package network
+
+import (
+	"net"
+
+	"bet24.com/log"
+	"bet24.com/public"
+)
+
+const (
+	MAX_USER_NUM       int    = 1024
+	MAX_SENDBUF_LEN    int    = 16384
+	MIN_FIRST_PACK_LEN int    = 7
+	SEED_XOR_KEY       uint32 = 0x5CC55CC5
+	LEN_EXCURSION      int    = 3
+	SNAP_SIZE          int    = 4
+	CMD_APPEND_SIZE    int    = 4
+	CMD_HEAD_SIZE      int    = 8
+)
+
+var sendMap = []byte{
+	0x70, 0x2F, 0x40, 0x5F, 0x44, 0x8E, 0x6E, 0x45, 0x7E, 0xAB, 0x2C, 0x1F, 0xB4, 0xAC, 0x9D, 0x91,
+	0x0D, 0x36, 0x9B, 0x0B, 0xD4, 0xC4, 0x39, 0x74, 0xBF, 0x23, 0x16, 0x14, 0x06, 0xEB, 0x04, 0x3E,
+	0x12, 0x5C, 0x8B, 0xBC, 0x61, 0x63, 0xF6, 0xA5, 0xE1, 0x65, 0xD8, 0xF5, 0x5A, 0x07, 0xF0, 0x13,
+	0xF2, 0x20, 0x6B, 0x4A, 0x24, 0x59, 0x89, 0x64, 0xD7, 0x42, 0x6A, 0x5E, 0x3D, 0x0A, 0x77, 0xE0,
+	0x80, 0x27, 0xB8, 0xC5, 0x8C, 0x0E, 0xFA, 0x8A, 0xD5, 0x29, 0x56, 0x57, 0x6C, 0x53, 0x67, 0x41,
+	0xE8, 0x00, 0x1A, 0xCE, 0x86, 0x83, 0xB0, 0x22, 0x28, 0x4D, 0x3F, 0x26, 0x46, 0x4F, 0x6F, 0x2B,
+	0x72, 0x3A, 0xF1, 0x8D, 0x97, 0x95, 0x49, 0x84, 0xE5, 0xE3, 0x79, 0x8F, 0x51, 0x10, 0xA8, 0x82,
+	0xC6, 0xDD, 0xFF, 0xFC, 0xE4, 0xCF, 0xB3, 0x09, 0x5D, 0xEA, 0x9C, 0x34, 0xF9, 0x17, 0x9F, 0xDA,
+	0x87, 0xF8, 0x15, 0x05, 0x3C, 0xD3, 0xA4, 0x85, 0x2E, 0xFB, 0xEE, 0x47, 0x3B, 0xEF, 0x37, 0x7F,
+	0x93, 0xAF, 0x69, 0x0C, 0x71, 0x31, 0xDE, 0x21, 0x75, 0xA0, 0xAA, 0xBA, 0x7C, 0x38, 0x02, 0xB7,
+	0x81, 0x01, 0xFD, 0xE7, 0x1D, 0xCC, 0xCD, 0xBD, 0x1B, 0x7A, 0x2A, 0xAD, 0x66, 0xBE, 0x55, 0x33,
+	0x03, 0xDB, 0x88, 0xB2, 0x1E, 0x4E, 0xB9, 0xE6, 0xC2, 0xF7, 0xCB, 0x7D, 0xC9, 0x62, 0xC3, 0xA6,
+	0xDC, 0xA7, 0x50, 0xB5, 0x4B, 0x94, 0xC0, 0x92, 0x4C, 0x11, 0x5B, 0x78, 0xD9, 0xB1, 0xED, 0x19,
+	0xE9, 0xA1, 0x1C, 0xB6, 0x32, 0x99, 0xA3, 0x76, 0x9E, 0x7B, 0x6D, 0x9A, 0x30, 0xD6, 0xA9, 0x25,
+	0xC7, 0xAE, 0x96, 0x35, 0xD0, 0xBB, 0xD2, 0xC8, 0xA2, 0x08, 0xF3, 0xD1, 0x73, 0xF4, 0x48, 0x2D,
+	0x90, 0xCA, 0xE2, 0x58, 0xC1, 0x18, 0x52, 0xFE, 0xDF, 0x68, 0x98, 0x54, 0xEC, 0x60, 0x43, 0x0F}
+
+var recvMap = []byte{
+	0x51, 0xA1, 0x9E, 0xB0, 0x1E, 0x83, 0x1C, 0x2D, 0xE9, 0x77, 0x3D, 0x13, 0x93, 0x10, 0x45, 0xFF,
+	0x6D, 0xC9, 0x20, 0x2F, 0x1B, 0x82, 0x1A, 0x7D, 0xF5, 0xCF, 0x52, 0xA8, 0xD2, 0xA4, 0xB4, 0x0B,
+	0x31, 0x97, 0x57, 0x19, 0x34, 0xDF, 0x5B, 0x41, 0x58, 0x49, 0xAA, 0x5F, 0x0A, 0xEF, 0x88, 0x01,
+	0xDC, 0x95, 0xD4, 0xAF, 0x7B, 0xE3, 0x11, 0x8E, 0x9D, 0x16, 0x61, 0x8C, 0x84, 0x3C, 0x1F, 0x5A,
+	0x02, 0x4F, 0x39, 0xFE, 0x04, 0x07, 0x5C, 0x8B, 0xEE, 0x66, 0x33, 0xC4, 0xC8, 0x59, 0xB5, 0x5D,
+	0xC2, 0x6C, 0xF6, 0x4D, 0xFB, 0xAE, 0x4A, 0x4B, 0xF3, 0x35, 0x2C, 0xCA, 0x21, 0x78, 0x3B, 0x03,
+	0xFD, 0x24, 0xBD, 0x25, 0x37, 0x29, 0xAC, 0x4E, 0xF9, 0x92, 0x3A, 0x32, 0x4C, 0xDA, 0x06, 0x5E,
+	0x00, 0x94, 0x60, 0xEC, 0x17, 0x98, 0xD7, 0x3E, 0xCB, 0x6A, 0xA9, 0xD9, 0x9C, 0xBB, 0x08, 0x8F,
+	0x40, 0xA0, 0x6F, 0x55, 0x67, 0x87, 0x54, 0x80, 0xB2, 0x36, 0x47, 0x22, 0x44, 0x63, 0x05, 0x6B,
+	0xF0, 0x0F, 0xC7, 0x90, 0xC5, 0x65, 0xE2, 0x64, 0xFA, 0xD5, 0xDB, 0x12, 0x7A, 0x0E, 0xD8, 0x7E,
+	0x99, 0xD1, 0xE8, 0xD6, 0x86, 0x27, 0xBF, 0xC1, 0x6E, 0xDE, 0x9A, 0x09, 0x0D, 0xAB, 0xE1, 0x91,
+	0x56, 0xCD, 0xB3, 0x76, 0x0C, 0xC3, 0xD3, 0x9F, 0x42, 0xB6, 0x9B, 0xE5, 0x23, 0xA7, 0xAD, 0x18,
+	0xC6, 0xF4, 0xB8, 0xBE, 0x15, 0x43, 0x70, 0xE0, 0xE7, 0xBC, 0xF1, 0xBA, 0xA5, 0xA6, 0x53, 0x75,
+	0xE4, 0xEB, 0xE6, 0x85, 0x14, 0x48, 0xDD, 0x38, 0x2A, 0xCC, 0x7F, 0xB1, 0xC0, 0x71, 0x96, 0xF8,
+	0x3F, 0x28, 0xF2, 0x69, 0x74, 0x68, 0xB7, 0xA3, 0x50, 0xD0, 0x79, 0x1D, 0xFC, 0xCE, 0x8A, 0x8D,
+	0x2E, 0x62, 0x30, 0xEA, 0xED, 0x2B, 0x26, 0xB9, 0x81, 0x7C, 0x46, 0x89, 0x73, 0xA2, 0xF7, 0x72}
+
+type Encrypt_DataLink struct {
+	recvBuffer        []byte
+	m_bFirstPack      bool
+	sendMap           []byte
+	recvMap           []byte
+	m_dwRecvSeed      uint32
+	m_dwSendSeed      uint32
+	m_cbSendRoundFrom uint8
+	m_cbRecvRoundFrom uint8
+}
+
+func NewEncrypt_DataLink() *Encrypt_DataLink {
+	var obj = new(Encrypt_DataLink)
+	obj.clear()
+	return obj
+}
+
+func (this *Encrypt_DataLink) clear() {
+	this.recvBuffer = nil
+	this.m_bFirstPack = true
+	this.m_cbRecvRoundFrom = 0
+	this.m_cbSendRoundFrom = 0
+}
+
+func (this *Encrypt_DataLink) OnDataArrive(buffer []byte, onCommand func([]byte)) bool {
+	if buffer == nil {
+		return true
+	}
+	if this.recvBuffer != nil {
+		if buffer != nil {
+			buffer = append(this.recvBuffer, buffer...)
+		} else {
+			buffer = this.recvBuffer
+		}
+		this.recvBuffer = nil
+	}
+	totalLen := len(buffer)
+	if totalLen == 0 {
+		return true
+	}
+	// 不够包头
+	if totalLen < 4 {
+		this.appendTemBuffer(buffer)
+		return true
+	}
+	// 解析长度
+	var ba *public.ByteArray = public.CreateByteArray(buffer)
+	var cmdLen int
+	_cl, _ := ba.ReadUInt8()
+	cmdLen = int(_cl)
+	if cmdLen == 0xFF {
+		_cl, _ := ba.ReadInt16()
+		cmdLen = int(_cl)
+	}
+
+	if ba.Available() < cmdLen {
+		// 粘包
+		this.appendTemBuffer(buffer)
+
+		return true
+	}
+
+	// 是否第一个包
+	cmdBuffer := make([]byte, cmdLen)
+	ba.ReadBytes(cmdBuffer, cmdLen, 0)
+	if this.m_bFirstPack {
+		if cmdLen < MIN_FIRST_PACK_LEN {
+			log.Release("DoRead() error,The FirstPack's Len= %d", cmdLen)
+			return false
+		}
+
+		_, cmdBuffer = this.decodeFirstPack(cmdBuffer)
+		this.m_bFirstPack = false
+		cmdLen -= 4
+
+	} else {
+
+		_, cmdBuffer = this.decodeNormalPack(cmdBuffer)
+	}
+
+	if !this.checkData(cmdBuffer) {
+		log.Release("RecvData() error,The CheckSum is wrong,cmdlen = %d,RecvedLen = %d\n", cmdLen, totalLen)
+		this.clear()
+		return false
+	}
+
+	cmdBuffer = cmdBuffer[1:]
+
+	onCommand(cmdBuffer)
+
+	nAvailable := ba.Available()
+	if nAvailable > 0 {
+
+		available := make([]byte, nAvailable)
+		ba.ReadBytes(available, nAvailable, 0)
+		this.appendTemBuffer(available)
+		return this.OnDataArrive([]byte{}, onCommand)
+	}
+	return true
+}
+
+func (this *Encrypt_DataLink) appendTemBuffer(buffer []byte) {
+	if this.recvBuffer == nil {
+		this.recvBuffer = buffer[:]
+		return
+	}
+
+	this.recvBuffer = append(this.recvBuffer, buffer...)
+}
+
+func (this *Encrypt_DataLink) SendData(data []byte, conn net.Conn) {
+	isClient := false
+	var buf []byte
+	var ba *public.ByteArray = public.CreateByteArray(buf)
+	dataLen := len(data)
+	if isClient && this.m_bFirstPack {
+		dataLen += 4
+	}
+
+	ba.WriteUInt8(0xff)
+	ba.WriteUInt16(uint16(dataLen + 1))
+	checkSum := this.getCheckSum(data)
+	var dwXorkey uint32
+	if isClient && this.m_bFirstPack {
+		// 初始化key
+		dwXorkey = uint32(this.seedMap(uint16(this.m_dwSendSeed)))
+		dwXorkey |= uint32(uint32(this.seedMap(uint16(dwXorkey>>16))) << 16)
+		dwXorkey ^= SEED_XOR_KEY
+		this.m_dwSendSeed = dwXorkey
+		this.m_dwRecvSeed = dwXorkey
+	}
+
+	var encryptData = []byte{checkSum}
+	encryptData = append(encryptData, data...)
+	encryptData = this.encryptData(encryptData)
+	if isClient && this.m_bFirstPack {
+		this.m_bFirstPack = false
+		// 散存密钥
+		var xorkey [4]byte
+		indsertIndex := [4]int{1, 3, 6, 8}
+		for i := 0; i < 4; i++ {
+			xorkey[i] = byte(dwXorkey % 0x100)
+			dwXorkey /= 0x100
+
+			rear := append([]byte{}, encryptData[indsertIndex[i]:]...)
+			encryptData = append(encryptData[0:indsertIndex[i]], xorkey[i])
+			encryptData = append(encryptData, rear...)
+		}
+	}
+
+	ba.WriteBytes(encryptData)
+	conn.Write(ba.Bytes())
+}
+
+func (this *Encrypt_DataLink) decodeFirstPack(buffer []byte) (bool, []byte) {
+	InitSeed := make([]byte, 4)
+	InitSeed[0] = buffer[1]
+	InitSeed[1] = buffer[3]
+	InitSeed[2] = buffer[6]
+	InitSeed[3] = buffer[8]
+	buffer = append(buffer[:8], buffer[9:]...)
+	buffer = append(buffer[:6], buffer[7:]...)
+	buffer = append(buffer[:3], buffer[4:]...)
+	buffer = append(buffer[:1], buffer[2:]...)
+
+	ba := public.CreateByteArray(InitSeed)
+	seed, _ := ba.ReadInt32()
+	this.m_dwRecvSeed = uint32(seed)
+
+	this.m_dwSendSeed = this.m_dwRecvSeed
+
+	if !this.checkSeed(this.m_dwRecvSeed) {
+		log.Release("Error at DeCodeFirstPack,CheckSeed() Faild")
+		return false, buffer
+	}
+	return this.decodeNormalPack(buffer)
+}
+
+func (this *Encrypt_DataLink) decodeNormalPack(buffer []byte) (bool, []byte) {
+	buf := public.CreateByteArray(buffer)
+	inputlen := len(buffer)
+
+	var bufTemp []byte
+	var ret *public.ByteArray = public.CreateByteArray(bufTemp)
+	//解第一层的XOR
+	for nOff := 0; nOff < inputlen; nOff += 4 {
+		if buf.Available() >= 4 {
+			dwBuf, _ := buf.ReadUInt32()
+			dwResult := dwBuf ^ this.m_dwRecvSeed
+			ret.WriteInt32(int32(dwResult))
+			wSeedIndex1 := uint16(dwBuf % 0x10000)
+			wSeedIndex1 = this.seedMap(wSeedIndex1)
+			wSeedIndex2 := uint16(dwBuf / 0x10000)
+			wSeedIndex2 = this.seedMap(wSeedIndex2)
+			this.m_dwRecvSeed = (uint32(wSeedIndex1) + uint32(wSeedIndex2)*0x10000) ^ SEED_XOR_KEY
+		} else {
+			// 补足长度
+			complen := 4 - buf.Available()
+			buf.SetWriteEnd()
+			for i := 0; i < complen; i++ {
+				buf.WriteInt8(0)
+			}
+			dwBuf, _ := buf.ReadUInt32()
+			dwResult := dwBuf ^ this.m_dwRecvSeed
+			ret.WriteInt32(int32(dwResult))
+			var dwNewResult uint32 = 0
+			var pos uint32 = 0
+			for i := 0; i < 4-complen; i++ {
+				tempInt := (dwResult % 0x100)
+				tempInt = tempInt << pos
+				dwNewResult += tempInt
+				dwResult /= 0x100
+				pos += 8
+			}
+			dwBuf = dwNewResult ^ this.m_dwRecvSeed
+			wSeedIndex1 := uint16(dwBuf % 0x10000)
+			wSeedIndex1 = this.seedMap(wSeedIndex1)
+			wSeedIndex2 := uint16(dwBuf / 0x10000)
+			wSeedIndex2 = this.seedMap(wSeedIndex2)
+			this.m_dwRecvSeed = (uint32(wSeedIndex1) + uint32(wSeedIndex2)*0x10000) ^ SEED_XOR_KEY
+		}
+	}
+	buffer = (ret.Bytes())[:inputlen]
+	//字节映射表解码
+	for nOff := 0; nOff < inputlen; nOff++ {
+		buffer[nOff] = this.mapRecvByte(uint8(buffer[nOff]))
+	}
+
+	return true, buffer
+}
+
+func (this *Encrypt_DataLink) checkSeed(seed uint32) bool {
+	return true
+}
+
+func (this *Encrypt_DataLink) mapSendByte(cbData uint8) byte {
+	ret := sendMap[uint8(cbData+this.m_cbSendRoundFrom)]
+	this.m_cbSendRoundFrom += 3
+	return ret
+
+}
+
+func (this *Encrypt_DataLink) mapRecvByte(cbData uint8) byte {
+	ret := recvMap[cbData] - this.m_cbRecvRoundFrom
+	this.m_cbRecvRoundFrom += 3
+	return ret
+}
+
+func (this *Encrypt_DataLink) checkData(buffer []byte) bool {
+	bufLen := len(buffer)
+	if bufLen < 2 {
+		log.Release("checkData  error bufLen  = %d", bufLen)
+		return false
+	}
+	var checkSum uint8 = 0
+	for i := 0; i < bufLen; i++ {
+		checkSum += uint8(buffer[i])
+	}
+	if checkSum != 0 {
+		log.Release("checkData  error checkSum  = %d", checkSum)
+		return false
+	}
+	return true
+}
+
+func (this *Encrypt_DataLink) getCheckSum(buffer []byte) uint8 {
+	var checkSum uint8 = 0
+	bufLen := len(buffer)
+	for i := 0; i < bufLen; i++ {
+		checkSum += uint8(buffer[i])
+	}
+	checkSum = 255 - checkSum + 1
+	return checkSum
+}
+
+func (this *Encrypt_DataLink) encryptData(buffer []byte) []byte {
+	buf := public.CreateByteArray(buffer)
+	inputlen := len(buffer)
+
+	//字节表映射
+	for nOff := 0; nOff < inputlen; nOff++ {
+		buffer[nOff] = this.mapSendByte(uint8(buffer[nOff]))
+	}
+
+	// 补足长度
+	complen := (4 - inputlen%4) % 4
+	buf.SetWriteEnd()
+	for i := 0; i < complen; i++ {
+		buf.WriteInt8(0)
+	}
+
+	var bufTemp []byte
+	var ret *public.ByteArray = public.CreateByteArray(bufTemp)
+
+	for nOff := 0; nOff < inputlen; nOff += 4 {
+		dwBuf, _ := buf.ReadUInt32()
+		dwResult := uint32(dwBuf) ^ this.m_dwSendSeed
+		ret.WriteInt32(int32(dwResult))
+
+		//得到下一个SendSeed
+		wSeedIndex1 := uint16(dwResult % 0x10000)
+		wSeedIndex1 = this.seedMap(wSeedIndex1)
+		wSeedIndex2 := uint16(dwResult / 0x10000)
+		wSeedIndex2 = this.seedMap(wSeedIndex2)
+		this.m_dwSendSeed = (uint32(wSeedIndex1) + uint32(wSeedIndex2)*0x10000) ^ SEED_XOR_KEY
+	}
+
+	buffer = (ret.Bytes())[:inputlen]
+	return buffer
+}
+
+func (this *Encrypt_DataLink) seedMap(seed uint16) uint16 {
+	dwHold := uint32(seed)
+	dwHold = dwHold*241103 + 2533101
+	return uint16(dwHold >> 16)
+}

+ 114 - 0
network/protobuf.go

@@ -0,0 +1,114 @@
+package network
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"github.com/golang/protobuf/proto"
+	"bet24.com/log"
+	"math"
+	"reflect"
+)
+
+// -------------------------
+// | id | protobuf message |
+// -------------------------
+type Processor struct {
+	littleEndian bool
+	msgInfo      []*MsgInfo
+	msgID        map[reflect.Type]uint16
+}
+
+type MsgInfo struct {
+	msgType       reflect.Type
+}
+
+type MsgRaw struct {
+	msgID      uint16
+	msgRawData []byte
+}
+
+func NewProcessor() *Processor {
+	p := new(Processor)
+	p.littleEndian = false
+	p.msgID = make(map[reflect.Type]uint16)
+	return p
+}
+
+// It's dangerous to call the method on routing or marshaling (unmarshaling)
+func (p *Processor) SetByteOrder(littleEndian bool) {
+	p.littleEndian = littleEndian
+}
+
+// It's dangerous to call the method on routing or marshaling (unmarshaling)
+func (p *Processor) Register(msg proto.Message) uint16 {
+	msgType := reflect.TypeOf(msg)
+	if msgType == nil || msgType.Kind() != reflect.Ptr {
+		log.Fatal("protobuf message pointer required")
+	}
+	if _, ok := p.msgID[msgType]; ok {
+		log.Fatal("message %s is already registered", msgType)
+	}
+	if len(p.msgInfo) >= math.MaxUint16 {
+		log.Fatal("too many protobuf messages (max = %v)", math.MaxUint16)
+	}
+
+	i := new(MsgInfo)
+	i.msgType = msgType
+	p.msgInfo = append(p.msgInfo, i)
+	id := uint16(len(p.msgInfo) - 1)
+	p.msgID[msgType] = id
+	return id
+}
+
+// goroutine safe
+func (p *Processor) Unmarshal(data []byte) (interface{}, error) {
+	if len(data) < 2 {
+		return nil, errors.New("protobuf data too short")
+	}
+
+	// id
+	var id uint16
+	if p.littleEndian {
+		id = binary.LittleEndian.Uint16(data)
+	} else {
+		id = binary.BigEndian.Uint16(data)
+	}
+	if id >= uint16(len(p.msgInfo)) {
+		return nil, fmt.Errorf("message id %v not registered", id)
+	}
+
+	// msg
+	i := p.msgInfo[id]	
+	msg := reflect.New(i.msgType.Elem()).Interface()
+	return msg, proto.UnmarshalMerge(data[2:], msg.(proto.Message))	
+}
+
+// goroutine safe
+func (p *Processor) Marshal(msg interface{}) ([][]byte, error) {
+	msgType := reflect.TypeOf(msg)
+	// id
+	_id, ok := p.msgID[msgType]
+	if !ok {
+		err := fmt.Errorf("message %s not registered", msgType)
+		return nil, err
+	}
+
+	id := make([]byte, 2)
+	if p.littleEndian {
+		binary.LittleEndian.PutUint16(id, _id)
+	} else {
+		binary.BigEndian.PutUint16(id, _id)
+	}
+
+	// data
+	data, err := proto.Marshal(msg.(proto.Message))
+	return [][]byte{id, data}, err
+}
+
+// goroutine safe
+func (p *Processor) Range(f func(id uint16, t reflect.Type)) {
+	for id, i := range p.msgInfo {
+		f(uint16(id), i.msgType)
+	}
+}

+ 163 - 0
network/ws_conn.go

@@ -0,0 +1,163 @@
+package network
+
+import (
+	"bet24.com/log"
+	"errors"
+	"github.com/gorilla/websocket"
+	"net"
+	_ "runtime/debug"
+	"sync"
+)
+
+type WebsocketConnSet map[*websocket.Conn]struct{}
+
+type WSConn struct {
+	sync.Mutex
+	conn        *websocket.Conn
+	writeChan   chan []byte
+	maxMsgLen   uint32
+	closeFlag   bool
+	messageType int
+}
+
+func newWSConn(conn *websocket.Conn, pendingWriteNum int, maxMsgLen uint32, isBinary bool) *WSConn {
+	wsConn := new(WSConn)
+	wsConn.conn = conn
+	wsConn.writeChan = make(chan []byte, pendingWriteNum)
+	wsConn.maxMsgLen = maxMsgLen
+	if isBinary {
+		wsConn.messageType = websocket.BinaryMessage
+	} else {
+		wsConn.messageType = websocket.TextMessage
+	}
+
+	go func() {
+		for b := range wsConn.writeChan {
+			if b == nil {
+				log.Debug("exiting write routine by nil message")
+				break
+			}
+
+			err := conn.WriteMessage(wsConn.messageType, b)
+			if err != nil {
+				log.Debug("exiting write routine by WriteMessage error %v", err)
+				break
+			}
+		}
+
+		conn.Close()
+		wsConn.Lock()
+		log.Debug("exiting write routine")
+		wsConn.closeFlag = true
+		wsConn.Unlock()
+	}()
+
+	return wsConn
+}
+
+func (wsConn *WSConn) doDestroy() {
+	//wsConn.conn.UnderlyingConn().(*net.TCPConn).SetLinger(0)
+	wsConn.conn.Close()
+
+	if !wsConn.closeFlag {
+		close(wsConn.writeChan)
+		wsConn.closeFlag = true
+	}
+}
+
+func (wsConn *WSConn) Destroy() {
+	wsConn.Lock()
+	defer wsConn.Unlock()
+
+	wsConn.doDestroy()
+}
+
+func (wsConn *WSConn) Close() {
+	wsConn.Lock()
+	defer wsConn.Unlock()
+	if wsConn.closeFlag {
+		return
+	}
+
+	wsConn.doWrite(nil)
+	log.Debug("wsConn.Close()")
+	wsConn.closeFlag = true
+}
+
+func (wsConn *WSConn) doWrite(b []byte) {
+	if len(wsConn.writeChan) == cap(wsConn.writeChan) {
+		log.Debug("close conn: channel full")
+		wsConn.doDestroy()
+		return
+	}
+
+	wsConn.writeChan <- b
+}
+
+func (wsConn *WSConn) LocalAddr() net.Addr {
+	return wsConn.conn.LocalAddr()
+}
+
+func (wsConn *WSConn) RemoteAddr() net.Addr {
+	return wsConn.conn.RemoteAddr()
+}
+
+// goroutine not safe
+func (wsConn *WSConn) ReadMsg() ([]byte, error) {
+	_, b, err := wsConn.conn.ReadMessage()
+	return b, err
+}
+
+func (wsConn *WSConn) WriteData(b []byte) error {
+	wsConn.Lock()
+	defer wsConn.Unlock()
+	if wsConn.closeFlag {
+		//log.Debug("WriteData closing %s", string(b))
+		//log.Debug("%s", debug.Stack())
+		return errors.New("closing")
+	}
+
+	wsConn.doWrite(b)
+	return nil
+}
+
+// args must not be modified by the others goroutines
+// 暂时不考虑粘包问题
+func (wsConn *WSConn) writeMsg(args ...[]byte) error {
+	wsConn.Lock()
+	defer wsConn.Unlock()
+	if wsConn.closeFlag {
+		return nil
+	}
+
+	// get len
+	var msgLen uint32
+	for i := 0; i < len(args); i++ {
+		msgLen += uint32(len(args[i]))
+	}
+
+	// check len
+	if msgLen > wsConn.maxMsgLen {
+		return errors.New("message too long")
+	} else if msgLen < 1 {
+		return errors.New("message too short")
+	}
+
+	// don't copy
+	if len(args) == 1 {
+		wsConn.doWrite(args[0])
+		return nil
+	}
+
+	// merge the args
+	msg := make([]byte, msgLen)
+	l := 0
+	for i := 0; i < len(args); i++ {
+		copy(msg[l:], args[i])
+		l += len(args[i])
+	}
+
+	wsConn.doWrite(msg)
+
+	return nil
+}

+ 165 - 0
network/ws_server.go

@@ -0,0 +1,165 @@
+package network
+
+import (
+	"crypto/tls"
+	"net"
+	"net/http"
+	"sync"
+	"time"
+
+	"bet24.com/log"
+	"github.com/gorilla/websocket"
+)
+
+type WSServer struct {
+	Addr            string
+	MaxConnNum      int
+	PendingWriteNum int
+	MaxMsgLen       uint32
+	HTTPTimeout     time.Duration
+	CertFile        string
+	KeyFile         string
+	NewAgent        func(*WSConn) Agent
+	IsTextMessage   bool
+	ln              net.Listener
+	handler         *WSHandler
+}
+
+type WSHandler struct {
+	maxConnNum      int
+	pendingWriteNum int
+	maxMsgLen       uint32
+	newAgent        func(*WSConn) Agent
+	upgrader        websocket.Upgrader
+	conns           WebsocketConnSet
+	mutexConns      sync.Mutex
+	wg              sync.WaitGroup
+	isBinary        bool
+}
+
+func (handler *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	if r.Method != "GET" {
+		http.Error(w, "Method not allowed", 405)
+		return
+	}
+	conn, err := handler.upgrader.Upgrade(w, r, nil)
+	if err != nil {
+		log.Debug("upgrade error: %v", err)
+		return
+	}
+	conn.SetReadLimit(int64(handler.maxMsgLen))
+
+	handler.wg.Add(1)
+	defer handler.wg.Done()
+	conn.SetRealIP(r.Header.Get("X-Real-IP"))
+	handler.mutexConns.Lock()
+	if handler.conns == nil {
+		handler.mutexConns.Unlock()
+		conn.Close()
+		return
+	}
+	if len(handler.conns) >= handler.maxConnNum {
+		handler.mutexConns.Unlock()
+		conn.Close()
+		log.Debug("too many connections")
+		return
+	}
+	handler.conns[conn] = struct{}{}
+	handler.mutexConns.Unlock()
+
+	wsConn := newWSConn(conn, handler.pendingWriteNum, handler.maxMsgLen, handler.isBinary)
+	agent := handler.newAgent(wsConn)
+	agent.Run()
+
+	// cleanup
+	//log.Debug("cleanup connection")
+	wsConn.Close()
+	handler.mutexConns.Lock()
+	delete(handler.conns, conn)
+	handler.mutexConns.Unlock()
+	agent.OnClose()
+}
+
+func (server *WSServer) Start() {
+	ln, err := net.Listen("tcp", server.Addr)
+	if err != nil {
+		log.Fatal("%v", err)
+	}
+
+	if server.MaxConnNum <= 0 {
+		server.MaxConnNum = 100
+		log.Release("invalid MaxConnNum, reset to %v", server.MaxConnNum)
+	}
+	if server.PendingWriteNum <= 0 {
+		server.PendingWriteNum = 100
+		log.Release("invalid PendingWriteNum, reset to %v", server.PendingWriteNum)
+	}
+	if server.MaxMsgLen <= 0 {
+		server.MaxMsgLen = 4096
+		log.Release("invalid MaxMsgLen, reset to %v", server.MaxMsgLen)
+	}
+	if server.HTTPTimeout <= 0 {
+		server.HTTPTimeout = 10 * time.Second
+		log.Release("invalid HTTPTimeout, reset to %v", server.HTTPTimeout)
+	}
+	if server.NewAgent == nil {
+		log.Fatal("NewAgent must not be nil")
+	}
+
+	if server.CertFile != "" || server.KeyFile != "" {
+		config := &tls.Config{}
+		config.NextProtos = []string{"http/1.1"}
+
+		var err error
+		config.Certificates = make([]tls.Certificate, 1)
+		config.Certificates[0], err = tls.LoadX509KeyPair(server.CertFile, server.KeyFile)
+		if err != nil {
+			log.Fatal("%v", err)
+		}
+
+		ln = tls.NewListener(ln, config)
+	}
+
+	server.ln = ln
+	server.handler = &WSHandler{
+		maxConnNum:      server.MaxConnNum,
+		pendingWriteNum: server.PendingWriteNum,
+		maxMsgLen:       server.MaxMsgLen,
+		newAgent:        server.NewAgent,
+		isBinary:        !server.IsTextMessage,
+		conns:           make(WebsocketConnSet),
+		upgrader: websocket.Upgrader{
+			HandshakeTimeout: server.HTTPTimeout,
+			CheckOrigin:      func(_ *http.Request) bool { return true },
+		},
+	}
+
+	httpServer := &http.Server{
+		Addr:           server.Addr,
+		Handler:        server.handler,
+		ReadTimeout:    server.HTTPTimeout,
+		WriteTimeout:   server.HTTPTimeout,
+		MaxHeaderBytes: 1024,
+	}
+
+	go httpServer.Serve(ln)
+}
+
+func (server *WSServer) Close() {
+	server.ln.Close()
+
+	server.handler.mutexConns.Lock()
+	for conn := range server.handler.conns {
+		conn.Close()
+	}
+	server.handler.conns = nil
+	server.handler.mutexConns.Unlock()
+
+	server.handler.wg.Wait()
+}
+
+func (server *WSServer) GetConnectionCount() int {
+	server.handler.mutexConns.Lock()
+	defer server.handler.mutexConns.Unlock()
+	return len(server.handler.conns)
+}

+ 181 - 0
profile/profile.go

@@ -0,0 +1,181 @@
+package profile
+
+import (
+	"os"
+	"path/filepath"
+	"runtime"
+	"runtime/pprof"
+
+	"bet24.com/log"
+)
+
+const (
+	cpuMode = iota
+	memMode
+	mutexMode
+	blockMode
+	traceMode
+	goroutineMode
+	threadCreateMode
+)
+
+type Profile struct {
+	// 分析模式
+	mode int
+
+	path string
+
+	//内存配置文件采样速率,分析器将会在每分配指定的字节数量后对内存使用情况进行取样
+	memProfileRate int
+
+	closer func()
+
+	stopped uint32
+
+	namePrefix string
+}
+
+func NamePrefix(name string) func(*Profile) {
+	return func(p *Profile) {
+		p.namePrefix = name
+	}
+}
+
+// CPUProfile enables cpu profiling.
+// It disables any previous profiling settings.
+func CPUProfile(p *Profile) { p.mode = cpuMode }
+
+// DefaultMemProfileRate is the default memory profiling rate.
+const DefaultMemProfileRate = 4096
+
+// MemProfile enables memory profiling.
+// It disables any previous profiling settings.
+func MemProfile(p *Profile) {
+	p.memProfileRate = DefaultMemProfileRate
+	p.mode = memMode
+}
+
+//GoRTProfile enables goroutine profiling
+func GoRTProfile(p *Profile) { p.mode = goroutineMode }
+
+//block enables goroutine profiling
+func BlockProfile(p *Profile) { p.mode = blockMode }
+
+//MutexProfile enables goroutine profiling
+func MutexProfile(p *Profile) { p.mode = mutexMode }
+
+// ProfilePath controls the base path where various profiling
+// files are written. If blank, the base path will be generated
+// by os.MkdirTemp.
+func ProfilePath(path string) func(*Profile) {
+	return func(p *Profile) {
+		p.path = path
+	}
+}
+
+// Stop stops the profile and flushes any unwritten data.
+func (p *Profile) Stop() {
+	p.closer()
+}
+
+// Start starts a new profiling session.
+// The caller should call the Stop method on the value returned
+// to cleanly stop profiling.
+func Start(options ...func(*Profile)) interface {
+	Stop()
+} {
+	var prof Profile
+	for _, option := range options {
+		option(&prof)
+	}
+
+	path, err := func() (string, error) {
+		if p := prof.path; p != "" {
+			return p, os.MkdirAll(p, 0777)
+		}
+		return os.MkdirTemp("", "profile")
+	}()
+
+	if err != nil {
+		log.Fatal("profile: could not create initial output directory: %v", err)
+	}
+
+	logf := func(format string, args ...interface{}) {
+		log.Debug(format, args...)
+	}
+
+	switch prof.mode {
+	case cpuMode:
+		fn := filepath.Join(path, prof.namePrefix+"cpu.pprof")
+		f, err := os.Create(fn)
+		if err != nil {
+			log.Fatal("profile: could not create cpu profile %q: %v", fn, err)
+		}
+		logf("profile: cpu profiling enabled, %s", fn)
+		pprof.StartCPUProfile(f)
+		prof.closer = func() {
+			pprof.StopCPUProfile()
+			f.Close()
+			logf("profile: cpu profiling disabled, %s", fn)
+		}
+
+	case memMode:
+		fn := filepath.Join(path, prof.namePrefix+"mem.pprof")
+		f, err := os.Create(fn)
+		if err != nil {
+			log.Fatal("profile: could not create memory profile %q: %v", fn, err)
+		}
+		old := runtime.MemProfileRate
+		runtime.MemProfileRate = prof.memProfileRate
+		logf("profile: memory profiling enabled (rate %d), %s", runtime.MemProfileRate, fn)
+		prof.closer = func() {
+			pprof.Lookup("heap").WriteTo(f, 0)
+			f.Close()
+			runtime.MemProfileRate = old
+			logf("profile: memory profiling disabled, %s", fn)
+		}
+	case goroutineMode:
+		fn := filepath.Join(path, prof.namePrefix+"goroutine.pprof")
+		f, err := os.Create(fn)
+		if err != nil {
+			log.Fatal("profile: could not create goroutine profile %q: %v", fn, err)
+		}
+
+		logf("profile: goroutine profiling enabled, %s", fn)
+		prof.closer = func() {
+			pprof.Lookup("goroutine").WriteTo(f, 0)
+			f.Close()
+			logf("profile: goroutine profiling disabled, %s", fn)
+		}
+
+	case blockMode:
+		fn := filepath.Join(path, prof.namePrefix+"block.pprof")
+		f, err := os.Create(fn)
+		if err != nil {
+			log.Fatal("profile: could not create block profile %q: %v", fn, err)
+		}
+
+		logf("profile: block profiling enabled, %s", fn)
+		prof.closer = func() {
+			pprof.Lookup("block").WriteTo(f, 0)
+			f.Close()
+			logf("profile: block profiling disabled, %s", fn)
+		}
+
+	case mutexMode:
+		fn := filepath.Join(path, prof.namePrefix+"mutex.pprof")
+		f, err := os.Create(fn)
+		if err != nil {
+			log.Fatal("profile: could not create mutex profile %q: %v", fn, err)
+		}
+
+		logf("profile: mutex profiling enabled, %s", fn)
+		prof.closer = func() {
+			pprof.Lookup("mutex").WriteTo(f, 0)
+			f.Close()
+			logf("profile: mutex profiling disabled, %s", fn)
+		}
+	}
+
+	return &prof
+}

+ 330 - 0
public/ByteArray.go

@@ -0,0 +1,330 @@
+package public
+
+import (
+	"encoding/binary"
+	"io"
+)
+
+type ByteArray struct {
+	buf      []byte
+	posWrite int
+	posRead  int
+	endian   binary.ByteOrder
+}
+
+var ByteArrayEndian binary.ByteOrder = binary.LittleEndian
+
+func CreateByteArray(bytes []byte) *ByteArray {
+	var ba *ByteArray
+	if bytes != nil && len(bytes) > 0 {
+		ba = &ByteArray{buf: bytes}
+	} else {
+		ba = &ByteArray{}
+	}
+
+	ba.endian = binary.LittleEndian
+
+	return ba
+}
+
+func (this *ByteArray) Length() int {
+	return len(this.buf)
+}
+
+func (this *ByteArray) Available() int {
+	return this.Length() - this.posRead
+}
+
+func (this *ByteArray) SetEndian(endian binary.ByteOrder) {
+	this.endian = endian
+}
+
+func (this *ByteArray) GetEndian() binary.ByteOrder {
+	if this.endian == nil {
+		return ByteArrayEndian
+	}
+	return this.endian
+}
+
+func (this *ByteArray) grow(l int) {
+	if l == 0 {
+		return
+	}
+	space := len(this.buf) - this.posWrite
+	if space >= l {
+		return
+	}
+
+	needGrow := l - space
+	bufGrow := make([]byte, needGrow)
+
+	this.buf = append(this.buf, bufGrow...)
+}
+
+func (this *ByteArray) SetWritePos(pos int) error {
+	if pos > this.Length() {
+		this.posWrite = this.Length()
+		return io.EOF
+	} else {
+		this.posWrite = pos
+	}
+	return nil
+}
+
+func (this *ByteArray) SetWriteEnd() {
+	this.SetWritePos(this.Length())
+}
+
+func (this *ByteArray) GetWritePos() int {
+	return this.posWrite
+}
+
+func (this *ByteArray) SetReadPos(pos int) error {
+	if pos > this.Length() {
+		this.posRead = this.Length()
+		return io.EOF
+	} else {
+		this.posRead = pos
+	}
+	return nil
+}
+
+func (this *ByteArray) SetReadEnd() {
+	this.SetReadPos(this.Length())
+}
+
+func (this *ByteArray) GetReadPos() int {
+	return this.posRead
+}
+
+func (this *ByteArray) Seek(pos int) error {
+	err := this.SetWritePos(pos)
+	this.SetReadPos(pos)
+
+	return err
+}
+
+func (this *ByteArray) Reset() {
+	this.buf = []byte{}
+	this.Seek(0)
+}
+
+func (this *ByteArray) Bytes() []byte {
+	return this.buf
+}
+
+func (this *ByteArray) BytesAvailable() []byte {
+	return this.buf[this.posRead:]
+}
+
+//==========write
+func (this *ByteArray) Write(bytes []byte) (l int, err error) {
+	this.grow(len(bytes))
+
+	l = copy(this.buf[this.posWrite:], bytes)
+	this.posWrite += l
+
+	return l, nil
+}
+
+func (this *ByteArray) WriteBytes(bytes []byte) (l int, err error) {
+	return this.Write(bytes)
+}
+
+func (this *ByteArray) WriteByte(b byte) error {
+	bytes := make([]byte, 1)
+	bytes[0] = b
+	_, err := this.WriteBytes(bytes)
+	return err
+}
+
+func (this *ByteArray) WriteInt8(value int8) {
+	binary.Write(this, this.endian, &value)
+}
+
+func (this *ByteArray) WriteUInt8(value uint8) {
+	binary.Write(this, this.endian, &value)
+}
+
+func (this *ByteArray) WriteInt16(value int16) {
+	binary.Write(this, this.endian, &value)
+}
+
+func (this *ByteArray) WriteUInt16(value uint16) {
+	binary.Write(this, this.endian, &value)
+}
+
+func (this *ByteArray) WriteInt32(value int32) {
+	binary.Write(this, this.endian, &value)
+}
+
+func (this *ByteArray) WriteUInt32(value uint32) {
+	binary.Write(this, this.endian, &value)
+}
+
+/*func (this *ByteArray) WriteInt(value int) {
+	binary.Write(this, this.endian, &value)
+}
+
+func (this *ByteArray) WriteUInt(value uint) {
+	binary.Write(this, this.endian, &value)
+}
+*/
+func (this *ByteArray) WriteInt64(value int64) {
+	binary.Write(this, this.endian, &value)
+}
+
+func (this *ByteArray) WriteFloat32(value float32) {
+	binary.Write(this, this.endian, &value)
+}
+
+func (this *ByteArray) WriteFloat64(value float64) {
+	binary.Write(this, this.endian, &value)
+}
+
+func (this *ByteArray) WriteBool(value bool) {
+	var bb byte
+	if value {
+		bb = 1
+	} else {
+		bb = 0
+	}
+
+	this.WriteByte(bb)
+}
+
+func (this *ByteArray) WriteString(value string) {
+	this.WriteBytes([]byte(value))
+}
+
+func (this *ByteArray) WriteStringWithLen(value string, stringLen int) {
+	byString := []byte(value)
+	this.WriteBytes(byString)
+	for i := 0; i < stringLen-len(byString); i++ {
+		this.WriteUInt8(0)
+	}
+}
+
+func (this *ByteArray) WriteUTF(value string) {
+	this.WriteInt16(int16(len(value)))
+	this.WriteBytes([]byte(value))
+}
+
+//==========read
+
+func (this *ByteArray) Read(bytes []byte) (l int, err error) {
+	if len(bytes) == 0 {
+		return
+	}
+	if len(bytes) > this.Length()-this.posRead {
+		return 0, io.EOF
+	}
+	l = copy(bytes, this.buf[this.posRead:])
+	this.posRead += l
+
+	return l, nil
+}
+
+func (this *ByteArray) ReadBytes(bytes []byte, length int, offset int) (l int, err error) {
+	return this.Read(bytes[offset : offset+length])
+}
+
+func (this *ByteArray) ReadByte() (b byte, err error) {
+	bytes := make([]byte, 1)
+	_, err = this.ReadBytes(bytes, 1, 0)
+
+	if err == nil {
+		b = bytes[0]
+	}
+
+	return
+}
+
+func (this *ByteArray) ReadInt8() (ret int8, err error) {
+	err = binary.Read(this, this.endian, &ret)
+	return
+}
+
+func (this *ByteArray) ReadUInt8() (ret uint8, err error) {
+	err = binary.Read(this, this.endian, &ret)
+	return
+}
+
+func (this *ByteArray) ReadInt16() (ret int16, err error) {
+	err = binary.Read(this, this.endian, &ret)
+	return
+}
+
+func (this *ByteArray) ReadUInt16() (ret uint16, err error) {
+	err = binary.Read(this, this.endian, &ret)
+	return
+}
+
+func (this *ByteArray) ReadInt32() (ret int32, err error) {
+	err = binary.Read(this, this.endian, &ret)
+	return
+}
+
+func (this *ByteArray) ReadUInt32() (ret uint32, err error) {
+	err = binary.Read(this, this.endian, &ret)
+	return
+}
+
+func (this *ByteArray) ReadInt64() (ret int64, err error) {
+	err = binary.Read(this, this.endian, &ret)
+	return
+}
+
+func (this *ByteArray) ReadFloat32() (ret float32, err error) {
+	err = binary.Read(this, this.endian, &ret)
+	return
+}
+
+func (this *ByteArray) ReadFloat64() (ret float64, err error) {
+	err = binary.Read(this, this.endian, &ret)
+	return
+}
+
+func (this *ByteArray) ReadBool() (ret bool, err error) {
+	var bb byte
+	bb, err = this.ReadByte()
+	if err == nil {
+		if bb == 1 {
+			ret = true
+		} else {
+			ret = false
+		}
+	} else {
+		ret = false
+	}
+	return
+}
+
+func (this *ByteArray) ReadString(length int) (ret string, err error) {
+	bytes := make([]byte, length)
+	_, err = this.ReadBytes(bytes, length, 0)
+	if err == nil {
+		// 有可能有末尾的多余空格
+		for i := 0; i < length; i++ {
+			if bytes[i] == 0 {
+				bytes = bytes[:i]
+				break
+			}
+		}
+		ret = string(bytes)
+	} else {
+		ret = ""
+	}
+	return
+}
+
+func (this *ByteArray) ReadUTF() (ret string, err error) {
+	var l int16
+	l, err = this.ReadInt16()
+
+	if err != nil {
+		return "", err
+	}
+
+	return this.ReadString(int(l))
+}

+ 153 - 0
public/IdNumber.go

@@ -0,0 +1,153 @@
+package public
+
+import (
+	"errors"
+	"fmt"
+	"math"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+)
+
+/*
+MIT License
+Copyright (c) [year] [fullname]
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+// Author: @BlueSky335 github home page : https://github.com/bluesky335
+
+// 计算规则参考“中国国家标准化管理委员会”官方文档:http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=080D6FBF2BB468F9007657F26D60013E
+
+type IdNumber string
+
+func New(number string) IdNumber {
+	return IdNumber(number)
+}
+
+func (id IdNumber) IsValid() bool {
+	//a1与对应的校验码对照表,其中key表示a1,value表示校验码,value中的10表示校验码X
+	var a1Map = map[int]int{
+		0:  1,
+		1:  0,
+		2:  10,
+		3:  9,
+		4:  8,
+		5:  7,
+		6:  6,
+		7:  5,
+		8:  4,
+		9:  3,
+		10: 2,
+	}
+
+	var idStr = strings.ToUpper(string(id))
+	var reg, err = regexp.Compile(`^[0-9]{17}[0-9X]$`)
+	if err != nil {
+		return false
+	}
+	if !reg.Match([]byte(idStr)) {
+		return false
+	}
+	var sum int
+	var signChar = ""
+	for index, c := range idStr {
+		var i = 18 - index
+		if i != 1 {
+			if v, err := strconv.Atoi(string(c)); err == nil {
+				//计算加权因子
+				var weight = int(math.Pow(2, float64(i-1))) % 11
+				sum += v * weight
+			} else {
+				return false
+			}
+		} else {
+			signChar = string(c)
+		}
+	}
+	var a1 = a1Map[sum%11]
+	var a1Str = fmt.Sprintf("%d", a1)
+	if a1 == 10 {
+		a1Str = "X"
+	}
+	return a1Str == signChar
+}
+
+type Date struct {
+}
+
+func (id IdNumber) GetBirthday() (date time.Time, err error) {
+	if !id.IsValid() {
+		err = errors.New("invalid id number")
+		return
+	}
+	var yearStr = subString(string(id), 6, 4)
+	var monthStr = subString(string(id), 10, 2)
+	var dayStr = subString(string(id), 12, 2)
+	year, err := strconv.Atoi(yearStr)
+	if err != nil {
+		return
+	}
+	month, err := strconv.Atoi(monthStr)
+	if err != nil {
+		return
+	}
+	day, err := strconv.Atoi(dayStr)
+	if err != nil {
+		return
+	}
+	date = time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local)
+	return
+}
+
+type Gender int
+
+const (
+	Female Gender = 0
+	Male   Gender = 1
+)
+
+func (id IdNumber) GetGender() (gender Gender, err error) {
+	if !id.IsValid() {
+		err = errors.New("invalid id number")
+		return
+	}
+	numStr := subString(string(id), 14, 3)
+	num, err := strconv.Atoi(numStr)
+	if err != nil {
+		return
+	}
+	gender = Gender(num % 2)
+	return
+}
+
+func subString(str string, begin, length int) string {
+	rs := []rune(str)
+	lth := len(rs)
+	if begin < 0 {
+		begin = 0
+	}
+	if begin >= lth {
+		begin = lth
+	}
+	end := begin + length
+	if end > lth {
+		end = lth
+	}
+	return string(rs[begin:end])
+}

+ 709 - 0
public/Public.go

@@ -0,0 +1,709 @@
+package public
+
+import (
+	"bytes"
+	"crypto"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/hmac"
+	"crypto/md5"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha1"
+	"crypto/sha256"
+	"crypto/sha512"
+	"crypto/x509"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"io"
+	"math"
+	mathRand "math/rand"
+	"net/http"
+	"net/url"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+	"unsafe"
+
+	"golang.org/x/crypto/sha3"
+
+	"bet24.com/log"
+	"github.com/axgle/mahonia"
+)
+
+func ConvertToString(src string, srcCode string, tagCode string) string {
+	srcCoder := mahonia.NewDecoder(srcCode)
+	srcResult := srcCoder.ConvertString(src)
+	tagCoder := mahonia.NewEncoder(tagCode)
+	return tagCoder.ConvertString(srcResult)
+}
+
+func GetUtf8(src string) string {
+	return ConvertToString(src, "GB18030", "UTF-8")
+}
+
+func GetGBK(src string) string {
+	return ConvertToString(src, "UTF-8", "GB18030")
+}
+
+const ENCRYPT_KEY_LENGTH = 10
+
+func DecryptDBString(src string) string {
+	lpszIn := []byte(src)
+	if len(lpszIn) >= ENCRYPT_KEY_LENGTH*4 {
+		szSoureLengthBuf := string([]byte{lpszIn[0], lpszIn[1]})
+		nSoureLength64, _ := strconv.ParseInt(szSoureLengthBuf, 16, 0)
+		nSoureLength := int(nSoureLength64)
+		lpszOut := make([]byte, nSoureLength)
+		for i := 0; i < nSoureLength; i++ {
+			szKeyBuffer := string([]byte{lpszIn[i*4], lpszIn[i*4+1]})
+			szEncryptBuffer := string([]byte{lpszIn[i*4+2], lpszIn[i*4+3]})
+			uKey64, _ := strconv.ParseInt(szKeyBuffer, 16, 0)
+			uEncrypt64, _ := strconv.ParseInt(szEncryptBuffer, 16, 0)
+			uKey := uint8(uKey64)
+			uEncrypt := uint8(uEncrypt64)
+			lpszOut[i] = uKey ^ uEncrypt
+		}
+		return string(lpszOut)
+	}
+	return src
+}
+
+func StringIpToInt(ipstring string) uint32 {
+	ipSegs := strings.Split(ipstring, ".")
+	var ipInt int = 0
+	var pos uint = 0
+	for _, ipSeg := range ipSegs {
+		tempInt, _ := strconv.Atoi(ipSeg)
+		tempInt = tempInt << pos
+		ipInt = ipInt + tempInt
+		pos += 8
+	}
+	//fmt.Println("StringIpToInt", ipstring, ipInt)
+	return uint32(ipInt)
+}
+
+func IpIntToString(ipInt uint32) string {
+	ipSegs := make([]string, 4)
+	var len int = len(ipSegs)
+	buffer := bytes.NewBufferString("")
+	for i := 0; i < len; i++ {
+		tempInt := ipInt & 0xFF
+		ipSegs[len-i-1] = strconv.Itoa(int(tempInt))
+		ipInt = ipInt >> 8
+	}
+	for i := 0; i < len; i++ {
+		buffer.WriteString(ipSegs[i])
+		if i < len-1 {
+			buffer.WriteString(".")
+		}
+	}
+	return buffer.String()
+}
+
+// md5加密方式
+func GetMd5String(s string) string {
+	h := md5.New()
+	h.Write([]byte(s))
+	return hex.EncodeToString(h.Sum(nil))
+}
+
+func HmacSHA1(key string, data string) string {
+	mac := hmac.New(sha1.New, []byte(key))
+	mac.Write([]byte(data))
+	return hex.EncodeToString(mac.Sum(nil))
+}
+
+func HmacSHA256(key, data string) string {
+	mac := hmac.New(sha256.New, []byte(key))
+	mac.Write([]byte(data))
+	return hex.EncodeToString(mac.Sum(nil))
+}
+func SHA256(data string) string {
+	hash := sha256.New()
+	hash.Write([]byte(data))
+	hashed := hash.Sum(nil)
+	return hex.EncodeToString(hashed)
+}
+
+func HmacSHA512(key, data string) string {
+	mac := hmac.New(sha512.New, []byte(key))
+	mac.Write([]byte(data))
+	return hex.EncodeToString(mac.Sum(nil))
+}
+
+func Hmac_SHA3_SHA512(key, data string) string {
+	mac := hmac.New(sha3.New512, []byte(key))
+	mac.Write([]byte(data))
+	return hex.EncodeToString(mac.Sum(nil))
+}
+
+// base64编码
+func Base64EncodeStr(src string) string {
+	return string(base64.StdEncoding.EncodeToString([]byte(src)))
+}
+
+// base64解码
+func Base64DecodeStr(src string) string {
+	a, err := base64.StdEncoding.DecodeString(src)
+	if err != nil {
+		return ""
+	}
+	return string(a)
+}
+
+// 加密数据
+func AesEncrypt(origData, key []byte) ([]byte, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	blockSize := block.BlockSize()
+	origData = PKCS5Padding(origData, blockSize)
+	blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
+	crypted := make([]byte, len(origData))
+	blockMode.CryptBlocks(crypted, origData)
+	return crypted, nil
+}
+
+// 解密数据
+func AesDecrypt(crypted, key []byte) ([]byte, error) {
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	blockSize := block.BlockSize()
+	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
+	origData := make([]byte, len(crypted))
+
+	blockMode.CryptBlocks(origData, crypted)
+	origData = PKCS5UnPadding(origData)
+	return origData, nil
+}
+
+// 加密解密需要数据一定的格式, 如果愿数据不符合要求,需要加一些padding
+func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
+	padding := blockSize - len(ciphertext)%blockSize
+	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
+	return append(ciphertext, padtext...)
+}
+
+// 加密解密需要数据一定的格式, 如果愿数据不符合要求,需要加一些padding
+func PKCS5UnPadding(origData []byte) []byte {
+	length := len(origData)
+	unpadding := int(origData[length-1])
+	return origData[:(length - unpadding)]
+}
+
+// 根据经纬度计算两点之间距离(米)
+func GetDistance(lat1, lng1, lat2, lng2 float64) float64 {
+	radius := 6378137.0 //赤道半径
+	rad := math.Pi / 180.0
+	lat1 = lat1 * rad
+	lng1 = lng1 * rad
+	lat2 = lat2 * rad
+	lng2 = lng2 * rad
+	theta := lng2 - lng1
+	dist := math.Acos(math.Sin(lat1)*math.Sin(lat2) + math.Cos(lat1)*math.Cos(lat2)*math.Cos(theta))
+	return dist * radius
+}
+
+// HttpSMSCode请求并获取返回信息
+func HttpSMSCode(number, smsSendMsg, authSecret, smsPostUrl, code string) (string, error) {
+
+	//发送的验证码短息内容
+	sendMsg := fmt.Sprintf(smsSendMsg, code)
+
+	//设置提交数据
+	data := struct {
+		AuthSecret string `json:"authSecret"`
+		Number     string `json:"number"`
+		Sms        string `json:"sms"`
+	}{
+		AuthSecret: authSecret,
+		Number:     number,
+		Sms:        sendMsg,
+	}
+
+	buf, _ := json.Marshal(data)
+
+	msg := string(buf)
+	log.Debug("httpSMSCode data=%s", msg)
+
+	//请求
+	body := HttpPostByJson(smsPostUrl, msg)
+
+	//打印返回文本
+	return string(body), nil
+}
+
+// HttpSMSSend请求并获取返回信息
+func HttpSMSSend(phone, smsSendMsg, smsAppID, smsApiKey, smsPostUrl string) (string, error) {
+	if phone == "" || smsSendMsg == "" || smsAppID == "" || smsApiKey == "" || smsPostUrl == "" {
+		return "空信息", nil
+	}
+
+	client := http.Client{}
+
+	// 设置提交数据
+	data := fmt.Sprintf("account=%v&password=%v&mobile=%v&content=%v",
+		smsAppID, smsApiKey, phone, smsSendMsg)
+
+	log.Debug("httpPostSMSCode data=%v", data)
+
+	// 请求
+	request, err := http.NewRequest("POST", smsPostUrl, strings.NewReader(data))
+	if err != nil {
+		log.Release("httpPostSMSCode send Request failer err=%v", err)
+		return "", err // handle error
+	}
+
+	// 设置Content-Type
+	request.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
+
+	response, err := client.Do(request) // 返回
+	if err != nil {
+		log.Release("httpPostSMSCode client.Do return failer err=%v", err)
+		return "", err
+	}
+
+	defer response.Body.Close()
+
+	body, err := io.ReadAll(response.Body)
+	if err != nil {
+		return "", err
+	}
+
+	// 打印返回文本
+	log.Debug(string(body))
+	return string(body), nil
+}
+
+// HttpWithdraw请求提现并获取返回信息
+func HttpWithdraw(postUrl, data string) (string, error) {
+
+	//log.Debug("HttpWithdraw postUrl=%s  data=%s", postUrl, data)
+
+	client := http.Client{}
+
+	//请求
+	request, err := http.NewRequest("POST", postUrl, strings.NewReader(data))
+	//request, err := http.NewRequest("GET", url, nil)
+	if err != nil {
+		log.Release("HttpWithdraw send Request failer err=%v", err)
+		return "", err // handle error
+	}
+
+	//设置Content-Type
+	request.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
+
+	response, err := client.Do(request) //返回
+	if err != nil {
+		log.Release("HttpWithdraw client.Do return failer err=%v", err)
+		return "", err
+	}
+
+	defer response.Body.Close()
+
+	body, err := io.ReadAll(response.Body)
+	if err != nil {
+		return "", err
+	}
+
+	//打印返回文本
+	//log.Debug(string(body))
+	return string(body), nil
+}
+
+// 检查手机号并返回手机号
+func CheckTelValid(tel string) (string, error) {
+	reg := regexp.MustCompile(`^(\()?(\+62|62|0)(\d{2,3})?\)?[ .-]?\d{2,4}[ .-]?\d{2,4}[ .-]?\d{2,4}$`)
+	matchs := reg.FindStringSubmatch(tel)
+	if len(matchs) <= 0 {
+		errString := fmt.Sprintf("tel format fail %s", tel)
+		return "", errors.New(errString)
+	}
+
+	return tel, nil
+}
+
+func Sha256WithRsa(source, secret string) string {
+	decodeString, err := base64.StdEncoding.DecodeString(secret)
+	if err != nil {
+		panic(err)
+	}
+	private, err := x509.ParsePKCS8PrivateKey(decodeString)
+	if err != nil {
+		panic(err)
+	}
+
+	//h := crypto.Hash.New(crypto.SHA256)
+	h := sha256.New()
+	h.Write([]byte(source))
+	hashed := h.Sum(nil)
+	signature, err := rsa.SignPKCS1v15(rand.Reader, private.(*rsa.PrivateKey),
+		crypto.SHA256, hashed)
+	if err != nil {
+		panic(err)
+	}
+
+	return base64.StdEncoding.EncodeToString(signature)
+}
+
+// 根据SHA256WithRSA算法获取签名对象实例
+func VerifyRsaSignBySHA256(content string, sign string, publicKey string) error {
+	publicKeyByte, err := base64.StdEncoding.DecodeString(publicKey)
+	if err != nil {
+		return err
+	}
+	pub, err := x509.ParsePKIXPublicKey(publicKeyByte)
+	if err != nil {
+		return err
+	}
+	hashed := sha256.Sum256([]byte(content))
+	signature, err := base64.StdEncoding.DecodeString(sign)
+	if err != nil {
+		return err
+	}
+	return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hashed[:], signature)
+}
+
+// 根据SHA1WithRSA算法获取签名对象实例
+func VerifyRsaSignBySHA1(content string, sign string, publicKey string) error {
+	publicKeyByte, err := base64.StdEncoding.DecodeString(publicKey)
+	if err != nil {
+		return err
+	}
+	pub, err := x509.ParsePKIXPublicKey(publicKeyByte)
+	if err != nil {
+		return err
+	}
+	hashed := sha1.Sum([]byte(content))
+	signature, err := base64.StdEncoding.DecodeString(sign)
+	if err != nil {
+		return err
+	}
+	return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA1, hashed[:], signature)
+}
+
+func CheckMobile(phone string) bool {
+	// 匹配规则
+	// ^1第一位为一
+	// [345789]{1} 后接一位345789 的数字
+	// \\d \d的转义 表示数字 {9} 接9位
+	// $ 结束符
+	regRuler := "^1[345789]{1}\\d{9}$"
+
+	// 正则调用规则
+	reg := regexp.MustCompile(regRuler)
+
+	// 返回 MatchString 是否匹配
+	return reg.MatchString(phone)
+}
+
+const (
+	letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+	// 6 bits to represent a letter index
+	letterIdBits = 6
+	// All 1-bits as many as letterIdBits
+	letterIdMask = 1<<letterIdBits - 1
+	letterIdMax  = 63 / letterIdBits
+)
+
+// 指定随机的字符串
+func RandStr(n int) string {
+	var src = mathRand.NewSource(time.Now().UnixNano())
+	b := make([]byte, n)
+	// A rand.Int63() generates 63 random bits, enough for letterIdMax letters!
+	for i, cache, remain := n-1, src.Int63(), letterIdMax; i >= 0; {
+		if remain == 0 {
+			cache, remain = src.Int63(), letterIdMax
+		}
+		if idx := int(cache & letterIdMask); idx < len(letters) {
+			b[i] = letters[idx]
+			i--
+		}
+		cache >>= letterIdBits
+		remain--
+	}
+	return *(*string)(unsafe.Pointer(&b))
+}
+
+// 解密【模拟了Java SHA1PRNG处理】
+func Sha1Decrypt(data, key string) (string, error) {
+	dataByte, _ := Hex2bin(data)
+	keys, err := AesSha1prng([]byte(key), 128)
+	if err != nil {
+		return "", err
+	}
+	block, err := aes.NewCipher(generateKey(keys))
+	if err != nil {
+		return "", err
+	}
+	decrypted := make([]byte, len(dataByte))
+	size := block.BlockSize()
+	for bs, be := 0, size; bs < len(dataByte); bs, be = bs+size, be+size {
+		block.Decrypt(decrypted[bs:be], dataByte[bs:be])
+	}
+	decrypted = PKCS5UnPadding(decrypted)
+	return string(decrypted), nil
+}
+
+// 加密【模拟了Java SHA1PRNG处理】
+func Sha1Encrypt(data, key []byte) (string, error) {
+	keys, err := AesSha1prng(key, 128)
+	if err != nil {
+		return "", err
+	}
+	block, err := aes.NewCipher(generateKey(keys))
+	if err != nil {
+		return "", err
+	}
+	data = PKCS5Padding(data, block.BlockSize())
+	decrypted := make([]byte, len(data))
+	size := block.BlockSize()
+	for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size {
+		block.Encrypt(decrypted[bs:be], data[bs:be])
+	}
+	return Bin2hex(decrypted), nil
+}
+
+// 模拟java SHA1PRNG 处理
+func AesSha1prng(keyBytes []byte, encryptLength int) ([]byte, error) {
+	hashs := Sha1(Sha1(keyBytes))
+	maxLen := len(hashs)
+	realLen := encryptLength / 8
+	if realLen > maxLen {
+		return nil, errors.New("invalid length")
+	}
+
+	return hashs[0:realLen], nil
+}
+
+func Sha1(data []byte) []byte {
+	h := sha1.New()
+	h.Write(data)
+	bs := h.Sum(nil)
+	h.Reset()
+	return bs
+}
+
+// 生成密钥
+func generateKey(key []byte) (genKey []byte) {
+	genKey = make([]byte, 16)
+	copy(genKey, key)
+	for i := 16; i < len(key); {
+		for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
+			genKey[j] ^= key[i]
+		}
+	}
+	return genKey
+}
+
+func Bin2hex(b []byte) string {
+	return base64.StdEncoding.EncodeToString(b)
+}
+
+func Hex2bin(x string) ([]byte, error) {
+	return base64.StdEncoding.DecodeString(x)
+}
+
+// MD5withRSA 签名
+func MD5withRSASign(params url.Values, keys string) error {
+	quUrl, err := url.QueryUnescape(params.Encode())
+	if err != nil {
+		return err
+	}
+	out, err := rsaSignWithMd5(quUrl, keys)
+	if err != nil {
+		return err
+	}
+	params.Add("sign", out)
+	return nil
+}
+
+// 签名开始
+func rsaSignWithMd5(data string, prvKey string) (sign string, err error) {
+	//如果密钥是urlSafeBase64的话需要处理下
+	prvKey = Base64URLDecode(prvKey)
+	keyBytes, err := base64.StdEncoding.DecodeString(prvKey)
+	if err != nil {
+		return "", err
+	}
+	privateKey, err := x509.ParsePKCS8PrivateKey(keyBytes)
+	if err != nil {
+		return "", err
+	}
+	h := md5.New()
+	h.Write([]byte(data))
+	hash := h.Sum(nil)
+	signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey.(*rsa.PrivateKey), crypto.MD5, hash[:])
+	if err != nil {
+		return "", err
+	}
+	out := base64.RawURLEncoding.EncodeToString(signature)
+	return out, nil
+}
+
+// 验签(MD5withRSA)
+func VerifyMD5withRSA(params url.Values, key string) error {
+	sign := params.Get("sign")
+	params.Del("sign")
+	quUrl, _ := url.QueryUnescape(params.Encode())
+	return rsaVerifySignWithMd5(quUrl, sign, key)
+}
+
+// 验签开始
+func rsaVerifySignWithMd5(originalData, signData, pubKey string) error {
+	sign, err := base64.RawURLEncoding.DecodeString(signData)
+	if err != nil {
+		return err
+	}
+	pubKey = Base64URLDecode(pubKey)
+	public, err := base64.StdEncoding.DecodeString(pubKey)
+	if err != nil {
+		return err
+	}
+	pub, err := x509.ParsePKIXPublicKey(public)
+	if err != nil {
+		return err
+	}
+	hash := md5.New()
+	hash.Write([]byte(originalData))
+	return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.MD5, hash.Sum(nil), sign)
+}
+
+// MD5withRSA 解密
+func MD5withRSADecrypt(sign, privateKey string) string {
+	key := chunkSplit(privateKey, 64, "\n")
+	key = fmt.Sprintf("-----BEGIN RSA PRIVATE KEY-----\n%s\n-----END RSA PRIVATE KEY-----", key)
+	decodedBytes, err := base64.StdEncoding.DecodeString(sign)
+	if err != nil {
+		return ""
+	}
+	block, _ := pem.Decode([]byte(key))
+	if block == nil {
+		return ""
+	}
+	keys, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+	if err != nil {
+		return ""
+	}
+	resCrypto := ""
+	for _, v := range strSplit(string(decodedBytes), 128) {
+		// 使用 RSA 私钥解密密文
+		plaintext, errs := rsa.DecryptPKCS1v15(rand.Reader, keys.(*rsa.PrivateKey), []byte(v))
+		if errs != nil {
+			return ""
+		}
+		resCrypto += string(plaintext)
+	}
+	return resCrypto
+}
+
+// 字符串分割密文
+func strSplit(s string, chunkSize int) []string {
+	var chunks []string
+	for i := 0; i < len(s); i += chunkSize {
+		end := i + chunkSize
+		if end > len(s) {
+			end = len(s)
+		}
+		chunks = append(chunks, s[i:end])
+	}
+	return chunks
+}
+
+// 块分割
+func chunkSplit(s string, chunkLen int, separator string) string {
+	var result strings.Builder
+	for i := 0; i < len(s); i += chunkLen {
+		end := i + chunkLen
+		if end > len(s) {
+			end = len(s)
+		}
+		result.WriteString(s[i:end])
+		if end < len(s) {
+			result.WriteString(separator)
+		}
+	}
+	return result.String()
+}
+
+//因为Base64转码后可能包含有+,/,=这些不安全的URL字符串,所以要进行换字符
+// '+' -> '-'
+// '/' -> '_'
+// '=' -> ''
+// 字符串长度不足4倍的位补"="
+
+func Base64URLDecode(data string) string {
+	var missing = (4 - len(data)%4) % 4
+	data += strings.Repeat("=", missing) //字符串长度不足4倍的位补"="
+	data = strings.Replace(data, "_", "/", -1)
+	data = strings.Replace(data, "-", "+", -1)
+	return data
+}
+
+func Base64UrlSafeEncode(data string) string {
+	safeUrl := strings.Replace(data, "/", "_", -1)
+	safeUrl = strings.Replace(safeUrl, "+", "-", -1)
+	safeUrl = strings.Replace(safeUrl, "=", "", -1)
+	return safeUrl
+}
+
+// 生成码
+func GenCode(length int) string {
+	var chars = []byte("ABCDEFGHJKLMNPQRTUVWXYZ123456789")
+	code := make([]byte, length)
+	clen := len(chars)
+	for i := 0; i < length; i++ {
+		index := mathRand.Intn(clen)
+		code[i] = byte(chars[index])
+	}
+
+	return string(code)
+}
+
+// SlicePage 分页算法(pageIndex 页索引、pageSize 页大小、nums 总记录数)
+// exploreList := manager.Mgr.GetExploreList()
+//
+//	totalCount := len(exploreList)
+//	start, end := public.SlicePage(req.PageIndex, req.PageSize, totalCount)
+//	rsp.RecordCount = totalCount
+//	rsp.List = this.getOwnerList(exploreList[start:end])
+func SlicePage(pageIndex, pageSize, nums int) (start, end int) {
+	if pageIndex <= 0 {
+		pageIndex = 1
+	}
+
+	if pageSize < 0 {
+		pageSize = 10
+	}
+
+	if pageSize > nums {
+		return 0, nums
+	}
+
+	// 计算起始行
+	start = (pageIndex - 1) * pageSize
+
+	// 计算终止行
+	end = start + pageSize
+
+	if end > nums {
+		end = nums
+	}
+
+	if start > end {
+		return 0, 0
+	}
+
+	// 起始、终止位置
+	return start, end
+}

+ 220 - 0
public/citizen.go

@@ -0,0 +1,220 @@
+package public
+
+import (
+	"errors"
+	"strconv"
+	"time"
+)
+
+var weight = [17]int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
+var valid_value = [11]byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
+var valid_province = []string{
+	"11", // 北京市
+	"12", // 天津市
+	"13", // 河北省
+	"14", // 山西省
+	"15", // 内蒙古自治区
+	"21", // 辽宁省
+	"22", // 吉林省
+	"23", // 黑龙江省
+	"31", // 上海市
+	"32", // 江苏省
+	"33", // 浙江省
+	"34", // 安徽省
+	"35", // 福建省
+	"36", // 山西省
+	"37", // 山东省
+	"41", // 河南省
+	"42", // 湖北省
+	"43", // 湖南省
+	"44", // 广东省
+	"45", // 广西壮族自治区
+	"46", // 海南省
+	"50", // 重庆市
+	"51", // 四川省
+	"52", // 贵州省
+	"53", // 云南省
+	"54", // 西藏自治区
+	"61", // 陕西省
+	"62", // 甘肃省
+	"63", // 青海省
+	"64", // 宁夏回族自治区
+	"65", // 新疆维吾尔自治区
+	"71", // 台湾省
+	"81", // 香港特别行政区
+	"91", // 澳门特别行政区
+}
+
+// Check citizen number 18 valid.
+func IsValidCitizenNo18(citizenNo18 *[]byte) bool {
+	nLen := len(*citizenNo18)
+	if nLen != 18 {
+		return false
+	}
+
+	nSum := 0
+	for i := 0; i < nLen-1; i++ {
+		n, _ := strconv.Atoi(string((*citizenNo18)[i]))
+		nSum += n * weight[i]
+	}
+	mod := nSum % 11
+	if valid_value[mod] == (*citizenNo18)[17] {
+		return true
+	}
+
+	return false
+}
+
+// Convert citizen 15 to 18.
+func Citizen15To18(citizenNo15 []byte) []byte {
+	nLen := len(citizenNo15)
+	if nLen != 15 {
+		return nil
+	}
+
+	citizenNo18 := make([]byte, 0)
+	citizenNo18 = append(citizenNo18, citizenNo15[:6]...)
+	citizenNo18 = append(citizenNo18, '1', '9')
+	citizenNo18 = append(citizenNo18, citizenNo15[6:]...)
+
+	sum := 0
+	for i, v := range citizenNo18 {
+		n, _ := strconv.Atoi(string(v))
+		sum += n * weight[i]
+	}
+	mod := sum % 11
+	citizenNo18 = append(citizenNo18, valid_value[mod])
+
+	return citizenNo18
+}
+
+func IsLeapYear(nYear int) bool {
+	if nYear <= 0 {
+		return false
+	}
+
+	if (nYear%4 == 0 && nYear%100 != 0) || nYear%400 == 0 {
+		return true
+	}
+
+	return false
+}
+
+// Check birthday's year month day valid.
+func CheckBirthdayValid(nYear, nMonth, nDay int) bool {
+	if nYear < 1900 || nMonth <= 0 || nMonth > 12 || nDay <= 0 || nDay > 31 {
+		return false
+	}
+
+	curYear, curMonth, curDay := time.Now().Date()
+	if nYear == curYear {
+		if nMonth > int(curMonth) {
+			return false
+		} else if nMonth == int(curMonth) && nDay > curDay {
+			return false
+		}
+	}
+
+	if 2 == nMonth {
+		if IsLeapYear(nYear) && nDay > 29 {
+			return false
+		} else if nDay > 28 {
+			return false
+		}
+	} else if 4 == nMonth || 6 == nMonth || 9 == nMonth || 11 == nMonth {
+		if nDay > 30 {
+			return false
+		}
+	}
+
+	return true
+}
+
+// Check province code valid.
+func CheckProvinceValid(citizenNo []byte) bool {
+	provinceCode := make([]byte, 0)
+	provinceCode = append(provinceCode, citizenNo[:2]...)
+	provinceStr := string(provinceCode)
+
+	for _, str := range valid_province {
+		if provinceStr == str {
+			return true
+		}
+	}
+
+	return false
+}
+
+// Check citizen number valid.
+func IsValidCitizenNo(citizenNo *[]byte) bool {
+	nLen := len(*citizenNo)
+	if nLen != 15 && nLen != 18 {
+		return false
+	}
+
+	for i, v := range *citizenNo {
+		n, _ := strconv.Atoi(string(v))
+		if n >= 0 && n <= 9 {
+			continue
+		}
+
+		if v == 'X' && i == 16 {
+			continue
+		}
+
+		return false
+	}
+
+	if !CheckProvinceValid(*citizenNo) {
+		return false
+	}
+
+	if nLen == 15 {
+		*citizenNo = Citizen15To18(*citizenNo)
+		if citizenNo == nil {
+			return false
+		}
+	} else if !IsValidCitizenNo18(citizenNo) {
+		return false
+	}
+
+	nYear, _ := strconv.Atoi(string((*citizenNo)[6:10]))
+	nMonth, _ := strconv.Atoi(string((*citizenNo)[10:12]))
+	nDay, _ := strconv.Atoi(string((*citizenNo)[12:14]))
+	if !CheckBirthdayValid(nYear, nMonth, nDay) {
+		return false
+	}
+
+	return true
+}
+
+// Get information from citizen number. Birthday, gender, province mask.
+func GetCitizenNoInfo(citizenNo []byte) (err error, birthday int64, isMale bool, addrMask int) {
+	err = nil
+	birthday = 0
+	isMale = false
+	addrMask = 0
+	if !IsValidCitizenNo(&citizenNo) {
+		err = errors.New("Invalid citizen number.")
+		return
+	}
+
+	// Birthday information.
+	nYear, _ := strconv.Atoi(string(citizenNo[6:10]))
+	nMonth, _ := strconv.Atoi(string(citizenNo[10:12]))
+	nDay, _ := strconv.Atoi(string(citizenNo[12:14]))
+	birthday = time.Date(nYear, time.Month(nMonth), nDay, 0, 0, 0, 0, time.Local).Unix()
+
+	// Gender information.
+	genderMask, _ := strconv.Atoi(string(citizenNo[16]))
+	if genderMask%2 == 0 {
+		isMale = false
+	} else {
+		isMale = true
+	}
+
+	// Address code mask.
+	addrMask, _ = strconv.Atoi(string(citizenNo[:2]))
+
+	return
+}

+ 113 - 0
public/httpReq.go

@@ -0,0 +1,113 @@
+package public
+
+import (
+	"io"
+	"net/http"
+	"net/url"
+	"strings"
+
+	"bet24.com/log"
+)
+
+// http post json 请求
+func HttpPostByJson(url string, data string) string {
+	req, err := http.NewRequest("POST", url, strings.NewReader(data))
+	if err != nil {
+		log.Error("HttpPostByJson NewRequest error %v", err)
+		return ""
+	}
+
+	req.Header.Add("Content-Type", "application/json")
+	req.Header.Add("Cache-Control", "no-cache")
+
+	resp, err := (&http.Client{}).Do(req)
+	if err != nil {
+		log.Error("HttpPostByJson Request Do error %v", err)
+		return ""
+	}
+	defer resp.Body.Close()
+
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		log.Error("HttpPostByJson Response error %v", err)
+		return ""
+	}
+
+	// log.Debug("HttpPost Send:%v", string(body))
+	return string(body)
+}
+
+// http post xml 请求
+func HttpPostByXML(url string, data string) string {
+	req, err := http.NewRequest("POST", url, strings.NewReader(data))
+	if err != nil {
+		log.Error("HttpPostByXML NewRequest error %v", err)
+		return ""
+	}
+
+	req.Header.Set("Accept", "application/xml")
+	//这里的http header的设置是必须设置的.
+	req.Header.Set("Content-Type", "application/xml;charset=utf-8")
+
+	resp, err := (&http.Client{}).Do(req)
+	if err != nil {
+		log.Error("HttpPostByXML Request Do error %v", err)
+		return ""
+	}
+	defer resp.Body.Close()
+
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		log.Error("HttpPostByXML Response error %v", err)
+		return ""
+	}
+
+	//log.Debug("HttpPost Send:%v", string(body))
+	return string(body)
+}
+
+// http get请求
+func HttpGet(url string) string {
+	//log.Debug("HttpGet url:%s", url)
+	req, err := http.NewRequest("GET", url, nil)
+	if err != nil {
+		log.Error("HttpGet NewRequest Error %v", err)
+		return ""
+	}
+
+	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+	req.Header.Add("Cache-Control", "no-cache")
+
+	resp, err := (&http.Client{}).Do(req)
+	if err != nil {
+		log.Error("HttpGet request error %v", err)
+		return ""
+	}
+	defer resp.Body.Close()
+
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		log.Error("HttpGet response error %v", err)
+		return ""
+	}
+	return string(body)
+}
+
+// http.PostForm 方法的post请求
+func HttpPostForm(url string, params url.Values) string {
+	resp, err := http.PostForm(url, params)
+	if err != nil {
+		log.Error("HttpPostForm request error %v", err)
+		return ""
+	}
+
+	defer resp.Body.Close()
+
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		log.Error("HttpPostForm response error %v", err)
+		return ""
+	}
+
+	return string(body)
+}

+ 96 - 0
public/rsa.go

@@ -0,0 +1,96 @@
+package public
+
+import (
+	"bytes"
+	"crypto/rsa"
+	"errors"
+	"io"
+)
+
+// 支持rsa公钥加密私钥解密;
+// 支持rsa公钥解密私钥加密。
+var RSA = &RSASecurity{}
+
+type RSASecurity struct {
+	pubStr string          // 公钥字符串
+	priStr string          // 私钥字符串
+	pubkey *rsa.PublicKey  // 公钥
+	prikey *rsa.PrivateKey // 私钥
+}
+
+// 设置公钥
+func (rsas *RSASecurity) SetPublicKey(pubStr string) (err error) {
+	rsas.pubStr = pubStr
+	rsas.pubkey, err = rsas.GetPublickey()
+	return err
+}
+
+// 设置私钥
+func (rsas *RSASecurity) SetPrivateKey(priStr string) (err error) {
+	rsas.priStr = priStr
+	rsas.prikey, err = rsas.GetPrivatekey()
+	return err
+}
+
+// *rsa.PublicKey
+func (rsas *RSASecurity) GetPrivatekey() (*rsa.PrivateKey, error) {
+	return getPriKey([]byte(rsas.priStr))
+}
+
+// *rsa.PrivateKey
+func (rsas *RSASecurity) GetPublickey() (*rsa.PublicKey, error) {
+	return getPubKey([]byte(rsas.pubStr))
+}
+
+// 公钥加密
+func (rsas *RSASecurity) PubKeyENCTYPT(input []byte) ([]byte, error) {
+	if rsas.pubkey == nil {
+		return []byte(""), errors.New(`Please set the public key in advance`)
+	}
+	output := bytes.NewBuffer(nil)
+	err := pubKeyIO(rsas.pubkey, bytes.NewReader(input), output, true)
+	if err != nil {
+		return []byte(""), err
+	}
+	return io.ReadAll(output)
+}
+
+// 公钥解密
+func (rsas *RSASecurity) PubKeyDECRYPT(input []byte) ([]byte, error) {
+	if rsas.pubkey == nil {
+		return []byte(""), errors.New(`Please set the public key in advance`)
+	}
+	output := bytes.NewBuffer(nil)
+	err := pubKeyIO(rsas.pubkey, bytes.NewReader(input), output, false)
+	if err != nil {
+		return []byte(""), err
+	}
+	return io.ReadAll(output)
+}
+
+// 私钥加密
+func (rsas *RSASecurity) PriKeyENCTYPT(input []byte) ([]byte, error) {
+	if rsas.prikey == nil {
+		return []byte(""), errors.New(`Please set the private key in advance`)
+	}
+	output := bytes.NewBuffer(nil)
+	err := priKeyIO(rsas.prikey, bytes.NewReader(input), output, true)
+	if err != nil {
+		return []byte(""), err
+	}
+	return io.ReadAll(output)
+}
+
+// 私钥解密
+func (rsas *RSASecurity) PriKeyDECRYPT(input []byte) ([]byte, error) {
+	if rsas.prikey == nil {
+		return []byte(""), errors.New(`Please set the private key in advance`)
+	}
+	output := bytes.NewBuffer(nil)
+	err := priKeyIO(rsas.prikey, bytes.NewReader(input), output, false)
+	if err != nil {
+		return []byte(""), err
+	}
+
+	return io.ReadAll(output)
+}

+ 355 - 0
public/rsa_ext.go

@@ -0,0 +1,355 @@
+package public
+
+import (
+	"bytes"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+	"io"
+	"math/big"
+)
+
+var (
+	ErrDataToLarge     = errors.New("message too long for RSA public key size")
+	ErrDataLen         = errors.New("data length error")
+	ErrDataBroken      = errors.New("data broken, first byte is not zero")
+	ErrKeyPairDismatch = errors.New("data is not encrypted by the private key")
+	ErrDecryption      = errors.New("decryption error")
+	ErrPublicKey       = errors.New("get public key error")
+	ErrPrivateKey      = errors.New("get private key error")
+)
+
+// 设置公钥
+func getPubKey(publickey []byte) (*rsa.PublicKey, error) {
+	// decode public key
+	block, _ := pem.Decode(publickey)
+	if block == nil {
+		return nil, errors.New("get public key error")
+	}
+	// x509 parse public key
+	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+	return pub.(*rsa.PublicKey), err
+}
+
+// 设置私钥
+func getPriKey(privatekey []byte) (*rsa.PrivateKey, error) {
+	block, _ := pem.Decode(privatekey)
+	if block == nil {
+		return nil, errors.New("get private key error")
+	}
+	pri, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+	if err == nil {
+		return pri, nil
+	}
+	pri2, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+	return pri2.(*rsa.PrivateKey), nil
+}
+
+// 公钥加密或解密byte
+func pubKeyByte(pub *rsa.PublicKey, in []byte, isEncrytp bool) ([]byte, error) {
+	k := (pub.N.BitLen() + 7) / 8
+	if isEncrytp {
+		k = k - 11
+	}
+	if len(in) <= k {
+		if isEncrytp {
+			return rsa.EncryptPKCS1v15(rand.Reader, pub, in)
+		} else {
+			return pubKeyDecrypt(pub, in)
+		}
+	} else {
+		iv := make([]byte, k)
+		out := bytes.NewBuffer(iv)
+		if err := pubKeyIO(pub, bytes.NewReader(in), out, isEncrytp); err != nil {
+			return nil, err
+		}
+		return io.ReadAll(out)
+	}
+}
+
+// 私钥加密或解密byte
+func priKeyByte(pri *rsa.PrivateKey, in []byte, isEncrytp bool) ([]byte, error) {
+	k := (pri.N.BitLen() + 7) / 8
+	if isEncrytp {
+		k = k - 11
+	}
+	if len(in) <= k {
+		if isEncrytp {
+			return priKeyEncrypt(rand.Reader, pri, in)
+		} else {
+			return rsa.DecryptPKCS1v15(rand.Reader, pri, in)
+		}
+	} else {
+		iv := make([]byte, k)
+		out := bytes.NewBuffer(iv)
+		if err := priKeyIO(pri, bytes.NewReader(in), out, isEncrytp); err != nil {
+			return nil, err
+		}
+		return io.ReadAll(out)
+	}
+}
+
+// 公钥加密或解密Reader
+func pubKeyIO(pub *rsa.PublicKey, in io.Reader, out io.Writer, isEncrytp bool) (err error) {
+	k := (pub.N.BitLen() + 7) / 8
+	if isEncrytp {
+		k = k - 11
+	}
+	buf := make([]byte, k)
+	var b []byte
+	size := 0
+	for {
+		size, err = in.Read(buf)
+		if err != nil {
+			if err == io.EOF {
+				return nil
+			}
+			return err
+		}
+		if size < k {
+			b = buf[:size]
+		} else {
+			b = buf
+		}
+		if isEncrytp {
+			b, err = rsa.EncryptPKCS1v15(rand.Reader, pub, b)
+		} else {
+			b, err = pubKeyDecrypt(pub, b)
+		}
+		if err != nil {
+			return err
+		}
+		if _, err = out.Write(b); err != nil {
+			return err
+		}
+	}
+	//return nil
+}
+
+// 私钥加密或解密Reader
+func priKeyIO(pri *rsa.PrivateKey, r io.Reader, w io.Writer, isEncrytp bool) (err error) {
+	k := (pri.N.BitLen() + 7) / 8
+	if isEncrytp {
+		k = k - 11
+	}
+	buf := make([]byte, k)
+	var b []byte
+	size := 0
+	for {
+		size, err = r.Read(buf)
+		if err != nil {
+			if err == io.EOF {
+				return nil
+			}
+			return err
+		}
+		if size < k {
+			b = buf[:size]
+		} else {
+			b = buf
+		}
+		if isEncrytp {
+			b, err = priKeyEncrypt(rand.Reader, pri, b)
+		} else {
+			b, err = rsa.DecryptPKCS1v15(rand.Reader, pri, b)
+		}
+		if err != nil {
+			return err
+		}
+		if _, err = w.Write(b); err != nil {
+			return err
+		}
+	}
+	//return nil
+}
+
+// 公钥解密
+func pubKeyDecrypt(pub *rsa.PublicKey, data []byte) ([]byte, error) {
+	k := (pub.N.BitLen() + 7) / 8
+	if k != len(data) {
+		return nil, ErrDataLen
+	}
+	m := new(big.Int).SetBytes(data)
+	if m.Cmp(pub.N) > 0 {
+		return nil, ErrDataToLarge
+	}
+	m.Exp(m, big.NewInt(int64(pub.E)), pub.N)
+	d := leftPad(m.Bytes(), k)
+	if d[0] != 0 {
+		return nil, ErrDataBroken
+	}
+	if d[1] != 0 && d[1] != 1 {
+		return nil, ErrKeyPairDismatch
+	}
+	var i = 2
+	for ; i < len(d); i++ {
+		if d[i] == 0 {
+			break
+		}
+	}
+	i++
+	if i == len(d) {
+		return nil, nil
+	}
+	return d[i:], nil
+}
+
+// 私钥加密
+func priKeyEncrypt(rand io.Reader, priv *rsa.PrivateKey, hashed []byte) ([]byte, error) {
+	tLen := len(hashed)
+	k := (priv.N.BitLen() + 7) / 8
+	if k < tLen+11 {
+		return nil, ErrDataLen
+	}
+	em := make([]byte, k)
+	em[1] = 1
+	for i := 2; i < k-tLen-1; i++ {
+		em[i] = 0xff
+	}
+	copy(em[k-tLen:k], hashed)
+	m := new(big.Int).SetBytes(em)
+	c, err := decrypt(rand, priv, m)
+	if err != nil {
+		return nil, err
+	}
+	copyWithLeftPad(em, c.Bytes())
+	return em, nil
+}
+
+// 从crypto/rsa复制
+var bigZero = big.NewInt(0)
+var bigOne = big.NewInt(1)
+
+// 从crypto/rsa复制
+func encrypt(c *big.Int, pub *rsa.PublicKey, m *big.Int) *big.Int {
+	e := big.NewInt(int64(pub.E))
+	c.Exp(m, e, pub.N)
+	return c
+}
+
+// 从crypto/rsa复制
+func decrypt(random io.Reader, priv *rsa.PrivateKey, c *big.Int) (m *big.Int, err error) {
+	if c.Cmp(priv.N) > 0 {
+		err = ErrDecryption
+		return
+	}
+	var ir *big.Int
+	if random != nil {
+		var r *big.Int
+
+		for {
+			r, err = rand.Int(random, priv.N)
+			if err != nil {
+				return
+			}
+			if r.Cmp(bigZero) == 0 {
+				r = bigOne
+			}
+			var ok bool
+			ir, ok = modInverse(r, priv.N)
+			if ok {
+				break
+			}
+		}
+		bigE := big.NewInt(int64(priv.E))
+		rpowe := new(big.Int).Exp(r, bigE, priv.N)
+		cCopy := new(big.Int).Set(c)
+		cCopy.Mul(cCopy, rpowe)
+		cCopy.Mod(cCopy, priv.N)
+		c = cCopy
+	}
+	if priv.Precomputed.Dp == nil {
+		m = new(big.Int).Exp(c, priv.D, priv.N)
+	} else {
+		m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0])
+		m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1])
+		m.Sub(m, m2)
+		if m.Sign() < 0 {
+			m.Add(m, priv.Primes[0])
+		}
+		m.Mul(m, priv.Precomputed.Qinv)
+		m.Mod(m, priv.Primes[0])
+		m.Mul(m, priv.Primes[1])
+		m.Add(m, m2)
+
+		for i, values := range priv.Precomputed.CRTValues {
+			prime := priv.Primes[2+i]
+			m2.Exp(c, values.Exp, prime)
+			m2.Sub(m2, m)
+			m2.Mul(m2, values.Coeff)
+			m2.Mod(m2, prime)
+			if m2.Sign() < 0 {
+				m2.Add(m2, prime)
+			}
+			m2.Mul(m2, values.R)
+			m.Add(m, m2)
+		}
+	}
+	if ir != nil {
+		m.Mul(m, ir)
+		m.Mod(m, priv.N)
+	}
+
+	return
+}
+
+// 从crypto/rsa复制
+func copyWithLeftPad(dest, src []byte) {
+	numPaddingBytes := len(dest) - len(src)
+	for i := 0; i < numPaddingBytes; i++ {
+		dest[i] = 0
+	}
+	copy(dest[numPaddingBytes:], src)
+}
+
+// 从crypto/rsa复制
+func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) {
+	_, err = io.ReadFull(rand, s)
+	if err != nil {
+		return
+	}
+	for i := 0; i < len(s); i++ {
+		for s[i] == 0 {
+			_, err = io.ReadFull(rand, s[i:i+1])
+			if err != nil {
+				return
+			}
+			s[i] ^= 0x42
+		}
+	}
+	return
+}
+
+// 从crypto/rsa复制
+func leftPad(input []byte, size int) (out []byte) {
+	n := len(input)
+	if n > size {
+		n = size
+	}
+	out = make([]byte, size)
+	copy(out[len(out)-n:], input)
+	return
+}
+
+// 从crypto/rsa复制
+func modInverse(a, n *big.Int) (ia *big.Int, ok bool) {
+	g := new(big.Int)
+	x := new(big.Int)
+	y := new(big.Int)
+	g.GCD(x, y, a, n)
+	if g.Cmp(bigOne) != 0 {
+		return
+	}
+	if x.Cmp(bigOne) < 0 {
+		x.Add(x, n)
+	}
+	return x, true
+}

+ 55 - 0
public/tagClientInfo.go

@@ -0,0 +1,55 @@
+package public
+
+import (
+	"math/rand"
+)
+
+type ClientInfo struct {
+	ComputerID   [3]uint32
+	SystemVer    [2]uint32
+	ComputerName string //12
+}
+
+func NewClientInfo(ba *ByteArray) *ClientInfo {
+	var this *ClientInfo = new(ClientInfo)
+	for i := 0; i < 3; i++ {
+		if ba != nil {
+			this.ComputerID[i], _ = ba.ReadUInt32()
+		} else {
+			this.ComputerID[i] = uint32(rand.Intn(65535))
+		}
+	}
+	for i := 0; i < 2; i++ {
+		if ba != nil {
+			this.SystemVer[i], _ = ba.ReadUInt32()
+		} else {
+			this.SystemVer[i] = 2018
+		}
+	}
+	if ba != nil {
+		this.ComputerName, _ = ba.ReadString(12)
+	} else {
+		this.ComputerName = "golang test"
+	}
+	return this
+}
+
+func (this *ClientInfo) Serialize(ba *ByteArray) {
+	for i := 0; i < 3; i++ {
+		ba.WriteUInt32(this.ComputerID[i])
+	}
+	for i := 0; i < 2; i++ {
+		ba.WriteUInt32(this.SystemVer[i])
+	}
+
+	ba.WriteStringWithLen(this.ComputerName, 12)
+}
+
+func (this *ClientInfo) GetMachineNum() []byte {
+	var tmpBuf []byte
+	ba := CreateByteArray(tmpBuf)
+	for i := 0; i < 3; i++ {
+		ba.WriteUInt32(this.ComputerID[i])
+	}
+	return ba.Bytes()
+}

+ 31 - 0
public/tagConnectInfo.go

@@ -0,0 +1,31 @@
+package public
+
+type ConnectInfo struct {
+	Size           uint16
+	GameInstallVer uint32
+	GameBuildVer   uint32
+	ConnectDelay   uint32
+}
+
+func NewConnectInfo(ba *ByteArray) *ConnectInfo {
+	var this *ConnectInfo = new(ConnectInfo)
+	if ba == nil {
+		this.Size = 14
+		this.GameInstallVer = 2018
+		this.GameBuildVer = 1
+		this.ConnectDelay = 0
+		return this
+	}
+	this.Size, _ = ba.ReadUInt16()
+	this.GameInstallVer, _ = ba.ReadUInt32()
+	this.GameBuildVer, _ = ba.ReadUInt32()
+	this.ConnectDelay, _ = ba.ReadUInt32()
+	return this
+}
+
+func (this *ConnectInfo) Serialize(ba *ByteArray) {
+	ba.WriteUInt16(this.Size)
+	ba.WriteUInt32(this.GameInstallVer)
+	ba.WriteUInt32(this.GameBuildVer)
+	ba.WriteUInt32(this.ConnectDelay)
+}

+ 27 - 0
public/tagVersionInfo.go

@@ -0,0 +1,27 @@
+package public
+
+type VersionInfo struct {
+	InstallVer  uint32
+	BuildVer    uint32
+	SubBuildVer uint32
+}
+
+func NewVersionInfo(ba *ByteArray) *VersionInfo {
+	var this *VersionInfo = new(VersionInfo)
+	if ba == nil {
+		this.InstallVer = 2018
+		this.BuildVer = 1
+		this.SubBuildVer = 1
+		return this
+	}
+	this.InstallVer, _ = ba.ReadUInt32()
+	this.BuildVer, _ = ba.ReadUInt32()
+	this.SubBuildVer, _ = ba.ReadUInt32()
+	return this
+}
+
+func (this *VersionInfo) Serialize(ba *ByteArray) {
+	ba.WriteUInt32(this.InstallVer)
+	ba.WriteUInt32(this.BuildVer)
+	ba.WriteUInt32(this.SubBuildVer)
+}

+ 58 - 0
public/timeTool.go

@@ -0,0 +1,58 @@
+package public
+
+import (
+	"strings"
+	"time"
+)
+
+func GetMonthFirstLastDay(now time.Time) (firstOfMonth int, lastOfMonth int) {
+	currentYear, currentMonth, _ := now.Date()
+	currentLocation := now.Location()
+
+	firstDate := time.Date(currentYear, currentMonth, 1, 0, 0, 0, 0, currentLocation)
+	lastDate := firstDate.AddDate(0, 1, -1)
+
+	return firstDate.Day(), lastDate.Day()
+}
+
+func GetMonthFirstLastTime(now time.Time) (time.Time, time.Time) {
+	currentYear, currentMonth, _ := now.Date()
+	currentLocation := now.Location()
+
+	firstDate := time.Date(currentYear, currentMonth, 1, 0, 0, 0, 0, currentLocation)
+	lastDate := firstDate.AddDate(0, 1, -1)
+
+	return firstDate, lastDate
+}
+
+//NotPassToday 是否超过 今天凌晨
+func NotPassToday(strTime string) (bool, error) {
+	//获取转换后的时间
+	compareTime, err := time.ParseInLocation("2006-01-02 15:04:05", strTime, time.Local)
+
+	if err != nil {
+		return false, err
+	}
+
+	//获取凌晨时间
+	todayTime, err := time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), time.Local)
+
+	if err != nil {
+		return false, err
+	}
+
+	return compareTime.Before(todayTime), nil
+}
+
+//日期转字符串
+func FormatDate(date time.Time, dateStyle string) string {
+	dateStyle = strings.Replace(dateStyle, "yyyy", "2006", 1)
+	dateStyle = strings.Replace(dateStyle, "yy", "06", 1)
+	dateStyle = strings.Replace(dateStyle, "MM", "01", 1)
+	dateStyle = strings.Replace(dateStyle, "dd", "02", 1)
+	dateStyle = strings.Replace(dateStyle, "HH", "15", 1)
+	dateStyle = strings.Replace(dateStyle, "mm", "04", 1)
+	dateStyle = strings.Replace(dateStyle, "ss", "05", 1)
+	dateStyle = strings.Replace(dateStyle, "SSS", "000", -1)
+	return date.Format(dateStyle)
+}

+ 38 - 0
public/zip.go

@@ -0,0 +1,38 @@
+package public
+
+import (
+	"bytes"
+	"io"
+	"log"
+	"os"
+
+	"github.com/alexmullins/zip"
+)
+
+//contents := []byte("Hello World")
+//	fileName := "test.txt"
+//	zipName := "./test.zip"
+//	password := "golang"
+//	Zip(contents, fileName, zipName, password)
+//文本压缩加密
+func Zip(contents []byte, fileName, zipName, password string) {
+	fzip, err := os.Create(zipName)
+	if err != nil {
+		log.Fatalln(err)
+	}
+
+	zipw := zip.NewWriter(fzip)
+	defer zipw.Close()
+
+	w, err := zipw.Encrypt(fileName, password)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	_, err = io.Copy(w, bytes.NewReader(contents))
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	zipw.Flush()
+}

+ 50 - 0
redis/channel_client.go

@@ -0,0 +1,50 @@
+package redis
+
+import (
+	"time"
+
+	"bet24.com/log"
+	"github.com/gomodule/redigo/redis"
+)
+
+const channel_name = "rbwar_channel"
+
+func Subscribe(onCommand func(data string)) {
+	conn := RedisClient.Get()
+	if conn == nil {
+		log.Release("Subscribe error conn == nil")
+		time.AfterFunc(time.Minute, func() {
+			Subscribe(onCommand)
+		})
+		return
+	}
+	psc := redis.PubSubConn{Conn: conn}
+	psc.Subscribe(channel_name)
+	for {
+		switch v := psc.Receive().(type) {
+		case redis.Message:
+			//log.Debug("%s: message: %s\n", v.Channel, v.Data)
+			onCommand(string(v.Data))
+		case redis.Subscription:
+			log.Release("%s: %s %d\n", v.Channel, v.Kind, v.Count)
+		case error:
+			log.Release("Subscribe error %v", v)
+			time.AfterFunc(time.Minute, func() {
+				Subscribe(onCommand)
+			})
+			return
+		}
+	}
+}
+
+func Publish(data string) {
+	go func(d string) {
+		conn := RedisClient.Get()
+		if conn == nil {
+			log.Release("Publish no pool connection")
+			return
+		}
+		conn.Do("PUBLISH", channel_name, d)
+		conn.Close()
+	}(data)
+}

+ 43 - 0
redis/channel_msg.go

@@ -0,0 +1,43 @@
+package redis
+
+type Channel_msg_base struct {
+	Message string
+	// 其他数据json信息
+	Data string
+}
+
+type Channel_msg struct {
+	Channel_msg_base
+	UserID    int    // 用户ID
+	IPAddress string //ip地址
+
+}
+
+const (
+
+	//来自webproxy服务器
+	UserEnterWebproxy = "UserEnterWebproxy"
+
+	//来自DataServer服务器
+	RefreshTask_From_Dataserver = "RefreshTask_From_Dataserver"
+	RankingRise_From_DataServer = "RankingRise_From_DataServer"
+
+	//其他
+	UserEnterDataserver    = "UserEnterDataserver"
+	Check_NewStatus_By_Web = "Check_NewStatus_By_Web"
+	UserOutWebproxy        = "UserOutWebproxy"
+	UserOutDataserver      = "UserOutDataserver"
+
+	//来自邀请服务器
+	InviteStart_From_InviteServer = "InviteStart_From_InviteServer"
+
+	//来自WEB站点
+	WhiteUsers_From_Web  = "WhiteUsers_From_Web"
+	CreateRoom_From_Web  = "CreateRoom_From_Web"
+	ApplyEnter_From_Web  = "ApplyEnter_From_Web"
+	ApplyHandle_From_Web = "ApplyHandle_From_Web"
+)
+
+type UserInfo struct {
+	NickName string
+}

+ 95 - 0
redis/keyOperate.go

@@ -0,0 +1,95 @@
+package redis
+
+import (
+	"github.com/gomodule/redigo/redis"
+	"bet24.com/log"
+)
+
+//向名称为key设置过期时间
+func Key_EXPIRE(key string, seconds int) bool {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Key_EXPIRE no redis connection")
+		return false
+	}
+	defer rc.Close()
+
+	i, err := redis.Int(rc.Do("EXPIRE", key, seconds))
+
+	if err != nil {
+		log.Release("Key_EXPIRE key=%v seconds=%v err=%v", key, seconds, err)
+		return false
+	}
+
+	if i == 1 {
+		return true
+	}
+
+	return false
+}
+
+//是否存在某个key
+func Key_EXISTS(key string) bool {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Key_EXISTS no redis connection")
+		return false
+	}
+	defer rc.Close()
+
+	i, err := redis.Int(rc.Do("EXISTS", key))
+
+	if err != nil {
+		log.Release("Key_EXISTS key=%v err=%v", key, err)
+		return false
+	}
+	return i >= 1
+}
+
+func Key_Del(key string) {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Key_Del no redis connection")
+		return
+	}
+	defer rc.Close()
+	_, err := redis.Int(rc.Do("DEL", key))
+	if err != nil {
+		log.Release("Key_Del key=%v err=%v", key, err)
+	}
+}
+
+func Key_GetKeys(key string) []string {
+	rc := RedisClient.Get()
+	var ret []string
+	if rc == nil {
+		log.Release("Key_GetKeys no redis connection")
+		return ret
+	}
+	defer rc.Close()
+	r, err := redis.Strings(rc.Do("KEYS", key))
+	if err != nil {
+		log.Release("Key_GetKeys key=%v err=%v", key, err)
+		return ret
+	}
+	return r
+}
+
+func Key_DelKeys(keys string) int {
+	ret := 0
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Key_DelKeys no redis connection")
+		return ret
+	}
+	defer rc.Close()
+	r, err := redis.Strings(rc.Do("KEYS", keys))
+	if err != nil {
+		log.Release("Key_DelKeys keys=%v err=%v", keys, err)
+		return ret
+	}
+	for _, v := range r {
+		rc.Do("DEL", v)
+	}
+	return len(r)
+}

+ 55 - 0
redis/pool.go

@@ -0,0 +1,55 @@
+package redis
+
+import (
+	"time"
+
+	"bet24.com/log"
+	"github.com/gomodule/redigo/redis"
+)
+
+var (
+	// 定义常量
+	RedisClient    *redis.Pool
+	REDIS_HOST     string
+	REDIS_PASSWORD string
+	REDIS_DB       int
+)
+
+func InitPool(serverUrl, password string, db int) {
+	if RedisClient != nil {
+		log.Release("redis.InitPool already inited")
+		return
+	}
+	log.Release("redis.InitPool %v,%v,%d", serverUrl, password, db)
+	REDIS_HOST = serverUrl
+	REDIS_DB = db
+	REDIS_PASSWORD = password
+
+	// 建立连接池
+	RedisClient = &redis.Pool{
+		// 从配置文件获取maxidle以及maxactive,取不到则用后面的默认值
+		MaxIdle:     3,
+		MaxActive:   1000,
+		Wait:        false,
+		IdleTimeout: 300 * time.Second,
+		Dial: func() (redis.Conn, error) {
+			c, err := redis.Dial("tcp", REDIS_HOST)
+			if err != nil {
+				log.Release("redis.Dial failed %v", err)
+				return nil, err
+			}
+			if len(REDIS_PASSWORD) > 0 {
+				if _, err := c.Do("AUTH", REDIS_PASSWORD); err != nil {
+					c.Close()
+					log.Release("connect redis invalid password")
+					return nil, err
+				}
+			}
+			// 选择db
+			if REDIS_DB > 0 {
+				c.Do("SELECT", REDIS_DB)
+			}
+			return c, nil
+		},
+	}
+}

+ 42 - 0
redis/setOperate.go

@@ -0,0 +1,42 @@
+package redis
+
+import (
+	"github.com/gomodule/redigo/redis"
+	"bet24.com/log"
+)
+
+//向名称为key的set中添加元素member
+func Set_SAdd(key, member string, expire int) bool {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Set_SAdd no redis connection")
+		return false
+	}
+	defer rc.Close()
+	_, err := rc.Do("SADD", key, member)
+	if err != nil {
+		log.Release("Set_SAdd key=%v member=%v err=%v", key, member, err)
+		return false
+	}
+	if expire > 0 {
+		rc.Do("expire", key, expire)
+	}
+	return true
+}
+
+//返回名称为key的set的所有元素
+func Set_SMembers(key string) ([]string, bool) {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Set_SMembers no redis connection")
+		return nil, false
+	}
+	defer rc.Close()
+	ret, err := redis.Strings(rc.Do("SMEMBERS", key))
+	if err != nil {
+		//log.Release("Set_SMembers key=%v err=%v", key, err)
+		var r []string
+		return r, true
+	}
+	return ret, true
+}

+ 153 - 0
redis/stringOperate.go

@@ -0,0 +1,153 @@
+package redis
+
+import (
+	"strconv"
+
+	"github.com/gomodule/redigo/redis"
+	"bet24.com/log"
+)
+
+//写数据
+func String_Set(key, value string) bool {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("String_Set no redis connection")
+		return false
+	}
+	defer rc.Close()
+	_, err := rc.Do("SET", key, value)
+	if err != nil {
+		log.Release("String_Set key=%v value=%v err=%v", key, value, err)
+		return false
+	}
+	return true
+}
+
+//写过期数据
+func String_SetEx(key, value string, seconds int) bool {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("String_SetEx no redis connection")
+		return false
+	}
+	defer rc.Close()
+	_, err := rc.Do("SETEX", key, seconds, value)
+	if err != nil {
+		log.Release("String_SetEx key=%v value=%v seconds=%v err=%v", key, value, seconds, err)
+		return false
+	}
+	return true
+}
+
+//获取数据
+func String_Get(key string) (string, bool) {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("String_Get no redis connection")
+		return "", false
+	}
+	defer rc.Close()
+	ret, err := redis.String(rc.Do("GET", key))
+	if err != nil {
+		//log.Release("String_Get key=%v err=%v", key, err)
+		return "", true
+	}
+	return ret, true
+}
+
+//递增
+func String_Incrby(key string, value int) (int, bool) {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("String_Incrby no redis connection")
+		return 0, false
+	}
+	defer rc.Close()
+	ret, err := redis.Int(rc.Do("INCRBY", key, value))
+	if err != nil {
+		log.Release("String_Incrby key=%v value=%v err=%v", key, value, err)
+		return 0, false
+	}
+
+	return ret, true
+}
+
+func String_GetInt(key string) int {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("String_GetInt no redis connection")
+		return 0
+	}
+	defer rc.Close()
+	ret, err := redis.String(rc.Do("GET", key))
+	if err != nil {
+		//log.Debug("String_Get key=%v err=%v", key, err)
+		return 0
+	}
+	r, e := strconv.Atoi(ret)
+	if e != nil {
+		return 0
+	}
+	return r
+}
+
+//在offset 位置写数据,返回: 指定偏移量原来储存的位
+func String_SetBit(key string, offset int, value int) (int, bool) {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("String_SetBit no redis connection")
+		return -1, false
+	}
+	defer rc.Close()
+	//不是0, 1
+	if value != 0 && value != 1 {
+		return -1, false
+	}
+
+	i, err := redis.Int(rc.Do("SETBIT", key, offset, value))
+	if err != nil {
+		log.Release("String_SetBit key=%v offset=%v value=%v err=%v", key, offset, value, err)
+		return -1, false
+	}
+
+	return i, true
+}
+
+//String_BITCOUNT 统计字符串被设置为1的bit数(注意: start, end 是指字节位置).
+func String_BITCOUNT(key string, start int, end int) (int, bool) {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("String_BITCOUNT no redis connection")
+		return -1, false
+	}
+	defer rc.Close()
+	i, err := redis.Int(rc.Do("BITCOUNT", key, start, end))
+	if err != nil {
+		log.Release("String_BITCOUNT key=%v start=%v end=%v err=%v", key, start, end, err)
+		return -1, false
+	}
+
+	return i, true
+}
+
+//String_GETSET 写数据并获取写前的旧数据
+func String_GETSET(key string, value string) (string, bool) {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("String_Get no redis connection")
+		return "", false
+	}
+	defer rc.Close()
+	ret, err := redis.String(rc.Do("GETSET", key, value))
+
+	if err != nil {
+		//redis 返回是 nil, 还没有 key
+		if err == redis.ErrNil {
+			return "", true
+		}
+
+		//其他错误
+		return "", false
+	}
+	return ret, true
+}

+ 133 - 0
redis/zsetOperate.go

@@ -0,0 +1,133 @@
+package redis
+
+import (
+	"github.com/gomodule/redigo/redis"
+	"bet24.com/log"
+	"strconv"
+)
+
+type Score_member struct {
+	Score  string
+	Member string
+}
+
+//执行一个有序zset插入
+func Zset_ZAdd(key string, score int, member string, expire int) bool {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Zset_ZAdd no redis connection")
+		return false
+	}
+	defer rc.Close()
+	_, err := rc.Do("ZADD", key, score, member)
+	if err != nil {
+		log.Release("Zset_ZAdd key=%v score=%v memeber=%v expire=%v err=%v", key, score, member, expire, err)
+		return false
+	}
+	if expire > 0 {
+		rc.Do("expire", key, expire)
+	}
+	return true
+}
+
+func Zset_ZInc(key string, score int, member string) bool {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Zset_ZAdd no redis connection")
+		return false
+	}
+	defer rc.Close()
+	_, err := rc.Do("ZINCRBY", key, score, member)
+	if err != nil {
+		log.Release("Zset_ZInc key=%v score=%v member=%v err=%v", key, score, member, err)
+		return false
+	}
+	return true
+}
+
+func Zset_ZRem(key string, member string) bool {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Zset_ZRem no redis connection")
+		return false
+	}
+	defer rc.Close()
+	_, err := rc.Do("ZREM", key, member)
+	if err != nil {
+		log.Release("ZREM key=%v member=%v err=%v", key, member, err)
+		return false
+	}
+	return true
+}
+
+func Zset_ZScore(key string, member string) int {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Zset_ZAdd no redis connection")
+		return 0
+	}
+	defer rc.Close()
+	r, err := redis.String(rc.Do("ZSCORE", key, member))
+	if err != nil {
+		log.Debug("%v", err)
+		return 0
+	}
+
+	ri, e := strconv.Atoi(r)
+	if e != nil {
+		log.Debug("%v", e)
+		return 0
+	}
+	return ri
+}
+
+//读取指定zset
+func Zset_ZRange(key string, start, stop int, desc bool, withScore bool) ([]Score_member, bool) {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Zset_ZRange no redis connection")
+		return nil, false
+	}
+	defer rc.Close()
+	cmd := "ZRANGE"
+	if desc {
+		cmd = "ZREVRANGE"
+	}
+	var rows []string
+	var err error
+	if withScore {
+		rows, err = redis.Strings(rc.Do(cmd, key, start, stop, "WITHSCORES"))
+	} else {
+		rows, err = redis.Strings(rc.Do(cmd, key, start, stop))
+	}
+
+	if err != nil {
+		log.Release("Zset_ZRange key=%v start=%v stop=%v desc=%v withScore=%v err=%v", key, start, stop, desc, withScore, err)
+		return nil, false
+	}
+
+	rowsLen := len(rows) / 2
+	if rowsLen <= 0 {
+		log.Debug("Zset_ZRange no data")
+		return nil, false
+	}
+
+	score_member_list := make([]Score_member, rowsLen)
+
+	for i := 0; i < len(rows)-1; i += 2 {
+		score_member_list[i/2].Member = string(rows[i])
+		score_member_list[i/2].Score = string(rows[i+1])
+	}
+
+	return score_member_list, true
+}
+
+func Zset_ZRemByScore(key string, min, max int) {
+	rc := RedisClient.Get()
+	if rc == nil {
+		log.Release("Zset_ZRange no redis connection")
+		return
+	}
+	defer rc.Close()
+	rc.Do("ZREMRANGEBYSCORE", key, min, max)
+}

BIN
servers/adminserver/adminserver


+ 46 - 0
servers/adminserver/adminserver.go

@@ -0,0 +1,46 @@
+package main
+
+import (
+	"fmt"
+	"time"
+
+	"bet24.com/log"
+	"bet24.com/redis"
+	"bet24.com/servers/adminserver/config"
+	"bet24.com/servers/adminserver/crons"
+	"bet24.com/servers/adminserver/dao"
+	"bet24.com/servers/adminserver/router"
+	"bet24.com/servers/adminserver/serverdata"
+	"bet24.com/servers/adminserver/service"
+	coreservice "bet24.com/servers/coreservice/client"
+	"bet24.com/servers/monitor"
+	"bet24.com/utils"
+)
+
+func main() {
+	//defer log.PanicHandler("webserver")
+
+	//redis
+	redis.InitPool(config.Server.ChannelUrl, config.Server.ChannelPassword, config.Server.RedisDB)
+	coreservice.SetServiceAddr(config.Server.ServiceAddr)
+
+	//数据库
+	dao.Run()
+	serverdata.Run()
+	go service.Run()
+	dao.RunTagManager()
+
+	// 子弹配置
+	// bullet.Run()
+
+	//监控
+	monitor.Run(config.Server.MonitorPort, config.Server.LogPath)
+	utils.SetConsoleTitle(fmt.Sprintf("adminserver port:%d monitor:%d", config.Server.TlsPort, config.Server.MonitorPort))
+	//定时器
+	go crons.Run()
+
+	log.Release("Server started %v", time.Now())
+
+	//gin 路由
+	router.Run()
+}

+ 60 - 0
servers/adminserver/agent/agentmgr.go

@@ -0,0 +1,60 @@
+package agent
+
+var mgr *agentManager
+
+type agentManager struct {
+}
+
+func Run() {
+	mgr = new(agentManager)
+}
+
+// 配置信息
+func (this *agentManager) getConfig() *configInfo {
+	return getConfig()
+}
+
+// 修改配置
+func (this *agentManager) updateConfig(req *configUp_in) {
+	updateConfig(req)
+}
+
+// 代理列表
+func (this *agentManager) getAgentList(req *request_base, sortType int) *agentList_out {
+	return getAgentList(req)
+}
+
+// 申请列表
+func (this *agentManager) getApplyList(req *request_base) *applyList_out {
+	return getAgentApplyList(req)
+}
+
+// 处理申请
+func (this *agentManager) dealApply(req *dealApply_req) int {
+	return dealApply(req)
+}
+
+// 会员列表
+func (this *agentManager) getMemberList(req *request_base) *memberInfo_out {
+	return getMemberList(req)
+}
+
+// 佣金日志
+func (this *agentManager) getCommissionLog(req *request_base) *commissionInfo_out {
+	return getCommissionLog(req)
+}
+
+// 佣金排行榜
+func (this *agentManager) getCommissionRankList(userId int, beginTime, endTime string) []*commissionRankInfo {
+	return getCommissionRankList(userId, beginTime, endTime)
+}
+
+// 创建代理
+func (this *agentManager) createAgent(opUserID int, opUserName string, userId, grade int, ipAddress string) int {
+	return createAgent(opUserID, opUserName, userId, grade, ipAddress)
+}
+
+// 设置代理状态
+func (this *agentManager) setStatus(opUserID int, opUserName string, userId, enabled int) {
+	setStatus(opUserID, opUserName, userId, enabled)
+}

+ 157 - 0
servers/adminserver/agent/controller.go

@@ -0,0 +1,157 @@
+package agent
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"github.com/gin-gonic/gin"
+)
+
+// 配置信息
+func GetConfig(c *gin.Context) {
+	resp := mgr.getConfig()
+	c.JSON(http.StatusOK, resp)
+}
+
+// 修改配置
+func UpdateConfig(c *gin.Context) {
+	var req configUp_in
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "agent.UpdateConfig", err)
+		return
+	}
+
+	mgr.updateConfig(&req)
+	c.JSON(http.StatusOK, "")
+	return
+}
+
+// 代理列表
+func GetList(c *gin.Context) {
+	var req struct {
+		Info     *request_base
+		SortType int
+	}
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "agent.GetList", err)
+		return
+	}
+
+	resp := mgr.getAgentList(req.Info, req.SortType)
+	c.JSON(http.StatusOK, resp)
+	return
+}
+
+// 申请列表
+func ApplyList(c *gin.Context) {
+	var req *request_base
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "agent.ApplyList", err)
+		return
+	}
+	resp := mgr.getApplyList(req)
+	c.JSON(http.StatusOK, resp)
+	return
+}
+
+// 处理申请
+func DealApply(c *gin.Context) {
+	var req *dealApply_req
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "agent.DealApply", err)
+		return
+	}
+	retCode := mgr.dealApply(req)
+	c.JSON(http.StatusOK, struct {
+		RetCode int
+	}{
+		RetCode: retCode,
+	})
+	return
+}
+
+// 会员列表
+func GetMemberList(c *gin.Context) {
+	req := new(request_base)
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "agent.GetMemberList", err)
+		return
+	}
+
+	resp := mgr.getMemberList(req)
+	c.JSON(http.StatusOK, resp)
+	return
+}
+
+// 佣金日志
+func GetCommissionLog(c *gin.Context) {
+	req := new(request_base)
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "agent.GetCommissionLog", err)
+		return
+	}
+
+	resp := mgr.getCommissionLog(req)
+	c.JSON(http.StatusOK, resp)
+	return
+}
+
+// 佣金排行榜
+func GetCommissionRankList(c *gin.Context) {
+	req := new(request_base)
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "agent.GetCommissionRankList", err)
+		return
+	}
+
+	list := mgr.getCommissionRankList(req.UserID, req.BeginTime, req.EndTime)
+	c.JSON(http.StatusOK, struct {
+		RecordCount int
+		List        interface{}
+	}{
+		RecordCount: len(list),
+		List:        list,
+	})
+	return
+}
+
+// 创建代理
+func Create(c *gin.Context) {
+	var req struct {
+		OpUserID   int
+		OpUserName string
+		UserId     int
+		Grade      int
+		IpAddress  string
+	}
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "agent.Create", err)
+		return
+	}
+
+	retCode := mgr.createAgent(req.OpUserID, req.OpUserName, req.UserId, req.Grade, req.IpAddress)
+	c.JSON(http.StatusOK, struct {
+		RetCode int
+	}{
+		RetCode: retCode,
+	})
+	return
+}
+
+// 设置代理状态
+func SetStatus(c *gin.Context) {
+	var req struct {
+		OpUserID   int
+		OpUserName string
+		UserId     int
+		Enabled    int
+	}
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "agent.SetStatus", err)
+		return
+	}
+
+	mgr.setStatus(req.OpUserID, req.OpUserName, req.UserId, req.Enabled)
+	c.JSON(http.StatusOK, nil)
+	return
+}

+ 129 - 0
servers/adminserver/agent/data.go

@@ -0,0 +1,129 @@
+package agent
+
+// 配置
+type configInfo struct {
+	IsOpen       int // 是否开启(1=开启  其他关闭)
+	BindSend     int // 绑码赠送
+	BetOneDirect int // 流水1级代理返佣(以万为基数)
+	BetTwoDirect int // 流水2级代理返佣(以万为基数)
+	TaxOneDirect int // 服务费1级代理返佣(以万为基数)
+	TaxTwoDirect int // 服务费2级代理返佣(以万为基数)
+	PayOneDirect int // 充值1级代理返佣(以万为基数)
+	PayTwoDirect int // 充值2级代理返佣(以万为基数)
+	AuditEnabled int // 审核是否启用
+}
+
+type configUp_in struct {
+	OpUserID   int    // 操作员ID
+	OpUserName string // 操作员名称
+	IpAddress  string // IP地址
+	configInfo
+}
+
+// 基础请求
+type request_base struct {
+	UserID    int    // 用户ID
+	BeginTime string // 开始时间
+	EndTime   string // 截止时间
+	PageIndex int    // 页索引
+	PageSize  int    // 页大小
+}
+
+// 代理信息
+type agentInfo struct {
+	UserID     int    // 用户ID
+	NickName   string // 昵称
+	Commission int    // 佣金
+	Profit     int    // 收益
+	Members    int    // 会员数
+	Enabled    int    // 是否启用
+	Crdate     string // 注册时间
+}
+
+// 代理列表
+type agentList_out struct {
+	RecordCount int // 记录数
+	List        []*agentInfo
+}
+
+// 会员信息
+type (
+	memberInfo struct {
+		HigherUserID   int    // 代理ID
+		HigherNickName string // 代理名称
+		UserID         int    // 用户ID
+		NickName       string // 昵称
+		Commission     int    // 佣金
+		NewCommission  int    // 新增佣金
+		BindTime       string // 绑码时间
+		LoginTime      string // 登录时间
+	}
+
+	memberInfo_out struct {
+		RecordCount int // 记录数
+		List        []*memberInfo
+	}
+)
+
+// 佣金信息
+type (
+	commissionInfo struct {
+		Rid             int    // 标识
+		UserID          int    // 用户ID
+		NickName        string // 昵称
+		FromUserID      int    // 源用户ID
+		FromNickName    string // 源用户昵称
+		Tax             int    // 台费
+		WantCommission  int    // 操作佣金
+		StillCommission int    // 剩余佣金
+		Direct          int    // 属级(1=直属  2=非直属)
+		Memo            string // 备注
+		Crdate          string // 时间
+		ChineseName     string // 游戏名称
+	}
+
+	commissionInfo_out struct {
+		RecordCount     int // 记录数
+		TotalCommission int // 总佣金
+		List            []*commissionInfo
+	}
+)
+
+// 佣金排行榜
+type commissionRankInfo struct {
+	Rid        int    // 序号
+	UserID     int    // 用户ID
+	NickName   string // 昵称
+	Grade      int    // 代理级别
+	BetAmount  int    // 下注金额
+	Commission int    // 佣金
+}
+
+// 申请列表
+type applyList_out struct {
+	RecordCount int // 记录数
+	List        []*applyInfo
+}
+
+// 申请列表
+type applyInfo struct {
+	ApplyID        int    // 申请ID
+	UserID         int    // 用户ID
+	NickName       string // 昵称
+	HigherUserID   int    // 上级用户ID
+	HigherNickName string // 上级用户昵称
+	ApplyStatus    int    // 申请状态(0=待审核 1=已通过 2=拒绝)
+	Memo           string // 备注(联系信息,如:电话)
+	DealTime       string // 处理时间
+	Crdate         string // 申请时间
+	OpUser         string // 操作员
+}
+
+// 处理申请
+type dealApply_req struct {
+	OpUserID    int    // 操作员ID
+	OpUserName  string // 操作员名称
+	IpAddress   string // IP地址
+	ApplyID     int    // 申请ID
+	ApplyStatus int    // 状态(0=审核 1=已通过 2=拒绝)
+}

+ 400 - 0
servers/adminserver/agent/transaction.go

@@ -0,0 +1,400 @@
+package agent
+
+import (
+	"runtime/debug"
+	"strings"
+
+	"bet24.com/database"
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+)
+
+// 代理配置
+func getConfig() *configInfo {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_AgentConfig_GetInfo")
+	sqlString := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlString)
+	if len(retRows) <= 0 {
+		return nil
+	}
+
+	ret := retRows[0]
+	return &configInfo{
+		IsOpen:       int((*ret[0].(*interface{})).(int64)),
+		BindSend:     int((*ret[1].(*interface{})).(int64)),
+		BetOneDirect: int((*ret[2].(*interface{})).(int64)),
+		BetTwoDirect: int((*ret[3].(*interface{})).(int64)),
+		TaxOneDirect: int((*ret[4].(*interface{})).(int64)),
+		TaxTwoDirect: int((*ret[5].(*interface{})).(int64)),
+		PayOneDirect: int((*ret[6].(*interface{})).(int64)),
+		PayTwoDirect: int((*ret[7].(*interface{})).(int64)),
+		AuditEnabled: int((*ret[8].(*interface{})).(int64)),
+	}
+}
+
+// 修改代理配置
+func updateConfig(req *configUp_in) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	var out agentList_out
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_AgentConfig_Update")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, req.OpUserID)
+	statement.AddParamter("@OpUserName", database.AdParamInput, database.AdVarChar, 32, req.OpUserName)
+	statement.AddParamter("@IsOpen", database.AdParamInput, database.AdInteger, 4, req.IsOpen)
+	statement.AddParamter("@BindSend", database.AdParamInput, database.AdInteger, 4, req.BindSend)
+	statement.AddParamter("@OneDirect", database.AdParamInput, database.AdInteger, 4, req.BetOneDirect)
+	statement.AddParamter("@TwoDirect", database.AdParamInput, database.AdInteger, 4, req.BetTwoDirect)
+	statement.AddParamter("@TaxOneDirect", database.AdParamInput, database.AdInteger, 4, req.TaxOneDirect)
+	statement.AddParamter("@TaxTwoDirect", database.AdParamInput, database.AdInteger, 4, req.TaxTwoDirect)
+	statement.AddParamter("@PayOneDirect", database.AdParamInput, database.AdInteger, 4, req.PayOneDirect)
+	statement.AddParamter("@PayTwoDirect", database.AdParamInput, database.AdInteger, 4, req.PayTwoDirect)
+	statement.AddParamter("@AuditEnabled", database.AdParamInput, database.AdInteger, 4, req.AuditEnabled)
+	statement.AddParamter("@IPAddress", database.AdParamInput, database.AdVarChar, 16, req.IpAddress)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, out.RecordCount)
+	sqlString := statement.GenSql()
+	dao.CenterDB.ExecSql(sqlString)
+}
+
+// 代理列表
+func getAgentList(req *request_base) *agentList_out {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	var out agentList_out
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_UserAgent_GetInfo")
+	statement.AddParamter("@UserID", database.AdParamInput, database.AdInteger, 4, req.UserID)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, req.BeginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, req.EndTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, req.PageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, req.PageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, out.RecordCount)
+	sqlString := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlString)
+	rowLen := len(retRows)
+	if rowLen <= 0 {
+		return nil
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var info agentInfo
+			info.UserID = int((*ret[0].(*interface{})).(int64))
+			info.NickName = (*ret[1].(*interface{})).(string)
+			info.Commission = int((*ret[2].(*interface{})).(int64))
+			info.Profit = int((*ret[3].(*interface{})).(int64))
+			info.Members = int((*ret[4].(*interface{})).(int64))
+			info.Enabled = int((*ret[5].(*interface{})).(int64))
+			info.Crdate = (*ret[6].(*interface{})).(string)
+			out.List = append(out.List, &info)
+		}
+	}
+
+	out.RecordCount = int((*retRows[rowLen-1][0].(*interface{})).(int64))
+	return &out
+}
+
+// 申请列表
+func getAgentApplyList(req *request_base) *applyList_out {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	var out applyList_out
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_UserAgent_GetApplyList")
+	statement.AddParamter("@UserID", database.AdParamInput, database.AdInteger, 4, req.UserID)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, req.BeginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, req.EndTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, req.PageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, req.PageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, out.RecordCount)
+	sqlString := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlString)
+	rowLen := len(retRows)
+	if rowLen <= 0 {
+		return nil
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var info applyInfo
+			info.ApplyID = int((*ret[0].(*interface{})).(int64))
+			info.UserID = int((*ret[1].(*interface{})).(int64))
+			info.NickName = (*ret[2].(*interface{})).(string)
+			info.HigherUserID = int((*ret[3].(*interface{})).(int64))
+			info.HigherNickName = (*ret[4].(*interface{})).(string)
+			info.ApplyStatus = int((*ret[5].(*interface{})).(int64))
+			memo := (*ret[6].(*interface{})).(string)
+			mList := strings.Split(memo, ",操作员:")
+			info.Memo = mList[0]
+			if len(mList) == 2 {
+				info.OpUser = mList[1]
+			}
+			info.DealTime = (*ret[7].(*interface{})).(string)
+			info.Crdate = (*ret[8].(*interface{})).(string)
+
+			out.List = append(out.List, &info)
+		}
+	}
+
+	out.RecordCount = int((*retRows[rowLen-1][0].(*interface{})).(int64))
+	return &out
+}
+
+// 处理申请
+func dealApply(req *dealApply_req) int {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	retCode := 0
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_UserAgent_DealApply")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, req.OpUserID)
+	statement.AddParamter("@OpUserName", database.AdParamInput, database.AdVarChar, 32, req.OpUserName)
+	statement.AddParamter("@ApplyID", database.AdParamInput, database.AdInteger, 4, req.ApplyID)
+	statement.AddParamter("@ApplyStatus", database.AdParamInput, database.AdInteger, 4, req.ApplyStatus)
+	statement.AddParamter("@IPAddress", database.AdParamInput, database.AdVarChar, 16, req.IpAddress)
+	statement.AddParamter("@RetCode", database.AdParamOutput, database.AdInteger, 4, retCode)
+	sqlString := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlString)
+	if len(retRows) <= 0 {
+		return retCode
+	}
+	retCode = int((*retRows[0][0].(*interface{})).(int64))
+	return retCode
+}
+
+// 会员列表
+func getMemberList(req *request_base) *memberInfo_out {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	out := new(memberInfo_out)
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_UserAgent_GetMemberList")
+	statement.AddParamter("@UserID", database.AdParamInput, database.AdInteger, 4, req.UserID)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, req.BeginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, req.EndTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, req.PageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, req.PageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, out.RecordCount)
+	sqlstring := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlstring)
+	rowLen := len(retRows)
+	if rowLen <= 0 {
+		return out
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var info memberInfo
+
+			info.UserID = int((*ret[0].(*interface{})).(int64))
+			info.NickName = (*ret[1].(*interface{})).(string)
+			info.Commission = int((*ret[2].(*interface{})).(int64))
+			info.NewCommission = int((*ret[3].(*interface{})).(int64))
+			info.BindTime = (*ret[4].(*interface{})).(string)
+			info.LoginTime = (*ret[5].(*interface{})).(string)
+			info.HigherUserID = int((*ret[6].(*interface{})).(int64))
+			info.HigherNickName = (*ret[7].(*interface{})).(string)
+
+			out.List = append(out.List, &info)
+		}
+	}
+
+	out.RecordCount = int((*retRows[rowLen-1][0].(*interface{})).(int64))
+	return out
+}
+
+// 佣金日志
+func getCommissionLog(req *request_base) *commissionInfo_out {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	out := new(commissionInfo_out)
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_UserAgent_GetCommissionLog")
+	statement.AddParamter("@UserID", database.AdParamInput, database.AdInteger, 4, req.UserID)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, req.BeginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, req.EndTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, req.PageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, req.PageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, out.RecordCount)
+	statement.AddParamter("@TotalCommission", database.AdParamOutput, database.AdInteger, 8, out.TotalCommission)
+	sqlstring := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlstring)
+	rowLen := len(retRows)
+	if rowLen <= 0 {
+		return out
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var info commissionInfo
+
+			info.Rid = int((*ret[0].(*interface{})).(int64))
+			info.UserID = int((*ret[1].(*interface{})).(int64))
+			info.NickName = (*ret[2].(*interface{})).(string)
+			info.FromUserID = int((*ret[3].(*interface{})).(int64))
+			info.FromNickName = (*ret[4].(*interface{})).(string)
+			info.Tax = int((*ret[5].(*interface{})).(int64))
+			info.WantCommission = int((*ret[6].(*interface{})).(int64))
+			info.StillCommission = int((*ret[7].(*interface{})).(int64))
+			info.Direct = int((*ret[8].(*interface{})).(int64))
+			info.Memo = (*ret[9].(*interface{})).(string)
+			info.Crdate = (*ret[10].(*interface{})).(string)
+			info.ChineseName = (*ret[11].(*interface{})).(string)
+
+			out.List = append(out.List, &info)
+		}
+	}
+
+	out.RecordCount = int((*retRows[rowLen-1][0].(*interface{})).(int64))
+	out.TotalCommission = int((*retRows[rowLen-1][1].(*interface{})).(int64))
+	return out
+}
+
+// 佣金排行榜
+func getCommissionRankList(userId int, beginTime, endTime string) []*commissionRankInfo {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_CommissionStat_RankList")
+	statement.AddParamter("@UserID", database.AdParamInput, database.AdInteger, 4, userId)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, beginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, endTime)
+	sqlstring := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlstring)
+	rowLen := len(retRows)
+	if rowLen <= 0 {
+		return nil
+	}
+
+	var out []*commissionRankInfo
+	for i := 0; i < rowLen; i++ {
+		ret := retRows[i]
+		var info commissionRankInfo
+
+		info.Rid = int((*ret[0].(*interface{})).(int64))
+		info.UserID = int((*ret[1].(*interface{})).(int64))
+		info.NickName = (*ret[2].(*interface{})).(string)
+		info.BetAmount = int((*ret[3].(*interface{})).(int64))
+		info.Commission = int((*ret[4].(*interface{})).(int64))
+		info.Grade = int((*ret[5].(*interface{})).(int64))
+
+		out = append(out, &info)
+	}
+	return out
+}
+
+// 创建代理
+func createAgent(opUserID int, opUserName string, userId, grade int, ipAddress string) int {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	retCode := 0
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_Agent_Create")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, opUserID)
+	statement.AddParamter("@OpUserName", database.AdParamInput, database.AdVarChar, 32, opUserName)
+	statement.AddParamter("@UserID", database.AdParamInput, database.AdInteger, 4, userId)
+	statement.AddParamter("@Grade", database.AdParamInput, database.AdInteger, 4, grade)
+	statement.AddParamter("@IPAddress", database.AdParamInput, database.AdVarChar, 16, ipAddress)
+	statement.AddParamter("@RetCode", database.AdParamOutput, database.AdInteger, 4, retCode)
+	sqlstring := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlstring)
+	if len(retRows) <= 0 {
+		return retCode
+	}
+
+	retCode = int((*retRows[0][0].(*interface{})).(int64))
+	return retCode
+}
+
+// 设置代理状态
+func setStatus(opUserID int, opUserName string, userId, enabled int) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_UserAgent_SetStatus")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, opUserID)
+	statement.AddParamter("@OpUserName", database.AdParamInput, database.AdVarChar, 32, opUserName)
+	statement.AddParamter("@UserID", database.AdParamInput, database.AdInteger, 4, userId)
+	statement.AddParamter("@Enabled", database.AdParamInput, database.AdInteger, 4, enabled)
+	sqlString := statement.GenSql()
+	dao.CenterDB.ExecSql(sqlString)
+}

+ 44 - 0
servers/adminserver/announce/announcemgr.go

@@ -0,0 +1,44 @@
+package announce
+
+import (
+	"bet24.com/log"
+	"bet24.com/servers/coreservice/client"
+)
+
+var mgr *announceManager
+
+type announceManager struct {
+}
+
+func Run() {
+	mgr = new(announceManager)
+	log.Debug("announce manager running...")
+}
+
+// 获取列表
+func (this *announceManager) getList(rid int) []*info {
+	return getList(rid)
+}
+
+// 发布公告
+func (this *announceManager) send(r *Req_Info) {
+	send(r)
+	this.refresh()
+}
+
+// 修改公告
+func (this *announceManager) update(r *Req_Info) {
+	update(r)
+	this.refresh()
+}
+
+// 删除公告
+func (this *announceManager) del(r *Req_Info) {
+	del(r)
+	this.refresh()
+}
+
+// 刷新数据
+func (this *announceManager) refresh() {
+	client.AnnounceRefresh()
+}

+ 63 - 0
servers/adminserver/announce/controller.go

@@ -0,0 +1,63 @@
+package announce
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+
+	"github.com/gin-gonic/gin"
+)
+
+// 公告列表
+func GetList(c *gin.Context) {
+	var req *Req_Info
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "announce.GetList", err)
+		return
+	}
+
+	var resp struct {
+		RecordCount int
+		List        interface{}
+	}
+
+	resp.List = mgr.getList(req.Rid)
+	c.JSON(http.StatusOK, resp)
+	return
+}
+
+// 发布公告
+func Send(c *gin.Context) {
+	var req *Req_Info
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "announce.Send", err)
+		return
+	}
+	mgr.send(req)
+	c.JSON(http.StatusOK, "success")
+	return
+}
+
+// 修改公告
+func Update(c *gin.Context) {
+	var req *Req_Info
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "announce.Update", err)
+		return
+	}
+	mgr.update(req)
+	c.JSON(http.StatusOK, "success")
+	return
+}
+
+// 删除公告
+func Del(c *gin.Context) {
+	var req *Req_Info
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "announce.Del", err)
+		return
+	}
+	mgr.del(req)
+	c.JSON(http.StatusOK, "success")
+	return
+}

+ 22 - 0
servers/adminserver/announce/data.go

@@ -0,0 +1,22 @@
+package announce
+
+type info struct {
+	Rid        int    // 标识
+	Title_En   string // 英文标题
+	Content_En string // 英文内容
+	Title_Eg   string // 埃及标题
+	Content_Eg string // 埃及内容
+	Priority   int    // 优先级,5个等级,5优先级最高,1优先级最低
+	Version    int    // 版本号
+	BeginTime  string // 开始时间
+	EndTime    string // 截止时间
+	Enabled    int    // 是否启用
+	Crdate     string // 时间
+}
+
+type Req_Info struct {
+	OpUserID   int    // 操作员ID
+	OpUserName string // 操作员名称
+	IpAddress  string // IP地址
+	info
+}

+ 87 - 0
servers/adminserver/announce/transaction.go

@@ -0,0 +1,87 @@
+package announce
+
+import (
+	"encoding/json"
+
+	"bet24.com/database"
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+)
+
+// 获取公告列表
+func getList(rid int) []*info {
+	var list []*info
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_Announce_GetList")
+	statement.AddParamter("@Rid", database.AdParamInput, database.AdInteger, 4, rid)
+	sqlString := statement.GenSql()
+	jsonData := dao.CenterDB.ExecSqlJson(sqlString)
+	if err := json.Unmarshal([]byte(jsonData), &list); err != nil {
+		log.Error("announce.transaction load json unmarshal err %v", err)
+	}
+	return list
+}
+
+// 发布公告
+func send(r *Req_Info) {
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_Announce_Send")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, r.OpUserID)
+	statement.AddParamter("@OpUserName", database.AdParamInput, database.AdVarChar, 32, r.OpUserName)
+	statement.AddParamter("@Title_En", database.AdParamInput, database.AdNVarChar, 32, r.Title_En)
+	statement.AddParamter("@Content_En", database.AdParamInput, database.AdNVarChar, 4000, r.Content_En)
+	statement.AddParamter("@Title_Eg", database.AdParamInput, database.AdNVarChar, 32, r.Title_Eg)
+	statement.AddParamter("@Content_Eg", database.AdParamInput, database.AdNVarChar, 4000, r.Content_Eg)
+	statement.AddParamter("@Priority", database.AdParamInput, database.AdInteger, 4, r.Priority)
+	statement.AddParamter("@Version", database.AdParamInput, database.AdInteger, 4, r.Version)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, r.BeginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, r.EndTime)
+	statement.AddParamter("@Enabled", database.AdParamInput, database.AdInteger, 4, r.Enabled)
+	statement.AddParamter("@IPAddress", database.AdParamInput, database.AdVarChar, 16, r.IpAddress)
+	sqlString := statement.GenSql()
+	dao.CenterDB.ExecSql(sqlString)
+	return
+}
+
+// 修改公告
+func update(r *Req_Info) {
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_Announce_Update")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, r.OpUserID)
+	statement.AddParamter("@OpUserName", database.AdParamInput, database.AdVarChar, 32, r.OpUserName)
+	statement.AddParamter("@Rid", database.AdParamInput, database.AdInteger, 4, r.Rid)
+	statement.AddParamter("@Title_En", database.AdParamInput, database.AdNVarChar, 32, r.Title_En)
+	statement.AddParamter("@Content_En", database.AdParamInput, database.AdNVarChar, 4000, r.Content_En)
+	statement.AddParamter("@Title_Eg", database.AdParamInput, database.AdNVarChar, 32, r.Title_Eg)
+	statement.AddParamter("@Content_Eg", database.AdParamInput, database.AdNVarChar, 4000, r.Content_Eg)
+	statement.AddParamter("@Priority", database.AdParamInput, database.AdInteger, 4, r.Priority)
+	statement.AddParamter("@Version", database.AdParamInput, database.AdInteger, 4, r.Version)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, r.BeginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, r.EndTime)
+	statement.AddParamter("@Enabled", database.AdParamInput, database.AdInteger, 4, r.Enabled)
+	statement.AddParamter("@IPAddress", database.AdParamInput, database.AdVarChar, 16, r.IpAddress)
+	sqlString := statement.GenSql()
+	dao.CenterDB.ExecSql(sqlString)
+	return
+}
+
+// 删除公告
+func del(r *Req_Info) {
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_Announce_Del")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, r.OpUserID)
+	statement.AddParamter("@OpUserName", database.AdParamInput, database.AdVarChar, 32, r.OpUserName)
+	statement.AddParamter("@Rid", database.AdParamInput, database.AdInteger, 4, r.Rid)
+	statement.AddParamter("@IPAddress", database.AdParamInput, database.AdVarChar, 16, r.IpAddress)
+	sqlString := statement.GenSql()
+	dao.CenterDB.ExecSql(sqlString)
+	return
+}

+ 150 - 0
servers/adminserver/audioroom/controllger.go

@@ -0,0 +1,150 @@
+package audioroom
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"github.com/gin-gonic/gin"
+)
+
+// 获取语聊房列表
+func GetRoomList(c *gin.Context) {
+	obj := NewGetList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getRoomList", err)
+		return
+	}
+	count, list := mgr.getRoomList(obj.In.SearchKey, obj.In.BeginTime, obj.In.EndTime,
+		obj.In.SortName, obj.In.SortType, obj.In.PageIndex, obj.In.PageSize, obj.In.IsRealTime)
+	obj.Out.Data.RecordCount = count
+	obj.Out.Data.List = list
+	c.JSON(http.StatusOK, obj.Out.Data)
+	return
+}
+
+// 获取语聊房详细信息
+func GetRoomDetail(c *gin.Context) {
+	obj := NewRoomDetail()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getRoomDetail", err)
+		return
+	}
+	obj.Out.Data.List = mgr.getRoomDetail(obj.In.RoomId, obj.In.IsRealTime)
+	c.JSON(http.StatusOK, obj.Out.Data.List)
+	return
+}
+
+// 获取语聊房成员
+func GetRoomMember(c *gin.Context) {
+	obj := NewRoomMember()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "GetRoomMember", err)
+		return
+	}
+	count, list := mgr.getRoomMember(obj.In.BeginTime, obj.In.EndTime, obj.In.RoomId,
+		obj.In.PageIndex, obj.In.PageSize, obj.In.IsRealTime)
+	obj.Out.Data.RecordCount = count
+	obj.Out.Data.List = list
+	c.JSON(http.StatusOK, obj.Out.Data)
+	return
+}
+
+// 获取语聊房房间的在线用户
+func GetRoomOnlineUsers(c *gin.Context) {
+	obj := NewRoomMember()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "GetRoomOnlineUsers", err)
+		return
+	}
+	count, list := mgr.getRoomOnlineUsers(obj.In.RoomId, obj.In.IsRealTime, obj.In.PageIndex, obj.In.PageSize)
+	obj.Out.Data.RecordCount = count
+	obj.Out.Data.List = list
+	c.JSON(http.StatusOK, obj.Out.Data)
+	return
+}
+
+// 获取语聊房麦位
+func GetRoomMic(c *gin.Context) {
+	obj := NewRoomDetail()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getRoomMic", err)
+		return
+	}
+	count, list := mgr.getRoomMic(obj.In.RoomId, obj.In.IsRealTime)
+	obj.Out.Data.RecordCount = count
+	obj.Out.Data.List = list
+	c.JSON(http.StatusOK, obj.Out.Data)
+	return
+}
+
+// 获取黑名单列表
+func GetBlackList(c *gin.Context) {
+	obj := NewBlackList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getBlackList", err)
+		return
+	}
+	count, list := mgr.getBlackList(obj.In.RoomId, obj.In.BlackType, obj.In.PageIndex,
+		obj.In.PageSize, obj.In.IsRealTime, obj.In.BeginTime, obj.In.EndTime)
+	obj.Out.Data.RecordCount = count
+	obj.Out.Data.List = list
+	c.JSON(http.StatusOK, obj.Out.Data)
+	return
+}
+
+// 获取房内操作日志
+func GetRoomLogRecord(c *gin.Context) {
+	obj := NewRoomLogRecord()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getRoomLogRecord", err)
+		return
+	}
+	count, list := mgr.getRoomLogRecord(obj.In.RoomId, obj.In.PageIndex, obj.In.PageSize, obj.In.BeginTime, obj.In.EndTime)
+	obj.Out.Data.RecordCount = count
+	obj.Out.Data.List = list
+	c.JSON(http.StatusOK, obj.Out.Data)
+	return
+}
+
+// 获取房间任务列表
+func GetRoomTask(c *gin.Context) {
+	obj := NewRoomTask()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getRoomTask", err)
+		return
+	}
+	count, list := mgr.getRoomTask(obj.In.IsRealTime, obj.In.RoomId, obj.In.PageIndex, obj.In.PageSize, obj.In.BeginTime, obj.In.EndTime)
+	obj.Out.Data.RecordCount = count
+	obj.Out.Data.List = list
+	c.JSON(http.StatusOK, obj.Out.Data)
+	return
+}
+
+// 获取用户的房间任务
+func GetUserRoomTask(c *gin.Context) {
+	obj := NewUserRoomTask()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getUserRoomTask", err)
+		return
+	}
+	count, list := mgr.getUserRoomTask(obj.In.RoomId, obj.In.UserId, obj.In.PageIndex, obj.In.PageSize)
+	obj.Out.Data.RecordCount = count
+	obj.Out.Data.List = list
+	c.JSON(http.StatusOK, obj.Out.Data)
+	return
+}
+
+// 获取房间上下麦日志
+func GetRoomMicLog(c *gin.Context) {
+	obj := NewRoomMicLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getRoomMicLog", err)
+		return
+	}
+	count, list := mgr.getRoomMicLog(obj.In.PageIndex, obj.In.PageSize, obj.In.SearchRoom,
+		obj.In.SearchUser, obj.In.BeginTime, obj.In.EndTime)
+	obj.Out.Data.RecordCount = count
+	obj.Out.Data.List = list
+	c.JSON(http.StatusOK, obj.Out.Data)
+	return
+}

+ 215 - 0
servers/adminserver/audioroom/data.go

@@ -0,0 +1,215 @@
+package audioroom
+
+import (
+	"bet24.com/database"
+	audioroomPb "bet24.com/servers/micros/audioroom/proto"
+)
+
+// 是否实时(1:是,0:否)
+func isRealTime(realTime int) bool {
+	return realTime == 1
+}
+
+// 获取房间列表
+type (
+	getList_in struct {
+		SearchKey  string // 搜索的内容
+		BeginTime  string // 开始时间
+		EndTime    string // 结束时间
+		IsRealTime int    // 是否实时数据(1:是,0:否)
+		PageIndex  int    // 第几页
+		PageSize   int    // 请求的个数
+		SortName   string // 排序名称
+		SortType   string // 排序类型
+	}
+
+	getList_out struct {
+		Data audioroomPb.AdminResponse
+	}
+
+	getList struct {
+		database.Trans_base
+		In  getList_in
+		Out getList_out
+	}
+)
+
+func NewGetList() *getList {
+	return &getList{}
+}
+
+// 语聊房详细信息
+type (
+	roomDetail_in struct {
+		RoomId     int // 房间id
+		IsRealTime int // 是否实时数据(1:是,0:否)
+	}
+
+	roomDetail_out struct {
+		Data audioroomPb.AdminResponse
+	}
+
+	roomDetail struct {
+		database.Trans_base
+		In  roomDetail_in
+		Out roomDetail_out
+	}
+)
+
+func NewRoomDetail() *roomDetail {
+	return &roomDetail{}
+}
+
+// 语聊房内的成员信息
+type (
+	roomMember_in struct {
+		RoomId     int    // 房间id
+		BeginTime  string // 开始时间
+		EndTime    string // 结束时间
+		PageIndex  int    // 第几页
+		PageSize   int    // 请求的个数
+		IsRealTime int    // 是否实时数据(1:是,0:否)
+	}
+
+	roomMember_out struct {
+		Data audioroomPb.AdminResponse
+	}
+
+	roomMember struct {
+		database.Trans_base
+		In  roomMember_in
+		Out roomMember_out
+	}
+)
+
+func NewRoomMember() *roomMember {
+	return &roomMember{}
+}
+
+// 获取黑名单列表
+type (
+	blackList_in struct {
+		RoomId     int    // 房间id
+		BlackType  int    // 黑名单的类型(1:房间,2:麦位)
+		BeginTime  string // 开始时间
+		EndTime    string // 结束时间
+		PageIndex  int    // 第几页
+		PageSize   int    // 请求的个数
+		IsRealTime int    // 是否实时数据(1:是,0:否)
+	}
+
+	blackList_out struct {
+		Data audioroomPb.AdminResponse
+	}
+
+	blackList struct {
+		database.Trans_base
+		In  blackList_in
+		Out blackList_out
+	}
+)
+
+func NewBlackList() *blackList {
+	return &blackList{}
+}
+
+// 获取房内操作日志
+type (
+	roomLogRecord_in struct {
+		RoomId    int    // 房间id
+		BeginTime string // 开始时间
+		EndTime   string // 结束时间
+		PageIndex int    // 第几页
+		PageSize  int    // 请求的个数
+	}
+
+	roomLogRecord_out struct {
+		Data audioroomPb.AdminResponse
+	}
+
+	roomLogRecord struct {
+		database.Trans_base
+		In  roomLogRecord_in
+		Out roomLogRecord_out
+	}
+)
+
+func NewRoomLogRecord() *roomLogRecord {
+	return &roomLogRecord{}
+}
+
+// 获取房间任务列表
+type (
+	roomTask_in struct {
+		IsRealTime int    // 是否实时数据(1:是,0:否)
+		RoomId     int    // 房间id
+		PageIndex  int    // 第几页
+		PageSize   int    // 请求的个数
+		BeginTime  string // 开始时间
+		EndTime    string // 结束时间
+	}
+
+	roomTask_out struct {
+		Data audioroomPb.AdminResponse
+	}
+
+	roomTask struct {
+		database.Trans_base
+		In  roomTask_in
+		Out roomTask_out
+	}
+)
+
+func NewRoomTask() *roomTask {
+	return &roomTask{}
+}
+
+// 获取用户的房间任务
+type (
+	userRoomTask_in struct {
+		RoomId    int // 房间id
+		UserId    int // 用户id
+		PageIndex int // 第几页
+		PageSize  int // 请求的个数
+	}
+
+	userRoomTask_out struct {
+		Data audioroomPb.AdminResponse
+	}
+
+	userRoomTask struct {
+		database.Trans_base
+		In  userRoomTask_in
+		Out userRoomTask_out
+	}
+)
+
+func NewUserRoomTask() *userRoomTask {
+	return &userRoomTask{}
+}
+
+// 获取房间上下麦日志
+type (
+	roomMicLog_in struct {
+		SearchRoom string // 搜索房间
+		SearchUser string // 搜索用户
+		BeginTime  string // 开始时间
+		EndTime    string // 结束时间
+		PageIndex  int    // 第几页
+		PageSize   int    // 请求的个数
+	}
+
+	roomMicLog_out struct {
+		Data audioroomPb.AdminResponse
+	}
+
+	roomMicLog struct {
+		database.Trans_base
+		In  roomMicLog_in
+		Out roomMicLog_out
+	}
+)
+
+func NewRoomMicLog() *roomMicLog {
+	return &roomMicLog{}
+}

+ 160 - 0
servers/adminserver/audioroom/manager.go

@@ -0,0 +1,160 @@
+package audioroom
+
+import (
+	"bet24.com/log"
+	audioroomPb "bet24.com/servers/micros/audioroom/proto"
+	user "bet24.com/servers/micros/userservices/proto"
+	"encoding/json"
+	"strconv"
+)
+
+var mgr *Manager
+
+type Manager struct {
+}
+
+func Run() {
+	mgr = new(Manager)
+}
+
+// 获取语聊房列表
+func (this *Manager) getRoomList(searchKey, beginTime, endTime, sortName, sortType string,
+	pageIndex, pageSize, realTime int) (int, interface{}) {
+	var roomId int
+	// 如果输入的是数字则直接替换成房间id
+	if num, err := strconv.ParseInt(searchKey, 10, 64); err == nil {
+		roomId = int(num)
+		searchKey = ""
+	}
+	if isRealTime(realTime) {
+		return audioroomPb.AdminGetRoomList(searchKey, sortName, sortType, roomId, pageIndex, pageSize)
+	}
+	return getRoomList(searchKey, beginTime, endTime, sortName, sortType, roomId, pageIndex, pageSize)
+}
+
+// 获取语聊房详细信息
+func (this *Manager) getRoomDetail(roomId, realTime int) interface{} {
+	if roomId <= 0 {
+		return nil
+	}
+	if isRealTime(realTime) {
+		return audioroomPb.AdminGetRoomDetail(roomId)
+	}
+	resp := getRoomDetail(roomId)
+	var mics []audioroomPb.MicInfo
+	if err := json.Unmarshal([]byte(resp.MicInfo), &mics); err != nil {
+		log.Debug("Manager.getRoomDetail json.Unmarshal error. err[%+v]", err)
+		return resp
+	}
+	resp.MicInfo = ""
+	resp.UpMicCount = audioroomPb.AdminGetUpMicCount(mics)
+	return resp
+}
+
+// 获取语聊房成员
+func (this *Manager) getRoomMember(beginTime, endTime string, roomId, pageIndex, pageSize, realTime int) (int, interface{}) {
+	if isRealTime(realTime) {
+		return audioroomPb.AdminGetRoomMember(roomId, pageIndex, pageSize)
+	}
+	return getRoomMember(beginTime, endTime, roomId, pageIndex, pageSize)
+}
+
+// 获取语聊房房间的在线用户
+func (this *Manager) getRoomOnlineUsers(roomId, realTime, pageIndex, pageSize int) (int, interface{}) {
+	if !isRealTime(realTime) {
+		return 0, nil
+	}
+	return audioroomPb.AdminGetRoomOnlineUsers(roomId, pageIndex, pageSize)
+}
+
+// 获取语聊房麦位
+func (this *Manager) getRoomMic(roomId, realTime int) (int, interface{}) {
+	if !isRealTime(realTime) {
+		return 0, nil
+	}
+	return audioroomPb.AdminGetRoomMic(roomId)
+}
+
+// 获取黑名单列表
+func (this *Manager) getBlackList(roomId, blackType, pageIndex, pageSize, realTime int, beginTime, endTime string) (int, interface{}) {
+	if isRealTime(realTime) {
+		return audioroomPb.AdminGetBlackList(roomId, blackType, pageIndex, pageSize)
+	}
+	return getBlackList(roomId, blackType, pageIndex, pageSize, beginTime, endTime)
+}
+
+// 获取房内操作日志
+func (this *Manager) getRoomLogRecord(roomId, pageIndex, pageSize int, beginTime, endTime string) (int, interface{}) {
+	count, list := getRoomLogRecord(roomId, pageIndex, pageSize, beginTime, endTime)
+	for k, v := range list {
+		userInfo := user.GetUserInfo(v.UserID)
+		if userInfo == nil {
+			continue
+		}
+		list[k].NickName = userInfo.NickName
+		toUserInfo := user.GetUserInfo(v.ToUserID)
+		if toUserInfo == nil {
+			continue
+		}
+		list[k].ToNickName = toUserInfo.NickName
+	}
+	return count, list
+}
+
+// 获取房间任务列表
+func (this *Manager) getRoomTask(realTime, roomId, pageIndex, pageSize int, beginTime, endTime string) (int, interface{}) {
+	if isRealTime(realTime) {
+		return audioroomPb.AdminGetRoomTask(roomId, pageIndex, pageSize)
+	}
+
+	sysTask := audioroomPb.GenerateSysTaskMap(true)
+	var sysTaskMap map[int]*audioroomPb.TaskConfig
+	if err := json.Unmarshal([]byte(sysTask), &sysTaskMap); err != nil {
+		log.Debug("Manager.getRoomTask GenerateSysTaskMap json Unmarshal fail. err:%+v", err)
+		return 0, nil
+	}
+
+	count, list := getRoomTask(roomId, pageIndex, pageSize, beginTime, endTime)
+	for k, v := range list {
+		task, ok := sysTaskMap[v.TaskID]
+		if ok {
+			list[k].TaskName = task.Name
+		}
+	}
+	return count, list
+}
+
+// 获取用户的房间任务
+func (this *Manager) getUserRoomTask(roomId, userId, pageIndex, pageSize int) (int, interface{}) {
+	sysTask := audioroomPb.GenerateSysTaskMap(false)
+	var sysTaskMap map[int]*audioroomPb.TaskConfig
+	if err := json.Unmarshal([]byte(sysTask), &sysTaskMap); err != nil {
+		log.Debug("Manager.getUserRoomTask GenerateSysTaskMap json Unmarshal fail. err:%+v", err)
+		return 0, []audioroomPb.AdminUserRoomTask{}
+	}
+
+	count, list := getUserRoomTask(roomId, userId, pageIndex, pageSize)
+	for k, v := range list {
+		task, ok := sysTaskMap[v.TaskID]
+		if ok {
+			list[k].TaskName = task.Name
+		}
+	}
+	return count, list
+}
+
+// 获取房间上下麦日志
+func (this *Manager) getRoomMicLog(pageIndex, pageSize int, searchRoom, searchUser, beginTime, endTime string) (int, interface{}) {
+	var roomId, userId int
+	// 如果输入的是数字则直接替换成房间id
+	if num, err := strconv.ParseInt(searchRoom, 10, 64); err == nil {
+		roomId = int(num)
+		searchRoom = ""
+	}
+	// 如果输入的是数字则直接替换成用户id
+	if num, err := strconv.ParseInt(searchUser, 10, 64); err == nil {
+		userId = int(num)
+		searchUser = ""
+	}
+	return getRoomMicLog(roomId, userId, pageIndex, pageSize, searchRoom, searchUser, beginTime, endTime)
+}

+ 396 - 0
servers/adminserver/audioroom/transaction.go

@@ -0,0 +1,396 @@
+package audioroom
+
+import (
+	"bet24.com/database"
+	"bet24.com/log"
+	audioroomPb "bet24.com/servers/micros/audioroom/proto"
+	dbengine "bet24.com/servers/micros/dbengine/proto"
+	"encoding/json"
+	"runtime/debug"
+)
+
+// 获取所有房间
+func getRoomList(roomName, beginTime, endTime, sortName, sortType string, roomId, pageIndex, pageSize int) (int, []audioroomPb.AdminRoomInfo) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+	var recordCount int
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_AudioRoom_GetAllRoom")
+	statement.AddParamter("@RoomId", database.AdParamInput, database.AdInteger, 4, roomId)
+	statement.AddParamter("@RoomName", database.AdParamInput, database.AdNVarChar, 32, roomName)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, beginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, endTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, pageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, pageSize)
+	statement.AddParamter("@SortName", database.AdParamInput, database.AdVarChar, 16, sortName)
+	statement.AddParamter("@SortType", database.AdParamInput, database.AdChar, 4, sortType)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, recordCount)
+	sqlString := statement.GenSql()
+	//log.Debug(sqlString)
+	retRows := dbengine.ExecuteRs(sqlString)
+	rowLen := len(retRows)
+	var records []audioroomPb.AdminRoomInfo
+	if rowLen <= 0 {
+		return 0, records
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var data audioroomPb.AdminRoomInfo
+			data.RoomId = int(ret[0].(int64))
+			data.RoomName = ret[1].(string)
+			data.UserId = int(ret[2].(int64))
+			data.NickName = ret[3].(string)
+			data.Level = int(ret[4].(int64))
+			data.Exps = int(ret[5].(int64))
+			data.MemberCount = int(ret[6].(int64))
+			data.CollectDiamond = int(ret[7].(int64))
+			data.DiamondAmount = int(ret[8].(int64))
+			data.CollectGold = int(ret[9].(int64))
+			data.GoldAmount = int(ret[10].(int64))
+			data.Crdate = ret[11].(string)
+			records = append(records, data)
+		}
+	}
+
+	if records == nil {
+		records = make([]audioroomPb.AdminRoomInfo, 0)
+	}
+	recordCount = int(retRows[rowLen-1][0].(int64))
+	return recordCount, records
+}
+
+// 获取语聊房详细信息
+func getRoomDetail(roomId int) audioroomPb.AdminRoomDetail {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_AudioRoom_GetExtraInfo")
+	statement.AddParamter("@RoomId", database.AdParamInput, database.AdInteger, 4, roomId)
+	sqlString := statement.GenSql()
+	//log.Debug(sqlString)
+	jsonData := dbengine.Execute(sqlString)
+	var ret []audioroomPb.AdminRoomDetail
+	if err := json.Unmarshal([]byte(jsonData), &ret); err != nil {
+		log.Error("transaction.getRoomDetail json unmarshal err %v", err)
+	}
+	if len(ret) <= 0 {
+		return audioroomPb.AdminRoomDetail{}
+	}
+	return ret[0]
+}
+
+// 获取语聊房成员
+func getRoomMember(beginTime, endTime string, roomId, pageIndex, pageSize int) (int, []audioroomPb.AdminRoomMember) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+	var recordCount int
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_AudioRoom_GetRoomMember")
+	statement.AddParamter("@RoomId", database.AdParamInput, database.AdInteger, 4, roomId)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, beginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, endTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, pageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, pageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, recordCount)
+	sqlString := statement.GenSql()
+	//log.Debug(sqlString)
+	retRows := dbengine.ExecuteRs(sqlString)
+	rowLen := len(retRows)
+	var records []audioroomPb.AdminRoomMember
+	if rowLen <= 0 {
+		return 0, records
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var data audioroomPb.AdminRoomMember
+			data.RoomID = int(ret[0].(int64))
+			data.UserID = int(ret[1].(int64))
+			data.NickName = ret[2].(string)
+			data.RoleID = int(ret[3].(int64))
+			data.Exps = int(ret[4].(int64))
+			data.Level = int(ret[5].(int64))
+			data.Crdate = ret[6].(string)
+			records = append(records, data)
+		}
+	}
+
+	if records == nil {
+		records = make([]audioroomPb.AdminRoomMember, 0)
+	}
+	recordCount = int(retRows[rowLen-1][0].(int64))
+	return recordCount, records
+}
+
+// 获取语聊房详细信息
+func getBlackList(roomId, blackType, pageIndex, pageSize int, beginTime, endTime string) (int, []audioroomPb.AdminRoomBlackList) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+	var recordCount int
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_AudioRoom_BlackIdentity")
+	statement.AddParamter("@RoomId", database.AdParamInput, database.AdInteger, 4, roomId)
+	statement.AddParamter("@BlackType", database.AdParamInput, database.AdInteger, 4, blackType)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, beginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, endTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, pageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, pageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, recordCount)
+	sqlString := statement.GenSql()
+	//log.Debug(sqlString)
+	retRows := dbengine.ExecuteRs(sqlString)
+	rowLen := len(retRows)
+	var records []audioroomPb.AdminRoomBlackList
+	if rowLen <= 0 {
+		return 0, records
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var data audioroomPb.AdminRoomBlackList
+			data.UserID = int(ret[0].(int64))
+			data.NickName = ret[1].(string)
+			data.RoleID = int(ret[2].(int64))
+			data.Level = int(ret[3].(int64))
+			data.ExpireTime = int(ret[4].(int64))
+			data.Crdate = ret[5].(string)
+			records = append(records, data)
+		}
+	}
+
+	if records == nil {
+		records = make([]audioroomPb.AdminRoomBlackList, 0)
+	}
+	recordCount = int(retRows[rowLen-1][0].(int64))
+	return recordCount, records
+}
+
+// 获取语聊房详细信息
+func getRoomLogRecord(roomId, pageIndex, pageSize int, beginTime, endTime string) (int, []audioroomPb.AdminRoomLogRecord) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+	var recordCount int
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_AudioRoom_GetRoomLogRecord")
+	statement.AddParamter("@RoomId", database.AdParamInput, database.AdInteger, 4, roomId)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, beginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, endTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, pageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, pageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, recordCount)
+	sqlString := statement.GenSql()
+	//log.Debug(sqlString)
+	retRows := dbengine.ExecuteRs(sqlString)
+	rowLen := len(retRows)
+	var records []audioroomPb.AdminRoomLogRecord
+	if rowLen <= 0 {
+		return 0, records
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var data audioroomPb.AdminRoomLogRecord
+			data.RoomID = int(ret[0].(int64))
+			data.UserID = int(ret[1].(int64))
+			data.ToUserID = int(ret[2].(int64))
+			data.OperateType = int(ret[3].(int64))
+			data.Crdate = ret[4].(string)
+			records = append(records, data)
+		}
+	}
+
+	if records == nil {
+		records = make([]audioroomPb.AdminRoomLogRecord, 0)
+	}
+	recordCount = int(retRows[rowLen-1][0].(int64))
+	return recordCount, records
+}
+
+// 获取房间任务列表
+func getRoomTask(roomId, pageIndex, pageSize int, beginTime, endTime string) (int, []audioroomPb.AdminRoomTask) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+	var recordCount int
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_AudioRoom_GetRoomTaskList")
+	statement.AddParamter("@RoomID", database.AdParamInput, database.AdInteger, 4, roomId)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, beginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, endTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, pageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, pageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, recordCount)
+	sqlString := statement.GenSql()
+	//log.Debug(sqlString)
+	retRows := dbengine.ExecuteRs(sqlString)
+	rowLen := len(retRows)
+	var records []audioroomPb.AdminRoomTask
+	if rowLen <= 0 {
+		return 0, records
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var data audioroomPb.AdminRoomTask
+			data.RoomID = int(ret[0].(int64))
+			data.TaskID = int(ret[1].(int64))
+			data.Schedule = int(ret[2].(int64))
+			data.CurrNum = int(ret[3].(int64))
+			data.UpdateTime = ret[4].(string)
+			records = append(records, data)
+		}
+	}
+
+	if records == nil {
+		records = make([]audioroomPb.AdminRoomTask, 0)
+	}
+	recordCount = int(retRows[rowLen-1][0].(int64))
+	return recordCount, records
+}
+
+// 获取用户的房间任务
+func getUserRoomTask(roomId, userId, pageIndex, pageSize int) (int, []audioroomPb.AdminUserRoomTask) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+	var recordCount int
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_AudioRoom_GetUserRoomTaskList")
+	statement.AddParamter("@RoomID", database.AdParamInput, database.AdInteger, 4, roomId)
+	statement.AddParamter("@UserID", database.AdParamInput, database.AdInteger, 4, userId)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, pageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, pageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, recordCount)
+	sqlString := statement.GenSql()
+	//log.Debug(sqlString)
+	retRows := dbengine.ExecuteRs(sqlString)
+	rowLen := len(retRows)
+	var records []audioroomPb.AdminUserRoomTask
+	if rowLen <= 0 {
+		return 0, records
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var data audioroomPb.AdminUserRoomTask
+			data.UserID = int(ret[0].(int64))
+			data.RoomID = int(ret[1].(int64))
+			data.TaskID = int(ret[2].(int64))
+			data.Schedule = int(ret[3].(int64))
+			data.CurrNum = int(ret[4].(int64))
+			data.Status = int(ret[5].(int64))
+			data.UpdateTime = ret[6].(string)
+			records = append(records, data)
+		}
+	}
+
+	if records == nil {
+		records = make([]audioroomPb.AdminUserRoomTask, 0)
+	}
+	recordCount = int(retRows[rowLen-1][0].(int64))
+	return recordCount, records
+}
+
+// 获取房间上下麦日志
+func getRoomMicLog(roomId, userId, pageIndex, pageSize int, roomName, nickName, beginTime, endTime string) (int, []audioroomPb.AdminRoomMicLog) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+	var recordCount int
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_AudioRoom_GetRoomMicLog")
+	statement.AddParamter("@RoomId", database.AdParamInput, database.AdInteger, 4, roomId)
+	statement.AddParamter("@RoomName", database.AdParamInput, database.AdNVarChar, 32, roomName)
+	statement.AddParamter("@UserId", database.AdParamInput, database.AdInteger, 4, userId)
+	statement.AddParamter("@NickName", database.AdParamInput, database.AdNVarChar, 32, nickName)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, beginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, endTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, pageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, pageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, recordCount)
+	sqlString := statement.GenSql()
+	//log.Debug(sqlString)
+	retRows := dbengine.ExecuteRs(sqlString)
+	rowLen := len(retRows)
+	var records []audioroomPb.AdminRoomMicLog
+	if rowLen <= 0 {
+		return 0, records
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var data audioroomPb.AdminRoomMicLog
+			data.RoomID = int(ret[0].(int64))
+			data.RoomName = ret[1].(string)
+			data.UserID = int(ret[2].(int64))
+			data.NickName = ret[3].(string)
+			data.RoleID = int(ret[4].(int64))
+			data.MicMode = int(ret[5].(int64))
+			data.OnMicTime = ret[6].(string)
+			data.OffMicTime = ret[7].(string)
+			data.Seconds = int(ret[8].(int64))
+			data.OpUserID = int(ret[9].(int64))
+			data.OpUserRoleID = int(ret[10].(int64))
+			records = append(records, data)
+		}
+	}
+
+	if records == nil {
+		records = make([]audioroomPb.AdminRoomMicLog, 0)
+	}
+	recordCount = int(retRows[rowLen-1][0].(int64))
+	return recordCount, records
+}

+ 46 - 0
servers/adminserver/badge/badge.go

@@ -0,0 +1,46 @@
+package badge
+
+import (
+	"bet24.com/log"
+	badge "bet24.com/servers/micros/badge/proto"
+	"encoding/json"
+	"time"
+)
+
+var mgr *badgeManager
+
+type badgeManager struct {
+	badge_list []badge.Badge
+}
+
+func getBadgeManager() *badgeManager {
+	if mgr == nil {
+		mgr = new(badgeManager)
+		mgr.refreshData()
+	}
+	return mgr
+}
+
+func (this *badgeManager) refreshData() {
+	this.load()
+	time.AfterFunc(1*time.Minute, this.refreshData)
+}
+
+func (this *badgeManager) load() {
+	data := badge.GetSysBadgeList()
+
+	if err := json.Unmarshal([]byte(data), &this.badge_list); err != nil {
+		log.Error("badge.load data unmarshal fail %v", err)
+	}
+
+	return
+}
+
+func (this *badgeManager) getBadgeName(badgeId int) string {
+	for _, v := range this.badge_list {
+		if v.BadgeId == badgeId {
+			return v.BadgeName
+		}
+	}
+	return ""
+}

+ 5 - 0
servers/adminserver/badge/badge_main.go

@@ -0,0 +1,5 @@
+package badge
+
+func GetBadgeName(badgeId int) string {
+	return getBadgeManager().getBadgeName(badgeId)
+}

+ 55 - 0
servers/adminserver/card/cardmgr.go

@@ -0,0 +1,55 @@
+package card
+
+import (
+	"bet24.com/log"
+)
+
+var mgr *cardManager
+
+type cardManager struct {
+}
+
+func Run() {
+	mgr = new(cardManager)
+	log.Debug("card Manager running...")
+}
+
+// 充值卡列表
+func (this *cardManager) getRechargeCardList(req *req_base) resp_base {
+	return getRechargeCardList(req)
+}
+
+// 生成兑换卡
+func (this *cardManager) genExchangeCard(req exchangeCard_req) {
+	genExchangeCard(req)
+}
+
+// 修改兑换卡
+func (this *cardManager) updateExchangeCard(req exchangeCard_req) {
+	updateExchangeCard(req)
+}
+
+// 兑换卡列表
+func (this *cardManager) getExchangeCardList(cardNo string) []*exchangeCard {
+	return getExchangeCardList(cardNo)
+}
+
+// 兑换日志
+func (this *cardManager) getExchangeCardLog(req exchangeCardLog_req) exchangeCardLog_resp {
+	return getExchangeCardLog(req)
+}
+
+// 生成比赛卡
+func (this *cardManager) genMatchCard(req matchCard_req) {
+	genMatchCard(req)
+}
+
+// 修改比赛卡
+func (this *cardManager) updateMatchCard(req matchCard_req) {
+	updateMatchCard(req)
+}
+
+// 比赛卡列表
+func (this *cardManager) getMatchCardList(cardNo string) []*matchCard {
+	return getMatchCardList(cardNo)
+}

+ 126 - 0
servers/adminserver/card/controller.go

@@ -0,0 +1,126 @@
+package card
+
+import (
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/character"
+	"github.com/gin-gonic/gin"
+	"net/http"
+	"strings"
+)
+
+// 充值卡列表
+func GetRechargeCardList(c *gin.Context) {
+	var req *req_base
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "GetRechargeCardList", err)
+		return
+	}
+
+	resp := mgr.getRechargeCardList(req)
+	c.JSON(http.StatusOK, resp)
+	return
+}
+
+// 生成兑换卡
+func GenExchangeCard(c *gin.Context) {
+	var req exchangeCard_req
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "GenExchangeCard", err)
+		return
+	}
+
+	// 判断是否已E开头
+	if req.CardNo != "" && !strings.HasPrefix(req.CardNo, "E") {
+		req.CardNo = "E" + req.CardNo
+	}
+
+	req.Items = character.GetSpecialCharacter(req.Items)
+	mgr.genExchangeCard(req)
+	c.JSON(http.StatusOK, nil)
+	return
+}
+
+// 修改兑换卡
+func UpdateExchangeCard(c *gin.Context) {
+	var req exchangeCard_req
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "UpdateExchangeCard", err)
+		return
+	}
+	req.Items = character.GetSpecialCharacter(req.Items)
+	mgr.updateExchangeCard(req)
+	c.JSON(http.StatusOK, nil)
+	return
+}
+
+// 兑换卡列表
+func GetExchangeCardList(c *gin.Context) {
+	var req exchangeCard_req
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "GetExchangeCardList", err)
+		return
+	}
+	list := mgr.getExchangeCardList(req.CardNo)
+	c.JSON(http.StatusOK, struct {
+		RecordCount int
+		List        interface{}
+	}{
+		RecordCount: len(list),
+		List:        list,
+	})
+	return
+}
+
+// 兑换日志
+func GetExchangeCardLog(c *gin.Context) {
+	var req exchangeCardLog_req
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "GetExchangeCardLog", err)
+		return
+	}
+	resp := mgr.getExchangeCardLog(req)
+	c.JSON(http.StatusOK, resp)
+	return
+}
+
+// 生成比赛卡
+func GenMatchCard(c *gin.Context) {
+	var req matchCard_req
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "GenMatchCard", err)
+		return
+	}
+	mgr.genMatchCard(req)
+	c.JSON(http.StatusOK, nil)
+	return
+}
+
+// 修改比赛卡
+func UpdateMatchCard(c *gin.Context) {
+	var req matchCard_req
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "UpdateMatchCard", err)
+		return
+	}
+	mgr.updateMatchCard(req)
+	c.JSON(http.StatusOK, nil)
+	return
+}
+
+// 比赛卡列表
+func GetMatchCardList(c *gin.Context) {
+	var req matchCard_req
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "GetMatchCardList", err)
+		return
+	}
+	list := mgr.getMatchCardList(req.CardNo)
+	c.JSON(http.StatusOK, struct {
+		RecordCount int
+		List        interface{}
+	}{
+		RecordCount: len(list),
+		List:        list,
+	})
+	return
+}

+ 82 - 0
servers/adminserver/card/data.go

@@ -0,0 +1,82 @@
+package card
+
+type req_base struct {
+	UserID    int    // 用户ID
+	Status    int    // 状态 (-1=所有  0=未使用  1=使用)
+	CardNo    string // 卡号
+	PageIndex int    // 页索引
+	PageSize  int    // 页大小
+}
+
+type resp_base struct {
+	RecordCount int    // 记录数
+	ErrorTimes  int    // 错误次数
+	Crdate      string // 时间
+	List        []*info
+}
+
+type info struct {
+	Rid        int    // 序号
+	CardNo     string // 卡号
+	GoldAmount int    // 金币
+	UserID     int    // 用户ID
+	NickName   string // 昵称
+	UseTime    string // 使用时间
+	Crdate     string // 生成时间
+}
+
+type exchangeCard_req struct {
+	OpUserID   int
+	OpUserName string
+	exchangeCard
+	IpAddress string
+}
+
+type exchangeCard struct {
+	CardNo     string // 卡号
+	PerDays    int    // 每天(0=无限制  1=每1天)
+	UseTimes   int    // 可使用次数
+	OpenTime   string `json:"StartTime" form:"StartTime"` // 开放时间
+	ExpireTime string // 过期时间
+	Items      string // 物品(json格式)
+	Crdate     string // 创建时间
+}
+
+type exchangeCardLog_req struct {
+	CardNo    string // 卡号
+	UserID    int    // 用户id
+	BeginTime string // 开始时间
+	EndTime   string // 截止时间
+	PageIndex int    // 页索引
+	PageSize  int    // 页大小
+}
+
+type exchangeCardLog_resp struct {
+	RecordCount int
+	List        []*exchangeCardLog
+}
+
+type exchangeCardLog struct {
+	Rid      int    // 标识
+	UserID   int    // 用户ID
+	NickName string // 昵称
+	CardNo   string // 卡号
+	Crdate   string // 时间
+}
+
+type matchCard_req struct {
+	OpUserID   int
+	OpUserName string
+	matchCard
+	IpAddress string
+}
+
+type matchCard struct {
+	CardNo     string // 卡号
+	OpenTime   string `json:"StartTime" form:"StartTime"` // 开放时间
+	ExpireTime string // 过期时间
+	TimeMemo   string // 时间描述
+	SceneMemo  string // 场地描述
+	UseTimes   int    // 累计使用次数
+	Crdate     string // 创建时间
+}

+ 281 - 0
servers/adminserver/card/transaction.go

@@ -0,0 +1,281 @@
+package card
+
+import (
+	"runtime/debug"
+
+	"bet24.com/database"
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+)
+
+func getRechargeCardList(req *req_base) resp_base {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	var resp resp_base
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_RechargeCard_GetList")
+	statement.AddParamter("@UserID", database.AdParamInput, database.AdInteger, 4, req.UserID)
+	statement.AddParamter("@Status", database.AdParamInput, database.AdInteger, 4, req.Status)
+	statement.AddParamter("@CardNo", database.AdParamInput, database.AdVarChar, 32, req.CardNo)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, req.PageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, req.PageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, resp.RecordCount)
+	statement.AddParamter("@ErrorTimes", database.AdParamOutput, database.AdInteger, 4, resp.ErrorTimes)
+	statement.AddParamter("@Crdate", database.AdParamOutput, database.AdVarChar, 32, resp.Crdate)
+	sqlString := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlString)
+	rowLen := len(retRows)
+	if rowLen <= 0 {
+		return resp
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var out info
+			out.Rid = int((*ret[0].(*interface{})).(int64))
+			out.CardNo = (*ret[1].(*interface{})).(string)
+			out.GoldAmount = int((*ret[2].(*interface{})).(int64))
+			out.UserID = int((*ret[3].(*interface{})).(int64))
+			out.NickName = (*ret[4].(*interface{})).(string)
+			out.UseTime = (*ret[5].(*interface{})).(string)
+			out.Crdate = (*ret[6].(*interface{})).(string)
+			resp.List = append(resp.List, &out)
+		}
+	}
+
+	resp.RecordCount = int((*retRows[rowLen-1][0].(*interface{})).(int64))
+	resp.ErrorTimes = int((*retRows[rowLen-1][1].(*interface{})).(int64))
+	resp.Crdate = (*retRows[rowLen-1][2].(*interface{})).(string)
+	return resp
+}
+
+// 生成兑换卡
+func genExchangeCard(req exchangeCard_req) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_ExchangeCard_Gen")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, req.OpUserID)
+	statement.AddParamter("@OpNickName", database.AdParamInput, database.AdVarChar, 32, req.OpUserName)
+	statement.AddParamter("@CardNo", database.AdParamInput, database.AdVarChar, 32, req.CardNo)
+	statement.AddParamter("@PerDays", database.AdParamInput, database.AdInteger, 4, req.PerDays-1)
+	statement.AddParamter("@UseTimes", database.AdParamInput, database.AdBigint, 8, req.UseTimes)
+	statement.AddParamter("@OpenTime", database.AdParamInput, database.AdVarChar, 32, req.OpenTime)
+	statement.AddParamter("@ExpireTime", database.AdParamInput, database.AdVarChar, 32, req.ExpireTime)
+	statement.AddParamter("@Items", database.AdParamInput, database.AdVarChar, 128, req.Items)
+	statement.AddParamter("@IPAddress", database.AdParamInput, database.AdVarChar, 16, req.IpAddress)
+	sqlString := statement.GenSql()
+	dao.CenterDB.ExecSql(sqlString)
+}
+
+// 修改兑换卡
+func updateExchangeCard(req exchangeCard_req) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_ExchangeCard_Update")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, req.OpUserID)
+	statement.AddParamter("@OpNickName", database.AdParamInput, database.AdVarChar, 32, req.OpUserName)
+	statement.AddParamter("@CardNo", database.AdParamInput, database.AdVarChar, 32, req.CardNo)
+	statement.AddParamter("@PerDays", database.AdParamInput, database.AdInteger, 4, req.PerDays-1)
+	statement.AddParamter("@UseTimes", database.AdParamInput, database.AdBigint, 8, req.UseTimes)
+	statement.AddParamter("@OpenTime", database.AdParamInput, database.AdVarChar, 32, req.OpenTime)
+	statement.AddParamter("@ExpireTime", database.AdParamInput, database.AdVarChar, 32, req.ExpireTime)
+	statement.AddParamter("@Items", database.AdParamInput, database.AdVarChar, 128, req.Items)
+	statement.AddParamter("@IPAddress", database.AdParamInput, database.AdVarChar, 16, req.IpAddress)
+	sqlString := statement.GenSql()
+	dao.CenterDB.ExecSql(sqlString)
+}
+
+// 获取兑换卡列表
+func getExchangeCardList(cardNo string) []*exchangeCard {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_ExchangeCard_GetList")
+	statement.AddParamter("@CardNo", database.AdParamInput, database.AdVarChar, 32, cardNo)
+	sqlString := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlString)
+	rowLen := len(retRows)
+	if rowLen <= 0 {
+		return nil
+	}
+
+	var list []*exchangeCard
+	for i := 0; i < rowLen; i++ {
+		ret := retRows[i]
+		var info exchangeCard
+		info.CardNo = (*ret[0].(*interface{})).(string)
+		info.PerDays = int((*ret[1].(*interface{})).(int64)) + 1
+		info.UseTimes = int((*ret[2].(*interface{})).(int64))
+		info.OpenTime = (*ret[3].(*interface{})).(string)
+		info.ExpireTime = (*ret[4].(*interface{})).(string)
+		info.Items = (*ret[5].(*interface{})).(string)
+		info.Crdate = (*ret[6].(*interface{})).(string)
+
+		list = append(list, &info)
+	}
+	return list
+}
+
+// 兑换日志
+func getExchangeCardLog(req exchangeCardLog_req) exchangeCardLog_resp {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	var resp exchangeCardLog_resp
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_ExchangeCard_GetLogList")
+	statement.AddParamter("@CardNo", database.AdParamInput, database.AdVarChar, 32, req.CardNo)
+	statement.AddParamter("@UserID", database.AdParamInput, database.AdInteger, 4, req.UserID)
+	statement.AddParamter("@BeginTime", database.AdParamInput, database.AdVarChar, 20, req.BeginTime)
+	statement.AddParamter("@EndTime", database.AdParamInput, database.AdVarChar, 20, req.EndTime)
+	statement.AddParamter("@PageIndex", database.AdParamInput, database.AdInteger, 4, req.PageIndex)
+	statement.AddParamter("@PageSize", database.AdParamInput, database.AdInteger, 4, req.PageSize)
+	statement.AddParamter("@RecordCount", database.AdParamOutput, database.AdInteger, 4, resp.RecordCount)
+	sqlString := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlString)
+	rowLen := len(retRows)
+	if rowLen <= 0 {
+		return resp
+	}
+
+	if rowLen > 1 {
+		for i := 0; i < rowLen-1; i++ {
+			ret := retRows[i]
+			var info exchangeCardLog
+			info.Rid = int((*ret[0].(*interface{})).(int64))
+			info.UserID = int((*ret[1].(*interface{})).(int64))
+			info.NickName = (*ret[2].(*interface{})).(string)
+			info.CardNo = (*ret[3].(*interface{})).(string)
+			info.Crdate = (*ret[4].(*interface{})).(string)
+			resp.List = append(resp.List, &info)
+		}
+	}
+	resp.RecordCount = int((*retRows[rowLen-1][0].(*interface{})).(int64))
+	return resp
+}
+
+// 生成比赛卡
+func genMatchCard(req matchCard_req) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_MatchCard_Gen")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, req.OpUserID)
+	statement.AddParamter("@OpNickName", database.AdParamInput, database.AdVarChar, 32, req.OpUserName)
+	statement.AddParamter("@OpenTime", database.AdParamInput, database.AdVarChar, 32, req.OpenTime)
+	statement.AddParamter("@ExpireTime", database.AdParamInput, database.AdVarChar, 32, req.ExpireTime)
+	statement.AddParamter("@TimeMemo", database.AdParamInput, database.AdNVarChar, 1024, req.TimeMemo)
+	statement.AddParamter("@SceneMemo", database.AdParamInput, database.AdNVarChar, 2048, req.SceneMemo)
+	statement.AddParamter("@IPAddress", database.AdParamInput, database.AdVarChar, 16, req.IpAddress)
+	sqlString := statement.GenSql()
+	dao.CenterDB.ExecSql(sqlString)
+}
+
+// 修改比赛卡
+func updateMatchCard(req matchCard_req) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_MatchCard_Update")
+	statement.AddParamter("@OpUserID", database.AdParamInput, database.AdInteger, 4, req.OpUserID)
+	statement.AddParamter("@OpNickName", database.AdParamInput, database.AdVarChar, 32, req.OpUserName)
+	statement.AddParamter("@CardNo", database.AdParamInput, database.AdVarChar, 32, req.CardNo)
+	statement.AddParamter("@OpenTime", database.AdParamInput, database.AdVarChar, 32, req.OpenTime)
+	statement.AddParamter("@ExpireTime", database.AdParamInput, database.AdVarChar, 32, req.ExpireTime)
+	statement.AddParamter("@TimeMemo", database.AdParamInput, database.AdNVarChar, 1024, req.TimeMemo)
+	statement.AddParamter("@SceneMemo", database.AdParamInput, database.AdNVarChar, 2048, req.SceneMemo)
+	statement.AddParamter("@IPAddress", database.AdParamInput, database.AdVarChar, 16, req.IpAddress)
+	sqlString := statement.GenSql()
+	dao.CenterDB.ExecSql(sqlString)
+}
+
+// 获取比赛卡列表
+func getMatchCardList(cardNo string) []*matchCard {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error("transaction recover err %v", err)
+			log.Error("%s", debug.Stack())
+		}
+	}()
+
+	statement := database.NewStatement()
+	statement.SetNeedReturnValue(false)
+	statement.SetOpenRecordSet(true)
+	statement.SetProcName("Manage_MatchCard_GetList")
+	statement.AddParamter("@CardNo", database.AdParamInput, database.AdVarChar, 32, cardNo)
+	sqlString := statement.GenSql()
+	retRows := dao.CenterDB.ExecSql(sqlString)
+	rowLen := len(retRows)
+	if rowLen <= 0 {
+		return nil
+	}
+
+	var list []*matchCard
+	for i := 0; i < rowLen; i++ {
+		ret := retRows[i]
+		var info matchCard
+		info.CardNo = (*ret[0].(*interface{})).(string)
+		info.UseTimes = int((*ret[1].(*interface{})).(int64))
+		info.OpenTime = (*ret[2].(*interface{})).(string)
+		info.ExpireTime = (*ret[3].(*interface{})).(string)
+		info.Crdate = (*ret[4].(*interface{})).(string)
+		info.TimeMemo = (*ret[5].(*interface{})).(string)
+		info.SceneMemo = (*ret[6].(*interface{})).(string)
+
+		list = append(list, &info)
+	}
+	return list
+}

+ 20 - 0
servers/adminserver/character/character.go

@@ -0,0 +1,20 @@
+package character
+
+import "strings"
+
+// 获取特殊字符
+func GetSpecialCharacter(character string) string {
+	character = strings.ReplaceAll(character, "0x22", "\"")
+	character = strings.ReplaceAll(character, "0x5B", "[")
+	character = strings.ReplaceAll(character, "0x5D", "]")
+	character = strings.ReplaceAll(character, "0x7B", "{")
+	character = strings.ReplaceAll(character, "0x7D", "}")
+	character = strings.ReplaceAll(character, "0x23", "#")
+	character = strings.ReplaceAll(character, "0x24", "$")
+	character = strings.ReplaceAll(character, "0x25", "%")
+	character = strings.ReplaceAll(character, "0x26", "&")
+	character = strings.ReplaceAll(character, "0x28", "(")
+	character = strings.ReplaceAll(character, "0x29", ")")
+	character = strings.ReplaceAll(character, "0x2A", "*")
+	return character
+}

+ 88 - 0
servers/adminserver/chat/controller.go

@@ -0,0 +1,88 @@
+package chat
+
+import (
+	"encoding/json"
+	"net/http"
+
+	"bet24.com/log"
+	coreClient "bet24.com/servers/coreservice/client"
+	"github.com/gin-gonic/gin"
+)
+
+// 获取机器人聊天列表
+func GetList(c *gin.Context) {
+	var ret struct {
+		RecordCount int
+		List        []robot_chat
+	}
+	resp := coreClient.GetRobotChatList()
+	if resp.Data != "" {
+		if err := json.Unmarshal([]byte(resp.Data), &ret.List); err != nil {
+			log.Error("chat.GetList json unmarshal error %v", err)
+		}
+	}
+	c.JSON(http.StatusOK, ret)
+	return
+}
+
+// 获取机器人聊天信息
+func GetInfo(c *gin.Context) {
+	var req robot_chat
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "chat.GetInfo", err)
+		return
+	}
+
+	var info robot_chat
+	resp := coreClient.GetRobotChatInfo(req.UserId)
+	if resp.Data != "" {
+		if err := json.Unmarshal([]byte(resp.Data), &info); err != nil {
+			log.Error("chat.GetInfo json unmarshal error %v", err)
+		}
+	}
+
+	var ret struct {
+		RecordCount int
+		List        []robot_chat
+	}
+	ret.List = append(ret.List, info)
+
+	c.JSON(http.StatusOK, ret)
+	return
+}
+
+// 添加机器人聊天信息
+func AddInfo(c *gin.Context) {
+	var req robot_chat
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "chat.AddInfo", err)
+		return
+	}
+	info := coreClient.AddRobotChatInfo(req.UserId, req.Msg, req.Seconds, req.BeginTime, req.EndTime)
+	c.JSON(http.StatusOK, info)
+	return
+}
+
+// 修改机器人聊天信息
+func UpdateInfo(c *gin.Context) {
+	var req robot_chat
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "chat.UpdateInfo", err)
+		return
+	}
+	info := coreClient.UpdateRobotChatInfo(req.UserId, req.Msg, req.Seconds, req.BeginTime, req.EndTime)
+	c.JSON(http.StatusOK, info)
+	return
+}
+
+// 删除机器人聊天信息
+func DelInfo(c *gin.Context) {
+	var req robot_chat
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "chat.DelInfo", err)
+		return
+	}
+	info := coreClient.DelRobotChatInfo(req.UserId)
+	c.JSON(http.StatusOK, info)
+	return
+}

+ 10 - 0
servers/adminserver/chat/data.go

@@ -0,0 +1,10 @@
+package chat
+
+type robot_chat struct {
+	UserId    int    // 用户id
+	Msg       string // 消息
+	Seconds   int    // 间隔时间(秒)
+	BeginTime string // 开始时间
+	EndTime   string // 截止时间
+	SendTime  string // 发送时间
+}

+ 24 - 0
servers/adminserver/config/conf.go

@@ -0,0 +1,24 @@
+package config
+
+import (
+	"log"
+	"time"
+)
+
+var (
+	// log conf
+	LogFlag = log.LstdFlags
+
+	// gate conf
+	PendingWriteNum        = 100
+	MaxMsgLen       uint32 = 65535
+	HTTPTimeout            = 10 * time.Second
+	LenMsgLen              = 2
+	LittleEndian           = false
+
+	// skeleton conf
+	GoLen              = 10000
+	TimerDispatcherLen = 10000
+	AsynCallLen        = 10000
+	ChanRPCLen         = 10000
+)

+ 146 - 0
servers/adminserver/config/json.go

@@ -0,0 +1,146 @@
+package config
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+	"os"
+	"time"
+
+	slog "bet24.com/log"
+	coreservice "bet24.com/servers/coreservice/client"
+	uuid "github.com/satori/go.uuid"
+)
+
+type conf_game struct {
+	GameID     int
+	Login      string
+	Password   string
+	Database   string
+	Datasource string
+}
+
+var Server struct {
+	LogLevel        string
+	FileLevel       string
+	LogPath         string
+	WSAddr          string
+	CertFile        string
+	KeyFile         string
+	MaxConnNum      int
+	Login           string
+	Password        string
+	Database        string
+	Datasource      string
+	ChannelUrl      string
+	ChannelPassword string
+	Games           []conf_game //游戏库
+	AdminserverID   string
+	MonitorPort     int
+	WebPort         int
+	WebKey          string
+	MSDBDatabase    string
+
+	TlsPort int    //HTTPS 端口
+	TlsCert string //HTTPS 证书FILE
+	TlsKey  string //HTTPS 证书KEY
+
+	RedisDB     int
+	ServiceAddr string
+
+	GOOGLE_APPLICATION_CREDENTIALS string // 谷歌凭证
+	GOOGLE_ZH_LANGUAGE             string // 中文
+	GOOGLE_OTHER_LANGUAGE          string // 其他语言
+
+	Exchange_Broadcast_Phone string `json:"exchange.broadcast.phone"`
+	Exchange_Broadcast_Cash  string `json:"exchange.broadcast.cash"`
+	Exchange_Title           string `json:"exchange.title"`
+	Exchange_Content         string `json:"exchange.content"`
+}
+
+func init() {
+	data, err := os.ReadFile("fishconf/adminserver.json")
+	if err != nil {
+		log.Fatalf("read config failed fishconf/adminserver.json ==> %v", err)
+	}
+	fmt.Println(string(data))
+	err = json.Unmarshal(data, &Server)
+	if err != nil {
+		log.Fatalf("Unmarshal config failed fishconf/adminserver.json err:%v", err)
+	}
+
+	logger, err := slog.New(Server.LogLevel, Server.FileLevel, Server.LogPath, log.LstdFlags)
+	if err == nil {
+		slog.Export(logger)
+	}
+
+	// 游戏库
+	for i, v := range Server.Games {
+		fmt.Printf("gameid=%d database=%s\n", v.GameID, v.Database)
+		if v.Login == "" {
+			Server.Games[i].Login = Server.Login
+		}
+		if v.Password == "" {
+			Server.Games[i].Password = Server.Password
+		}
+		if v.Datasource == "" {
+			Server.Games[i].Datasource = Server.Datasource
+		}
+	}
+
+	id, _ := uuid.NewV4()
+	Server.AdminserverID = id.String()
+	slog.Debug("Server.AdminserverID  = %v", Server.AdminserverID)
+	if Server.MonitorPort == 0 {
+		Server.MonitorPort = Server.WebPort + 100
+	}
+
+	loadData()
+}
+
+const config_key = "admin_config"
+
+var AdminConfig struct {
+	Phones          []string `json:"phones"`
+	SMSPostUrl      string   `json:"sms.postUrl"`
+	SMSAppId        string   `json:"sms.appId"`
+	SMSApiKey       string   `json:"sms.apiKey"`
+	SMSSendMsg      string   `json:"sms.sendMsg"`
+	MoneyValue      int      `json:"warning.moneyValue"`
+	MoneyMinutes    int      `json:"warning.moneyMinutes"`
+	LotteryValue    int      `json:"warning.lotteryValue"`
+	LotteryMinutes  int      `json:"warning.lotteryMinutes"`
+	RegValue        int      `json:"warning.regValue"`
+	RegMinutes      int      `json:"warning.regMinutes"`
+	TransferValue   int      `json:"warning.transferValue"`
+	TransferMinutes int      `json:"warning.transferMinutes"`
+}
+
+func loadData() {
+	loadRedisConfig()
+	go time.AfterFunc(5*time.Minute, loadData)
+}
+
+func loadRedisConfig() {
+	if data := coreservice.GetPlatformConfig(config_key); data != "" {
+		err := json.Unmarshal([]byte(data), &AdminConfig)
+		if err == nil {
+			return
+		}
+		slog.Release("Unmarshal config [%s] err:%v", string(data), err)
+		return
+	}
+
+	if data, err := os.ReadFile("fishconf/adminConfig.json"); err == nil {
+		err = json.Unmarshal([]byte(data), &AdminConfig)
+		if err == nil {
+			coreservice.SetPlatformConfig(config_key, string(data))
+			return
+		}
+		slog.Release("Unmarshal config [%s] err:%v", string(data), err)
+	} else {
+		slog.Release("read config failed fishconf/adminConfig.json %v", err)
+	}
+
+	return
+}

+ 300 - 0
servers/adminserver/controller/alluser.go

@@ -0,0 +1,300 @@
+package controller
+
+import (
+	"net/http"
+	"strconv"
+
+	"bet24.com/servers/coreservice/client"
+	userlabel "bet24.com/servers/micros/userlabel/proto"
+
+	"bet24.com/servers/adminserver/config"
+	"bet24.com/servers/adminserver/google"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+// 查询用户列表
+func AllUserList(c *gin.Context) {
+	obj := dao.NewAllUserList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "allUserList", err)
+		return
+	}
+
+	var (
+		userID   int
+		nickName string
+	)
+
+	nickName = obj.In.Data
+	if value, err := strconv.Atoi(obj.In.Data); err == nil {
+		userID = value
+	}
+
+	obj.In.UserID = userID
+	obj.In.NickName = nickName
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 查询用户详情信息
+func UserDetail(c *gin.Context) {
+	obj := dao.NewUserDetail()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "userDetail", err)
+		return
+	}
+	obj.DoAction(nil)
+
+	// 用户标签
+	obj.Out.Labels = userlabel.GetLabel(obj.In.UserID, 0)
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 查询被封用户列表
+func ForbidUserList(c *gin.Context) {
+	obj := dao.NewForbidUserList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "forbidUserList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 封杀玩家
+func ForbidUserAdd(c *gin.Context) {
+	obj := dao.NewForbidUserAdd()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "forbidUserAdd", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	obj.Out.ErrorMsg = ""
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 解除封杀
+func ForbidUserDel(c *gin.Context) {
+	obj := dao.NewForbidUserDel()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "forbidUserDel", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 玩家简单信息
+func UserSimpleInfo(c *gin.Context) {
+	obj := dao.NewUserSimpleInfo()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "userSimpleInfo", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 实时在线
+func CasinoOnlineList(c *gin.Context) {
+	obj := dao.NewCasinoOnlineList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "casinoOnlineList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 获取用户ID(根据昵称)
+func GetUserID(c *gin.Context) {
+	var info struct {
+		Data string
+	}
+	if err := c.ShouldBind(&info); err != nil {
+		log.Debug("%s shouldBind err %v", "getUserID", err)
+		return
+	}
+
+	var (
+		userID   int
+		nickName string
+	)
+
+	if value, err := strconv.Atoi(info.Data); err != nil {
+		nickName = info.Data
+	} else {
+		userID = value
+	}
+
+	//log.Debug("userID:%d nickName:%s tel:%s", userID, nickName, tel)
+
+	obj := dao.NewGetUserID()
+	obj.In.UserID = userID
+	obj.In.NickName = nickName
+	obj.DoAction(nil)
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 删除账号(后台)
+func DelUser(c *gin.Context) {
+	obj := dao.NewDelUser()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "delUser", err)
+		return
+	}
+	obj.DoAction(nil)
+	obj.Out.ErrorMsg = ""
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 绑定facebook
+func BindFacebook(c *gin.Context) {
+	obj := dao.NewBindFacebook()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "BindFacebook", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 个性签名列表
+func UserWordsList(c *gin.Context) {
+	obj := dao.NewUserWordsList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "UserWordsList", err)
+		return
+	}
+
+	obj.DoAction()
+
+	// 是否开启翻译
+	if ok, _ := google.IsTranslate(); ok {
+		for idx, v := range obj.Out.List {
+			if v.UserWords == "" || v.TransMsg != "" {
+				continue
+			}
+
+			transMsg, err := google.Translate(config.Server.GOOGLE_OTHER_LANGUAGE, config.Server.GOOGLE_ZH_LANGUAGE, v.UserWords)
+			if err != nil {
+				log.Error("controller.UserWordsList google.Translate error %+v --> %s", err, v.UserWords)
+				continue
+			}
+
+			obj.Out.List[idx].TransMsg = transMsg
+
+			transObj := dao.NewUserWordsTranslate()
+			transObj.In.ApplyID = v.ApplyID
+			transObj.In.TransMsg = transMsg
+			go transObj.DoAction()
+		}
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 个性签名审批
+func UserWordsSet(c *gin.Context) {
+	obj := dao.NewUserWordsSet()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "UserWordsSet", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 银行信息
+func BankInfo(c *gin.Context) {
+	obj := dao.NewBankInfo()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "BankInfo", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 用户标签列表
+func GetUserTagList(c *gin.Context) {
+	var (
+		req struct {
+			PageIndex  int
+			PageSize   int
+			ColorValue int
+		}
+		resp struct {
+			RecordCount int
+			List        interface{}
+		}
+	)
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "GetUserTagList", err)
+		return
+	}
+
+	resp.RecordCount, resp.List = dao.GetUserTagsList(req.ColorValue, req.PageIndex, req.PageSize)
+
+	c.JSON(http.StatusOK, resp)
+	return
+}
+
+// 修改昵称
+func ChangeNickName(c *gin.Context) {
+	obj := dao.NewChangeNickName()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChangeNickName", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 修改等级
+func ChangeLevel(c *gin.Context) {
+	obj := dao.NewChangeLevel()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChangeLevel", err)
+		return
+	}
+
+	obj.DoAction()
+	// go notification.AddNotification(ul.userId, notification.Notification_Level, string(d))
+
+	// 推送 等级礼包
+	if obj.Out.RetCode == 1 {
+		go client.OnUserLevelChange(obj.In.UserID, obj.Out.OldLv, obj.In.Lv)
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+}

+ 183 - 0
servers/adminserver/controller/cash.go

@@ -0,0 +1,183 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	notification "bet24.com/servers/micros/notification/proto"
+	"github.com/gin-gonic/gin"
+)
+
+// 金币日志
+func GetCashLog(c *gin.Context) {
+	obj := dao.NewGetCashLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getCashLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 钻石日志
+func GetDiamondLog(c *gin.Context) {
+	obj := dao.NewGetDiamondLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getDiamondLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 投注日志
+func GetBetLog(c *gin.Context) {
+	obj := dao.NewGetBetLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getBetLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 投注详情
+func GetBetDetail(c *gin.Context) {
+	obj := dao.NewGetBetDetail()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getBetDetail", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 加金
+func CashSend(c *gin.Context) {
+	obj := dao.NewCashSend()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "cashSend", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 扣金
+func CashDel(c *gin.Context) {
+	obj := dao.NewCashDel()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "cashDel", err)
+		return
+	}
+
+	obj.DoAction(nil)
+
+	// 通知客户端
+	go notification.AddNotification(obj.In.UserID, notification.Notification_Gold, "")
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 金币场解锁
+func CashUnlock(c *gin.Context) {
+	obj := dao.NewCashUnlock()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "cashUnlock", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 金币锁信息
+func CashLockInfo(c *gin.Context) {
+	obj := dao.NewCashLockInfo()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "cashLockInfo", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 货币统计
+func MoneyStat(c *gin.Context) {
+	obj := dao.NewMoneyStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "moneyStat", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 后台扣减钻石
+func DiamondWebReduce(c *gin.Context) {
+	obj := dao.NewDiamondWebReduce()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "diamondWebReduce", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 后台钻石日志
+func GetDiamondAdminLog(c *gin.Context) {
+	obj := dao.NewGetDiamondAdminLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getDiamondAdminLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 游戏金币流量统计
+func MoneyFlowStat(c *gin.Context) {
+	obj := dao.NewMoneyFlowStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "MoneyFlowStat", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 赠送日志
+func CashTransferLog(c *gin.Context) {
+	obj := dao.NewTransferLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipTransferLog", err)
+		return
+	}
+
+	obj.GetCashTransferLog()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 227 - 0
servers/adminserver/controller/chip.go

@@ -0,0 +1,227 @@
+package controller
+
+import (
+	"encoding/json"
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/redis"
+	"bet24.com/servers/adminserver/dao"
+	notification "bet24.com/servers/micros/notification/proto"
+	"github.com/gin-gonic/gin"
+)
+
+// 筹码日志
+func GetChipLog(c *gin.Context) {
+	obj := dao.NewGetChipLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "GetChipLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 税收总计
+func ChipTaxStatList(c *gin.Context) {
+	obj := dao.NewChipTaxStatList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipTaxStatList", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 筹码统计
+func ChipStat(c *gin.Context) {
+	obj := dao.NewChipStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipStat", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 筹码变化
+func GetUserChipStatList(c *gin.Context) {
+	obj := dao.NewGetUserChipStatList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "GetUserChipStatList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 用户筹码变化详情
+func GetChipStatDetail(c *gin.Context) {
+	obj := dao.NewGetChipStatDetail()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "GetChipStatDetail", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 后台管理--导出金币变化
+func ChipStatExport(c *gin.Context) {
+	obj := dao.NewChipStatExport()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipStatExport", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 投注日志
+func GetChipBetLog(c *gin.Context) {
+	obj := dao.NewGetChipBetLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "GetChipBetLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 发放筹码
+func ChipSend(c *gin.Context) {
+	obj := dao.NewChipSend()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipSend", err)
+		return
+	}
+
+	obj.DoAction(nil)
+
+	if obj.Out.RetCode == 1 {
+		// 通知客户端
+		notification.AddNotification(obj.In.UserID, notification.Notification_Chip, "")
+		notifyChanged(obj.In.UserID)
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 扣减筹码
+func ChipDel(c *gin.Context) {
+	obj := dao.NewChipDel()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipDel", err)
+		return
+	}
+
+	obj.DoAction(nil)
+
+	if obj.Out.RetCode == 1 {
+		// 通知客户端
+		notification.AddNotification(obj.In.UserID, notification.Notification_Chip, "")
+		notifyChanged(obj.In.UserID)
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+func notifyChanged(userId int) {
+	var d redis.Channel_msg
+	d.Message = "RefreshChip"
+	d.UserID = userId
+	js, _ := json.Marshal(d)
+	redis.Publish(string(js))
+}
+
+// 筹码排行
+func ChipTop(c *gin.Context) {
+	obj := dao.NewChipTop()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipTop", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 存量统计
+func ChipStatTotalList(c *gin.Context) {
+	obj := dao.NewChipStatTotalList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipStatTotalList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 存量统计(每天)
+func ChipStatTotalListByDay(c *gin.Context) {
+	obj := dao.NewChipStatTotalListByDay()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipStatTotalListByDay", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 赠送日志
+func ChipTransferLog(c *gin.Context) {
+	obj := dao.NewTransferLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipTransferLog", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+func ChipLoginStat(c *gin.Context) {
+	obj := dao.NewChipLoginStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ChipLoginStat", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+func BehaviorList(c *gin.Context) {
+	obj := dao.NewBehaviorList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "BehaviorList", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 212 - 0
servers/adminserver/controller/exchange.go

@@ -0,0 +1,212 @@
+package controller
+
+import (
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/character"
+	"bet24.com/servers/adminserver/dao"
+	"bet24.com/servers/adminserver/item"
+	"bet24.com/servers/coreservice/client"
+	item_inventory "bet24.com/servers/micros/item_inventory/proto"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+func SysExchange(c *gin.Context) {
+	c.JSON(http.StatusOK, struct {
+		RecordCount int
+		List        interface{}
+	}{
+		RecordCount: 0,
+		List:        client.GetExchangeType(),
+	})
+	return
+}
+
+// 兑换历史
+func ExchangeHistory(c *gin.Context) {
+	obj := dao.NewExchangeHistory()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ExchangeHistory", err)
+		return
+	}
+
+	obj.DoAction()
+
+	tools := item.GetSysItems()
+	for i := 0; i < len(obj.Out.List); i++ {
+		list := &obj.Out.List[i]
+		for j := 0; j < len(list.ItemPack); j++ {
+			history := &list.ItemPack[j]
+			sysItem, ok := tools[history.ItemId]
+			if !ok {
+				continue
+			}
+			obj.Out.List[i].Item = fmt.Sprintf("<b>%s</b>(Num:%d)", sysItem.Name, history.Count)
+			if sysItem.Type == item_inventory.Item_Physical || sysItem.Type == item_inventory.Item_GiftCard {
+				obj.Out.List[i].IsMust = 1
+			}
+		}
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+}
+
+// 兑换历史
+func ExchangeCash(c *gin.Context) {
+	obj := dao.NewExchangeCash()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ExchangeCash", err)
+		return
+	}
+
+	obj.DoAction()
+
+	tools := item.GetSysItems()
+	for i := 0; i < len(obj.Out.List); i++ {
+		list := &obj.Out.List[i]
+		for j := 0; j < len(list.ItemPack); j++ {
+			history := &list.ItemPack[j]
+			item, ok := tools[history.ItemId]
+			if !ok {
+				continue
+			}
+			obj.Out.List[i].Item = fmt.Sprintf("<b>%s</b>(Num:%d)", item.Name, history.Count)
+			if item.Type == item_inventory.Item_Physical || item.Type == item_inventory.Item_GiftCard {
+				obj.Out.List[i].IsMust = 1
+			}
+		}
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+}
+
+// 修改兑换历史
+func ExchangeHistoryUpdate(c *gin.Context) {
+	obj := dao.NewExchangeHistoryUpdate()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ExchangeHistoryUpdate", err)
+		return
+	}
+
+	if obj.In.Status == 0 {
+		obj.Out.RetCode = 11
+		obj.Out.ErrorMsg = "修改失败"
+		c.JSON(http.StatusOK, obj.Out)
+		return
+	}
+
+	obj.In.Items = character.GetSpecialCharacter(obj.In.Items)
+	obj.DoAction()
+
+	/*
+		// 兑换成功
+		if obj.Out.RetCode != 1 {
+			c.JSON(http.StatusOK, obj.Out)
+			return
+		}
+
+		// 拒绝,返还
+		if obj.In.Status == 2 {
+			itemId := 0
+			switch obj.In.ExchangeType {
+			case 1: // 奖券
+				itemId = item_inventory.Item_GiftCard
+			case 5: // 金币提现
+				itemId = item_inventory.Item_Gold
+			}
+
+			// 返还道具
+			if itemId > 0 && obj.In.Price > 0 {
+				var tools []item_inventory.ItemPack
+
+				tools = append(tools, item_inventory.ItemPack{
+					ItemId: itemId,
+					Count:  obj.In.Price,
+				})
+
+				client.SendSysMail(obj.In.UserID, mail.SysMail{
+					Id:         0,
+					Title:      config.Server.Exchange_Title,
+					Content:    config.Server.Exchange_Content,
+					Status:     0,
+					SourceName: "admin exchange",
+					Crdate:     common.GetTimeStamp(),
+					Tools:      tools,
+				})
+			}
+
+			c.JSON(http.StatusOK, obj.Out)
+			return
+		}
+
+		// 查询用户信息
+		resp := client.GetUserInfo(obj.In.UserID)
+		if resp.Data == "" {
+			c.JSON(http.StatusOK, obj.Out)
+			return
+		}
+
+		// 用户信息
+		var UserHotInfo struct {
+			UserId       int
+			NickName     string
+			Vip          int
+			FaceUrl      string
+			FaceId       int
+			Sex          int
+			UserWords    string
+			IsRobot      int   // 是否机器人
+			Achievements []int // 成就列表
+		}
+
+		if err := json.Unmarshal([]byte(resp.Data), &UserHotInfo); err != nil {
+			c.JSON(http.StatusOK, obj.Out)
+			return
+		}
+
+		tools := item.GetSysItems()
+
+		var items []item_inventory.ItemPack
+		if err := json.Unmarshal([]byte(obj.In.Items), &items); err != nil {
+			c.JSON(http.StatusOK, obj.Out)
+			return
+		}
+
+		for _, v := range items {
+			tmpItem, ok := tools[v.ItemId]
+			if !ok {
+				continue
+			}
+
+			broadcastMsg := ""
+
+			// 8=话费
+			if tmpItem.Type == 8 {
+				// SNG赛 Cash 类处理
+				if splitRemarks := strings.Split(obj.Out.Remark, ","); len(splitRemarks) > 0 {
+					if rid, err := strconv.Atoi(splitRemarks[0]); err != nil {
+						log.Error("ExchangeHistoryUpdate SNG 赛 Cash 处理 obj.In=%+v obj.Out=%+v ,err ==>%v", obj.In, obj.Out, err)
+					} else {
+						log.Debug("ExchangeHistoryUpdate SNG 赛 Cash 处理调用 rid=%d obj.In=%+v obj.Out=%+v", rid, obj.In, obj.Out)
+						go gameHistory.MyMatch_UpdateStatus(obj.In.UserID, rid, gameHistory.MyMatch_Status_Received)
+					}
+
+					continue
+				}
+
+				broadcastMsg = config.Server.Exchange_Broadcast_Phone
+			} else if tmpItem.Type == 11 { // 11=Cash
+				broadcastMsg = config.Server.Exchange_Broadcast_Cash
+			}
+
+			broadcastMsg = strings.ReplaceAll(broadcastMsg, "数量", fmt.Sprintf("<color=#04ff0a>%d</color>", v.Count))
+			broadcastMsg = strings.ReplaceAll(broadcastMsg, "玩家昵称", fmt.Sprintf("<color=#ffafd8>%s</color>", UserHotInfo.NickName))
+
+			go client.SendBroadcast(obj.In.UserID, 0, 0, broadcastMsg, "")
+		}
+	*/
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 31 - 0
servers/adminserver/controller/feedback.go

@@ -0,0 +1,31 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+// 客服反馈列表
+func FeedbackList(c *gin.Context) {
+	obj := dao.NewFeedbackList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "FeedbackList", err)
+		return
+	}
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+}
+
+// 客服反馈修改
+func FeedbackUpdate(c *gin.Context) {
+	obj := dao.NewFeedbackUp()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "FeedbackUpdate", err)
+		return
+	}
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+}

+ 219 - 0
servers/adminserver/controller/game.go

@@ -0,0 +1,219 @@
+package controller
+
+import (
+	waterPool "bet24.com/servers/micros/waterpool/proto"
+	"net/http"
+
+	"bet24.com/servers/adminserver/dao"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/serverdata"
+	"github.com/gin-gonic/gin"
+)
+
+// 获取简单游戏信息(GameID、ChineseName)
+func GetSimpleGames(c *gin.Context) {
+	list := serverdata.Games.GetSimpleGames()
+	c.JSON(http.StatusOK, struct {
+		RecordCount int
+		List        interface{}
+	}{
+		RecordCount: len(list),
+		List:        list,
+	})
+	return
+}
+
+// 审核游戏列表
+func GameRequestList(c *gin.Context) {
+	obj := dao.NewGetGameRequestList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "gameRequestList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 添加审核游戏
+func GameRequestAdd(c *gin.Context) {
+	obj := dao.NewGameRequestAdd()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "gameRequestAdd", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 删除审核游戏
+func GameRequestDel(c *gin.Context) {
+	obj := dao.NewGameRequestDel()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "gameRequestDel", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 所有游戏列表
+func GetAllGames(c *gin.Context) {
+	var info struct {
+		GameID int
+	}
+
+	if err := c.ShouldBind(&info); err != nil {
+		log.Debug("%s shouldBind err %v", "getAllGames", err)
+		return
+	}
+
+	if info.GameID > 0 {
+		var list []*dao.AllGameInfo
+		list = append(list, serverdata.Games.GetGameInfo(info.GameID))
+		c.JSON(http.StatusOK, struct {
+			RecordCount int
+			List        interface{}
+		}{
+			RecordCount: len(list),
+			List:        list,
+		})
+		return
+	}
+
+	list := serverdata.Games.GetGames()
+	c.JSON(http.StatusOK, struct {
+		RecordCount int
+		List        interface{}
+	}{
+		RecordCount: len(*list),
+		List:        list,
+	})
+	return
+}
+
+// 游戏信息修改
+func AllGameUpd(c *gin.Context) {
+	obj := dao.NewAllGameUpd()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "allGameUpd", err)
+		return
+	}
+
+	obj.DoAction(nil)
+
+	serverdata.Games.Refresh()
+
+	c.JSON(http.StatusOK, nil)
+	return
+}
+
+// 获取系统返还比率
+func GetSysOdds(c *gin.Context) {
+	obj := dao.NewSysOdds()
+	if err := c.ShouldBind(&obj); err != nil {
+		log.Debug("%s shouldBind err %v", "getSysOdds", err)
+		return
+	}
+	c.JSON(http.StatusOK, struct {
+		List interface{}
+	}{
+		List: obj.Get(),
+	})
+	return
+}
+
+// 设置系统返还比率
+func SetSysOdds(c *gin.Context) {
+	obj := dao.NewSysOdds()
+	if err := c.ShouldBind(&obj); err != nil {
+		log.Debug("%s shouldBind err %v", "setSysOdds", err)
+		return
+	}
+	log.Debug("SetSysOdds ==> %+v", obj)
+	b := obj.Set()
+	c.JSON(http.StatusOK, b)
+	return
+}
+
+type GetGameInventoryList_in struct {
+	GameID int
+}
+
+type GameInventoryInfo struct {
+	GameName          string  // 游戏名称
+	GameID            int     // 游戏ID
+	RoomName          string  // 房间名称
+	RoomType          int     // 房间类型
+	InventoryValue    int     // 实时库存值
+	ControlRate       float64 // 实时控制率
+	MinInventoryValue int     // 库存取值下限
+	MaxInventoryValue int     // 库存取值上限
+	MaxControlRate    int     // 控制率上限
+}
+
+type GetGameInventoryList_out struct {
+	RecordCount int
+	List        []GameInventoryInfo
+}
+
+// 获取游戏库存列表
+func GetGameInventoryList(c *gin.Context) {
+	var in GetGameInventoryList_in
+	if err := c.ShouldBind(&in); err != nil {
+		log.Debug("%s shouldBind err %v", "GetGameInventoryList", err)
+		return
+	}
+
+	resp := waterPool.GetInventoryList(in.GameID)
+
+	var out GetGameInventoryList_out
+	out.RecordCount = resp.Count
+	for _, v := range resp.List {
+		g := serverdata.Games.GetGameInfo(v.GameID)
+		if g == nil {
+			continue
+		}
+		out.List = append(out.List, GameInventoryInfo{
+			GameName:          g.GameName,
+			GameID:            v.GameID,
+			RoomName:          v.RoomName,
+			RoomType:          v.RoomType,
+			InventoryValue:    v.InventoryValue,
+			ControlRate:       v.ControlRate,
+			MinInventoryValue: v.MinInventoryValue,
+			MaxInventoryValue: v.MaxInventoryValue,
+			MaxControlRate:    v.MaxControlRate,
+		})
+	}
+
+	c.JSON(http.StatusOK, out)
+	return
+}
+
+// 更新或者修改单个库存
+func UpdateGameInventory(c *gin.Context) {
+	var in GameInventoryInfo
+	if err := c.ShouldBind(&in); err != nil {
+		log.Debug("%s shouldBind err %v", "UpdateGameInventory", err)
+		return
+	}
+
+	// 修改库存配置
+	waterPool.UpdateInventoryList(in.GameID,
+		in.RoomName,
+		in.RoomType,
+		in.InventoryValue,
+		in.MinInventoryValue,
+		in.MaxInventoryValue,
+		in.MaxControlRate)
+
+	c.JSON(http.StatusOK, "")
+	return
+}

+ 48 - 0
servers/adminserver/controller/giftcard.go

@@ -0,0 +1,48 @@
+package controller
+
+import (
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"bet24.com/servers/adminserver/item"
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+// 礼品卡列表
+func GiftCardList(c *gin.Context) {
+	obj := dao.NewGiftCardList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "GiftCardList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+
+	if len(obj.Out.List) > 0 {
+		items := item.GetSysItems()
+		for i, v := range obj.Out.List {
+			value, ok := items[v.ItemID]
+			if !ok {
+				continue
+			}
+			obj.Out.List[i].ItemName = value.Name
+			obj.Out.List[i].ItemDesc = value.Desc
+		}
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 礼品卡处理
+func GiftCardDeal(c *gin.Context) {
+	obj := dao.NewGiftCardDeal()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "GiftCardDeal", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 107 - 0
servers/adminserver/controller/item.go

@@ -0,0 +1,107 @@
+package controller
+
+import (
+	"bet24.com/servers/adminserver/item"
+	item_inventory "bet24.com/servers/micros/item_inventory/proto"
+	"net/http"
+	"sort"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+func ItemLog(c *gin.Context) {
+	obj := dao.NewUserItemLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "itemLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+func GetItems(c *gin.Context) {
+	type tool struct {
+		Id   int    //道具ID
+		Type int    //道具类型
+		Name string //道具名称
+		Desc string //道具描述
+	}
+
+	items := item.GetSysItems()
+
+	var tools []tool
+	for _, v := range items {
+		tools = append(tools, tool{
+			Id:   v.Id,
+			Type: v.Type,
+			Name: v.Name,
+			Desc: v.Desc,
+		})
+	}
+
+	//道具ID排序
+	sort.SliceStable(tools, func(i, j int) bool {
+		return tools[i].Id < tools[j].Id
+	})
+
+	//道具类型排序
+	sort.SliceStable(tools, func(i, j int) bool {
+		return tools[i].Type < tools[j].Type
+	})
+
+	c.JSON(http.StatusOK, struct {
+		RecordCount int
+		List        []tool
+	}{
+		RecordCount: len(tools),
+		List:        tools,
+	})
+	return
+}
+
+func GetUserItemList(c *gin.Context) {
+	obj := dao.NewUserItemList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getUserItemList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+
+	if len(obj.Out.List) > 0 {
+		items := item.GetSysItems()
+		for i, v := range obj.Out.List {
+			value, ok := items[v.ItemID]
+			if !ok {
+				continue
+			}
+			obj.Out.List[i].ItemName = value.Name
+		}
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+func ReduceUserItem(c *gin.Context) {
+	var req struct {
+		UserId     int
+		ItemId     int
+		Count      int
+		OpUserID   int
+		OpUserName string
+	}
+
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "reduceUserItem", err)
+		return
+	}
+
+	_, errorMsg := item_inventory.ReduceItemByAdmin(req.OpUserID, req.OpUserName, req.UserId, req.ItemId, req.Count)
+	c.String(http.StatusOK, errorMsg)
+	return
+}

+ 48 - 0
servers/adminserver/controller/job.go

@@ -0,0 +1,48 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+//作业列表
+func JobList(c *gin.Context) {
+	obj := dao.NewJobList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "jobList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+//作业简单列表
+func JobSimpleList(c *gin.Context) {
+	obj := dao.NewJobSimpleList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "jobSimpleList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+//作业历史列表
+func JobHistoryList(c *gin.Context) {
+	obj := dao.NewJobHistoryList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "jobHistoryList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 115 - 0
servers/adminserver/controller/log.go

@@ -0,0 +1,115 @@
+package controller
+
+import (
+	"bet24.com/servers/adminserver/character"
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+// 日志列表
+func LogList(c *gin.Context) {
+	obj := dao.NewLogList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "logList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 系统日志列表
+func SysLogList(c *gin.Context) {
+	obj := dao.NewSysLogList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "sysLogList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 登录日志列表
+func LoginLogList(c *gin.Context) {
+	obj := dao.NewLoginLogList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "loginLogList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 注册日志列表
+func RegisterLogList(c *gin.Context) {
+	obj := dao.NewRegisterLogList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "registerLogList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 注册日志列表
+func RegisterLogList_V2(c *gin.Context) {
+	obj := dao.NewRegisterLogList_v2()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "RegisterLogList_V2", err)
+		return
+	}
+
+	obj.In.UTMSources = character.GetSpecialCharacter(obj.In.UTMSources)
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 流水排行
+func DailyBetRank(c *gin.Context) {
+	obj := dao.NewDailyBetRank()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "dailyBetRank", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 流水列表
+func DailyBetList(c *gin.Context) {
+	obj := dao.NewDailyBetList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "dailyBetList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 贈送日誌
+func SendLog(c *gin.Context) {
+	obj := dao.NewSendLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "sendLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 266 - 0
servers/adminserver/controller/mail.go

@@ -0,0 +1,266 @@
+package controller
+
+import (
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/character"
+	"bet24.com/servers/adminserver/config"
+	"bet24.com/servers/adminserver/dao"
+	"bet24.com/servers/adminserver/google"
+	"bet24.com/servers/adminserver/item"
+	"bet24.com/servers/adminserver/serverdata"
+	item_inventory "bet24.com/servers/micros/item_inventory/proto"
+	"encoding/json"
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+// 留言板列表
+func ServiceMessageList(c *gin.Context) {
+	obj := dao.NewServiceMessageList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "serviceMessageList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 用户留言详细信息
+func ServiceDetailList(c *gin.Context) {
+	obj := dao.NewServiceDetailList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "serviceDetailList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+
+	// 是否开启翻译
+	if ok, _ := google.IsTranslate(); ok {
+		for idx, v := range obj.Out.List {
+			if v.Msg == "" || v.TransMsg != "" {
+				continue
+			}
+
+			transMsg, err := google.Translate(config.Server.GOOGLE_OTHER_LANGUAGE, config.Server.GOOGLE_ZH_LANGUAGE, v.Msg)
+			if err != nil {
+				log.Error("controller.ServiceDetailList google.Translate error %+v --> %s", err, v.Msg)
+				continue
+			}
+
+			obj.Out.List[idx].TransMsg = transMsg
+
+			transObj := dao.NewMsgTranslate()
+			transObj.In.MessageID = v.MessageID
+			transObj.In.OpUserID = -1
+			transObj.In.OpUserName = "System"
+			transObj.In.TransMsg = transMsg
+			go transObj.DoAction()
+		}
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 客服回复
+func ServiceSend(c *gin.Context) {
+	obj := dao.NewServiceSend()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "serviceSend", err)
+		return
+	}
+
+	obj.In.Msg = character.GetSpecialCharacter(obj.In.Msg)
+	obj.In.TransMsg = character.GetSpecialCharacter(obj.In.TransMsg)
+
+	// 是否开启翻译
+	if ok, _ := google.IsTranslate(); ok {
+
+		log.Debug("ServiceSend obj.In 2 ==> %+v", obj.In)
+
+		if obj.In.Msg == "" && obj.In.TransMsg != "" {
+			msg, err := google.Translate(config.Server.GOOGLE_ZH_LANGUAGE, config.Server.GOOGLE_OTHER_LANGUAGE, obj.In.TransMsg)
+			if err != nil {
+				log.Error("controller.ServiceDetailList google.Translate error %+v --> %s", err, obj.In.TransMsg)
+			}
+
+			obj.In.Msg = msg
+		}
+	} else if obj.In.TransMsg != "" {
+		obj.In.Msg = obj.In.TransMsg
+		obj.In.TransMsg = ""
+	}
+
+	// 没有消息,不允许发送
+	if obj.In.Msg == "" {
+		c.JSON(http.StatusOK, nil)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, nil)
+	return
+}
+
+// 系统广播列表
+func TimeBroadcastList(c *gin.Context) {
+	obj := dao.NewTimeBroadcastList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "timeBroadcastList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 定时广播发送
+func TimeBroadcastSend(c *gin.Context) {
+	obj := dao.NewTimeBroadcastSend()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "TimeBroadcastSend", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, nil)
+	return
+}
+
+// 定时广播删除
+func TimeBroadcastDel(c *gin.Context) {
+	obj := dao.NewTimeBroadcastDel()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "timeBroadcastDel", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, nil)
+	return
+}
+
+// 客服留言小红点提示
+func Tip(c *gin.Context) {
+	c.JSON(http.StatusOK, struct {
+		List interface{}
+	}{
+		List: serverdata.Tip.GetList(),
+	})
+	return
+}
+
+// 发送系统消息
+func SysMessageSend(c *gin.Context) {
+	obj := dao.NewSysMessageSend()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "sysMessageSend", err)
+		return
+	}
+
+	var items []item_inventory.ItemPack
+	items = append(items, item.AddItems(obj.In.ItemID_1, obj.In.ItemCount_1)...)
+	items = append(items, item.AddItems(obj.In.ItemID_2, obj.In.ItemCount_2)...)
+	items = append(items, item.AddItems(obj.In.ItemID_3, obj.In.ItemCount_3)...)
+	items = append(items, item.AddItems(obj.In.ItemID_4, obj.In.ItemCount_4)...)
+	items = append(items, item.AddItems(obj.In.ItemID_5, obj.In.ItemCount_5)...)
+
+	if len(items) > 0 {
+		buff, _ := json.Marshal(items)
+		obj.In.Tools = string(buff)
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 获取系统消息列表
+func SysMessageList(c *gin.Context) {
+	obj := dao.NewSysMessageList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "sysMessageList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 客服留言翻译
+func MsgTranslate(c *gin.Context) {
+	obj := dao.NewMsgTranslate()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "MsgTranslate", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, "")
+	return
+}
+
+// 留言标签列表
+func MsgTagList(c *gin.Context) {
+	obj := dao.NewMsgTagList()
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 留言标签统计
+func MsgTagStat(c *gin.Context) {
+	obj := dao.NewMsgTagStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "MsgTagStat", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 根据标签获取列表
+func ServiceMessageListByTag(c *gin.Context) {
+	obj := dao.NewServiceMessageListByTag()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ServiceMessageListByTag", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 获取客服留言信息
+func ServiceMessageInfo(c *gin.Context) {
+	obj := dao.NewServiceMessageInfo()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ServiceMessageInfo", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 标签统计
+func ServiceMessageTagStat(c *gin.Context) {
+	obj := dao.NewServiceMessageTagStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ServiceMessageTagStat", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 38 - 0
servers/adminserver/controller/notfound.go

@@ -0,0 +1,38 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"github.com/gin-gonic/gin"
+)
+
+//404错误
+func NotFoundRoute(c *gin.Context) {
+	_ = c.Request.ParseForm()
+	log.Debug("%v %v not found route ip[%v]",
+		c.Request.URL.Path, c.Request.Form, c.Request.RemoteAddr)
+
+	c.JSON(http.StatusNotFound, struct {
+		RetCode  int
+		ErrorMsg string
+	}{
+		RetCode:  -1,
+		ErrorMsg: "Not Found Page (404)",
+	})
+}
+
+func NotFoundMethod(c *gin.Context) {
+
+	_ = c.Request.ParseForm()
+	log.Debug("%v %v not found route ip[%v]",
+		c.Request.URL.Path, c.Request.Form, c.Request.RemoteAddr)
+
+	c.JSON(http.StatusNotFound, struct {
+		RetCode  int
+		ErrorMsg string
+	}{
+		RetCode:  -1,
+		ErrorMsg: "Not Found Page (404)",
+	})
+}

+ 56 - 0
servers/adminserver/controller/partner.go

@@ -0,0 +1,56 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/servers/adminserver/serverdata"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+//渠道列表
+func PartnerList(c *gin.Context) {
+	list := serverdata.Partners.GetPartners()
+	c.JSON(http.StatusOK, struct {
+		RecordCount int
+		List        interface{}
+	}{
+		RecordCount: len(list),
+		List:        list,
+	})
+	return
+}
+
+//添加渠道
+func PartnerAdd(c *gin.Context) {
+	obj := dao.NewPartnerAdd()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "partnerAdd", err)
+		return
+	}
+
+	obj.DoAction(nil)
+
+	serverdata.Partners.Refresh()
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+//删除渠道
+func PartnerDel(c *gin.Context) {
+	obj := dao.NewPartnerDel()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "partnerDel", err)
+		return
+	}
+
+	obj.DoAction(nil)
+
+	serverdata.Partners.Refresh()
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 248 - 0
servers/adminserver/controller/pay.go

@@ -0,0 +1,248 @@
+package controller
+
+import (
+	"bet24.com/servers/adminserver/shop"
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+
+	coreClient "bet24.com/servers/coreservice/client"
+)
+
+// 订单列表
+func OrderList(c *gin.Context) {
+	obj := dao.NewOrderList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "orderList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	for i, v := range obj.Out.List {
+		productName := shop.GetProductFormatStr(v.ProductID)
+		if len(productName) <= 0 {
+			continue
+		}
+		obj.Out.List[i].ProductName = productName
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 获取各渠道充值列表
+func PayList(c *gin.Context) {
+	obj := dao.NewPayList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "payList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 充值统计列表
+func PayStatList(c *gin.Context) {
+	obj := dao.NewPayStatList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "payStatList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 登录渠道充值统计
+func PayListByPartner(c *gin.Context) {
+	obj := dao.NewPayListByPartner()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "payListByPartner", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 日充值总额
+func PayListByDay(c *gin.Context) {
+	obj := dao.NewPayListByDay()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "payListByDay", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 充值日志
+func PayLog(c *gin.Context) {
+	obj := dao.NewPayLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "payLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	for i, v := range obj.Out.List {
+		productName := shop.GetProductFormatStr(v.ProductID)
+		if len(productName) <= 0 {
+			continue
+		}
+		obj.Out.List[i].ProductName = productName
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 充值排行
+func PayRank(c *gin.Context) {
+	obj := dao.NewPayRank()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "payRank", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 苹果日志
+func AppleLog(c *gin.Context) {
+	obj := dao.NewAppleLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "appleLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 苹果错误日志
+func AppleErrorLog(c *gin.Context) {
+	obj := dao.NewAppleErrorLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "appleErrorLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// Google日志
+func GoogleLog(c *gin.Context) {
+	obj := dao.NewGoogleLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "appleErrorLog", err)
+		return
+	}
+
+	obj.DoAction()
+	for i, v := range obj.Out.List {
+		productName := shop.GetProductFormatStr(v.ProductID)
+		if len(productName) <= 0 {
+			continue
+		}
+		obj.Out.List[i].ProductName = productName
+	}
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 手动充值
+func ManualPay(c *gin.Context) {
+	obj := dao.NewManualPay()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "manualPay", err)
+		return
+	}
+	obj.DoAction()
+	if obj.Out.RetCode == 1 {
+		// 充值
+		resp := coreClient.Recharge(obj.In.UserID, obj.In.ProductID)
+		log.Debug("%s 充值成功 %+v", "manualPay", resp)
+	}
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 手动充值列表
+func ManualPayList(c *gin.Context) {
+	obj := dao.NewManualPayList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "manualPayList", err)
+		return
+	}
+	obj.DoAction()
+	for i, v := range obj.Out.List {
+		productName := shop.GetProductFormatStr(v.ProductID)
+		if len(productName) <= 0 {
+			continue
+		}
+		obj.Out.List[i].ProductName = productName
+	}
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 充值日志
+func PayChipLog(c *gin.Context) {
+	obj := dao.NewPayChipLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "PayChipLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	for i, v := range obj.Out.List {
+		productName := shop.GetProductFormatStr(v.ProductID)
+		if len(productName) <= 0 {
+			continue
+		}
+		obj.Out.List[i].ProductName = productName
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 日充值总额
+func PayChipListByDay(c *gin.Context) {
+	obj := dao.NewPayChipListByDay()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "PayChipListByDay", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 付费用户列表
+func PayUserList(c *gin.Context) {
+	obj := dao.NewPayUserList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "PayUserList", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 53 - 0
servers/adminserver/controller/platformInfo.go

@@ -0,0 +1,53 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+//平台信息列表
+func PlatformInfoList(c *gin.Context) {
+	obj := dao.NewPlatformInfoList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "platformInfoList", err)
+		return
+	}
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+//平台信息修改
+func PlatformInfoUp(c *gin.Context) {
+	obj := dao.NewPlatformInfoUp()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "platformInfoUp", err)
+		return
+	}
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+//平台配置信息
+func PlatformConfig(c *gin.Context) {
+	obj := dao.NewPlatformConfig()
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+//修改平台配置信息
+func PlatformConfigUp(c *gin.Context) {
+	obj := dao.NewPlatformConfigUp()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "platformConfigUp", err)
+		return
+	}
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 33 - 0
servers/adminserver/controller/rank.go

@@ -0,0 +1,33 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+func ScoreRankList(c *gin.Context) {
+	obj := dao.NewScoreRankList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "ScoreRankList", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+func AddRankScore(c *gin.Context) {
+	obj := dao.NewAddScore()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "AddRankScore", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, "")
+	return
+}

+ 77 - 0
servers/adminserver/controller/role.go

@@ -0,0 +1,77 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+//角色列表
+func RoleList(c *gin.Context) {
+	obj := dao.NewRoleList()
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+//添加角色用户
+func RoleUserAdd(c *gin.Context) {
+	obj := dao.NewRoleUserAdd()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "roleUserAdd", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, nil)
+	return
+}
+
+//用户角色列表
+func RoleListByAdmin(c *gin.Context) {
+	obj := dao.NewRoleListByAdmin()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "roleListByAdmin", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+//角色设置页面
+func RoleSetPage(c *gin.Context) {
+	obj := dao.NewRoleSetPage()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "roleSetPage", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+//角色页面列表
+func RolePageList(c *gin.Context) {
+	obj := dao.NewRolePageList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "rolePageList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+//角色用户列表
+func RoleUserList(c *gin.Context) {
+	obj := dao.NewRoleUserList()
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 41 - 0
servers/adminserver/controller/shop.go

@@ -0,0 +1,41 @@
+package controller
+
+import (
+	"bet24.com/log"
+	"bet24.com/servers/coreservice/client"
+	"encoding/json"
+)
+
+// 汇率
+type exchangeRate struct {
+	Currency    string  // 币种
+	CountryName string  // 国家名称
+	CountryCode string  // 国家编码
+	Rate        float64 // 汇率
+}
+
+func GetExchangeRate(currency string) *exchangeRate {
+	var list []*exchangeRate
+
+	respExchange := client.GetExchangeRateList()
+	if respExchange.RetCode != 1 {
+		log.Error("%s PayRequest client ==> %+v", "GetExchangeRate.GetExchangeRateList", respExchange)
+		return nil
+	}
+
+	if err := json.Unmarshal([]byte(respExchange.Data), &list); err != nil {
+		log.Error("%s PayRequest json unmarshal err %v", "GetExchangeRate.GetExchangeRateList", err)
+		return nil
+	}
+
+	var info *exchangeRate
+
+	for _, v := range list {
+		info = v
+		if info.Currency == currency {
+			return info
+		}
+	}
+
+	return info
+}

+ 21 - 0
servers/adminserver/controller/sign.go

@@ -0,0 +1,21 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+//签到列表
+func SignList(c *gin.Context) {
+	obj := dao.NewSignList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "signList", err)
+		return
+	}
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 346 - 0
servers/adminserver/controller/stat.go

@@ -0,0 +1,346 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+// 日常统计
+func DailyStat(c *gin.Context) {
+	obj := dao.NewDailyStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "dailyStat", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 在线统计
+func OnlineStat(c *gin.Context) {
+	obj := dao.NewOnlineStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "onlineStat", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 在线统计(每天)
+func OnlineStatListByDay(c *gin.Context) {
+	obj := dao.NewOnlineStatListByDay()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "onlineStatListByDay", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 在线统计报表(小时)
+func OnlineStatReport(c *gin.Context) {
+	obj := dao.NewOnlineStatReport()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "onlineStatReport", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 同时在线统计报表(小时)
+func OnlineUserReport(c *gin.Context) {
+	obj := dao.NewOnlineUserReport()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "OnlineUserReport", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 游戏统计(小时)
+func GameStatHour(c *gin.Context) {
+	obj := dao.NewGameStatHour()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "gameStatHour", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 存量统计
+func MoneyStatTotalList(c *gin.Context) {
+	obj := dao.NewMoneyStatTotalList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "moneyStatTotalList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 存量统计(每天)
+func MoneyStatTotalListByDay(c *gin.Context) {
+	obj := dao.NewMoneyStatTotalListByDay()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "moneyStatTotalListByDay", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 货币排行
+func CurrencyTop(c *gin.Context) {
+	obj := dao.NewCurrencyTop()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "currencyTop", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 货币变化
+func GetUserMoneyStatList(c *gin.Context) {
+	obj := dao.NewGetUserMoneyStatList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getUserMoneyStatList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 用户货币变化详情
+func GetMoneyStatDetail(c *gin.Context) {
+	obj := dao.NewGetMoneyStatDetail()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getMoneyStatDetail", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 游戏计
+func GameDailyStat(c *gin.Context) {
+	obj := dao.NewGameDailyStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "gameDailyStat", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 后台管理--导出金币变化
+func MoneyStatExport(c *gin.Context) {
+	obj := dao.NewMoneyStatExport()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "moneyStatExport", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 用户日常统计
+func UserDailyStat(c *gin.Context) {
+	obj := dao.NewUserDailyStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "userDailyStat", err)
+		return
+	}
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 税收总计
+func TaxStatList(c *gin.Context) {
+	obj := dao.NewTaxStatList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "TaxStatList", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 游戏记录详情报表
+func GameRecordReportDetail(c *gin.Context) {
+	obj := dao.NewGameRecordReportDetail()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "GameRecordReportDetail", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 注册用户转化报表
+func RegConvertReport(c *gin.Context) {
+	obj := dao.NewRegConvertReport()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "RegConvertReport", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 登录用户转化报表
+func LoginConvertReport(c *gin.Context) {
+	obj := dao.NewLoginConvertReport()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "LoginConvertReport", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 留存统计
+func LiveStatList(c *gin.Context) {
+	obj := dao.NewLiveStatList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "LiveStatList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 渠道留存统计
+func LiveStatListByPartner(c *gin.Context) {
+	obj := dao.NewLiveStatListByPartner()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "LiveStatListByPartner", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 渠道登录统计
+func LoginStatByPartner(c *gin.Context) {
+	obj := dao.NewLoginStatPartner()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "LoginStatByPartner", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 在线统计报表(小时)
+func OnlineStatReportChip(c *gin.Context) {
+	obj := dao.NewOnlineStatReportChip()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "onlineStatReportChip", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 同时在线统计报表(小时)
+func OnlineUserReportChip(c *gin.Context) {
+	obj := dao.NewOnlineUserReportChip()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "OnlineUserReportChip", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 游戏统计(小时)
+func GameStatHourChip(c *gin.Context) {
+	obj := dao.NewGameStatHourChip()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "gameStatHourChip", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 在线统计(每天)
+func OnlineStatListByDayChip(c *gin.Context) {
+	obj := dao.NewOnlineStatListByDayChip()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "onlineStatListByDay", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 留存统计
+func RetentionStatList(c *gin.Context) {
+	obj := dao.NewRetentionStatList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "RetentionStatList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 257 - 0
servers/adminserver/controller/track.go

@@ -0,0 +1,257 @@
+package controller
+
+import (
+	"bet24.com/servers/adminserver/badge"
+	"bet24.com/servers/adminserver/gift"
+	"bet24.com/servers/adminserver/item"
+	"bet24.com/servers/adminserver/shop"
+	"bet24.com/servers/adminserver/task"
+	"fmt"
+	"net/http"
+	"strconv"
+	"strings"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+// 获取轨迹产品id、道具id等信息
+func getTrackId(trackLevel, trackItem string) (oldItem, name string) {
+	var (
+		itemId    string
+		productId string
+		giftId    string
+		taskId    string
+		badgeId   string
+	)
+
+	switch trackLevel {
+	case "充值成功":
+		productId = trackItem
+
+	case "商城":
+		if strings.Contains(trackItem, "道具 --> 点击") {
+			oldItem = "道具 --> 点击"
+		} else if strings.Contains(trackItem, "购买弹窗 --> 打开shop/") {
+			oldItem = "购买弹窗 --> 打开shop/"
+		} else if strings.Contains(trackItem, "购买弹窗 --> 打开") {
+			oldItem = "购买弹窗 --> 打开"
+		} else if strings.Contains(trackItem, "购买弹窗 --> 点击购买") {
+			oldItem = "购买弹窗 --> 点击购买"
+		} else if strings.Contains(trackItem, "金币或钻石 --> 点击") {
+			oldItem = "金币或钻石 --> 点击"
+		}
+		if oldItem == "" {
+			log.Debug("track.getTrackId is empty ==>level=%s item=%s", trackLevel, trackItem)
+			return
+		}
+
+		switch oldItem {
+		case "道具 --> 点击":
+			fallthrough
+		case "购买弹窗 --> 打开":
+			itemId = strings.ReplaceAll(trackItem, oldItem, "")
+		default:
+			productId = strings.ReplaceAll(trackItem, oldItem, "")
+		}
+
+	case "新手充值":
+		if strings.Contains(trackItem, "点击") {
+			oldItem = "点击"
+		}
+		if oldItem == "" {
+			log.Debug("track.getTrackId is empty ==>level=%s item=%s", trackLevel, trackItem)
+			return
+		}
+
+		productId = strings.ReplaceAll(trackItem, oldItem, "")
+
+	case "首冲":
+		if strings.Contains(trackItem, "购买 --> ") {
+			oldItem = "购买 --> "
+		}
+		if oldItem == "" {
+			log.Debug("track.getTrackId is empty ==>level=%s item=%s", trackLevel, trackItem)
+			return
+		}
+
+		productId = strings.ReplaceAll(trackItem, oldItem, "")
+
+	case "背包":
+		if strings.Contains(trackItem, "道具 --> 点击") {
+			oldItem = "道具 --> 点击"
+		} else if strings.Contains(trackItem, "礼物 --> 点击") {
+			oldItem = "礼物 --> 点击"
+		}
+
+		if oldItem == "" {
+			log.Debug("track.getTrackId is empty ==>level=%s item=%s", trackLevel, trackItem)
+			return
+		}
+
+		switch oldItem {
+		case "道具 --> 点击":
+			fallthrough
+		case "礼物 --> 点击":
+			itemId = strings.ReplaceAll(trackItem, oldItem, "")
+		default:
+			productId = strings.ReplaceAll(trackItem, oldItem, "")
+		}
+
+	case "礼物赠送":
+		if strings.Contains(trackItem, "礼物Id:") {
+			oldItem = "礼物Id:"
+		}
+		if oldItem == "" {
+			log.Debug("track.getTrackId is empty ==>level=%s item=%s", trackLevel, trackItem)
+			return
+		}
+
+		giftId = strings.ReplaceAll(trackItem, oldItem, "")
+
+	case "送礼物":
+		if strings.Contains(trackItem, "赠送 --> 点击") {
+			oldItem = "赠送 --> 点击"
+		}
+
+		if oldItem == "" {
+			log.Debug("track.getTrackId is empty ==>level=%s item=%s", trackLevel, trackItem)
+			return
+		}
+
+		giftId = strings.ReplaceAll(trackItem, oldItem, "")
+
+	case "vip":
+		if strings.Contains(trackItem, "vip卡 --> 点击") {
+			oldItem = "vip卡 --> 点击"
+		}
+
+		if oldItem == "" {
+			log.Debug("track.getTrackId is empty ==>level=%s item=%s", trackLevel, trackItem)
+			return
+		}
+
+		itemId = strings.ReplaceAll(trackItem, oldItem, "")
+
+	case "任务":
+		if strings.Contains(trackItem, "领取 --> ") {
+			oldItem = "领取 --> "
+		} else if strings.Contains(trackItem, "前往 --> ") {
+			oldItem = "前往 --> "
+		}
+
+		if oldItem == "" {
+			log.Debug("track.getTrackId is empty ==>level=%s item=%s", trackLevel, trackItem)
+			return
+		}
+
+		taskId = strings.ReplaceAll(trackItem, oldItem, "")
+
+	case "徽章佩戴":
+		//if strings.Contains(trackItem, "Id:") {
+		//	oldItem = "Id:"
+		//}
+
+		if oldItem == "" {
+			log.Debug("track.getTrackId is empty ==>level=%s item=%s", trackLevel, trackItem)
+			return
+		}
+	}
+
+	if productId != "" {
+		if name = shop.GetProductName(productId); name == "" {
+			return
+		}
+		name = fmt.Sprintf("%s (商品id:%s)", name, productId)
+	} else if itemId != "" {
+		id, err := strconv.Atoi(itemId)
+		if err != nil {
+			log.Error("track.getTrackId itemId=%s err=%+v", itemId, err)
+			return
+		}
+
+		if name = item.GetItemName(id); name == "" {
+			return
+		}
+		name = fmt.Sprintf("%s (道具id:%d)", name, id)
+	} else if giftId != "" {
+		id, err := strconv.Atoi(giftId)
+		if err != nil {
+			log.Error("track.getTrackId giftId=%s err=%+v", giftId, err)
+			return
+		}
+		if name = gift.GetGiftName(id); name == "" {
+			return
+		}
+		name = fmt.Sprintf("%s (礼物id:%d)", name, id)
+	} else if taskId != "" {
+		id, err := strconv.Atoi(taskId)
+		if err != nil {
+			log.Error("track.getTrackId giftId=%s err=%+v", taskId, err)
+			return
+		}
+		if name = task.GetTaskName(id); name == "" {
+			return
+		}
+		name = fmt.Sprintf("%s (任务id:%d)", name, id)
+	} else if badgeId != "" {
+		id, err := strconv.Atoi(badgeId)
+		if err != nil {
+			log.Error("track.getTrackId giftId=%s err=%+v", badgeId, err)
+			return
+		}
+		if name = badge.GetBadgeName(id); name == "" {
+			return
+		}
+		name = fmt.Sprintf("%s (徽章id:%d)", name, id)
+	}
+
+	return
+}
+
+// 游戏轨迹记录
+func UserTrackList(c *gin.Context) {
+	obj := dao.NewUserTrackList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "userTrackList", err)
+		return
+	}
+	obj.DoAction()
+
+	for i, v := range obj.Out.List {
+		oldItem, name := getTrackId(v.Level, v.Item)
+		if name == "" {
+			continue
+		}
+
+		obj.Out.List[i].Item = fmt.Sprintf("%s %s", oldItem, name)
+	}
+
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 游戏轨迹统计
+func UserTrackStat(c *gin.Context) {
+	obj := dao.NewUserTrackStat()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "userTrackStat", err)
+		return
+	}
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 用户足迹
+func TrackList(c *gin.Context) {
+	obj := dao.NewTrackList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "TrackList", err)
+		return
+	}
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 187 - 0
servers/adminserver/controller/user.go

@@ -0,0 +1,187 @@
+package controller
+
+import (
+	waterPool "bet24.com/servers/micros/waterpool/proto"
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+// 后台登陆
+func Login(c *gin.Context) {
+	obj := dao.NewUserLogin()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "login", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	obj.Out.ErrorMsg = ""
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 获取页面列表
+func PageList(c *gin.Context) {
+	obj := dao.NewPageList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "pageList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	obj.Out.ErrorMsg = ""
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 获取管理用户信息
+func GetInfo(c *gin.Context) {
+	obj := dao.NewGetInfo()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getInfo", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 修改密码
+func UpdatePassword(c *gin.Context) {
+	obj := dao.NewUpdatePassword()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "updatePassword", err)
+		return
+	}
+
+	//判断2次密码是否一致
+	if obj.In.NewPassword != obj.In.NewPassword2 {
+		obj.Out.RetCode = 11
+		obj.Out.ErrorMsg = ""
+		c.JSON(http.StatusOK, obj.Out)
+		return
+	}
+
+	obj.DoAction(nil)
+	obj.Out.ErrorMsg = ""
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 校验页面
+func VerifyPage(c *gin.Context) {
+	obj := dao.NewVerifyPage()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "verifyPage", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	obj.Out.ErrorMsg = ""
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 管理用户列表
+func UserList(c *gin.Context) {
+	obj := dao.NewUserList()
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 删除后台管理用户
+func UserDel(c *gin.Context) {
+	obj := dao.NewUserDel()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "userDel", err)
+		return
+	}
+	obj.DoAction(nil)
+	obj.Out.ErrorMsg = ""
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 添加备注
+func UpdateMemo(c *gin.Context) {
+	obj := dao.NewUpdateMemo()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "updateMemo", err)
+		return
+	}
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 添加管理用户
+func UserAdd(c *gin.Context) {
+	obj := dao.NewUserAdd()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "userAdd", err)
+		return
+	}
+	obj.DoAction(nil)
+	obj.Out.ErrorMsg = ""
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 获取后台登录密码
+func GetPassword(c *gin.Context) {
+	obj := dao.NewGetPassword()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getPassword", err)
+		return
+	}
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 获取个人奖池
+func GetUserPrizePool(c *gin.Context) {
+	var req struct {
+		UserId int
+	}
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "getUserPrizePool", err)
+		return
+	}
+
+	value := waterPool.GetUserWaterPool(req.UserId)
+	c.JSON(http.StatusOK, value)
+	return
+}
+
+// 获取奖池日志列表
+func GetPrizePoolList(c *gin.Context) {
+	obj := dao.NewGetPrizePoolList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "getPrizePoolList", err)
+		return
+	}
+
+	obj.Out.Data = waterPool.GetUserWaterPoolGrantRecords(obj.In.UserId, obj.In.BeginTime,
+		obj.In.EndTime, obj.In.PageIndex, obj.In.PageSize)
+	c.JSON(http.StatusOK, obj.Out.Data)
+	return
+}
+
+// 发放个人奖池
+func SendPrizePool(c *gin.Context) {
+	obj := dao.NewSendPrizePool()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "sendPrizePool", err)
+		return
+	}
+
+	waterPool.GrantUserNewWaterPool(obj.In.UserId, obj.In.Value, obj.In.GenType)
+	c.JSON(http.StatusOK, "ok")
+	return
+}

+ 21 - 0
servers/adminserver/controller/utm.go

@@ -0,0 +1,21 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+// 流量渠道列表
+func UTMSourceList(c *gin.Context) {
+	list := dao.GetUTMSource()
+	c.JSON(http.StatusOK, struct {
+		RecordCount int
+		List        interface{}
+	}{
+		RecordCount: len(list),
+		List:        list,
+	})
+	return
+}

+ 48 - 0
servers/adminserver/controller/white.go

@@ -0,0 +1,48 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+// 白名单列表
+func WhiteList(c *gin.Context) {
+	obj := dao.NewWhiteList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "WhiteList", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 添加白名单
+func WhiteAdd(c *gin.Context) {
+	obj := dao.NewWhiteAdd()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "WhiteAdd", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, nil)
+	return
+}
+
+// 删除白名单
+func WhiteDel(c *gin.Context) {
+	obj := dao.NewWhiteDel()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "WhiteDel", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, nil)
+	return
+}

+ 74 - 0
servers/adminserver/controller/withdraw.go

@@ -0,0 +1,74 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+// 提现日志
+func WithdrawLog(c *gin.Context) {
+	obj := dao.NewWithdrawLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "WithdrawLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 提现统计
+func WithdrawStatList(c *gin.Context) {
+	obj := dao.NewWithdrawStatList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "WithdrawStatList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 提现排行
+func WithdrawRank(c *gin.Context) {
+	obj := dao.NewWithdrawRank()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "WithdrawRank", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 提现审核列表
+func WithdrawAuditList(c *gin.Context) {
+	obj := dao.NewWithdrawAuditList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "WithdrawAuditList", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 提现日志
+func WithdrawFlashLog(c *gin.Context) {
+	obj := dao.NewWithdrawFlashLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "WithdrawFlashLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}

+ 27 - 0
servers/adminserver/controller/xwuserinfo.go

@@ -0,0 +1,27 @@
+package controller
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"bet24.com/servers/adminserver/dao"
+	"github.com/gin-gonic/gin"
+)
+
+//闲玩统计
+func XwInfoStat(c *gin.Context) {
+	obj := dao.NewXwInfoStat()
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+}
+
+//闲玩用户信息
+func XwUserInfoList(c *gin.Context) {
+	obj := dao.NewXwUserInfoList()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "xwUserInfoList", err)
+		return
+	}
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+}

+ 65 - 0
servers/adminserver/coupon/controller.go

@@ -0,0 +1,65 @@
+package coupon
+
+import (
+	"net/http"
+
+	"bet24.com/log"
+	"github.com/gin-gonic/gin"
+)
+
+func CouponRank(c *gin.Context) {
+	obj := NewUserCouponRank()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "CouponRank", err)
+		return
+	}
+
+	obj.DoAction()
+	c.JSON(http.StatusOK, obj.Out)
+}
+
+func CouponLog(c *gin.Context) {
+	obj := NewUserCouponLog()
+	if err := c.ShouldBind(&obj.In); err != nil {
+		log.Debug("%s shouldBind err %v", "CouponLog", err)
+		return
+	}
+
+	obj.DoAction(nil)
+	c.JSON(http.StatusOK, obj.Out)
+	return
+}
+
+// 天统计
+func DayStat(c *gin.Context) {
+	var req req_base
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "coupon.DayStat", err)
+		return
+	}
+
+	list := mgr.dayStat(req.BeginTime, req.EndTime)
+	c.JSON(http.StatusOK, struct {
+		List interface{}
+	}{
+		List: list,
+	})
+	return
+}
+
+// 小时统计
+func HourStat(c *gin.Context) {
+	var req req_base
+	if err := c.ShouldBind(&req); err != nil {
+		log.Debug("%s shouldBind err %v", "coupon.HourStat", err)
+		return
+	}
+
+	list := mgr.hourStat(req.BeginTime, req.EndTime)
+	c.JSON(http.StatusOK, struct {
+		List interface{}
+	}{
+		List: list,
+	})
+	return
+}

+ 87 - 0
servers/adminserver/coupon/couponmgr.go

@@ -0,0 +1,87 @@
+package coupon
+
+import (
+	"fmt"
+	"sort"
+	"time"
+
+	"bet24.com/log"
+)
+
+var mgr *couponManager
+
+type couponManager struct {
+	day_list  map[string]*statInfo
+	hour_list map[string][]*statInfo
+}
+
+func Run() {
+	mgr = new(couponManager)
+	mgr.day_list = make(map[string]*statInfo)
+	mgr.hour_list = make(map[string][]*statInfo)
+}
+
+func (this *couponManager) dayStat(beginTime, endTime string) []*statInfo {
+	var list []*statInfo
+	end, _ := time.Parse(dateFormat, endTime)
+	for begin, _ := time.Parse(dateFormat, beginTime); !begin.After(end); begin = begin.AddDate(0, 0, 1) {
+		dateStr := begin.Format(dateFormat)
+		key := fmt.Sprintf("%s", dateStr)
+		v, ok := this.day_list[key]
+		if ok {
+			list = append(list, v)
+			continue
+		}
+
+		for _, v := range statByDay(dateStr) {
+			log.Debug("couponmgr.dayStat ==> %+v", v)
+			if begin.Format(dateFormat) == time.Now().Format(dateFormat) {
+				list = append(list, v)
+				continue
+			}
+
+			key = fmt.Sprintf("%s", v.DateFlag)
+			this.day_list[key] = v
+			list = append(list, v)
+		}
+	}
+
+	sort.SliceStable(list, func(i, j int) bool {
+		return list[i].DateFlag > list[j].DateFlag
+	})
+
+	return list
+}
+
+func (this *couponManager) hourStat(beginTime, endTime string) []*statInfo {
+	var list []*statInfo
+	end, _ := time.Parse(dateFormat, endTime)
+
+	for begin, _ := time.Parse(dateFormat, beginTime); !begin.After(end); begin = begin.AddDate(0, 0, 1) {
+		dateStr := begin.Format(dateFormat)
+		key := fmt.Sprintf("%s", dateStr)
+		v, ok := this.hour_list[key]
+		if ok {
+			list = append(list, v...)
+			continue
+		}
+
+		for _, v := range statByHour(dateStr) {
+			log.Debug("couponmgr.hourStat ==> %+v", v)
+			if begin.Format(dateFormat) == time.Now().Format(dateFormat) {
+				list = append(list, v)
+				continue
+			}
+
+			key = fmt.Sprintf("%s", v.DateFlag)
+			this.hour_list[key] = append(this.hour_list[key], v)
+			list = append(list, v)
+		}
+	}
+
+	sort.SliceStable(list, func(i, j int) bool {
+		return list[i].DateFlag > list[j].DateFlag
+	})
+
+	return list
+}

+ 16 - 0
servers/adminserver/coupon/data.go

@@ -0,0 +1,16 @@
+package coupon
+
+const dateFormat = "2006-01-02"
+
+type req_base struct {
+	BeginTime string // 开始时间
+	EndTime   string // 截止时间
+}
+
+// 统计信息
+type statInfo struct {
+	DateFlag    string // 日期标识
+	Remark      string // 备注
+	CouponCount int    // 红包券数
+	UserCount   int    // 用户数
+}

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.