This commit is contained in:
jiayuqi7813
2022-05-21 23:29:23 +08:00
parent b8859af6d8
commit 7cb171bc90
83 changed files with 1687 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

1
.idea/.name generated Normal file
View File

@@ -0,0 +1 @@
main.go

12
.idea/dataSources.xml generated Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="snctf.db" uuid="1f1ae82f-c0e0-4fcb-a9c5-2156507a34a7">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/snctf.db</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/snctf.iml" filepath="$PROJECT_DIR$/.idea/snctf.iml" />
</modules>
</component>
</project>

9
.idea/snctf.iml generated Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

38
api/admin/auth.go Normal file
View File

@@ -0,0 +1,38 @@
package admin
import (
"github.com/gin-gonic/gin"
."main.go/type"
"main.go/api"
)
// AuthRequired 用于管理员权限控制的中间件
func AuthRequired()gin.HandlerFunc {
return func(c *gin.Context) {
session, err := api.Store.Get(c.Request, "SNCTFSESSID")
if err != nil {
c.JSON(200, gin.H{"code": 400, "msg": "Get SNCTFSESSID error"})
c.Abort()
return
}
user, ok := session.Values["user"].(User)
if !ok {
c.JSON(200, gin.H{"code": 400, "msg": "No session"})
c.Abort()
return
}
if user.Role != 1 {
c.JSON(200, gin.H{"code": 400, "msg": "Unauthorized access!"})
c.Abort()
return
}
c.Next()
}
}

79
api/admin/challenge.go Normal file
View File

@@ -0,0 +1,79 @@
package admin
import (
"fmt"
"github.com/gin-gonic/gin"
"main.go/api"
db "main.go/database"
. "main.go/type"
"strings"
)
// CrDb 专门用作给数据替换。
type CrDb struct {
Name string `json:"name" binding:"required"`
Score int `json:"score" binding:"required"`
Flag string `json:"flag"` // 暂时一个题只能一个flag
Description string `json:"description"`
Attachment string `json:"attachment"`
Category string `json:"category" binding:"required"`
Tags string `json:"tags"`
Hints string `json:"hints"`
Visible int `json:"visible"`
}
//NewChallenge 新建一个题目
func NewChallenge(c *gin.Context){
var request ChallengeRequest
if err := c.ShouldBindJSON(&request); err != nil {
fmt.Println(err)
c.JSON(400, gin.H{"code": 400, "msg": "Request format wrong!"})
return
}
challenge := &Challenge{
Name: request.Name,
Score: request.Score,
Flag: request.Flag,
Description: request.Description,
Attachment: request.Attachment,
Category: request.Category,
Tags: request.Tags,
Hints: request.Hints,
Visible: request.Visible,
}
if err := addChallenge(challenge); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Add challenge failure!"})
return
}
c.JSON(200, gin.H{"code": 200, "msg": "Add challenge success!"})
}
//addChallenge 添加题目内容
func addChallenge(c *Challenge) error {
api.Link()
DB := db.DBsnctf
// 使用逗号分隔字符串
attachmentString := strings.Join(c.Attachment, ",")
hintString := strings.Join(c.Hints, ",")
crdb := &CrDb{
Name: c.Name,
Score: c.Score,
Flag: c.Flag,
Description: c.Description,
Attachment: attachmentString,
Category: c.Category,
Tags: c.Tags,
Hints: hintString,
Visible: c.Visible,
}
//插入数据
err := DB.Table("challenge").Create(crdb).Error
//command := "INSERT INTO challenge (name,score,flag,description,attachment,category,tags,hints,visible) VALUES (?,?,?,?,?,?,?,?,?);"
//err := DB.Debug().Raw(command,c.Name, c.Score, c.Flag, c.Description, attachmentString, c.Category, c.Tags, hintString, c.Visible).Error
if err != nil {
return err
}
return nil
}

58
api/category.go Normal file
View File

@@ -0,0 +1,58 @@
package api
import (
"github.com/gin-gonic/gin"
db "main.go/database"
)
// GetCategories 获取所有题目分类。
func GetCategories(c *gin.Context) {
var categories []string
if err := getAllCategories(&categories); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get categories failure!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": categories})
}
//getAllCategories 操作数据库所有题目分类
func getAllCategories(categories *[]string) error {
Link()
DB := db.DBsnctf
rows,err:= DB.Raw("select category from category").Rows()
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var category string
if err := rows.Scan(&category); err != nil {
return err
}
*categories = append(*categories, category)
}
return rows.Err()
}
// CheckCategory 检查类别是否正确
func CheckCategory(c string) bool {
var categories []string
if err := getAllCategories(&categories); err != nil {
return false
}
for _, category := range categories {
if category == c {
return true
}
}
return false
}

84
api/challenge.go Normal file
View File

@@ -0,0 +1,84 @@
package api
import (
"errors"
"fmt"
"github.com/gin-gonic/gin"
db "main.go/database"
. "main.go/type"
"strings"
)
//GetAllChallenges 获取全部题目
func GetAllChallenges(c * gin.Context){
var challenges []ChallengeResponse
if err := getAllChallenges(c, &challenges); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get all challenges failure!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": challenges})
}
//GetChallengesByCategory 获取某个分类下的题目
func GetChallengesByCategory(c *gin.Context){
category := c.Param("category")
if matched := CheckCategory(category); !matched {
c.JSON(400, gin.H{"code": 400, "msg": "Wrong category!"})
return
}
var challenges []ChallengeResponse
if err := getAllChallenges(c, &challenges); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get all challenges failure!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": challenges})
}
// getAllChallenges 操作数据库获取所有题目。
func getAllChallenges(c *gin.Context, challenges *[]ChallengeResponse) error {
var attachmentString, hints string
Link()
DB := db.DBsnctf
rows,err := DB.Raw("SELECT id, name, score, description, attachment, category, tags, hints FROM challenge WHERE visible=1;").Rows()
if err != nil {
return err
}
defer rows.Close()
for rows.Next(){
var challenge ChallengeResponse
err = rows.Scan(&challenge.ID, &challenge.Name, &challenge.Score, &challenge.Description, &attachmentString, &challenge.Category, &challenge.Tags, &hints)
fmt.Println(err)
if err != nil {
return err
}
// 解析为切片
challenge.Attachment = strings.Split(attachmentString, ",")
challenge.Hints = strings.Split(hints, ",")
solverCount, err := getSolverCount(challenge.ID)
if err != nil {
return err
}
challenge.SolverCount = solverCount
session, err := Store.Get(c.Request, "SNCTFSESSID")
if err != nil {
c.JSON(200, gin.H{"code": 400, "msg": "Get SNCTFSESSID error"})
return err
}
user, ok := session.Values["user"].(User)
if !ok {
c.JSON(200, gin.H{"code": 400, "msg": "No session"})
return errors.New("no session")
}
challenge.IsSolved = hasAlreadySolved(user.ID, challenge.ID)
*challenges = append(*challenges, challenge)
}
return rows.Err()
}

39
api/notice.go Normal file
View File

@@ -0,0 +1,39 @@
package api
import (
"github.com/gin-gonic/gin"
. "main.go/type"
db "main.go/database"
)
// GetAllNotices 获取所有的公告
func GetAllNotices(c *gin.Context) {
var notices []Notice
if err := getAllNotices(&notices); err != nil {
c.JSON(200, gin.H{"code": 400, "msg": "Get all notices failure!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": notices})
}
func getAllNotices(notices *[]Notice) error {
Link()
DB := db.DBsnctf
command := "SELECT id, title, content, created_at FROM notice ORDER BY created_at ASC;"
rows, err := DB.Raw(command).Rows()
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var b Notice
err = rows.Scan(&b.ID, &b.Title, &b.Content, &b.CreatedAt)
if err != nil {
return err
}
*notices = append(*notices, b)
}
return rows.Err()
}

78
api/score.go Normal file
View File

@@ -0,0 +1,78 @@
package api
import (
"github.com/gin-gonic/gin"
db "main.go/database"
"main.go/tools"
. "main.go/type"
)
//GetAllScore 获取所有的积分,按照积分降序排列
func GetAllScore(c *gin.Context){
var s ScoreResponse
var scores []ScoreResponse
Link()
DB :=db.DBsnctf
//rows,err := DB.Raw("SELECT s.id, s.username, s.score FROM score AS s, user AS u WHERE u.hidden = 0 AND s.username = u.username ORDER BY s.score DESC;").Scan(&s).Rows()
rows,err := DB.Debug().Raw("SELECT s.id, s.username, s.score FROM score AS s, user AS u WHERE u.hidden = 0 AND s.username = u.username ORDER BY s.score DESC;").Rows()
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get all score error!"})
return
}
// 循环读取数据
for rows.Next() {
rows.Scan(&s.ID, &s.Username, &s.Score)
scores = append(scores, s)
}
c.JSON(200, gin.H{"code": 200, "data": scores})
}
//GetScoreByUserId 获取用户分数
func GetScoreByUserId(c *gin.Context) {
var score int
Link()
DB := db.DBsnctf
//获取用户id
id := c.Params.ByName("id")
if id == "" {
c.JSON(400, gin.H{"code": 400, "msg": "Need id!"})
return
}
//检查id是否合法
if !tools.CheckID(id) {
c.JSON(400, gin.H{"code": 400, "msg": "ID format error!"})
return
}
//查询用户信息
err := DB.Raw("SELECT s.score FROM score AS s, user AS u WHERE u.id = ? AND u.hidden = 0 AND u.username = s.username LIMIT 1;", id).Scan(&score).Error
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get info error!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": score})
}
//GetSelfScoreAndRank 获取当前登录用户的分数和排名
func GetSelfScoreAndRank(c *gin.Context){
var scoreAndRank ScoreRankResponse
DB := db.DBsnctf
session, err := Store.Get(c.Request, "SNCTFSESSID")
if err != nil {
c.JSON(200, gin.H{"code": 400, "msg": "Get SNCTFSESSID error"})
return
}
user, ok := session.Values["user"].(User)
if !ok {
c.JSON(200, gin.H{"code": 400, "msg": "No session"})
return
}
err = DB.Raw("SELECT score, (SELECT count(DISTINCT score) FROM score WHERE score>=s.score) AS rank FROM score AS s,user AS u WHERE u.id = ? AND u.username = s.username ORDER BY score DESC LIMIT 1;",user.ID).Scan(&scoreAndRank).Error
if err != nil {
c.JSON(200, gin.H{"code": 400, "msg": "Get info error!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": scoreAndRank})
}

27
api/session.go Normal file
View File

@@ -0,0 +1,27 @@
package api
import (
"encoding/gob"
"github.com/gorilla/securecookie"
"github.com/gorilla/sessions"
. "main.go/type"
)
// sessions 存储于文件系统
var Store *sessions.FilesystemStore
func init() {
Store = sessions.NewFilesystemStore("./sessions", securecookie.GenerateRandomKey(32))
Store.Options = &sessions.Options{
Domain: "",
Path: "/",
MaxAge: 24 * 60 * 60, // 1 day
// SameSite: http.SameSiteNoneMode,
Secure: false,
HttpOnly: false,
}
gob.Register(User{})
}

153
api/solve.go Normal file
View File

@@ -0,0 +1,153 @@
package api
import (
"github.com/gin-gonic/gin"
db "main.go/database"
."main.go/type"
"strconv"
)
//GetAllSolves 获取所有解题记录
func GetAllSolves(c *gin.Context){
var solves []SolveResponse
if err := getAllSolves(&solves); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get all solves failure!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": solves})
}
//GetSolvesByCid 获取某个用户的所有解题记录
func GetSolvesByCid(c *gin.Context){
var solves []SolveResponse
cid, err := strconv.ParseInt(c.Param("cid"), 10, 64)
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get solves failure!"})
return
}
if err := getSolvesByCid(&solves, int(cid)); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get solves failure!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": solves})
}
// GetSolvesByUid 根据用户id获取正确的flag提交记录。
func GetSolvesByUid(c *gin.Context) {
uid, err := strconv.ParseInt(c.Param("uid"), 10, 64)
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Wrong uid!"})
return
}
if uid == 1 {
c.JSON(400, gin.H{"code": 400, "msg": "Not allowed!"})
return
}
var solves []SolveResponse
if err := getSolvesByUid(&solves, int(uid)); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get specified solves failure!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": solves})
}
// GetSelfSolves 获取当前用户的所有解题记录
func GetSelfSolves(c *gin.Context){
var solves []SolveResponse
session, err := Store.Get(c.Request, "SNCTFSESSID")
if err != nil {
c.JSON(200, gin.H{"code": 400, "msg": "Get SNCTFSESSID error"})
return
}
user, ok := session.Values["user"].(User)
if !ok {
c.JSON(200, gin.H{"code": 400, "msg": "No session"})
return
}
if err := getSolvesByUid(&solves, user.ID); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get self solves failure!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": solves})
}
// getSolverCount 操作数据库获取指定id题目的解出人数。
func getSolverCount(id int) (count int, err error) {
Link()
DB := db.DBsnctf
//SELECT COUNT(*) FROM solve WHERE cid = ?;
err = DB.Table("solve").Select("COUNT(*)").Where("cid = ?", id).Scan(&count).Error
if err != nil {
return 0, err
}
return count, nil
}
// getAllSolves 操作数据库获取所有正确的提交记录,按提交时间从早到晚排序。
func getAllSolves(solves *[]SolveResponse) error {
DB :=db.DBsnctf
rows,err := DB.Raw("SELECT s.id, s.uid, s.cid, u.username, c.name, s.submitted_at, c.score FROM solve AS s, user AS u, challenge AS c WHERE u.hidden=0 AND s.uid=u.id AND s.cid=c.id ORDER BY s.submitted_at ASC;").Rows()
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var s SolveResponse
err = rows.Scan(&s.ID, &s.Uid, &s.Cid, &s.Username, &s.ChallengeName, &s.SubmittedAt, &s.Score)
if err != nil {
return err
}
*solves = append(*solves, s)
}
return rows.Err()
}
// getSolvesByUid 操作数据库根据用户id获取正确的flag提交记录按提交时间从早到晚排序。
func getSolvesByUid(solves *[]SolveResponse, uid int) error {
DB :=db.DBsnctf
rows,err := DB.Debug().Raw("SELECT s.id, s.uid, s.cid, u.username, c.name, s.submitted_at, c.score FROM solve AS s, user AS u, challenge AS c WHERE u.hidden=0 AND s.uid=? AND u.id=s.uid AND c.id=s.cid ORDER BY s.submitted_at ASC;",uid).Rows()
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var s SolveResponse
err = rows.Scan(&s.ID, &s.Uid, &s.Cid, &s.Username, &s.ChallengeName, &s.SubmittedAt, &s.Score)
if err != nil {
return err
}
*solves = append(*solves, s)
}
return rows.Err()
}
// getSolvesByCid 操作数据库根据题目id获取正确的提交记录按提交时间从早到晚排序。
func getSolvesByCid(solves *[]SolveResponse, cid int) error {
DB :=db.DBsnctf
rows,err := DB.Raw("SELECT s.id, s.uid, s.cid, u.username, c.name, s.submitted_at, c.score FROM solve AS s, user AS u, challenge AS c WHERE u.hidden=0 AND s.cid=? AND u.id=s.uid AND c.id=s.cid ORDER BY s.submitted_at ASC;",cid).Rows()
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var s SolveResponse
err = rows.Scan(&s.ID, &s.Uid, &s.Cid, &s.Username, &s.ChallengeName, &s.SubmittedAt, &s.Score)
if err != nil {
return err
}
*solves = append(*solves, s)
}
return rows.Err()
}

211
api/submissions.go Normal file
View File

@@ -0,0 +1,211 @@
package api
import (
"fmt"
"github.com/gin-gonic/gin"
db "main.go/database"
"main.go/tools"
. "main.go/type"
"math"
)
// hasAlreadySolved 检查某道题是否已经被某用户解出。
func hasAlreadySolved(uid int, cid int) (exists bool) {
Link()
DB := db.DBsnctf
err := DB.Raw("SELECT EXISTS(SELECT 1 FROM solve WHERE uid=? AND cid=?)",uid,cid).Scan(&exists).Error
if err != nil {
return false
}
return exists
}
// isChallengeExisted 检查数据库中是否存在某个题目。
func isChallengeExisted(id int) (exists bool) {
Link()
DB := db.DBsnctf
command := "SELECT EXISTS(SELECT 1 FROM challenge WHERE id = ?);"
err := DB.Raw(command,id).Scan(&exists).Error
if err != nil {
return false
}
return exists
}
//addSubmission 添加一个提交记录。
func addSubmission(s *Submission) error {
Link()
DB := db.DBsnctf
err := DB.Table("submission").Create(&s).Error
if err != nil {
return err
}
return nil
}
// getFlag 根据题目id获取该题的flag
func getFlag(id int) (flag string, err error) {
Link()
DB := db.DBsnctf
err = DB.Table("challenge").Select("flag").Where("id = ?",id).Find(&flag).Error
if err != nil {
return "", err
}
return flag, nil
}
// addSolve 操作数据库加入一条正确的flag提交记录。
func addSolve(s *Solve) error {
DB := db.DBsnctf
err := DB.Table("solve").Create(&s).Error
if err != nil {
return err
}
return nil
}
// addUserScore 操作数据库为指定用户增加某题的分数。
func addUserScore(username string, cid int) error {
var newScore int
DB := db.DBsnctf
err := DB.Table("challenge").Select("score").Where("id = ?", cid).Find(&newScore).Error
if err != nil {
return err
}
command := "UPDATE score SET score=score+? WHERE username=?"
err = DB.Exec(command, newScore, username).Error
if err != nil {
return err
}
return nil
}
// updateUserScores 操作数据库更新解出用户的分数。
func updateUserScores(reducedScore, cid int) error {
DB:=db.DBsnctf
command := "UPDATE score SET score=score-? WHERE EXISTS(SELECT 1 FROM user,solve WHERE user.id=solve.uid AND score.username=user.username AND solve.cid=?);"
err := DB.Exec(command, reducedScore, cid).Error
return err
}
// editChallengeScore 操作数据库修改指定题目增的动态分数。
func editChallengeScore(cid int) (reducedScore int, err error) {
DB := db.DBsnctf
var currentScore int
err = DB.Table("challenge").Select("score").Where("id = ?", cid).Find(&currentScore).Error
command := "SELECT score FROM challenge WHERE id=? LIMIT 1;"
if err != nil {
return 0, err
}
solverCount, err := getSolverCount(cid)
if err != nil {
return 0, err
}
// According to https://github.com/o-o-overflow/scoring-playground
newScore := int(100 + (1000-100)/(1.0+float64(solverCount)*0.04*math.Log(float64(solverCount))))
reducedScore = currentScore - newScore
command = "UPDATE challenge SET score=? WHERE id=?;"
err = DB.Exec(command, newScore, cid).Error
if err != nil {
return 0, err
}
return reducedScore, nil
}
// SubmitFlag 提交flag
func SubmitFlag(c *gin.Context) {
var request SubmissionRequest
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Request format wrong!"})
return
}
session,err := Store.Get(c.Request, "SNCTFSESSID")
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "GET SNCTFSESSID error!"})
return
}
user,ok := session.Values["user"].(User)
if !ok {
c.JSON(400, gin.H{"code": 400, "msg": "GET user error!"})
return
}
// 检查题目是否存在
if !isChallengeExisted(request.Cid) {
c.JSON(400, gin.H{"code": 400, "msg": "Challenge not existed!"})
return
}
// Submission记录
solvedTime := tools.Timestamp()
submission := &Submission{
UserID: user.ID,
ChallengeID: request.Cid,
Flag: request.Flag,
IP: c.ClientIP(),
Time: solvedTime,
}
err = addSubmission(submission)
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Record submission failure!"})
return
}
// 是否已经解出该题
if hasAlreadySolved(user.ID, request.Cid) {
c.JSON(400, gin.H{"code": 400, "msg": "Already solved!"})
return
}
// 获取flag
flag, err := getFlag(request.Cid)
if err != nil {
fmt.Println(err)
c.JSON(400, gin.H{"code": 400, "msg": "Get flag failure!"})
return
}
// 检查flag是否正确
if flag != request.Flag {
c.JSON(400, gin.H{"code": 400, "msg": "Wrong flag!"})
return
}else {
// Solve记录
solve := &Solve{
UserID: user.ID,
ChallengeID: request.Cid,
Time: solvedTime,
}
err = addSolve(solve)
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Record solve failure!"})
return
}
//加分
err = addUserScore(user.Username, request.Cid)
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Add score failure!"})
return
}
// 题目动态分数
reducedScore, err := editChallengeScore(request.Cid)
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Edit challenge score failure!"})
return
}
//更新所有用户分数
err = updateUserScores(reducedScore, request.Cid)
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Update user scores failure!"})
return
}
c.JSON(200, gin.H{"code": 200, "msg": "Correct flag!"})
return
}
}

296
api/user.go Normal file
View File

@@ -0,0 +1,296 @@
package api
import (
"fmt"
"github.com/gin-gonic/gin"
_ "gorm.io/driver/sqlite"
db "main.go/database"
"main.go/tools"
. "main.go/type"
"regexp"
"unicode/utf8"
)
//连接数据库
func Link() {
err := db.Inimysql()
if err != nil{
panic(err)
}
}
func Login(c * gin.Context) {
var request LoginRequest
var user User
Link()
DB := db.DBsnctf
DB.AutoMigrate(&User{})
//用ShouldBindJSON解析绑定传入的Json数据。
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Bind json error!"})
return
}
//code 0用户名不存在
//code 1用户名或密码错误
err := DB.Take(&user,"username = ?",request.Username).Error
if err != nil {
c.JSON(200,gin.H{
"Error":true,
"Msg":"登陆失败",
"Code": 0,
})
return
}
//判断md5值与数据库内容是否相同
if user.Password != tools.MD5(request.Password){
c.JSON(200,gin.H{
"Error":true,
"Msg":"用户名或密码错误",
"Code": 1,
})
return
}
//身份认证结束
//session
// 设置session
session, _ := Store.Get(c.Request, "SNCTFSESSID")
user.Password = ""
// 根据remember值设置session有效期
if request.Remember {
session.Options.MaxAge = 7 * 24 * 60 * 60 // 7 days
} else {
session.Options.MaxAge = 24 * 60 * 60 // 1 day
}
//保存session
session.Values["user"] = user
err = session.Save(c.Request, c.Writer)
fmt.Println(err)
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Save SNCTFSESSID error"})
return
}
//登录成功
c.JSON(200, gin.H{"code": 200, "username": user.Username, "role": user.Role, "msg": "Login success!"})
}
func Register(c *gin.Context) {
var request RegisterRequest
var user User
var score ScoreResponse
Link()
DB := db.DBsnctf
err := DB.AutoMigrate(&User{})
if err != nil {
return
}
//用ShouldBindJSON解析绑定传入的Json数据。
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Bind json error!"})
return
}
//限制传入用户名为中文、数字、大小写字母下划线和横杠1到10位
if !checkUsername(request.Username) {
c.JSON(200, gin.H{
"Error": true,
"Msg": "用户名不符合规范",
"Code": 2,
})
return
}
//限制密码长度6到20位
if !checkPassword(request.Password) {
c.JSON(400, gin.H{"code": 400, "msg": "Password format error!"})
return
}
//限制传入邮箱符合格式
if !checkEmail(request.Email) {
c.JSON(400, gin.H{"code": 400, "msg": "Email format error!"})
return
}
//判断用户名是否已被使用
if isNameExisted(user, request.Username) {
c.JSON(200, gin.H{"code": 1000, "msg": "Username has already been used!"})
return
}
//判断邮箱是否已被使用
if isEmailExisted(user, request.Email) {
c.JSON(200, gin.H{"code": 1001, "msg": "Email has already been used!"})
return
}
user.Token = tools.Token()
user.Username = request.Username
user.Password = tools.MD5(request.Password)
user.Email = request.Email
user.Created = tools.Timestamp()
score.Score = 0
score.Username =request.Username
//创建数据
err1 := DB.Table("user").Create(&user).Error
err2 := DB.Table("score").Create(&score).Error
if err1 != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Register error!"})
return
}
if err2 != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Register error!"})
return
}
c.JSON(200, gin.H{
"success": "注册成功",
})
}
// Logout 实现用户注销登陆
func Logout(c *gin.Context) {
var user User
session, err := Store.Get(c.Request, "SNCTFSESSID")
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get CTFGOSESSID error"})
return
}
user, ok := session.Values["user"].(User)
if !ok {
c.JSON(400, gin.H{"code": 400, "msg": "No session"})
return
}
session.Options.MaxAge = -1
err = session.Save(c.Request, c.Writer)
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Save CTFGOSESSID error"})
return
}
fmt.Sprintf("[%s] logout success!", user.Username)
c.JSON(200, gin.H{"code": 200, "msg": "Logout success!"})
}
//GetInfoByUserId 获取用户信息
func GetInfoByUserId(c *gin.Context) {
var info PublicInfoResponse
Link()
DB := db.DBsnctf
//获取用户id
id := c.Params.ByName("id")
if id == "" {
c.JSON(400, gin.H{"code": 400, "msg": "Need id!"})
return
}
//检查id是否合法
if !tools.CheckID(id) {
c.JSON(400, gin.H{"code": 400, "msg": "ID format error!"})
return
}
err := DB.Debug().Raw("SELECT username,affiliation,country,team_id FROM user WHERE id = ? LIMIT 1", id).Scan(&info).Error
//err := DB.Where("id = ?", id).First(user).Error
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get info error!"})
return
}
c.JSON(200, gin.H{"code": 200, "data": info})
}
// checkUsername 验证用户名是否符合中文数字字母下划线横杠长度1到10位返回true或false
func checkUsername(username string) bool {
if !(utf8.RuneCountInString(username) > 0) || !(utf8.RuneCountInString(username) < 11) {
return false
}
pattern := `^[-\w\p{Han}]+$`
reg := regexp.MustCompile(pattern)
return reg.MatchString(username)
}
// checkEmail 验证是否符合邮箱格式返回true或false
func checkEmail(email string) bool {
pattern := `^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$`
reg := regexp.MustCompile(pattern)
return reg.MatchString(email)
}
// checkPassword 验证密码是否符合长度6到20位返回true或false
func checkPassword(password string) bool {
if !(utf8.RuneCountInString(password) > 5) || !(utf8.RuneCountInString(password) < 21) {
return false
}
return true
}
// isNameExisted 判断用户名是否已经被占用被占用返回true未被占用则返回false
func isNameExisted(user User, username string) bool {
Link()
DB := db.DBsnctf
err := DB.First(&user,"Username = ?",username).Error
if err != nil {
return false
}
return true
}
// isNameExisted 判断邮箱是否已经被占用被占用返回true未被占用则返回false
func isEmailExisted(user User, email string) bool {
Link()
DB := db.DBsnctf
err := DB.First(&user,"Email = ?",email).Error
if err != nil {
return false
}
return true
}
// Session 获取当前用户session信息
func Session(c *gin.Context) {
var user User
// 默认在此之前已经通过了中间件的session权限验证
session, _ := Store.Get(c.Request, "SNCTFSESSID")
user = session.Values["user"].(User)
c.JSON(200, gin.H{"code": 200, "data": user})
}
//下面是身份认证用 AUTH部分
// AuthRequired 用于普通用户权限控制的中间件
func AuthRequired()gin.HandlerFunc{
return func(c *gin.Context) {
session, err := Store.Get(c.Request, "SNCTFSESSID")
if err != nil {
c.JSON(400, gin.H{"code": 400, "msg": "Get SNCTFSESSID error"})
c.Abort()
return
}
user, ok := session.Values["user"].(User)
if !ok {
c.JSON(400, gin.H{"code": 400, "msg": "No session"})
c.Abort()
return
}
if user.Role != 0&&user.Role!=1{
c.JSON(400, gin.H{"code": 400, "msg": "Permission denied"})
c.Abort()
return
}
c.Next()
}
}

30
database/db.go Normal file
View File

@@ -0,0 +1,30 @@
package database
import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
//定义全局数据库
var (
DBsnctf *gorm.DB
)
//定义全局数据库连接
func Inimysql()(err error){
DBsnctf, err = gorm.Open(sqlite.Open("snctf.db"), &gorm.Config{
NamingStrategy: schema.NamingStrategy{
SingularTable: true, // 使用单数表名
},
})
if err != nil {
panic("failed to connect database")
}
return
}
func DBLink() {
err := Inimysql()
if err != nil{
panic(err)
}
}

31
go.mod Normal file
View File

@@ -0,0 +1,31 @@
module main.go
go 1.17
require (
github.com/gin-gonic/gin v1.7.7
github.com/gorilla/securecookie v1.1.1
github.com/gorilla/sessions v1.2.1
gorm.io/driver/sqlite v1.3.2
gorm.io/gorm v1.23.5
)
require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/golang/protobuf v1.3.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mattn/go-sqlite3 v1.14.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
)

73
go.sum Normal file
View File

@@ -0,0 +1,73 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.3.2 h1:nWTy4cE52K6nnMhv23wLmur9Y3qWbZvOBz+V4PrGAxg=
gorm.io/driver/sqlite v1.3.2/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U=
gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM=
gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=

0
identifier.sqlite Normal file
View File

7
main.go Normal file
View File

@@ -0,0 +1,7 @@
package main
import "main.go/routers"
func main() {
routers.Initrouter()
}

72
routers/router.go Normal file
View File

@@ -0,0 +1,72 @@
package routers
import (
"github.com/gin-gonic/gin"
"main.go/api"
"main.go/api/admin"
)
func Initrouter(){
router := gin.Default()
api_v1 := router.Group("/api/v1")
//公共接口(无需登录)
public := api_v1.Group("")
{
//用户登录
public.POST("/login",api.Login)
//用户注册
public.POST("/register",api.Register)
//用户登出
public.GET("/logout",api.Logout)
//获取指定id用户可公开信息
public.GET("/user/:id",api.GetInfoByUserId)
//获取指定id用户分数
public.GET("/score/:id",api.GetScoreByUserId)
//获取所有用户分数,降序排列
public.GET("/score",api.GetAllScore)
//获取全部公告
public.GET("/notice",api.GetAllNotices)
}
// 普通用户api需要用户登陆且Role=0才能访问
personal := api_v1.Group("/user")
personal.Use(api.AuthRequired())
{
// 获取当前用户信息
personal.GET("/session", api.Session)
// 获取题目分类
personal.GET("/category", api.GetCategories)
// 获取所有题目信息
personal.GET("/challenges/all", api.GetAllChallenges)
// 获取指定分类题目信息
personal.GET("/challenges/:category", api.GetChallengesByCategory)
// 提交flag
personal.POST("/submitflag", api.SubmitFlag)
// 获取所有正确的flag提交记录
personal.GET("/solves/all", api.GetAllSolves)
// 获取指定用户正确的flag提交记录
personal.GET("/solves/uid/:uid", api.GetSolvesByUid)
// 获取指定题目正确的flag提交记录
personal.GET("/solves/cid/:cid", api.GetSolvesByCid)
// 获取当前用户正确flag提交记录即解题记录按时间从早到晚排序
personal.GET("/solves/self", api.GetSelfSolves)
// 获取当前用户分数、排名
personal.GET("/score/self", api.GetSelfScoreAndRank)
// 校内排行api暂时留空
}
// 管理员api需要用户登陆且Role=1才能访问
manager := api_v1.Group("/admin")
manager.Use(admin.AuthRequired())
{
// 创建新题目
manager.POST("/challenge", admin.NewChallenge)
}
router.Run(":9000")
}

View File

@@ -0,0 +1 @@
MTY1MTY1MDA1NHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXyZp7R_7HdiX8UyxFTMz3PPRiS83yhpcaLmGMFD-L145A==

View File

@@ -0,0 +1 @@
MTY1MTU4Mjk5OHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUVBU0JoTnpnM056VXhOek0yTnpVMk9XWTBabVV6WlRnd01tRXdOMkk0Tm1KaU13RURNVEl6QWdzeE1qTTBRSEZ4TG1OdmJRZjh4TjlxaEFBPXzX2Hfpvc6Jpgio2o1bCyD8p5MlWNkPlboWDL4O92SG8w==

View File

@@ -0,0 +1 @@
MTY1MTY1MDA0OHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXx0YsVP0Bsx_UC-SMnT2H5sXa3Rv-emyNOprM7KTZO22g==

View File

@@ -0,0 +1 @@
MTY1Mjk3NTUwM3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18R_nBzwfvM0VB9HgjG3j_tOYrJh9OwzMtHi7AxxPqDG4=

View File

@@ -0,0 +1 @@
MTY1MTY3NDQ4NnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18aaWkxhTEgthoUKJ1GTlpyzmrevXI2QOM7XmE1f4Tws4=

View File

@@ -0,0 +1 @@
MTY1MTY3MzM5OXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18g3L0zUnti_MnEg_YIhPvXDONG7L4o30Yq1IHE4hKPzI=

View File

@@ -0,0 +1 @@
MTY1MTY2NTYyNnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXyEWhEqOaCFOXqnMIdP2SHN9WFhZxAjVudLfyUTS4zkfg==

View File

@@ -0,0 +1 @@
MTY1MTY1MDgyMXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXwtNDxPyD59Y9CBHfAh54_pGb0xED5BrnS12WfwMbrHxQ==

View File

@@ -0,0 +1 @@
MTY1MTY2NTQ2M3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXyBdgjcvRGhK6JnTrLlQETdtrVHCfqXHN9UWI5yMVsMTg==

View File

@@ -0,0 +1 @@
MTY1MTU4MjEyNXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUVBU0JoTnpnM056VXhOek0yTnpVMk9XWTBabVV6WlRnd01tRXdOMkk0Tm1KaU13RURNVEl6QWdzeE1qTTBRSEZ4TG1OdmJRZjh4TjlxaEFBPXz6W0gwBf2X0RyprFJTaSBL1JLYgGYkXgcIh29Db_gJpw==

View File

@@ -0,0 +1 @@
MTY1Mjk3Mzc2OHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18ONHNYhjemKmcTQ56VURz0wNePYzECS31waCtlRhCu78=

View File

@@ -0,0 +1 @@
MTY1MTY1MDk3M3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXyYBQByVjLbJZ2x4QafNqgpp-n6kCesEB6BNfoXvq-1ig==

View File

@@ -0,0 +1 @@
MTY1MTY1MDcxMHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXzPyoA6p6szfVSUU-zkLkOCK4zfP6gZq5orisMvUYEDuA==

View File

@@ -0,0 +1 @@
MTY1MTU3NDg2NnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUVBU0JoTnpnM056VXhOek0yTnpVMk9XWTBabVV6WlRnd01tRXdOMkk0Tm1KaU13RURNVEl6QWdzeE1qTTBRSEZ4TG1OdmJRZjh4TjlxaEFBPXy1hayYz7EXP5XMGKWMk_wssR8J1BlbjDrxaakLbTIh1Q==

View File

@@ -0,0 +1 @@
MTY1MTY2NTYyMXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXx7IIV8mOmTS0o0qjO2cO8ESW-joxUKV1YJS3-WHMUsFw==

View File

@@ -0,0 +1 @@
MTY1MTY1MDYzOXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXwcSl56VFVQxQEhpD-LhkTqwgcmHgnPsmyT5kMXen_-1A==

View File

@@ -0,0 +1 @@
MTY1MTY3NDA3NnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18EL_WCkeFjFbdJfyQGOSGVdIiX90CG6tvNZGdzl-mz2Y=

View File

@@ -0,0 +1 @@
MTY1MTU3NDk0NnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUVBU0JoTnpnM056VXhOek0yTnpVMk9XWTBabVV6WlRnd01tRXdOMkk0Tm1KaU13RURNVEl6QWdzeE1qTTBRSEZ4TG1OdmJRZjh4TjlxaEFBPXyOhGtdUodGwIpp0X9-g40AHGjmu3wvk-AU00RFNBkUuA==

View File

@@ -0,0 +1 @@
MTY1MTY3NDQ4OXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18eF3jTQqiTGwMrs-jtADV7OUSEV_wRzjg4EPnsC3tODw=

View File

@@ -0,0 +1 @@
MTY1MTY1MTEwMXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXz5N5DorLr_UFgR8-PWyhwNcuD4pxzodlbWGkz7ANTDeA==

View File

@@ -0,0 +1 @@
MTY1MTY1MDc0NnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXxXvX5_tBpv8gObNjrYH-KN7qp4tSGZ9725DdUo6qCe7g==

View File

@@ -0,0 +1 @@
MTY1MTY1MTE0OHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXwcVGMp_v68wUnLRiSrd_xE_xurHal0es8Gxhq2FwOz4A==

View File

@@ -0,0 +1 @@
MTY1MTY3MzkwNHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18rYkgKtXvBGRfxZ9HaRsSscZ2QAXjFu9Y9b1pwoeu-B0=

View File

@@ -0,0 +1 @@
MTY1MTY1MDE0NXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXxt8__tXjZbcAc0ZhuT_1Ae991kPMs2j823Shb1IgUMhw==

View File

@@ -0,0 +1 @@
MTY1MTY1MDc0N3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXzQxs1oG1_iJaION26ztr96l3eyW0Bm6hvMT6X9wucpzw==

View File

@@ -0,0 +1 @@
MTY1MTY3MzE2M3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18XfrVpy5QOn89OAXXX_p5Om024hdVvn9DzpOVBUOKfTc=

View File

@@ -0,0 +1 @@
MTY1MTY1MDYzOXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXwcSl56VFVQxQEhpD-LhkTqwgcmHgnPsmyT5kMXen_-1A==

View File

@@ -0,0 +1 @@
MTY1MTU4MjE3OHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUVBU0JoTnpnM056VXhOek0yTnpVMk9XWTBabVV6WlRnd01tRXdOMkk0Tm1KaU13RURNVEl6QWdzeE1qTTBRSEZ4TG1OdmJRZjh4TjlxaEFBPXyzrYkoEMyAeckMlz8wT3gRi8kpbicHZdXjmaYCSYEbTQ==

View File

@@ -0,0 +1 @@
MTY1MTY3NDA3N3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT188eytn4LgdEMhXv4tFo0JNWC070N3GUuIsRNEYTyvx5c=

View File

@@ -0,0 +1 @@
MTY1MTY1MDcxMHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXzPyoA6p6szfVSUU-zkLkOCK4zfP6gZq5orisMvUYEDuA==

View File

@@ -0,0 +1 @@
MTY1MTY1MDE1MnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXzM8T4GoEMSqIe8zK2A6wn67v1nguMDHjUUo-yjKjNfcQ==

View File

@@ -0,0 +1 @@
MTY1MTY1MDM2MXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXx7XIYKo0HoZNY_DZVwi9ellyBp7o7V2gvM9Vb0pUli3Q==

View File

@@ -0,0 +1 @@
MTY1MTY1MDk3MnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXwR9evf4tXU9hUpH4hw_D6l7w4n0j-1Vf16locrZWzLFQ==

View File

@@ -0,0 +1 @@
MTY1MTY3MzE2MnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18br434P_axalM2X4F6b6cEEkrCpk8OnhOsjp85410v0c=

View File

@@ -0,0 +1 @@
MTY1MTY2NTQ2MnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXyfWEkkjK48q8lwLJEJSc7cQXbRGdDabcUHO9FVZID_5w==

View File

@@ -0,0 +1 @@
MTY1MTY0OTk3OHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXz0n4VX35X4e92mOLcdNVwHgoxgzHHGs7fSQ33yrgyMbA==

View File

@@ -0,0 +1 @@
MTY1MTY1MDM1M3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXzkpY_PPKBue5Qf7ZOP3tDQATS2rujJjRsNsVHTEL94lQ==

View File

@@ -0,0 +1 @@
MTY1Mjk3MTY3NHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT1808avPSF-CPY2M9KO1Gx-opThsHsrJxKGaUPR7BZp9WQ=

View File

@@ -0,0 +1 @@
MTY1MTY1MDcxMHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXzPyoA6p6szfVSUU-zkLkOCK4zfP6gZq5orisMvUYEDuA==

View File

@@ -0,0 +1 @@
MTY1MTU3NzQwOXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUVBU0JoTnpnM056VXhOek0yTnpVMk9XWTBabVV6WlRnd01tRXdOMkk0Tm1KaU13RURNVEl6QWdzeE1qTTBRSEZ4TG1OdmJRZjh4TjlxaEFBPXwP-FCJdqMaFJIxqG_AYodOb2iE8gguAw2E3W5WVu4v8g==

View File

@@ -0,0 +1 @@
MTY1MTY3NDE5MnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18gUD_A631PFOBncH-QOxKbkmt0xtW6Fgug3qcEUfijcA=

View File

@@ -0,0 +1 @@
MTY1MTY1MTEwMnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXxgHRdZoPZBE0kDMmtyHrzAaMfiKhlGdCF47u58n45cSw==

View File

@@ -0,0 +1 @@
MTY1MTY3NDE5M3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18Cyx59YJB_tTb2EBULWXlfVECSpk1iqkG-odREjbKGsc=

View File

@@ -0,0 +1 @@
MTY1MTY1MDcxMHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXzPyoA6p6szfVSUU-zkLkOCK4zfP6gZq5orisMvUYEDuA==

View File

@@ -0,0 +1 @@
MTY1MTU4MjQzNXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUVBU0JoTnpnM056VXhOek0yTnpVMk9XWTBabVV6WlRnd01tRXdOMkk0Tm1KaU13RURNVEl6QWdzeE1qTTBRSEZ4TG1OdmJRZjh4TjlxaEFBPXw8cY50NHs9S6zCZtQkXsjSnr7Wv1O2LJ1X2cLAjybXIA==

View File

@@ -0,0 +1 @@
MTY1MTU4MTg5MHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUVBU0JoTnpnM056VXhOek0yTnpVMk9XWTBabVV6WlRnd01tRXdOMkk0Tm1KaU13RURNVEl6QWdzeE1qTTBRSEZ4TG1OdmJRZjh4TjlxaEFBPXzKFszom5pRA96lq3Lb2fT6iDLQL1sguZ3xph75DDNpCQ==

View File

@@ -0,0 +1 @@
MTY1MTY1MTE0OHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXwcVGMp_v68wUnLRiSrd_xE_xurHal0es8Gxhq2FwOz4A==

View File

@@ -0,0 +1 @@
MTY1MTY1MDgxOXxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXyD0OzJ2XvmQTfT3cln5USKo4wbM01lrwy_1tkmotJG-w==

View File

@@ -0,0 +1 @@
MTY1MTY3NDE5M3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18Cyx59YJB_tTb2EBULWXlfVECSpk1iqkG-odREjbKGsc=

View File

@@ -0,0 +1 @@
MTY1MTY3MzQwNHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18UB3CM0FYHNdONL4rdGwb5t1aFPoJvD0sQsEEM4YJxHo=

View File

@@ -0,0 +1 @@
MTY1MTY1MDcxMHxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUVAtRVBRRUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdBPXzPyoA6p6szfVSUU-zkLkOCK4zfP6gZq5orisMvUYEDuA==

View File

@@ -0,0 +1 @@
MTY1MTY3MzkwM3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT184E0y_hLsOmZ_gsWkLUJ_O2Xo6AGbJfaUboiHww2JZoM=

View File

@@ -0,0 +1 @@
MTY1MTY3MzMwM3xEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18XAWDOQNDSejAMWM96plPufODrSs0R38IJWaPlh7NpZc=

View File

@@ -0,0 +1 @@
MTY1Mjk3MjEwMnxEdi1CQkFFQ180SUFBUkFCRUFBQV84cl9nZ0FCQm5OMGNtbHVad3dHQUFSMWMyVnlFVzFoYVc0dVoyOHZkSGx3WlM1VmMyVnlfNE1EQVFFRVZYTmxjZ0hfaEFBQkRRRUNTVVFCQkFBQkJWUnZhMlZ1QVF3QUFRaFZjMlZ5Ym1GdFpRRU1BQUVJVUdGemMzZHZjbVFCREFBQkJVVnRZV2xzQVF3QUFRdEJabVpwYkdsaGRHbHZiZ0VNQUFFSFEyOTFiblJ5ZVFFTUFBRUhWMlZpYzJsMFpRRU1BQUVHU0dsa1pHVnVBUVFBQVFaQ1lXNXVaV1FCQkFBQkJsUmxZVzFKUkFFRUFBRUhRM0psWVhSbFpBRUVBQUVFVW05c1pRRUVBQUFBUXYtRVB3RUNBU0JqTjJVeU1EazBaRGxtTkRVd1ltVmhNak5tTURWa01HTmpZemszWldWaVpRRUVNVEl6TkFJS01USXpRSEZ4TG1OdmJRZjh4TjlxUmdFQ0FBPT18EA6m0QoNTA0TT7IkJ-AfPqtOHKKazFKMpf5FQI2Xr6A=

BIN
snctf.db Normal file

Binary file not shown.

55
tools/aes.go Normal file
View File

@@ -0,0 +1,55 @@
package tools
import (
"bytes"
"crypto/aes"
"crypto/cipher"
)
var Aeskey = []byte("snowywar12345678") //aeskey
//@brief:填充明文
func PKCS5Padding(plaintext []byte, blockSize int) []byte{
padding := blockSize-len(plaintext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)},padding)
return append(plaintext,padtext...)
}
//@brief:去除填充数据
func PKCS5UnPadding(origData []byte) []byte{
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
//@brief:AES加密
func AesEncrypt(origData, key []byte) ([]byte, error){
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
//AES分组长度为128位所以blockSize=16单位字节
blockSize := block.BlockSize()
origData = PKCS5Padding(origData,blockSize)
blockMode := cipher.NewCBCEncrypter(block,key[:blockSize]) //初始向量的长度必须等于块block的长度16字节
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted,origData)
return crypted, nil
}
//@brief:AES解密
func AesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
//AES分组长度为128位所以blockSize=16单位字节
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) //初始向量的长度必须等于块block的长度16字节
origData := make([]byte, len(crypted))
blockMode.CryptBlocks(origData, crypted)
origData = PKCS5UnPadding(origData)
return origData, nil
}

14
tools/checkid.go Normal file
View File

@@ -0,0 +1,14 @@
package tools
import "regexp"
// CheckID 验证id是否为非负正整数。
func CheckID(id string) bool {
if id == "1" {
return false
}
pattern := `^[1-9]\d*$`
reg := regexp.MustCompile(pattern)
return reg.MatchString(id)
}

13
tools/md5.go Normal file
View File

@@ -0,0 +1,13 @@
package tools
import (
"crypto/md5"
"encoding/hex"
)
func MD5(v string)string{
d := []byte(v)
m := md5.New()
m.Write(d)
return hex.EncodeToString(m.Sum(nil))
}

35
tools/token.go Normal file
View File

@@ -0,0 +1,35 @@
package tools
import (
"crypto/rand"
"fmt"
"io"
"time"
)
// Random 生成随机数。
func Random() []byte {
b := make([]byte, 32)
//ReadFull从rand.Reader精确地读取len(b)字节数据填充进b
//rand.Reader是一个全局、共享的密码用强随机数生成器
if _, err := io.ReadFull(rand.Reader, b); err != nil {
fmt.Printf("random number generation error: %v", err)
}
return b
}
// Token 生成随机token。
func Token() string {
b := Random()[:16]
return fmt.Sprintf("%x", b)
}
// Timestamp 用于获取当前10位数时间戳。
func Timestamp() int {
// time_zone := time.FixedZone("UTC", 0)
// t := time.Now().In(time_zone).Unix()
t := time.Now().Unix()
return int(t)
}

20
type/adminTypes.go Normal file
View File

@@ -0,0 +1,20 @@
package types
// ChallengeRequest 定义新增/修改题目的一个请求
type ChallengeRequest struct {
Name string `json:"name" binding:"required"`
Score int `json:"score" binding:"required"`
Flag string `json:"flag"` // 暂时一个题只能一个flag
Description string `json:"description"`
Attachment []string `json:"attachment"`
Category string `json:"category" binding:"required"`
Tags string `json:"tags"`
Hints []string `json:"hints"`
Visible int `json:"visible"`
}
// NoticeRequest 定义新增公告的一个请求
type NoticeRequest struct {
Title string `form:"title" json:"title" binding:"required"`
Content string `form:"content" json:"content" binding:"required"`
}

58
type/commentypes.go Normal file
View File

@@ -0,0 +1,58 @@
package types
//user定义用户结构体。
type User struct {
ID int `json:"id"` //用户id唯一自增
Token string `json:"token"` //用户token唯一
Username string `json:"username"` //用户名,唯一
Password string `json:"password"` //用户密码md5值md5(原密码)
Email string `json:"email"` //邮箱,唯一
Affiliation string `json:"affiliation"` //组织、战队或机构等非必需默认为0
Country string `json:"country"` //国家非必需默认为0
Website string `json:"website"` //个人链接默认为0
Hidden int `json:"hidden"` //1隐藏0显示默认为0
Banned int `json:"banned"` //1禁止0正常默认为1邮箱激活后为0
TeamID int `json:"team_id"` //队伍id在团队模式下必须个人模式非必需默认为0
Created int `json:"created"` //用户注册时间10位数时间戳
Role int `json:"role"` //0普通用户默认为01普通管理员2所有者最高权限
}
// Notice 定义一个公告
type Notice struct {
ID int `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
CreatedAt int `json:"created_at"`
}
// Challenge 定义一个题目
type Challenge struct {
ID int `json:"id"`
Name string `json:"name"`
Score int `json:"score"`
Flag string `json:"flag"`
Description string `json:"description"`
Attachment []string `json:"attachment"`
Category string `json:"category"`
Tags string `json:"tags"`
Hints []string `json:"hints"`
Visible int `json:"visible"` // 0表示隐藏1表示可见
}
// Submission 表示一次flag提交记录
type Submission struct {
ID int `json:"id"`
UserID int `json:"uid" gorm:"column:uid"`
ChallengeID int `json:"cid" gorm:"column:cid"`
Flag string `json:"flag"`
IP string `json:"ip"`
Time int `json:"submitted_at" gorm:"column:submitted_at"`
}
// Solve 表示一次正确的flag提交记录
type Solve struct {
ID int `json:"id" `
UserID int `json:"uid" gorm:"column:uid"`
ChallengeID int `json:"cid" gorm:"column:cid"`
Time int `json:"solved_at" gorm:"column:submitted_at"`
}

124
type/userTypes.go Normal file
View File

@@ -0,0 +1,124 @@
package types
// LoginRequest 定义接收登录数据的结构体。
type LoginRequest struct {
// binding:"required"修饰的字段,若接收为空值,则报错,是必须字段
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
Remember bool `json:"remember"`
}
// RegisterRequest 定义接收注册数据的结构体。
type RegisterRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
Email string `json:"email" binding:"required"`
CaptchaID string `json:"captchaid" binding:"required"`
Solution string `json:"solution" binding:"required"`
}
// InfoRequest 定义接收用户修改信息的结构体。
type InfoRequest struct {
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
Affiliation string `json:"affiliation"`
Country string `json:"country"`
Website string `json:"website"`
}
// InstallRequest 定义接收installRequest数据的结构体。
type InstallRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
Email string `json:"email" binding:"required"`
}
// SubmissionRequest 定义接收提交flag数据的结构体。
type SubmissionRequest struct {
Cid int `json:"cid" binding:"required"`
Flag string `json:"flag" binding:"required"`
}
// StudentInfo 定义校内学生信息结构体。
type StudentInfo struct {
Username string `json:"username"`
StudentID string `json:"student_id"`
QQ string `json:"qq"`
}
// SubmitStudentInfoRequest 定义接收提交校内学生用户信息的结构体。
type SubmitStudentInfoRequest struct {
Student1 StudentInfo `json:"student1" binding:"required"`
Student2 StudentInfo `json:"student2"`
Student3 StudentInfo `json:"student3"`
Student4 StudentInfo `json:"student4"`
}
// OthersInfo 定义校外用户信息结构体。
type OthersInfo struct {
Username string `json:"username"`
Email string `json:"email"`
QQ string `json:"qq"`
}
// SubmitOthersInfoRequest 定义接收提交校外学生用户信息的结构体。
type SubmitOthersInfoRequest struct {
Others1 OthersInfo `json:"others1" binding:"required"`
Others2 OthersInfo `json:"others2"`
Others3 OthersInfo `json:"others3"`
Others4 OthersInfo `json:"others4"`
}
// ScoreResponse 定义返回得分情况结构体。
type ScoreResponse struct {
ID int `json:"id"`
Username string `json:"username"`
Score int `json:"score"`
}
// SolveResponse 定义返回解题情况结构体。
type SolveResponse struct {
ID int `json:"id"`
Uid int `json:"uid"`
Cid int `json:"cid"`
Username string `json:"username"`
ChallengeName string `json:"challenge_name"`
SubmittedAt int `json:"submitted_at"`
Score int `json:"score"`
}
// PublicInfoResponse 定义返回用户公开信息结构体。
type PublicInfoResponse struct {
Username string `json:"username"`
Affiliation string `json:"affiliation"`
Country string `json:"country"`
TeamID int `json:"team_id"`
}
// ChallengeResponse 定义获取题目的一个响应。
type ChallengeResponse struct {
ID int `json:"id"`
Name string `json:"name"`
Score int `json:"score"`
Description string `json:"description"` //题目描述
Attachment []string `json:"attachment"` //题目附件
Category string `json:"category"` //分类
Tags string `json:"tags"` //标签
Hints []string `json:"hints"` //提示
SolverCount int `json:"solver_count"` //解决人数
IsSolved bool `json:"is_solved"` // true已解决false未解决
}
// ScoreRankResponse 定义获取当前用户分数和排名的一个响应。
type ScoreRankResponse struct {
Score int `json:"score"`
Rank int `json:"rank"`
}
// StudentsOrOthersInfoResponse 定义获取校内用户或校外用户信息的响应。
type StudentsOrOthersInfoResponse struct {
Username string `json:"username"`
IDOrEmail string `json:"id_email"`
QQ string `json:"qq"`
}