rename the utils package
This commit is contained in:
parent
1c9c5c6f6a
commit
97f9f3660b
|
@ -18,7 +18,7 @@ Features:
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
**Required env variables to run this bot:**
|
**Required ENV variables:**
|
||||||
|
|
||||||
```
|
```
|
||||||
DB_USER=your_pgdb_user
|
DB_USER=your_pgdb_user
|
||||||
|
|
|
@ -39,8 +39,8 @@ func Attach(c *cron.Cron, cfg Config) {
|
||||||
checkEnnoblements := trackDuration(log, h.checkEnnoblements, "checkEnnoblements")
|
checkEnnoblements := trackDuration(log, h.checkEnnoblements, "checkEnnoblements")
|
||||||
checkBotServers := trackDuration(log, h.checkBotServers, "checkBotServers")
|
checkBotServers := trackDuration(log, h.checkBotServers, "checkBotServers")
|
||||||
deleteClosedTribalWarsServers := trackDuration(log,
|
deleteClosedTribalWarsServers := trackDuration(log,
|
||||||
h.deleteClosedTribalWarsServers,
|
h.deleteClosedTWServers,
|
||||||
"deleteClosedTribalWarsServers")
|
"deleteClosedTWServers")
|
||||||
updateBotStatus := trackDuration(log, h.updateBotStatus, "updateBotStatus")
|
updateBotStatus := trackDuration(log, h.updateBotStatus, "updateBotStatus")
|
||||||
c.AddFunc("@every 1m", checkEnnoblements)
|
c.AddFunc("@every 1m", checkEnnoblements)
|
||||||
c.AddFunc("@every 30m", checkBotServers)
|
c.AddFunc("@every 30m", checkBotServers)
|
||||||
|
|
|
@ -3,7 +3,7 @@ package cron
|
||||||
import (
|
import (
|
||||||
"github.com/tribalwarshelp/shared/tw/twmodel"
|
"github.com/tribalwarshelp/shared/tw/twmodel"
|
||||||
|
|
||||||
"github.com/tribalwarshelp/dcbot/utils"
|
"github.com/tribalwarshelp/dcbot/tw/twutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ennoblements []*twmodel.Ennoblement
|
type ennoblements []*twmodel.Ennoblement
|
||||||
|
@ -19,8 +19,8 @@ func (e ennoblements) getLastEnnoblement() *twmodel.Ennoblement {
|
||||||
func (e ennoblements) getLostVillagesByTribe(tribeID int) ennoblements {
|
func (e ennoblements) getLostVillagesByTribe(tribeID int) ennoblements {
|
||||||
filtered := ennoblements{}
|
filtered := ennoblements{}
|
||||||
for _, ennoblement := range e {
|
for _, ennoblement := range e {
|
||||||
if (!utils.IsPlayerTribeNil(ennoblement.NewOwner) && ennoblement.NewOwner.Tribe.ID == tribeID) ||
|
if (!twutil.IsPlayerTribeNil(ennoblement.NewOwner) && ennoblement.NewOwner.Tribe.ID == tribeID) ||
|
||||||
utils.IsPlayerTribeNil(ennoblement.OldOwner) ||
|
twutil.IsPlayerTribeNil(ennoblement.OldOwner) ||
|
||||||
ennoblement.OldOwner.Tribe.ID != tribeID {
|
ennoblement.OldOwner.Tribe.ID != tribeID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,9 @@ func (e ennoblements) getLostVillagesByTribe(tribeID int) ennoblements {
|
||||||
func (e ennoblements) getConqueredVillagesByTribe(tribeID int, showInternals bool) ennoblements {
|
func (e ennoblements) getConqueredVillagesByTribe(tribeID int, showInternals bool) ennoblements {
|
||||||
filtered := ennoblements{}
|
filtered := ennoblements{}
|
||||||
for _, ennoblement := range e {
|
for _, ennoblement := range e {
|
||||||
if utils.IsPlayerTribeNil(ennoblement.NewOwner) ||
|
if twutil.IsPlayerTribeNil(ennoblement.NewOwner) ||
|
||||||
ennoblement.NewOwner.Tribe.ID != tribeID ||
|
ennoblement.NewOwner.Tribe.ID != tribeID ||
|
||||||
(!showInternals && !utils.IsPlayerTribeNil(ennoblement.OldOwner) && ennoblement.OldOwner.Tribe.ID == tribeID) {
|
(!showInternals && !twutil.IsPlayerTribeNil(ennoblement.OldOwner) && ennoblement.OldOwner.Tribe.ID == tribeID) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
filtered = append(filtered, ennoblement)
|
filtered = append(filtered, ennoblement)
|
||||||
|
|
|
@ -9,10 +9,11 @@ import (
|
||||||
|
|
||||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||||
|
|
||||||
"github.com/tribalwarshelp/dcbot/message"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/tribalwarshelp/dcbot/message"
|
||||||
|
"github.com/tribalwarshelp/dcbot/tw/twutil"
|
||||||
|
|
||||||
"github.com/tribalwarshelp/golang-sdk/sdk"
|
"github.com/tribalwarshelp/golang-sdk/sdk"
|
||||||
|
|
||||||
"github.com/tribalwarshelp/dcbot/discord"
|
"github.com/tribalwarshelp/dcbot/discord"
|
||||||
|
@ -20,7 +21,6 @@ import (
|
||||||
"github.com/tribalwarshelp/dcbot/models"
|
"github.com/tribalwarshelp/dcbot/models"
|
||||||
"github.com/tribalwarshelp/dcbot/observation"
|
"github.com/tribalwarshelp/dcbot/observation"
|
||||||
"github.com/tribalwarshelp/dcbot/server"
|
"github.com/tribalwarshelp/dcbot/server"
|
||||||
"github.com/tribalwarshelp/dcbot/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
|
@ -116,7 +116,7 @@ func (h *handler) loadVersions(servers []string) ([]*twmodel.Version, error) {
|
||||||
Code: versionCodes,
|
Code: versionCodes,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "cannot load versions")
|
return nil, errors.Wrap(err, "couldn't load versions")
|
||||||
}
|
}
|
||||||
|
|
||||||
return versionList.Items, nil
|
return versionList.Items, nil
|
||||||
|
@ -130,7 +130,7 @@ func (h *handler) checkEnnoblements() {
|
||||||
}
|
}
|
||||||
log.
|
log.
|
||||||
WithField("servers", servers).
|
WithField("servers", servers).
|
||||||
Info("checkEnnoblements: loaded servers")
|
Info("checkEnnoblements: servers have been loaded")
|
||||||
|
|
||||||
groups, total, err := h.groupRepo.Fetch(context.Background(), nil)
|
groups, total, err := h.groupRepo.Fetch(context.Background(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -139,7 +139,7 @@ func (h *handler) checkEnnoblements() {
|
||||||
}
|
}
|
||||||
log.
|
log.
|
||||||
WithField("numberOfGroups", total).
|
WithField("numberOfGroups", total).
|
||||||
Info("checkEnnoblements: loaded groups")
|
Info("checkEnnoblements: groups have been loaded")
|
||||||
|
|
||||||
versions, err := h.loadVersions(servers)
|
versions, err := h.loadVersions(servers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -148,13 +148,13 @@ func (h *handler) checkEnnoblements() {
|
||||||
}
|
}
|
||||||
log.
|
log.
|
||||||
WithField("numberOfVersions", len(versions)).
|
WithField("numberOfVersions", len(versions)).
|
||||||
Info("checkEnnoblements: loaded versions")
|
Info("checkEnnoblements: versions have been loaded")
|
||||||
|
|
||||||
ennoblementsByServerKey, err := h.loadEnnoblements(servers)
|
ennoblementsByServerKey, err := h.loadEnnoblements(servers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorln("checkEnnoblements:", err)
|
log.Errorln("checkEnnoblements:", err)
|
||||||
}
|
}
|
||||||
log.Info("checkEnnoblements: loaded ennoblements")
|
log.Info("checkEnnoblements: ennoblements have been loaded")
|
||||||
|
|
||||||
for _, g := range groups {
|
for _, g := range groups {
|
||||||
if g.ConqueredVillagesChannelID == "" && g.LostVillagesChannelID == "" {
|
if g.ConqueredVillagesChannelID == "" && g.LostVillagesChannelID == "" {
|
||||||
|
@ -165,11 +165,11 @@ func (h *handler) checkEnnoblements() {
|
||||||
conqueredVillagesMsg := &discord.MessageEmbed{}
|
conqueredVillagesMsg := &discord.MessageEmbed{}
|
||||||
for _, obs := range g.Observations {
|
for _, obs := range g.Observations {
|
||||||
enblmnts, ok := ennoblementsByServerKey[obs.Server]
|
enblmnts, ok := ennoblementsByServerKey[obs.Server]
|
||||||
version := utils.FindVersionByCode(versions, twmodel.VersionCodeFromServerKey(obs.Server))
|
version := twutil.FindVersionByCode(versions, twmodel.VersionCodeFromServerKey(obs.Server))
|
||||||
if ok && version != nil && version.Host != "" {
|
if ok && version != nil && version.Host != "" {
|
||||||
if g.LostVillagesChannelID != "" {
|
if g.LostVillagesChannelID != "" {
|
||||||
for _, ennoblement := range enblmnts.getLostVillagesByTribe(obs.TribeID) {
|
for _, ennoblement := range enblmnts.getLostVillagesByTribe(obs.TribeID) {
|
||||||
if !utils.IsPlayerTribeNil(ennoblement.NewOwner) &&
|
if !twutil.IsPlayerTribeNil(ennoblement.NewOwner) &&
|
||||||
g.Observations.Contains(obs.Server, ennoblement.NewOwner.Tribe.ID) {
|
g.Observations.Contains(obs.Server, ennoblement.NewOwner.Tribe.ID) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ func (h *handler) checkEnnoblements() {
|
||||||
|
|
||||||
if g.ConqueredVillagesChannelID != "" {
|
if g.ConqueredVillagesChannelID != "" {
|
||||||
for _, ennoblement := range enblmnts.getConqueredVillagesByTribe(obs.TribeID, g.ShowInternals) {
|
for _, ennoblement := range enblmnts.getConqueredVillagesByTribe(obs.TribeID, g.ShowInternals) {
|
||||||
isInTheSameGroup := !utils.IsPlayerTribeNil(ennoblement.OldOwner) &&
|
isInTheSameGroup := !twutil.IsPlayerTribeNil(ennoblement.OldOwner) &&
|
||||||
g.Observations.Contains(obs.Server, ennoblement.OldOwner.Tribe.ID)
|
g.Observations.Contains(obs.Server, ennoblement.OldOwner.Tribe.ID)
|
||||||
if (!g.ShowInternals && isInTheSameGroup) ||
|
if (!g.ShowInternals && isInTheSameGroup) ||
|
||||||
(!g.ShowEnnobledBarbarians && isBarbarian(ennoblement.OldOwner)) {
|
(!g.ShowEnnobledBarbarians && isBarbarian(ennoblement.OldOwner)) {
|
||||||
|
@ -267,27 +267,27 @@ func (h *handler) checkBotServers() {
|
||||||
} else {
|
} else {
|
||||||
log.
|
log.
|
||||||
WithField("numberOfDeletedServers", len(deleted)).
|
WithField("numberOfDeletedServers", len(deleted)).
|
||||||
Info("checkBotServers: deleted servers")
|
Info("checkBotServers: some of the servers have been deleted")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) deleteClosedTribalWarsServers() {
|
func (h *handler) deleteClosedTWServers() {
|
||||||
servers, err := h.observationRepo.FetchServers(context.Background())
|
servers, err := h.observationRepo.FetchServers(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("deleteClosedTribalWarsServers: " + err.Error())
|
log.Error("deleteClosedTWServers: " + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.
|
log.
|
||||||
WithField("servers", servers).
|
WithField("servers", servers).
|
||||||
Info("deleteClosedTribalWarsServers: loaded servers")
|
Info("deleteClosedTWServers: loaded servers")
|
||||||
|
|
||||||
list, err := h.api.Server.Browse(0, 0, []string{"key ASC"}, &twmodel.ServerFilter{
|
list, err := h.api.Server.Browse(0, 0, []string{"key ASC"}, &twmodel.ServerFilter{
|
||||||
Key: servers,
|
Key: servers,
|
||||||
Status: []twmodel.ServerStatus{twmodel.ServerStatusClosed},
|
Status: []twmodel.ServerStatus{twmodel.ServerStatusClosed},
|
||||||
}, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorln("deleteClosedTribalWarsServers: " + err.Error())
|
log.Errorln("deleteClosedTWServers: " + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if list == nil || list.Items == nil {
|
if list == nil || list.Items == nil {
|
||||||
|
@ -304,11 +304,11 @@ func (h *handler) deleteClosedTribalWarsServers() {
|
||||||
Server: keys,
|
Server: keys,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorln("deleteClosedTribalWarsServers: " + err.Error())
|
log.Errorln("deleteClosedTWServers: " + err.Error())
|
||||||
} else {
|
} else {
|
||||||
log.
|
log.
|
||||||
WithField("numberOfDeletedObservations", len(deleted)).
|
WithField("numberOfDeletedObservations", len(deleted)).
|
||||||
Infof("deleteClosedTribalWarsServers: deleted observations")
|
Infof("deleteClosedTWServers: some of the observations have been deleted")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,11 @@ import (
|
||||||
"github.com/tribalwarshelp/shared/tw/twmodel"
|
"github.com/tribalwarshelp/shared/tw/twmodel"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tribalwarshelp/dcbot/utils"
|
"github.com/tribalwarshelp/dcbot/tw/twutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isBarbarian(p *twmodel.Player) bool {
|
func isBarbarian(p *twmodel.Player) bool {
|
||||||
return utils.IsPlayerNil(p) || p.ID == 0
|
return twutil.IsPlayerNil(p) || p.ID == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func trackDuration(log *logrus.Entry, fn func(), fnName string) func() {
|
func trackDuration(log *logrus.Entry, fn func(), fnName string) func() {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/tribalwarshelp/dcbot/discord"
|
"github.com/tribalwarshelp/dcbot/discord"
|
||||||
"github.com/tribalwarshelp/dcbot/message"
|
"github.com/tribalwarshelp/dcbot/message"
|
||||||
"github.com/tribalwarshelp/dcbot/utils"
|
"github.com/tribalwarshelp/dcbot/tw/twutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type messageType string
|
type messageType string
|
||||||
|
@ -54,23 +54,23 @@ func newMessage(cfg newMessageConfig) checkEnnoblementsMsg {
|
||||||
newOwnerTribeTag: "-",
|
newOwnerTribeTag: "-",
|
||||||
localizer: cfg.localizer,
|
localizer: cfg.localizer,
|
||||||
}
|
}
|
||||||
if !utils.IsVillageNil(cfg.ennoblement.Village) {
|
if !twutil.IsVillageNil(cfg.ennoblement.Village) {
|
||||||
data.village = cfg.ennoblement.Village.FullName()
|
data.village = cfg.ennoblement.Village.FullName()
|
||||||
data.villageURL = twurlbuilder.BuildVillageURL(cfg.server, cfg.host, cfg.ennoblement.Village.ID)
|
data.villageURL = twurlbuilder.BuildVillageURL(cfg.server, cfg.host, cfg.ennoblement.Village.ID)
|
||||||
}
|
}
|
||||||
if !utils.IsPlayerNil(cfg.ennoblement.OldOwner) {
|
if !twutil.IsPlayerNil(cfg.ennoblement.OldOwner) {
|
||||||
data.oldOwnerName = cfg.ennoblement.OldOwner.Name
|
data.oldOwnerName = cfg.ennoblement.OldOwner.Name
|
||||||
data.oldOwnerURL = twurlbuilder.BuildPlayerURL(cfg.server, cfg.host, cfg.ennoblement.OldOwner.ID)
|
data.oldOwnerURL = twurlbuilder.BuildPlayerURL(cfg.server, cfg.host, cfg.ennoblement.OldOwner.ID)
|
||||||
}
|
}
|
||||||
if !utils.IsPlayerTribeNil(cfg.ennoblement.OldOwner) {
|
if !twutil.IsPlayerTribeNil(cfg.ennoblement.OldOwner) {
|
||||||
data.oldOwnerTribeTag = cfg.ennoblement.OldOwner.Tribe.Tag
|
data.oldOwnerTribeTag = cfg.ennoblement.OldOwner.Tribe.Tag
|
||||||
data.oldOwnerTribeURL = twurlbuilder.BuildTribeURL(cfg.server, cfg.host, cfg.ennoblement.OldOwner.Tribe.ID)
|
data.oldOwnerTribeURL = twurlbuilder.BuildTribeURL(cfg.server, cfg.host, cfg.ennoblement.OldOwner.Tribe.ID)
|
||||||
}
|
}
|
||||||
if !utils.IsPlayerNil(cfg.ennoblement.NewOwner) {
|
if !twutil.IsPlayerNil(cfg.ennoblement.NewOwner) {
|
||||||
data.newOwnerName = cfg.ennoblement.NewOwner.Name
|
data.newOwnerName = cfg.ennoblement.NewOwner.Name
|
||||||
data.newOwnerURL = twurlbuilder.BuildPlayerURL(cfg.server, cfg.host, cfg.ennoblement.NewOwner.ID)
|
data.newOwnerURL = twurlbuilder.BuildPlayerURL(cfg.server, cfg.host, cfg.ennoblement.NewOwner.ID)
|
||||||
}
|
}
|
||||||
if !utils.IsPlayerTribeNil(cfg.ennoblement.NewOwner) {
|
if !twutil.IsPlayerTribeNil(cfg.ennoblement.NewOwner) {
|
||||||
data.newOwnerTribeTag = cfg.ennoblement.NewOwner.Tribe.Tag
|
data.newOwnerTribeTag = cfg.ennoblement.NewOwner.Tribe.Tag
|
||||||
data.newOwnerTribeURL = twurlbuilder.BuildTribeURL(cfg.server, cfg.host, cfg.ennoblement.NewOwner.Tribe.ID)
|
data.newOwnerTribeURL = twurlbuilder.BuildTribeURL(cfg.server, cfg.host, cfg.ennoblement.NewOwner.Tribe.ID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"github.com/tribalwarshelp/golang-sdk/sdk"
|
"github.com/tribalwarshelp/golang-sdk/sdk"
|
||||||
|
|
||||||
"github.com/tribalwarshelp/dcbot/message"
|
"github.com/tribalwarshelp/dcbot/message"
|
||||||
"github.com/tribalwarshelp/dcbot/utils"
|
"github.com/tribalwarshelp/dcbot/tw/twutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -117,13 +117,13 @@ func (s *Session) translateCoords(ctx *commandCtx, m *discordgo.MessageCreate) {
|
||||||
villageURL := twurlbuilder.BuildVillageURL(ctx.server.CoordsTranslation, version.Host, village.ID)
|
villageURL := twurlbuilder.BuildVillageURL(ctx.server.CoordsTranslation, version.Host, village.ID)
|
||||||
playerName := "-"
|
playerName := "-"
|
||||||
playerURL := ""
|
playerURL := ""
|
||||||
if !utils.IsPlayerNil(village.Player) {
|
if !twutil.IsPlayerNil(village.Player) {
|
||||||
playerName = village.Player.Name
|
playerName = village.Player.Name
|
||||||
playerURL = twurlbuilder.BuildPlayerURL(ctx.server.CoordsTranslation, version.Host, village.Player.ID)
|
playerURL = twurlbuilder.BuildPlayerURL(ctx.server.CoordsTranslation, version.Host, village.Player.ID)
|
||||||
}
|
}
|
||||||
tribeName := "-"
|
tribeName := "-"
|
||||||
tribeURL := ""
|
tribeURL := ""
|
||||||
if !utils.IsPlayerTribeNil(village.Player) {
|
if !twutil.IsPlayerTribeNil(village.Player) {
|
||||||
tribeName = village.Player.Tribe.Name
|
tribeName = village.Player.Tribe.Name
|
||||||
tribeURL = twurlbuilder.BuildTribeURL(ctx.server.CoordsTranslation, version.Host, village.Player.Tribe.ID)
|
tribeURL = twurlbuilder.BuildTribeURL(ctx.server.CoordsTranslation, version.Host, village.Player.Tribe.ID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
"github.com/tribalwarshelp/dcbot/message"
|
"github.com/tribalwarshelp/dcbot/message"
|
||||||
"github.com/tribalwarshelp/dcbot/models"
|
"github.com/tribalwarshelp/dcbot/models"
|
||||||
"github.com/tribalwarshelp/dcbot/utils"
|
"github.com/tribalwarshelp/dcbot/tw/twutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -741,7 +741,7 @@ func (s *Session) handleObservationsCommand(ctx *commandCtx, m *discordgo.Messag
|
||||||
if observation.Tribe != nil {
|
if observation.Tribe != nil {
|
||||||
tag = observation.Tribe.Tag
|
tag = observation.Tribe.Tag
|
||||||
}
|
}
|
||||||
version := utils.FindVersionByCode(versionList.Items, twmodel.VersionCodeFromServerKey(observation.Server))
|
version := twutil.FindVersionByCode(versionList.Items, twmodel.VersionCodeFromServerKey(observation.Server))
|
||||||
tribeURL := ""
|
tribeURL := ""
|
||||||
if version != nil {
|
if version != nil {
|
||||||
tribeURL = twurlbuilder.BuildTribeURL(observation.Server, version.Host, observation.TribeID)
|
tribeURL = twurlbuilder.BuildTribeURL(observation.Server, version.Host, observation.TribeID)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package utils
|
package twutil
|
||||||
|
|
||||||
import "github.com/tribalwarshelp/shared/tw/twmodel"
|
import "github.com/tribalwarshelp/shared/tw/twmodel"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package utils
|
package twutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tribalwarshelp/shared/tw/twmodel"
|
"github.com/tribalwarshelp/shared/tw/twmodel"
|
Reference in New Issue