439 lines
21 KiB
Go
439 lines
21 KiB
Go
package models
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/uptrace/bun"
|
|
)
|
|
|
|
// ─── Roles ──────────────────────────────────────────────────
|
|
type Role string
|
|
|
|
const (
|
|
RoleAdmin Role = "admin"
|
|
RoleModerator Role = "moderator"
|
|
RoleUser Role = "user"
|
|
)
|
|
|
|
// ─── User ───────────────────────────────────────────────────
|
|
type User struct {
|
|
bun.BaseModel `bun:"table:users,alias:u"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
Email string `bun:"email,notnull,unique" json:"email"`
|
|
Username string `bun:"username,notnull,unique" json:"username"`
|
|
Password string `bun:"password,notnull" json:"-"`
|
|
Role Role `bun:"role,notnull,default:'user'" json:"role"`
|
|
IsActive bool `bun:"is_active,notnull,default:true" json:"is_active"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
|
|
UserGames []*UserGame `bun:"rel:has-many,join:id=user_id" json:"user_games,omitempty"`
|
|
}
|
|
|
|
// ─── Game ───────────────────────────────────────────────────
|
|
type Game struct {
|
|
bun.BaseModel `bun:"table:games,alias:g"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
Name string `bun:"name,notnull,unique" json:"name"`
|
|
Slug string `bun:"slug,notnull,unique" json:"slug"`
|
|
Description string `bun:"description" json:"description"`
|
|
ImageURL string `bun:"image_url" json:"image_url"`
|
|
IsActive bool `bun:"is_active,notnull,default:true" json:"is_active"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
|
|
Variables []*GameVariable `bun:"rel:has-many,join:id=game_id" json:"variables,omitempty"`
|
|
Notifications []Notification `bun:"rel:has-many,join:id=game_id" json:"notifications,omitempty"`
|
|
Leaderboards []Leaderboard `bun:"rel:has-many,join:id=game_id" json:"leaderboards,omitempty"`
|
|
Modules []Module `bun:"-" json:"modules,omitempty"`
|
|
}
|
|
|
|
type GameVariableType string
|
|
|
|
const (
|
|
GameVariableTypeNumber GameVariableType = "number"
|
|
GameVariableTypeString GameVariableType = "string"
|
|
GameVariableTypeTable GameVariableType = "table"
|
|
GameVariableTypeVector GameVariableType = "vector"
|
|
)
|
|
|
|
type GameVariableTableValueType string
|
|
|
|
const (
|
|
GameVariableTableValueTypeNumber GameVariableTableValueType = "number"
|
|
GameVariableTableValueTypeString GameVariableTableValueType = "string"
|
|
)
|
|
|
|
type GameVariable struct {
|
|
bun.BaseModel `bun:"table:game_variables,alias:gv"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
GameID int64 `bun:"game_id,notnull" json:"game_id"`
|
|
Key string `bun:"key,notnull" json:"key"`
|
|
Type GameVariableType `bun:"type,notnull" json:"type"`
|
|
NumberValue *float64 `bun:"number_value" json:"number_value,omitempty"`
|
|
StringValue *string `bun:"string_value" json:"string_value,omitempty"`
|
|
TableValueType *GameVariableTableValueType `bun:"table_value_type" json:"table_value_type,omitempty"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
|
|
Game *Game `bun:"rel:belongs-to,join:game_id=id" json:"game,omitempty"`
|
|
Items []*GameVariableItem `bun:"rel:has-many,join:id=game_variable_id" json:"items,omitempty"`
|
|
}
|
|
|
|
type GameVariableItem struct {
|
|
bun.BaseModel `bun:"table:game_variable_items,alias:gvi"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
GameVariableID int64 `bun:"game_variable_id,notnull" json:"game_variable_id"`
|
|
Key string `bun:"item_key,notnull" json:"key,omitempty"`
|
|
Index *int64 `bun:"-" json:"index,omitempty"`
|
|
NumberValue *float64 `bun:"number_value" json:"number_value,omitempty"`
|
|
StringValue *string `bun:"string_value" json:"string_value,omitempty"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
|
|
Variable *GameVariable `bun:"rel:belongs-to,join:game_variable_id=id" json:"-"`
|
|
}
|
|
|
|
type Module struct {
|
|
bun.BaseModel `bun:"table:modules,alias:m"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
Key string `bun:"key,notnull,unique" json:"key"`
|
|
Name string `bun:"name,notnull" json:"name"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
}
|
|
|
|
type Language struct {
|
|
bun.BaseModel `bun:"table:languages,alias:l"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
Code string `bun:"code,notnull,unique" json:"code"`
|
|
Name string `bun:"name,notnull" json:"name"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
}
|
|
|
|
type GameModule struct {
|
|
bun.BaseModel `bun:"table:game_modules,alias:gm"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
GameID int64 `bun:"game_id,notnull" json:"game_id"`
|
|
ModuleID int64 `bun:"module_id,notnull" json:"module_id"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
|
|
Game *Game `bun:"rel:belongs-to,join:game_id=id" json:"-"`
|
|
Module *Module `bun:"rel:belongs-to,join:module_id=id" json:"module,omitempty"`
|
|
}
|
|
|
|
type Notification struct {
|
|
bun.BaseModel `bun:"table:notifications,alias:n"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
GameID int64 `bun:"game_id,notnull" json:"game_id"`
|
|
Name string `bun:"name,notnull" json:"name"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
Game *Game `bun:"rel:belongs-to,join:game_id=id" json:"game,omitempty"`
|
|
Descriptions []NotificationDescription `bun:"rel:has-many,join:id=notification_id" json:"descriptions,omitempty"`
|
|
Variables []NotificationVariableDef `bun:"rel:has-many,join:id=notification_id" json:"variables,omitempty"`
|
|
Entries []NotificationEntry `bun:"rel:has-many,join:id=notification_id" json:"entries,omitempty"`
|
|
Macros []string `bun:"-" json:"macros,omitempty"`
|
|
}
|
|
|
|
type NotificationDescription struct {
|
|
bun.BaseModel `bun:"table:notification_descriptions,alias:nd"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
NotificationID int64 `bun:"notification_id,notnull" json:"notification_id"`
|
|
LanguageID int64 `bun:"language_id,notnull" json:"language_id"`
|
|
Description string `bun:"description,notnull" json:"description"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
Language *Language `bun:"rel:belongs-to,join:language_id=id" json:"language,omitempty"`
|
|
Notification *Notification `bun:"rel:belongs-to,join:notification_id=id" json:"-"`
|
|
}
|
|
|
|
type NotificationVariableDef struct {
|
|
bun.BaseModel `bun:"table:notification_variable_defs,alias:nvd"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
NotificationID int64 `bun:"notification_id,notnull" json:"notification_id"`
|
|
Key string `bun:"key,notnull" json:"key"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
Notification *Notification `bun:"rel:belongs-to,join:notification_id=id" json:"-"`
|
|
}
|
|
|
|
type NotificationEntry struct {
|
|
bun.BaseModel `bun:"table:notification_entries,alias:ne"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
NotificationID int64 `bun:"notification_id,notnull" json:"notification_id"`
|
|
TimeSecond int64 `bun:"time_second,notnull" json:"time_second"`
|
|
Image string `bun:"image,notnull" json:"image"`
|
|
Login string `bun:"login,notnull" json:"login"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
Notification *Notification `bun:"rel:belongs-to,join:notification_id=id" json:"-"`
|
|
Variables []NotificationEntryVariable `bun:"rel:has-many,join:id=notification_entry_id" json:"variables,omitempty"`
|
|
}
|
|
|
|
type NotificationEntryVariable struct {
|
|
bun.BaseModel `bun:"table:notification_entry_variables,alias:nev"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
NotificationEntryID int64 `bun:"notification_entry_id,notnull" json:"notification_entry_id"`
|
|
NotificationVariableID int64 `bun:"notification_variable_id,notnull" json:"notification_variable_id"`
|
|
Value string `bun:"value,notnull" json:"value"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
Key string `bun:"-" json:"key,omitempty"`
|
|
Entry *NotificationEntry `bun:"rel:belongs-to,join:notification_entry_id=id" json:"-"`
|
|
Variable *NotificationVariableDef `bun:"rel:belongs-to,join:notification_variable_id=id" json:"-"`
|
|
}
|
|
|
|
type LeaderboardSortOrder string
|
|
|
|
const (
|
|
LeaderboardSortOrderDesc LeaderboardSortOrder = "desc"
|
|
LeaderboardSortOrderAsc LeaderboardSortOrder = "asc"
|
|
)
|
|
|
|
type LeaderboardPeriodType string
|
|
|
|
const (
|
|
LeaderboardPeriodAllTime LeaderboardPeriodType = "all_time"
|
|
LeaderboardPeriodDaily LeaderboardPeriodType = "daily"
|
|
LeaderboardPeriodWeekly LeaderboardPeriodType = "weekly"
|
|
LeaderboardPeriodMonthly LeaderboardPeriodType = "monthly"
|
|
)
|
|
|
|
type Leaderboard struct {
|
|
bun.BaseModel `bun:"table:leaderboards,alias:lb"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
GameID int64 `bun:"game_id,notnull" json:"game_id"`
|
|
Key string `bun:"key,notnull" json:"key"`
|
|
Name string `bun:"name,notnull" json:"name"`
|
|
SortOrder LeaderboardSortOrder `bun:"sort_order,notnull" json:"sort_order"`
|
|
PeriodType LeaderboardPeriodType `bun:"period_type,notnull" json:"period_type"`
|
|
IsActive bool `bun:"is_active,notnull,default:true" json:"is_active"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
|
|
Game *Game `bun:"rel:belongs-to,join:game_id=id" json:"game,omitempty"`
|
|
Groups []LeaderboardGroup `bun:"rel:has-many,join:id=leaderboard_id" json:"groups,omitempty"`
|
|
}
|
|
|
|
type LeaderboardGroup struct {
|
|
bun.BaseModel `bun:"table:leaderboard_groups,alias:lbg"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
LeaderboardID int64 `bun:"leaderboard_id,notnull" json:"leaderboard_id"`
|
|
Key string `bun:"key,notnull" json:"key"`
|
|
Name string `bun:"name,notnull" json:"name"`
|
|
IsDefault bool `bun:"is_default,notnull,default:false" json:"is_default"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
|
|
Leaderboard *Leaderboard `bun:"rel:belongs-to,join:leaderboard_id=id" json:"leaderboard,omitempty"`
|
|
Members []LeaderboardGroupMember `bun:"rel:has-many,join:id=group_id" json:"members,omitempty"`
|
|
}
|
|
|
|
type LeaderboardGroupMember struct {
|
|
bun.BaseModel `bun:"table:leaderboard_group_members,alias:lbgm"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
GroupID int64 `bun:"group_id,notnull" json:"group_id"`
|
|
UserID int64 `bun:"user_id,notnull" json:"user_id"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
|
|
Group *LeaderboardGroup `bun:"rel:belongs-to,join:group_id=id" json:"-"`
|
|
User *User `bun:"rel:belongs-to,join:user_id=id" json:"user,omitempty"`
|
|
}
|
|
|
|
type LeaderboardScore struct {
|
|
bun.BaseModel `bun:"table:leaderboard_scores,alias:lbs"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
LeaderboardID int64 `bun:"leaderboard_id,notnull" json:"leaderboard_id"`
|
|
UserGameID int64 `bun:"user_game_id,notnull" json:"user_game_id"`
|
|
Score float64 `bun:"score,notnull" json:"score"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
|
|
Leaderboard *Leaderboard `bun:"rel:belongs-to,join:leaderboard_id=id" json:"leaderboard,omitempty"`
|
|
UserGame *UserGame `bun:"rel:belongs-to,join:user_game_id=id" json:"user_game,omitempty"`
|
|
}
|
|
|
|
type LeaderboardRankItem struct {
|
|
Rank int64 `json:"rank"`
|
|
UserID int64 `json:"user_id"`
|
|
UserGameID int64 `json:"user_game_id"`
|
|
Username string `json:"username"`
|
|
Score float64 `json:"score"`
|
|
}
|
|
|
|
// ─── UserGame (pivot — user's connected games + balance) ────
|
|
type UserGame struct {
|
|
bun.BaseModel `bun:"table:user_games,alias:ug"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
UserID int64 `bun:"user_id,notnull" json:"user_id"`
|
|
GameID int64 `bun:"game_id,notnull" json:"game_id"`
|
|
Balance float64 `bun:"balance,notnull,default:0" json:"balance"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
|
|
|
|
User *User `bun:"rel:belongs-to,join:user_id=id" json:"user,omitempty"`
|
|
Game *Game `bun:"rel:belongs-to,join:game_id=id" json:"game,omitempty"`
|
|
}
|
|
|
|
// ─── Invite Link ────────────────────────────────────────────
|
|
type InviteLink struct {
|
|
bun.BaseModel `bun:"table:invite_links,alias:il"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
Code string `bun:"code,notnull,unique" json:"code"`
|
|
Role Role `bun:"role,notnull,default:'user'" json:"role"`
|
|
MaxUses int `bun:"max_uses,notnull,default:1" json:"max_uses"`
|
|
UsedCount int `bun:"used_count,notnull,default:0" json:"used_count"`
|
|
CreatedByID int64 `bun:"created_by_id,notnull" json:"created_by_id"`
|
|
ExpiresAt *time.Time `bun:"expires_at" json:"expires_at"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
|
|
CreatedBy *User `bun:"rel:belongs-to,join:created_by_id=id" json:"created_by,omitempty"`
|
|
}
|
|
|
|
// ─── Balance Transaction Log ────────────────────────────────
|
|
type BalanceTransaction struct {
|
|
bun.BaseModel `bun:"table:balance_transactions,alias:bt"`
|
|
|
|
ID int64 `bun:"id,pk,autoincrement" json:"id"`
|
|
UserGameID int64 `bun:"user_game_id,notnull" json:"user_game_id"`
|
|
Amount float64 `bun:"amount,notnull" json:"amount"`
|
|
Type string `bun:"type,notnull" json:"type"` // "topup" | "withdraw"
|
|
Comment string `bun:"comment" json:"comment"`
|
|
AdminID int64 `bun:"admin_id,notnull" json:"admin_id"`
|
|
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
|
|
}
|
|
|
|
// ─── Request / Response DTOs ────────────────────────────────
|
|
type LoginRequest struct {
|
|
Email string `json:"email" binding:"required,email"`
|
|
Password string `json:"password" binding:"required,min=6"`
|
|
}
|
|
|
|
type RegisterRequest struct {
|
|
Email string `json:"email" binding:"required,email"`
|
|
Username string `json:"username" binding:"required,min=3"`
|
|
Password string `json:"password" binding:"required,min=6"`
|
|
InviteCode string `json:"invite_code"`
|
|
}
|
|
|
|
type TopUpRequest struct {
|
|
Amount float64 `json:"amount" binding:"required,gt=0"`
|
|
Comment string `json:"comment"`
|
|
}
|
|
|
|
type CreateInviteRequest struct {
|
|
Role Role `json:"role" binding:"required"`
|
|
MaxUses int `json:"max_uses" binding:"required,gt=0"`
|
|
}
|
|
|
|
type CreateGameRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
Slug string `json:"slug" binding:"required"`
|
|
Description string `json:"description"`
|
|
ImageURL string `json:"image_url"`
|
|
}
|
|
|
|
type GameVariableItemRequest struct {
|
|
Key string `json:"key"`
|
|
Index *int64 `json:"index"`
|
|
NumberValue *float64 `json:"number_value"`
|
|
StringValue *string `json:"string_value"`
|
|
}
|
|
|
|
type UpsertGameVariableRequest struct {
|
|
Key string `json:"key" binding:"required"`
|
|
Type GameVariableType `json:"type" binding:"required"`
|
|
NumberValue *float64 `json:"number_value"`
|
|
StringValue *string `json:"string_value"`
|
|
TableValueType *GameVariableTableValueType `json:"table_value_type"`
|
|
Items []GameVariableItemRequest `json:"items"`
|
|
}
|
|
|
|
type ConnectGameModuleRequest struct {
|
|
ModuleKey string `json:"module_key" binding:"required"`
|
|
}
|
|
|
|
type UpsertLanguageRequest struct {
|
|
Code string `json:"code" binding:"required"`
|
|
Name string `json:"name" binding:"required"`
|
|
}
|
|
|
|
type NotificationDescriptionRequest struct {
|
|
LanguageID int64 `json:"language_id" binding:"required"`
|
|
Description string `json:"description" binding:"required"`
|
|
}
|
|
|
|
type NotificationVariableRequest struct {
|
|
Key string `json:"key" binding:"required"`
|
|
}
|
|
|
|
type NotificationEntryVariableRequest struct {
|
|
Key string `json:"key" binding:"required"`
|
|
Value string `json:"value"`
|
|
}
|
|
|
|
type NotificationEntryRequest struct {
|
|
TimeSecond int64 `json:"time_second"`
|
|
Image string `json:"image" binding:"required"`
|
|
Login string `json:"login" binding:"required"`
|
|
Variables []NotificationEntryVariableRequest `json:"variables"`
|
|
}
|
|
|
|
type UpsertNotificationRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
Descriptions []NotificationDescriptionRequest `json:"descriptions" binding:"required"`
|
|
Variables []NotificationVariableRequest `json:"variables"`
|
|
Entries []NotificationEntryRequest `json:"entries" binding:"required"`
|
|
}
|
|
|
|
type UpsertLeaderboardRequest struct {
|
|
Key string `json:"key" binding:"required"`
|
|
Name string `json:"name" binding:"required"`
|
|
SortOrder LeaderboardSortOrder `json:"sort_order" binding:"required"`
|
|
PeriodType LeaderboardPeriodType `json:"period_type" binding:"required"`
|
|
IsActive *bool `json:"is_active"`
|
|
}
|
|
|
|
type UpsertLeaderboardGroupRequest struct {
|
|
Key string `json:"key" binding:"required"`
|
|
Name string `json:"name" binding:"required"`
|
|
IsDefault *bool `json:"is_default"`
|
|
}
|
|
|
|
type AddLeaderboardGroupMemberRequest struct {
|
|
UserID int64 `json:"user_id" binding:"required"`
|
|
}
|
|
|
|
type UpsertLeaderboardScoreRequest struct {
|
|
UserGameID int64 `json:"user_game_id" binding:"required"`
|
|
Score float64 `json:"score" binding:"required"`
|
|
}
|
|
|
|
type ConnectGameRequest struct {
|
|
GameID int64 `json:"game_id" binding:"required"`
|
|
}
|
|
|
|
type UpdateUserRoleRequest struct {
|
|
Role Role `json:"role" binding:"required"`
|
|
}
|