common

package
v5.1.1 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2023 License: AGPL-3.0 Imports: 53 Imported by: 35

Documentation

Index

Constants

View Source
const (
	ConfigName  = `ConfigFromFile`
	SettingName = `ConfigFromDB`
)
View Source
const DirShardingNum = float64(50000)

DirShardingNum 文件夹分组基数

Variables

View Source
var (
	MustGetMyContext = defaults.MustGetContext
	MustGetContext   = defaults.MustGetContext
	NewMockContext   = defaults.NewMockContext
)
View Source
var (

	//ErrUserNotLoggedIn 用户未登录
	ErrUserNotLoggedIn = echo.NewError(`User not logged in`, code.Unauthenticated)
	//ErrUserNotFound 用户不存在
	ErrUserNotFound = echo.NewError(`User does not exist`, code.UserNotFound)
	//ErrUserNoPerm 用户无权限
	ErrUserNoPerm = echo.NewError(`User has no permission`, code.NonPrivileged)
	//ErrUserDisabled 用户已被禁用
	ErrUserDisabled = echo.NewError(`User has been disabled`, code.UserDisabled)
	//ErrBalanceNoEnough 余额不足
	ErrBalanceNoEnough = echo.NewError(`Balance is not enough`, code.BalanceNoEnough)
	//ErrCaptcha 验证码错误
	ErrCaptcha = echo.NewError(`Captcha is incorrect`, code.CaptchaError)
	//ErrCaptchaIdMissing 缺少captchaId
	ErrCaptchaIdMissing = echo.NewError(`Missing captchaId`, code.CaptchaIdMissing).SetZone(`captchaId`)
	//ErrInvalidAppID App ID 无效
	ErrInvalidAppID = echo.NewError(`Invalid app id`, code.InvalidAppID)
	//ErrInvalidSign 无效签名
	ErrInvalidSign = echo.NewError(`Invalid sign`, code.InvalidSignature)
	//ErrInvalidToken 令牌无效
	ErrInvalidToken = echo.NewError(`Invalid token`, code.InvalidToken)

	//ErrRepeatOperation 重复操作
	ErrRepeatOperation = echo.NewError(`Repeat operation`, code.RepeatOperation)
	//ErrUnsupported 不支持
	ErrUnsupported = echo.NewError(`Unsupported`, code.Unsupported)
	//ErrOperationTimeout 操作超时
	ErrOperationTimeout = echo.NewError(`Operation timeout`, code.OperationTimeout)
	//ErrOperationFail 操作失败
	ErrOperationFail = echo.NewError(`Operation fail`, code.Failure)

	//ErrResponseFormatError 响应格式错误
	ErrResponseFormatError = echo.NewError(`Response format error`, code.AbnormalResponse)
	//ErrRequestTimeout 提交超时
	ErrRequestTimeout = echo.NewError(`Request timeout`, code.RequestTimeout)
	//ErrRequestFail 提交失败
	ErrRequestFail = echo.NewError(`Request fail`, code.RequestFailure)

	// ErrIgnoreConfigChange 忽略配置文件更改
	ErrIgnoreConfigChange = errors.New(`Ignore configuration file changes`)

	// ErrNext 需要继续向下检查
	ErrNext            = errors.New("Next")
	ErrConcurrentLock  = errors.New("Concurrent lock has been triggered")
	ErrContextCanceled = errors.New("Context canceled")
)
View Source
var (
	// Sorts 获取数据查询时的排序方式
	Sorts                = clientPagination.Sorts
	Paging               = dbPagination.Paging
	PagingWithPagination = dbPagination.PagingWithPagination
	PagingWithLister     = dbPagination.PagingWithLister
	PagingWithListerCond = dbPagination.PagingWithListerCond
	PagingWithSelectList = dbPagination.PagingWithSelectList
	NewLister            = dbPagination.NewLister
	NewListParam         = dbPagination.NewListParam
	NewOffsetLister      = dbPagination.NewOffsetLister
)
View Source
var (
	ErrInvalidIPAddress = errors.New("Invalid IP address")
	ErrNotSet           = errors.New("Not set")
)
View Source
var ErrorProcessors = []render.ErrorProcessor{
	func(ctx echo.Context, err error) (processed bool, newErr error) {
		if errors.Is(err, db.ErrNoMoreRows) {
			return true, echo.NewError(ctx.T(`数据不存在`), stdCode.DataNotFound)
		}
		return false, err
	},
}
View Source
var LogParsers = map[string]LogParser{}

LogParsers 日志格式解析器

View Source
var NewErrors = errorslice.New
View Source
var SQLKeyReplacer = strings.NewReplacer("`", "``", ".", "`.`")
View Source
var (
	SonyflakeStartDate = `2018-09-01 08:08:08`
)

Functions

func BackendURL

func BackendURL(ctx echo.Context) string

func BatchAdd

func BatchAdd(ctx echo.Context, field string, adder Adder, before func(*string) error, seperators ...string) (added []string, err error)

BatchAdd 批量添加(常用于批量添加分类) BatchAdd(ctx, `ident,>name`, adder, before, `=`) 可以通过在字段名称前面添加“>”前缀来指定表单字段名称,如果不指定则默认使用第一个作为表单字段名

func BoolToFlag

func BoolToFlag(v bool) string

func CaptchaForm

func CaptchaForm(c echo.Context, args ...interface{}) template.HTML

func CaptchaInfo

func CaptchaInfo(hostAlias string, captchaName string, captchaID string, args ...string) echo.H

CaptchaInfo 新验证码信息

func ClearHTML

func ClearHTML(title string) string

ClearHTML 清除所有HTML标签及其属性,一般用处理文章标题等不含HTML标签的字符串

func ContentEncode

func ContentEncode(content string, contypes ...string) string

func CookieConfig

func CookieConfig() scookie.Config

func Crypto

func Crypto() codec.Codec

func Decrypt

func Decrypt(secret string, datas ...*string)

Decrypt 数据解密

func DecryptedByRandomSecret

func DecryptedByRandomSecret(ctx echo.Context, sessionKey string, datas ...*string)

DecryptedByRandomSecret 用上次设置的随机密码解密

func DeleteRandomSecret

func DeleteRandomSecret(ctx echo.Context, sessionKey string)

DeleteRandomSecret 删除随机密码

func DirSharding

func DirSharding(id uint64) uint64

DirSharding 文件夹分组(暂不使用)

func Encrypt

func Encrypt(secret string, datas ...*string)

Encrypt 数据加密

func Err

func Err(ctx echo.Context, err error) (ret interface{})

Err 获取错误信息

func FlagToBool

func FlagToBool(v string) bool

func Float32Sum

func Float32Sum(numbers ...float32) float32

func Float64Sum

func Float64Sum(numbers ...float64) float64

func FloorNumber

func FloorNumber(page int, pageSize int, index int) int

FloorNumber 楼层号

func GenAndRecordCaptchaID

func GenAndRecordCaptchaID(ctx echo.Context, opt *hdlCaptcha.Options) string

func GenCaptchaError

func GenCaptchaError(ctx echo.Context, hostAlias string, captchaName string, id string, args ...string) echo.Data

func GenPassword

func GenPassword() (string, error)

func GenSecret

func GenSecret(sizes ...uint) string

GenSecret 生成随机密钥

func GetBoolFlag

func GetBoolFlag(value string, defaults ...string) string

func GetCaptchaID

func GetCaptchaID(ctx echo.Context, id string) (string, error)

func GetContype

func GetContype(value string, defaults ...string) string

func GetEnumValue

func GetEnumValue(enums []string, value string, defaults string) string

func GetErr

func GetErr(key string) (err error)

func GetHistoryOrNewCaptchaID

func GetHistoryOrNewCaptchaID(ctx echo.Context) string

func GetLocalIP

func GetLocalIP(ver ...int) (string, error)

GetLocalIP 获取本机网卡IP

func GetLocalIPs added in v5.0.1

func GetLocalIPs() (ipv4 []string, ipv6 []string, err error)

GetLocalIPs 获取本机网卡IP

func GetLocalIPv4 added in v5.0.1

func GetLocalIPv4() (ipv4 string, err error)

GetLocalIPv4 获取本机网卡IPv4

func GetLocalIPv6 added in v5.0.1

func GetLocalIPv6() (ipv6 string, err error)

GetLocalIPv6 获取本机网卡IPv6

func GetNowTime

func GetNowTime(ctx echo.Context) time.Time

GetNowTime 获取当前时间(同一个context中只获取一次)

func HPoolGet

func HPoolGet() echo.H

func HPoolRelease

func HPoolRelease(m echo.H)

func HTMLFilter

func HTMLFilter() *bluemonday.Policy

HTMLFilter 构建自定义的HTML标签过滤器

func IDSharding

func IDSharding(id uint64, shardingNum float64) uint64

IDSharding 按照ID进行分片

func IPv4ToMachineID

func IPv4ToMachineID(ipv4 string) (uint16, error)

func IsAnonymousMode

func IsAnonymousMode(ownerType string) bool

func IsCaptchaErrCode

func IsCaptchaErrCode(code stdCode.Code) bool

IsCaptchaErrCode 是否验证码错误码

func IsCaptchaError

func IsCaptchaError(err error) bool

IsCaptchaError 用户验证码错误

func IsErr

func IsErr(err error, key string) bool

func IsError

func IsError(err interface{}) bool

IsError 是否是错误信息

func IsFailureCode

func IsFailureCode(code stdCode.Code) bool

func IsMessage

func IsMessage(err interface{}) bool

IsMessage 判断err是否为Message

func IsNoRetry

func IsNoRetry(err error) bool

func IsOk

func IsOk(err interface{}) bool

IsOk 是否是成功信息

func IsUserDisabled

func IsUserDisabled(err error) bool

IsUserDisabled 用户是否被禁用

func IsUserNoPerm

func IsUserNoPerm(err error) bool

IsUserNoPerm 用户是否没有操作权限

func IsUserNotFound

func IsUserNotFound(err error) bool

IsUserNotFound 用户是否不存在

func IsUserNotLoggedIn

func IsUserNotLoggedIn(err error) bool

IsUserNotLoggedIn 用户是否未登录

func JSONBytesParseError

func JSONBytesParseError(err error, jsonBytes []byte) error

func LogShow

func LogShow(ctx echo.Context, logFile string, extensions ...echo.H) error

LogShow 获取日志内容用于显示

func LookPath

func LookPath(bin string, otherPaths ...string) (string, error)

LookPath 获取二进制可执行文件路径

func MD5Sharding

func MD5Sharding(str interface{}, length ...int) string

MD5Sharding 按照MD5进行分片

func MarkdownPickoutCodeblock

func MarkdownPickoutCodeblock(content string) (repl []string, newContent string)

func MarkdownRestorePickout

func MarkdownRestorePickout(repl []string, content string) string

func ModTimeCache

func ModTimeCache(dir string, name string) (time.Time, error)

ModTimeCache 缓存文件修改时间

func ModelObjects

func ModelObjects(m factory.Model) []interface{}

func MonthSharding

func MonthSharding(ctx echo.Context) string

MonthSharding 按照日期月进行分片

func MyCleanTags

func MyCleanTags(value string) string

func MyCleanText

func MyCleanText(value string) string

func MyRemoveXSS

func MyRemoveXSS(content string) string

func NewSonyflake

func NewSonyflake(startDate string, machineIDs ...uint16) (*sonyflake.Sonyflake, error)

NewSonyflake 19位

func NewStrictPolicy

func NewStrictPolicy() *bluemonday.Policy

func NewUGCPolicy

func NewUGCPolicy() *bluemonday.Policy

func NextID

func NextID(machineIDs ...uint16) (uint64, error)
func NoLink() *bluemonday.Policy

func NoRetry

func NoRetry(err error) *errNoRetry

func OkString

func OkString(err interface{}) string

OkString 获取成功信息

func OnErrorRetry

func OnErrorRetry(f func() error, maxTimes int, interval time.Duration) error

func ParseMachineIDFromEnvVar added in v5.1.1

func ParseMachineIDFromEnvVar() (uint16, error)

func ParseMysqlConnectionURL

func ParseMysqlConnectionURL(settings *mysql.ConnectionURL)

func ParseSQL

func ParseSQL(sqlFile string, isFile bool, installer func(string) error) (err error)

func ProcessError

func ProcessError(ctx echo.Context, err error) error

func ReadCache

func ReadCache(dir string, name string) (content []byte, err error)

ReadCache 读缓存文件

func RegisterErr

func RegisterErr(key string, err error)

func RemoveBytesXSS

func RemoveBytesXSS(content []byte, noLinks ...bool) []byte

func RemoveCache

func RemoveCache(dir string, names ...string) (err error)

RemoveCache 删除缓存文件

func RemoveReaderXSS

func RemoveReaderXSS(reader io.Reader, noLinks ...bool) *bytes.Buffer

func RemoveXSS

func RemoveXSS(content string, noLinks ...bool) string

RemoveXSS 清除不安全的HTML标签和属性,一般用于处理文章内容

func ReplaceCharset

func ReplaceCharset(sqlStr string, charset string, checkCreateDDL ...bool) string

ReplaceCharset 替换DDL语句中的字符集

func ReplacePrefix

func ReplacePrefix(m factory.Model, field string, oldPrefix string, newPrefix string) error

ReplacePrefix 替换前缀数据

func Retry

func Retry(maxRetries int, fn func() error, stepDuration ...time.Duration) error

func RetryBy added in v5.0.1

func RetryBy(maxRetries int, fn func() error, stepDuration func(int) time.Duration) error

func SQLLineParser

func SQLLineParser(exec func(string) error, useCommentSQL ...bool) func(string) error

func SeekLinesWithoutComments

func SeekLinesWithoutComments(r io.Reader) (string, error)

func SendErr

func SendErr(ctx echo.Context, err error)

SendErr 记录错误信息 (SendFail的别名)

func SendFail

func SendFail(ctx echo.Context, msg string)

SendFail 记录失败信息

func SendOk

func SendOk(ctx echo.Context, msg string)

SendOk 记录成功信息

func SetRandomSecret

func SetRandomSecret(ctx echo.Context, sessionKey string, storeKey ...string)

SetRandomSecret 设置随机密码

func SetSonyflake

func SetSonyflake(startDate string, machineIDs ...uint16) (sonyFlake *sonyflake.Sonyflake, err error)

func Setting

func Setting(group ...string) echo.H

func SonyflakeInit

func SonyflakeInit(machineIDs ...uint16) *sonyflake.Sonyflake

func SplitSingleMutibytes

func SplitSingleMutibytes(content string) string

func SplitSingleMutibytesBytes

func SplitSingleMutibytesBytes(content []byte) []byte

func StringMapPoolGet

func StringMapPoolGet() param.StringMap

func StringMapPoolRelease

func StringMapPoolRelease(m param.StringMap)

func SystemAPIKey

func SystemAPIKey() string

func TemplateTags

func TemplateTags(keys ...string) echo.H

func Tx

func URLValuesPoolGet

func URLValuesPoolGet() url.Values

func URLValuesPoolRelease

func URLValuesPoolRelease(m url.Values)

func UniqueID

func UniqueID(machineIDs ...uint16) (string, error)

func VerifyAndSetCaptcha

func VerifyAndSetCaptcha(ctx echo.Context, hostAlias string, captchaName string, args ...string) echo.Data

VerifyAndSetCaptcha 验证码验证并设置新验证码信息

func VerifyCaptcha

func VerifyCaptcha(ctx echo.Context, hostAlias string, captchaName string, args ...string) echo.Data

VerifyCaptcha 验证码验证

func WithoutCommentsLineParser

func WithoutCommentsLineParser(exec func(string) error) func(string) error

func WriteCache

func WriteCache(dir string, name string, content []byte) (err error)

WriteCache 写缓存文件

func YearSharding

func YearSharding(ctx echo.Context) string

YearSharding 按照日期年进行分片

Types

type APIKeyGetter

type APIKeyGetter interface {
	APIKey() string
}

APIKeyGetter API Key

type Adder

type Adder interface {
	Set(interface{}, ...interface{})
	Add() (interface{}, error)
}

Adder interface

type ConfigFromDB

type ConfigFromDB interface {
	ConfigFromDB() echo.H
}

type CookieConfigGetter

type CookieConfigGetter interface {
	CookieConfig() scookie.Config
}

type ErrorTab

type ErrorTab interface {
	ErrorTab() string
}

type Errors

type Errors = errorslice.Errors

type List

type List = dbPagination.List

type Lister

type Lister = dbPagination.Lister

type LogParser

type LogParser func(line *tail.Line) (interface{}, error)

type Messager

type Messager interface {
	Successor
	error
}

Messager 信息接口

var DefaultNopMessage Messager = &NopMessage{}

DefaultNopMessage 默认空消息

func Message

func Message(err interface{}) Messager

Message 获取err中的信息接口

type NopMessage

type NopMessage struct {
}

NopMessage 空消息

func (*NopMessage) Error

func (n *NopMessage) Error() string

Error 错误信息

func (*NopMessage) String

func (n *NopMessage) String() string

String 信息字符串

func (*NopMessage) Success

func (n *NopMessage) Success() string

Success 成功信息

type OffsetListFunc

type OffsetListFunc = dbPagination.OffsetListFunc

type OffsetLister

type OffsetLister = dbPagination.OffsetLister

type PageListFunc

type PageListFunc = dbPagination.PageListFunc

type SQLQuery

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

func NewSQLQuery

func NewSQLQuery(ctx echo.Context) *SQLQuery

func NewSQLQueryLimit

func NewSQLQueryLimit(ctx echo.Context, offset int, limit int, linkIDs ...int) *SQLQuery

func (*SQLQuery) CacheKey

func (s *SQLQuery) CacheKey(cacheKey string) *SQLQuery

func (*SQLQuery) CacheTTL

func (s *SQLQuery) CacheTTL(ttlSeconds int64) *SQLQuery

func (*SQLQuery) GetFloat64

func (s *SQLQuery) GetFloat64(query string, args ...interface{}) (null.Float64, error)

func (*SQLQuery) GetInt

func (s *SQLQuery) GetInt(query string, args ...interface{}) (null.Int, error)

func (*SQLQuery) GetInt32

func (s *SQLQuery) GetInt32(query string, args ...interface{}) (null.Int32, error)

func (*SQLQuery) GetInt64

func (s *SQLQuery) GetInt64(query string, args ...interface{}) (null.Int64, error)

func (*SQLQuery) GetModel

func (s *SQLQuery) GetModel(name string, args ...interface{}) (interface{}, error)

func (*SQLQuery) GetModels

func (s *SQLQuery) GetModels(name string, args ...interface{}) ([]interface{}, error)

func (*SQLQuery) GetModelsWithPaging

func (s *SQLQuery) GetModelsWithPaging(name string, args ...interface{}) ([]interface{}, error)

func (*SQLQuery) GetRow

func (s *SQLQuery) GetRow(query string, args ...interface{}) (null.StringMap, error)

GetRow 查询一行多个字段值

func (*SQLQuery) GetRows

func (s *SQLQuery) GetRows(query string, args ...interface{}) (null.StringMapSlice, error)

GetRows 查询多行

func (*SQLQuery) GetString

func (s *SQLQuery) GetString(query string, args ...interface{}) (null.String, error)

func (*SQLQuery) GetUint

func (s *SQLQuery) GetUint(query string, args ...interface{}) (null.Uint, error)

func (*SQLQuery) GetUint32

func (s *SQLQuery) GetUint32(query string, args ...interface{}) (null.Uint32, error)

func (*SQLQuery) GetUint64

func (s *SQLQuery) GetUint64(query string, args ...interface{}) (null.Uint64, error)

func (*SQLQuery) GetValue

func (s *SQLQuery) GetValue(recv interface{}, query string, args ...interface{}) error

GetValue 查询单个字段值

func (*SQLQuery) Limit

func (s *SQLQuery) Limit(limit int) *SQLQuery

func (*SQLQuery) LinkID

func (s *SQLQuery) LinkID(dbLinkID int) *SQLQuery

func (*SQLQuery) LinkName

func (s *SQLQuery) LinkName(dbLinkName string) *SQLQuery

func (*SQLQuery) MustGetFloat64

func (s *SQLQuery) MustGetFloat64(query string, args ...interface{}) null.Float64

func (*SQLQuery) MustGetInt

func (s *SQLQuery) MustGetInt(query string, args ...interface{}) null.Int

func (*SQLQuery) MustGetInt32

func (s *SQLQuery) MustGetInt32(query string, args ...interface{}) null.Int32

func (*SQLQuery) MustGetInt64

func (s *SQLQuery) MustGetInt64(query string, args ...interface{}) null.Int64

func (*SQLQuery) MustGetModel

func (s *SQLQuery) MustGetModel(structName string, args ...interface{}) interface{}

func (*SQLQuery) MustGetModels

func (s *SQLQuery) MustGetModels(structName string, args ...interface{}) []interface{}

func (*SQLQuery) MustGetModelsWithPaging

func (s *SQLQuery) MustGetModelsWithPaging(structName string, args ...interface{}) []interface{}

func (*SQLQuery) MustGetRow

func (s *SQLQuery) MustGetRow(query string, args ...interface{}) null.StringMap

func (*SQLQuery) MustGetRows

func (s *SQLQuery) MustGetRows(query string, args ...interface{}) null.StringMapSlice

func (*SQLQuery) MustGetString

func (s *SQLQuery) MustGetString(query string, args ...interface{}) null.String

func (*SQLQuery) MustGetUint

func (s *SQLQuery) MustGetUint(query string, args ...interface{}) null.Uint

func (*SQLQuery) MustGetUint32

func (s *SQLQuery) MustGetUint32(query string, args ...interface{}) null.Uint32

func (*SQLQuery) MustGetUint64

func (s *SQLQuery) MustGetUint64(query string, args ...interface{}) null.Uint64

func (*SQLQuery) Offset

func (s *SQLQuery) Offset(offset int) *SQLQuery

func (*SQLQuery) OrderBy

func (s *SQLQuery) OrderBy(sorts ...interface{}) *SQLQuery

type SelectPageSortValues added in v5.1.0

type SelectPageSortValues struct {
	PKName   string
	PKValues []string
}

func SelectPageCond

func SelectPageCond(ctx echo.Context, cond *db.Compounds, pkAndLabelFields ...string) (sv *SelectPageSortValues)

func (SelectPageSortValues) AddToSorts added in v5.1.0

func (s SelectPageSortValues) AddToSorts(sorts []interface{}) []interface{}

func (SelectPageSortValues) IsEmpty added in v5.1.0

func (s SelectPageSortValues) IsEmpty() bool

func (SelectPageSortValues) IsMultiple added in v5.1.0

func (s SelectPageSortValues) IsMultiple() bool

func (SelectPageSortValues) OrderByString added in v5.1.0

func (s SelectPageSortValues) OrderByString() string

type SetContext

type SetContext interface {
	SetContext(echo.Context)
}

type SortedURLValues

type SortedURLValues []*URLValues

func NewSortedURLValues

func NewSortedURLValues(query string) SortedURLValues

func (*SortedURLValues) Add

func (s *SortedURLValues) Add(key, value string)

func (SortedURLValues) ApplyCond

func (s SortedURLValues) ApplyCond(cond *db.Compounds)

func (*SortedURLValues) Del

func (s *SortedURLValues) Del(key string)

func (SortedURLValues) Get

func (s SortedURLValues) Get(key string) string

func (SortedURLValues) Has

func (s SortedURLValues) Has(key string) bool

func (*SortedURLValues) ParseQuery

func (s *SortedURLValues) ParseQuery(query string) (err error)

ParseQuery 解析 URL Query copy from standard library src/net/url/url.go: func parseQuery(m Values, query string) (err error)

func (*SortedURLValues) Set

func (s *SortedURLValues) Set(key, value string)

type StatusColor

type StatusColor string

StatusColor 状态色

func HTTPStatusColor

func HTTPStatusColor(httpCode int) StatusColor

HTTPStatusColor HTTP状态码相应颜色

func (StatusColor) Bootstrap

func (s StatusColor) Bootstrap() string

Bootstrap 前端框架 bootstrap css 状态样式

func (StatusColor) String

func (s StatusColor) String() string

func (StatusColor) Terminal

func (s StatusColor) Terminal() func(string, ...interface{})

Terminal 控制台样式

type Stringify

type Stringify interface {
	Stringify(separator string) string
}

type Success

type Success struct {
	Value string
}

Success 成功信息

func (*Success) String

func (s *Success) String() string

func (*Success) Success

func (s *Success) Success() string

Success 成功信息

type Successor

type Successor interface {
	Success() string
}

Successor 成功信息接口

func NewOk

func NewOk(v string) Successor

NewOk 创建成功信息

func Ok

func Ok(v string) Successor

Ok 操作成功

type URLValues

type URLValues struct {
	Key    string
	Values []string
}

Jump to

Keyboard shortcuts

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