biz

package
v0.0.0-...-adb5103 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 23, 2024 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrUserNotFound    = errors.New(400, "user not found", "user not found")
	ErrPasswordInvalid = errors.New(400, "password invalid", "user not found")
)

ProviderSet is biz providers.

Functions

func ConvertToDeptTree

func ConvertToDeptTree(deptList []*model.SysDept) []*pb.DeptTree

func ConvertToDeptTreeChildren

func ConvertToDeptTreeChildren(deptList []*pb.DeptTree) []*pb.DeptTree

Types

type AuthUseCase

type AuthUseCase struct {
	// contains filtered or unexported fields
}

func NewAuthUseCase

func NewAuthUseCase(conf *conf.Auth, userRepo SysUserRepo, roleRepo SysRoleRepo, logger log.Logger) *AuthUseCase

func (*AuthUseCase) Login

func (receiver *AuthUseCase) Login(ctx context.Context, req *pb.LoginRequest) (token string, expireAt int64, pErr error)

type CasbinRuleRepo

type CasbinRuleRepo interface {
	GetModel() model.Model
	GetAdapter() persist.Adapter

	UpdateCasbin(ctx context.Context, roleKey string, p [][]string) error
	ClearCasbin(v int, p ...string) error
	UpdateCasbinApi(ctx context.Context, oldPath string, newPath string, oldMethod string, newMethod string) error
	GetPolicyPathByRoleId(roleKey string) [][]string
}

type CasbinRuleUseCase

type CasbinRuleUseCase struct {
	// contains filtered or unexported fields
}

func NewCasbinRuleUseCase

func NewCasbinRuleUseCase(repo CasbinRuleRepo, logger log.Logger) *CasbinRuleUseCase

func (*CasbinRuleUseCase) ClearCasbin

func (c *CasbinRuleUseCase) ClearCasbin(roleKey string) error

func (*CasbinRuleUseCase) GetPolicyPathByRoleId

func (c *CasbinRuleUseCase) GetPolicyPathByRoleId(roleKey string) [][]string

func (*CasbinRuleUseCase) UpdateCasbin

func (c *CasbinRuleUseCase) UpdateCasbin(ctx context.Context, roleKey string, apis []*pb.ApiBase) error
type MenuSimpleTree struct {
	MenuId   int64             `json:"menuId"`
	MenuName string            `json:"menuName"`
	Children []*MenuSimpleTree `json:"children,omitempty"`
}
type MenuTree struct {
	model.SysMenu
	Children []*MenuTree `json:"children,omitempty"`
}

type OssRepo

type OssRepo interface {
	UploadFile(file multipart.File, path string) (string, error)
}

type RedisRepo

type RedisRepo interface {
	SetHashKey(context.Context, string, string, interface{}) error
	GetHashKey(context.Context, string, string) (string, error)
	DelHashKey(ctx context.Context, key string, field string) error
	GetHashLen(ctx context.Context, key string) error
	Lock(context.Context, string, interface{}, time.Duration) (bool, error)
	IncrHashKey(context.Context, string, string, int64) error
	GetHashAllKeyAndVal(context.Context, string) (map[string]string, error)
	Set(ctx context.Context, key string, value string, expire time.Duration) error
	Get(ctx context.Context, key string) string
	SRem(ctx context.Context, key string, members ...interface{}) (int64, error)
}

type SysApiRepo

type SysApiRepo interface {
	FindByID(ctx context.Context, id int64) (*model.SysAPI, error)
	Create(ctx context.Context, api *model.SysAPI) error
	Save(ctx context.Context, api *model.SysAPI) error
	Delete(ctx context.Context, id int64) error
	FindAll(ctx context.Context) ([]*model.SysAPI, error)
	ListPage(ctx context.Context, page, size int32, path string, description string, group string, method string) ([]*model.SysAPI, error)
	ListPageCount(ctx context.Context) (int32, error)
}

type SysApiUseCase

type SysApiUseCase struct {
	// contains filtered or unexported fields
}

func NewSysApiUseCase

func NewSysApiUseCase(repo SysApiRepo, casbinRepo CasbinRuleRepo, logger log.Logger) *SysApiUseCase

func (*SysApiUseCase) AllApi

func (a *SysApiUseCase) AllApi(ctx context.Context) ([]*model.SysAPI, error)

func (*SysApiUseCase) CreateApi

func (a *SysApiUseCase) CreateApi(ctx context.Context, api *model.SysAPI) (*model.SysAPI, error)

func (*SysApiUseCase) DeleteApi

func (a *SysApiUseCase) DeleteApi(ctx context.Context, id int64) error

func (*SysApiUseCase) GetApiByID

func (a *SysApiUseCase) GetApiByID(ctx context.Context, id int64) (*model.SysAPI, error)

func (*SysApiUseCase) GetPolicyPathByRoleKey

func (a *SysApiUseCase) GetPolicyPathByRoleKey(ctx context.Context, roleKey string) ([][]string, error)

func (*SysApiUseCase) ListPage

func (a *SysApiUseCase) ListPage(ctx context.Context, page, size int32, path, description string, group, method string) ([]*model.SysAPI, int32, error)

func (*SysApiUseCase) UpdateApi

func (a *SysApiUseCase) UpdateApi(ctx context.Context, api *model.SysAPI) (*model.SysAPI, error)

type SysDeptRepo

type SysDeptRepo interface {
	Create(ctx context.Context, dept *model.SysDept) error
	Save(ctx context.Context, dept *model.SysDept) error

	UpdateByID(ctx context.Context, id int64, dept *model.SysDept) error

	Delete(ctx context.Context, id int64) error

	FindByIDList(ctx context.Context, ids ...int64) ([]*model.SysDept, error)

	FindByID(ctx context.Context, id int64) (*model.SysDept, error)
	ListByNameStatusId(ctx context.Context, deptName string, status int32, id int64) ([]*model.SysDept, error)
	GetRoleDeptId(ctx context.Context, roleId int32) ([]int32, error)
	SelectDept(ctx context.Context) ([]*pb.DeptTree, error)
	SelectDeptLabel(ctx context.Context) ([]*pb.DeptLabel, error)
}

type SysDeptUseCase

type SysDeptUseCase struct {
	// contains filtered or unexported fields
}

func NewSysDeptUseCase

func NewSysDeptUseCase(repo SysDeptRepo, logger log.Logger) *SysDeptUseCase

func (*SysDeptUseCase) CreateDept

func (d *SysDeptUseCase) CreateDept(ctx context.Context, sysDept *model.SysDept) (*model.SysDept, error)

func (*SysDeptUseCase) DeleteDept

func (d *SysDeptUseCase) DeleteDept(ctx context.Context, id int64) error

func (*SysDeptUseCase) FindDeptByIDList

func (d *SysDeptUseCase) FindDeptByIDList(ctx context.Context, ids []int64) ([]*model.SysDept, error)

func (*SysDeptUseCase) GetDept

func (d *SysDeptUseCase) GetDept(ctx context.Context, id int64) (*model.SysDept, error)

func (*SysDeptUseCase) GetDeptList

func (d *SysDeptUseCase) GetDeptList(ctx context.Context) ([]*pb.DeptTree, error)

func (*SysDeptUseCase) ListByNameStatusId

func (d *SysDeptUseCase) ListByNameStatusId(ctx context.Context, deptName string, status int32, id int64) ([]*model.SysDept, error)

func (*SysDeptUseCase) RoleDeptTreeSelect

func (d *SysDeptUseCase) RoleDeptTreeSelect(ctx context.Context, roleId int32) (*pb.RoleDeptTreeSelectReply, error)

func (*SysDeptUseCase) UpdateDept

func (d *SysDeptUseCase) UpdateDept(ctx context.Context, sysDept *model.SysDept) (*model.SysDept, error)

type SysDictDatumRepo

type SysDictDatumRepo interface {
	Create(ctx context.Context, post *model.SysDictDatum) error
	Save(ctx context.Context, post *model.SysDictDatum) error
	Delete(ctx context.Context, ids []int64) error
	FindByID(ctx context.Context, id int64) (*model.SysDictDatum, error)
	FindByIDList(ctx context.Context, ids ...int64) ([]*model.SysDictDatum, error)
	FindAll(ctx context.Context) ([]*model.SysDictDatum, error)

	ListPage(ctx context.Context, dictLabel, dictType string, status int32, page, size int32) ([]*model.SysDictDatum, error)
	ListPageCount(ctx context.Context, dictLabel, dictType string, status int32) (int32, error)
}

type SysDictDatumUseCase

type SysDictDatumUseCase struct {
	// contains filtered or unexported fields
}

func NewSysDictDatumUseCase

func NewSysDictDatumUseCase(repo SysDictDatumRepo, logger log.Logger) *SysDictDatumUseCase

func (*SysDictDatumUseCase) CreateDictData

func (p *SysDictDatumUseCase) CreateDictData(ctx context.Context, post *model.SysDictDatum) (*model.SysDictDatum, error)

func (*SysDictDatumUseCase) DeleteDictData

func (p *SysDictDatumUseCase) DeleteDictData(ctx context.Context, id []int64) error

func (*SysDictDatumUseCase) FindDictDataAll

func (p *SysDictDatumUseCase) FindDictDataAll(ctx context.Context) ([]*model.SysDictDatum, error)

func (*SysDictDatumUseCase) FindDictDataByID

func (p *SysDictDatumUseCase) FindDictDataByID(ctx context.Context, id int64) (*model.SysDictDatum, error)

func (*SysDictDatumUseCase) FindDictDataByIDList

func (p *SysDictDatumUseCase) FindDictDataByIDList(ctx context.Context, ids []int64) ([]*model.SysDictDatum, error)

func (*SysDictDatumUseCase) ListDictData

func (p *SysDictDatumUseCase) ListDictData(ctx context.Context, dictLabel, dictType string, status int32, page, size int32) ([]*model.SysDictDatum, int32, error)

func (*SysDictDatumUseCase) UpdateDictData

func (p *SysDictDatumUseCase) UpdateDictData(ctx context.Context, post *model.SysDictDatum) (*model.SysDictDatum, error)

type SysDictTypeRepo

type SysDictTypeRepo interface {
	Create(ctx context.Context, post *model.SysDictType) error
	Save(ctx context.Context, post *model.SysDictType) error
	Delete(ctx context.Context, ids []int64) error
	FindByID(ctx context.Context, id int64) (*model.SysDictType, error)
	FindByIDList(ctx context.Context, ids ...int64) ([]*model.SysDictType, error)
	FindAll(ctx context.Context) ([]*model.SysDictType, error)

	ListPage(ctx context.Context, dictName, dictType string, status int32, page, size int32) ([]*model.SysDictType, error)
	ListPageCount(ctx context.Context, dictName, dictType string, status int32) (int32, error)
}

type SysDictTypeUseCase

type SysDictTypeUseCase struct {
	// contains filtered or unexported fields
}

func NewSysDictTypeUseCase

func NewSysDictTypeUseCase(repo SysDictTypeRepo, logger log.Logger) *SysDictTypeUseCase

func (*SysDictTypeUseCase) CreateDictType

func (p *SysDictTypeUseCase) CreateDictType(ctx context.Context, post *model.SysDictType) (*model.SysDictType, error)

func (*SysDictTypeUseCase) DeleteDictType

func (p *SysDictTypeUseCase) DeleteDictType(ctx context.Context, id []int64) error

func (*SysDictTypeUseCase) FindDictTypeAll

func (p *SysDictTypeUseCase) FindDictTypeAll(ctx context.Context) ([]*model.SysDictType, error)

func (*SysDictTypeUseCase) FindDictTypeByID

func (p *SysDictTypeUseCase) FindDictTypeByID(ctx context.Context, id int64) (*model.SysDictType, error)

func (*SysDictTypeUseCase) FindDictTypeByIDList

func (p *SysDictTypeUseCase) FindDictTypeByIDList(ctx context.Context, ids []int64) ([]*model.SysDictType, error)

func (*SysDictTypeUseCase) ListDictType

func (p *SysDictTypeUseCase) ListDictType(ctx context.Context, dictName, dictType string, status int32, page, size int32) ([]*model.SysDictType, int32, error)

func (*SysDictTypeUseCase) UpdateDictType

func (p *SysDictTypeUseCase) UpdateDictType(ctx context.Context, post *model.SysDictType) (*model.SysDictType, error)

type SysLogCase

type SysLogCase struct {
	// contains filtered or unexported fields
}

func NewSysLogCase

func NewSysLogCase(repo SysLogRepo) *SysLogCase

func (*SysLogCase) Create

func (r *SysLogCase) Create(ctx context.Context, log *model.SysLog) error

type SysLogRepo

type SysLogRepo interface {
	Create(ctx context.Context, log *model.SysLog) error
}

type SysMenuRepo

type SysMenuRepo interface {
	Create(ctx context.Context, menu *model.SysMenu) error
	Save(ctx context.Context, menu *model.SysMenu) error
	Delete(ctx context.Context, id int64) error
	DeleteMultiple(ctx context.Context, ids []int64) error
	GetAllChildren(ctx context.Context, id int64) ([]int64, error)

	FindById(ctx context.Context, id int64) (*model.SysMenu, error)
	ListAll(ctx context.Context) ([]*model.SysMenu, error)
	FindByNameStatus(ctx context.Context, name string, status int32) ([]*model.SysMenu, error)
	GetRoleMenuId(ctx context.Context, roleId int64) ([]int32, error)
	SelectMenuLabel(data model.SysMenu) ([]*pb.MenuLabel, error)
}

type SysMenuUseCase

type SysMenuUseCase struct {
	// contains filtered or unexported fields
}

func NewSysMenusUseCase

func NewSysMenusUseCase(repo SysMenuRepo, logger log.Logger) *SysMenuUseCase

func (*SysMenuUseCase) CreateMenus

func (m *SysMenuUseCase) CreateMenus(ctx context.Context, menu *model.SysMenu) (*model.SysMenu, error)

func (*SysMenuUseCase) DeleteMenus

func (m *SysMenuUseCase) DeleteMenus(ctx context.Context, id int64) error

func (*SysMenuUseCase) GetMenus

func (m *SysMenuUseCase) GetMenus(ctx context.Context, id int64) (*model.SysMenu, error)

func (*SysMenuUseCase) ListByNameStatus

func (m *SysMenuUseCase) ListByNameStatus(ctx context.Context, menuName string, status int32) ([]*model.SysMenu, error)

func (*SysMenuUseCase) RoleMenuTreeSelect

func (*SysMenuUseCase) UpdateMenus

func (m *SysMenuUseCase) UpdateMenus(ctx context.Context, menu *model.SysMenu) (*model.SysMenu, error)

type SysPostRepo

type SysPostRepo interface {
	Create(ctx context.Context, post *model.SysPost) error
	Save(ctx context.Context, post *model.SysPost) error
	Delete(ctx context.Context, ids []int64) error
	FindByID(ctx context.Context, id int64) (*model.SysPost, error)
	FindByIDList(ctx context.Context, ids ...int64) ([]*model.SysPost, error)
	FindAll(ctx context.Context) ([]*model.SysPost, error)

	ListPage(ctx context.Context, postName, postCode string, status int32, page, size int32) ([]*model.SysPost, error)
	ListPageCount(ctx context.Context, postName, postCode string, status int32) (int32, error)
}

type SysPostUseCase

type SysPostUseCase struct {
	// contains filtered or unexported fields
}

func NewSysPostUseCase

func NewSysPostUseCase(repo SysPostRepo, logger log.Logger, uc *SysUserUseCase) *SysPostUseCase

func (*SysPostUseCase) CreatePost

func (p *SysPostUseCase) CreatePost(ctx context.Context, post *model.SysPost) (*model.SysPost, error)

func (*SysPostUseCase) DeletePost

func (p *SysPostUseCase) DeletePost(ctx context.Context, ids []int64) error

func (*SysPostUseCase) FindPostAll

func (p *SysPostUseCase) FindPostAll(ctx context.Context) ([]*model.SysPost, error)

func (*SysPostUseCase) FindPostByID

func (p *SysPostUseCase) FindPostByID(ctx context.Context, id int64) (*model.SysPost, error)

func (*SysPostUseCase) FindPostByIDList

func (p *SysPostUseCase) FindPostByIDList(ctx context.Context, ids []int64) ([]*model.SysPost, error)

func (*SysPostUseCase) ListPost

func (p *SysPostUseCase) ListPost(ctx context.Context, postName, postCode string, status int32, page, size int32) ([]*model.SysPost, int32, error)

func (*SysPostUseCase) UpdatePost

func (p *SysPostUseCase) UpdatePost(ctx context.Context, post *model.SysPost) (*model.SysPost, error)

type SysRoleMenuRepo

type SysRoleMenuRepo interface {
	Create(ctx context.Context, roleMenus ...*model.SysRoleMenu) error
	DeleteByRoleId(ctx context.Context, roleIDs ...int64) error
	GetPermission(ctx context.Context, roleID int64) ([]string, error)
	FindMenuByRoleId(ctx context.Context, roleID int64) ([]*model.SysMenu, error)
	SelectMenuRole(ctx context.Context, roleName string) ([]*pb.MenuTree, error)
}

type SysRoleMenuUseCase

type SysRoleMenuUseCase struct {
	// contains filtered or unexported fields
}

func NewSysRoleMenuUseCase

func NewSysRoleMenuUseCase(repo SysRoleMenuRepo, logger log.Logger) *SysRoleMenuUseCase

func (*SysRoleMenuUseCase) CreateRoleMenus

func (r *SysRoleMenuUseCase) CreateRoleMenus(ctx context.Context, role *model.SysRole, menuIDs []int64) error

func (*SysRoleMenuUseCase) DeleteByRoleId

func (r *SysRoleMenuUseCase) DeleteByRoleId(ctx context.Context, roleIDs ...int64) error

func (*SysRoleMenuUseCase) FindMenuByRoleId

func (r *SysRoleMenuUseCase) FindMenuByRoleId(ctx context.Context, roleID int64) ([]*model.SysMenu, error)

func (*SysRoleMenuUseCase) GetPermission

func (r *SysRoleMenuUseCase) GetPermission(ctx context.Context, roleID int64) ([]string, error)

func (*SysRoleMenuUseCase) SelectMenuRole

func (r *SysRoleMenuUseCase) SelectMenuRole(ctx context.Context, roleName string) ([]*pb.MenuTree, error)

type SysRoleRepo

type SysRoleRepo interface {
	Create(ctx context.Context, role *model.SysRole) error
	Save(ctx context.Context, role *model.SysRole) error
	Delete(ctx context.Context, id ...int64) error
	FindByID(ctx context.Context, id int64) (*model.SysRole, error)
	FindByIDList(ctx context.Context, ids ...int64) ([]*model.SysRole, error)
	FindAll(ctx context.Context) ([]*model.SysRole, error)
	ListPage(ctx context.Context, name, key string, status int32, page, size int32) ([]*model.SysRole, error)
	Count(ctx context.Context, name, key string, status int32) (int32, error)
	Update(ctx context.Context, role *model.SysRole) error
	Roles(ctx context.Context) ([]*model.SysRole, error)
}

type SysRoleUseCase

type SysRoleUseCase struct {
	// contains filtered or unexported fields
}

func NewSysRoleUseCase

func NewSysRoleUseCase(repo SysRoleRepo, logger log.Logger, rmc *SysRoleMenuUseCase, casbin *CasbinRuleUseCase, userUseCase *SysUserUseCase, tx Transaction, menuRepo SysMenuRepo) *SysRoleUseCase

func (*SysRoleUseCase) ChangeDataScope

func (r *SysRoleUseCase) ChangeDataScope(ctx context.Context, id int64, scope int32) error

func (*SysRoleUseCase) ChangeRoleStatus

func (r *SysRoleUseCase) ChangeRoleStatus(ctx context.Context, id int64, status int32) error

func (*SysRoleUseCase) CreateRole

func (r *SysRoleUseCase) CreateRole(ctx context.Context, role *model.SysRole, menuIds []int64, apis []*pb.ApiBase) (*model.SysRole, error)

func (*SysRoleUseCase) DeleteRole

func (r *SysRoleUseCase) DeleteRole(ctx context.Context, ids []int64) error

func (*SysRoleUseCase) FindRoleAll

func (r *SysRoleUseCase) FindRoleAll(ctx context.Context) ([]*model.SysRole, error)

func (*SysRoleUseCase) FindRoleByIDList

func (r *SysRoleUseCase) FindRoleByIDList(ctx context.Context, ids []int64) ([]*model.SysRole, error)

func (*SysRoleUseCase) GetRole

func (r *SysRoleUseCase) GetRole(ctx context.Context, id int64) (*model.SysRole, error)

func (*SysRoleUseCase) GetRoleMenuId

func (r *SysRoleUseCase) GetRoleMenuId(ctx context.Context, roleId int64) ([]int32, error)

func (*SysRoleUseCase) ListPage

func (r *SysRoleUseCase) ListPage(ctx context.Context, roleName, roleKey string, status int32, page, size int32) ([]*model.SysRole, int32, error)

func (*SysRoleUseCase) Roles

func (r *SysRoleUseCase) Roles(ctx context.Context) ([]*model.SysRole, error)

func (*SysRoleUseCase) UpdateRole

func (r *SysRoleUseCase) UpdateRole(ctx context.Context, role *model.SysRole, menuIds []int64, apis []*pb.ApiBase) (*model.SysRole, error)

type SysUserRepo

type SysUserRepo interface {
	Save(ctx context.Context, user *model.SysUser) (*model.SysUser, error)
	Delete(ctx context.Context, id int64) error
	UpdateByID(ctx context.Context, id int64, user *model.SysUser) error
	Create(ctx context.Context, g *model.SysUser) (*model.SysUser, error)

	FindByID(ctx context.Context, id int64) (*model.SysUser, error)
	FindByUsername(ctx context.Context, username string) (*model.SysUser, error)
	FindByPostId(ctx context.Context, postId int64) ([]*model.SysUser, error)
	ListPage(ctx context.Context, page, size int32, condition UserListCondition) ([]*model.SysUser, error)
	Count(ctx context.Context, condition UserListCondition) (int32, error)
	CountByRoleId(ctx context.Context, roleId int64) (int64, error)
	FindAll(ctx context.Context) ([]*model.SysUser, error)
}

type SysUserUseCase

type SysUserUseCase struct {
	// contains filtered or unexported fields
}

SysUserUseCase is a SysUser use case.

func NewSysUserUseCase

func NewSysUserUseCase(userRepo SysUserRepo, uploadRepo OssRepo, severConfig *conf.Server, logger log.Logger) *SysUserUseCase

NewSysUserUseCase new a SysUser use case.

func (*SysUserUseCase) ChangeStatus

func (uc *SysUserUseCase) ChangeStatus(ctx context.Context, id int64, status int32) error

func (*SysUserUseCase) CountByRoleId

func (uc *SysUserUseCase) CountByRoleId(ctx context.Context, roleId int64) (int64, error)

func (*SysUserUseCase) CreateSysUser

func (uc *SysUserUseCase) CreateSysUser(ctx context.Context, u *model.SysUser) (*model.SysUser, error)

CreateSysUser creates a SysUser, and returns the new SysUser.

func (*SysUserUseCase) DeleteSysUser

func (uc *SysUserUseCase) DeleteSysUser(ctx context.Context, id int64) error

func (*SysUserUseCase) FindByPostId

func (uc *SysUserUseCase) FindByPostId(ctx context.Context, postId int64) ([]*model.SysUser, error)

func (*SysUserUseCase) FindSysUserById

func (uc *SysUserUseCase) FindSysUserById(ctx context.Context, id int64) (*model.SysUser, error)

func (*SysUserUseCase) FindSysUserByUsername

func (uc *SysUserUseCase) FindSysUserByUsername(ctx context.Context, username string) (*model.SysUser, error)

func (*SysUserUseCase) ListPage

func (uc *SysUserUseCase) ListPage(ctx context.Context, req *pb.ListSysuserRequest) (users []*model.SysUser, total int32, err error)

func (*SysUserUseCase) UpdateAvatar

func (uc *SysUserUseCase) UpdateAvatar(ctx context.Context) error

func (*SysUserUseCase) UpdatePassword

func (uc *SysUserUseCase) UpdatePassword(ctx context.Context, id int64, newPwd, oldPwd string) error

func (*SysUserUseCase) UpdateSysUser

func (uc *SysUserUseCase) UpdateSysUser(ctx context.Context, u *model.SysUser) error

func (*SysUserUseCase) UploadFile

func (uc *SysUserUseCase) UploadFile(ctx context.Context) (string, error)

type Transaction

type Transaction interface {
	Transaction(context.Context, func(ctx context.Context) error) error
}

type UserListCondition

type UserListCondition struct {
	UserName string
	Phone    string
	Status   int32
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL