pokercompetition

package module
v0.0.122 Latest Latest
Warning

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

Go to latest
Published: Apr 25, 2024 License: Apache-2.0 Imports: 14 Imported by: 0

README

pokercompetition

pokercompetition is poker competition engine written in golang.

Documentation

Index

Constants

View Source
const (
	// CompetitionStateStatus
	CompetitionStateStatus_PreRegistering CompetitionStateStatus = "pre-registering" // 賽事已建立 (但不可報名)
	CompetitionStateStatus_Registering    CompetitionStateStatus = "registering"     // 賽事已建立 (可報名參賽)
	CompetitionStateStatus_DelayedBuyIn   CompetitionStateStatus = "delayed_buy_in"  // 賽事已建立 (延遲買入)
	CompetitionStateStatus_StoppedBuyIn   CompetitionStateStatus = "stopped_buy_in"  // 賽事已建立 (停止買入)
	CompetitionStateStatus_End            CompetitionStateStatus = "end"             // 賽事已結束 (正常結束)
	CompetitionStateStatus_AutoEnd        CompetitionStateStatus = "auto_end"        // 賽事已結束 (開賽未成功自動關閉)
	CompetitionStateStatus_ForceEnd       CompetitionStateStatus = "force_end"       // 賽事已結束 (其他原因強制關閉)
	CompetitionStateStatus_Restoring      CompetitionStateStatus = "restoring"       // 賽事資料轉移中 (Graceful Shutdown Use)

	// CompetitionPlayerStatus
	CompetitionPlayerStatus_WaitingTableBalancing CompetitionPlayerStatus = "waiting_table_balancing" // 等待拆併桌中
	CompetitionPlayerStatus_Playing               CompetitionPlayerStatus = "playing"                 // 比賽中
	CompetitionPlayerStatus_ReBuyWaiting          CompetitionPlayerStatus = "re_buy_waiting"          // 等待補碼中 (已不再桌次內)
	CompetitionPlayerStatus_Knockout              CompetitionPlayerStatus = "knockout"                // 已淘汰
	CompetitionPlayerStatus_CashLeaving           CompetitionPlayerStatus = "cash_leaving"            // 現金桌離開中 (結算時就會離開)

	// CompetitionMode
	CompetitionMode_CT   CompetitionMode = "ct"   // 倒數錦標賽
	CompetitionMode_MTT  CompetitionMode = "mtt"  // 大型錦標賽
	CompetitionMode_Cash CompetitionMode = "cash" // 現金桌

	// CompetitionRule
	CompetitionRule_Default   CompetitionRule = "default"    // 常牌
	CompetitionRule_ShortDeck CompetitionRule = "short_deck" // 短牌
	CompetitionRule_Omaha     CompetitionRule = "omaha"      // 奧瑪哈

	// CompetitionAdvanceRule
	CompetitionAdvanceRule_PlayerCount CompetitionAdvanceRule = "player_count" // 晉級方式: 尚未淘汰玩家人數
	CompetitionAdvanceRule_BlindLevel  CompetitionAdvanceRule = "blind_level"  // 晉級方式: 盲注等級

	// CompetitionAdvanceStatus
	CompetitionAdvanceStatus_NotStart CompetitionAdvanceStatus = "adv_not_start" // 晉級狀態: 未開始
	CompetitionAdvanceStatus_Updating CompetitionAdvanceStatus = "adv_updating"  // 晉級狀態: 晉級計算中
	CompetitionAdvanceStatus_End      CompetitionAdvanceStatus = "adv_end"       // 晉級狀態: 已結束
)
View Source
const (
	UnsetValue       = -1
	NoStopBuyInIndex = -2
)
View Source
const (
	CompetitionStateEvent_BlindActivated   = "BlindActivated"
	CompetitionStateEvent_BlindUpdated     = "BlindUpdated"
	CompetitionStateEvent_Started          = "Started"
	CompetitionStateEvent_TableUpdated     = "TableUpdated"
	CompetitionStateEvent_TableGameSettled = "TableGameSettled"
	CompetitionStateEvent_KnockoutPlayers  = "KnockoutPlayers"
	CompetitionStateEvent_CashOutPlayers   = "CashOutPlayers"
	CompetitionStateEvent_Settled          = "Settled"
)

Variables

View Source
var (
	ErrCompetitionInvalidCreateSetting            = errors.New("competition: invalid create competition setting")
	ErrCompetitionStartRejected                   = errors.New("competition: already started")
	ErrCompetitionUpdateBlindInitialLevelRejected = errors.New("competition: not allowed to update blind initial level")
	ErrCompetitionLeaveRejected                   = errors.New("competition: not allowed to leave")
	ErrCompetitionRefundRejected                  = errors.New("competition: not allowed to refund")
	ErrCompetitionQuitRejected                    = errors.New("competition: not allowed to quit")
	ErrCompetitionNoRedeemChips                   = errors.New("competition: not redeem any chips")
	ErrCompetitionAddonRejected                   = errors.New("competition: not allowed to addon")
	ErrCompetitionReBuyRejected                   = errors.New("competition: not allowed to re-buy")
	ErrCompetitionBuyInRejected                   = errors.New("competition: not allowed to buy in")
	ErrCompetitionExceedReBuyLimit                = errors.New("competition: exceed re-buy limit")
	ErrCompetitionExceedAddonLimit                = errors.New("competition: exceed addon limit")
	ErrCompetitionPlayerNotFound                  = errors.New("competition: player not found")
	ErrCompetitionTableNotFound                   = errors.New("competition: table not found")
	ErrMatchInitFailed                            = errors.New("competition: failed to init match")
	ErrMatchTableReservePlayerFailed              = errors.New("competition: failed to balance player to table by match")
)
View Source
var (
	ErrManagerCompetitionNotFound = errors.New("manager: competition not found")
)

Functions

func NewPokerTableSetting

func NewPokerTableSetting(competitionID string, competitionMeta CompetitionMeta, tableSetting TableSetting) pokertable.TableSetting

Types

type AddonSetting

type AddonSetting struct {
	IsBreakOnly bool    `json:"is_break_only"` // 是否中場休息限定
	RedeemChips []int64 `json:"redeem_chips"`  // 可兌換籌碼數
	MaxTime     int     `json:"max_time"`      // 最大次數
}

type AdvanceSetting added in v0.0.50

type AdvanceSetting struct {
	Rule        CompetitionAdvanceRule `json:"rule"`         // 晉級方式
	PlayerCount int                    `json:"player_count"` // 晉級人數
	BlindLevel  int                    `json:"blind_level"`  // 晉級盲注級別
}

type AdvanceState added in v0.0.50

type AdvanceState struct {
	Status          CompetitionAdvanceStatus `json:"status"`            // 晉級狀態
	TotalTables     int                      `json:"total_tables"`      // 總桌數
	UpdatedTables   int                      `json:"updated_tables"`    // 已更新桌數
	UpdatedTableIDs []string                 `json:"updated_table_ids"` // 已更新桌次 ID
}

type Blind

type Blind struct {
	ID                   string       `json:"id"`                     // ID
	InitialLevel         int          `json:"initial_level"`          // 起始盲注級別
	FinalBuyInLevelIndex int          `json:"final_buy_in_level_idx"` // 最後買入盲注等級索引值
	DealerBlindTime      int          `json:"dealer_blind_time"`      // Dealer 位置要收取的前注倍數 (短牌用)
	Levels               []BlindLevel `json:"levels"`                 // 級別資訊列表
}

type BlindLevel

type BlindLevel struct {
	Level      int   `json:"level"`       // 盲注等級(-1 表示中場休息)
	SB         int64 `json:"sb"`          // 小盲籌碼量
	BB         int64 `json:"bb"`          // 大盲籌碼量
	Ante       int64 `json:"ante"`        // 前注籌碼量
	Duration   int   `json:"duration"`    // 等級持續時間 (Seconds)
	AllowAddon bool  `json:"allow_addon"` // 是否允許增購
}

type BlindState

type BlindState struct {
	FinalBuyInLevelIndex int     `json:"final_buy_in_level_idx"` // 最後買入盲注等級索引值
	CurrentLevelIndex    int     `json:"current_level_index"`    // 現在盲注等級級別索引值
	EndAts               []int64 `json:"end_ats"`                // 每個等級結束時間 (Seconds)
}

func (BlindState) IsStopBuyIn added in v0.0.35

func (bs BlindState) IsStopBuyIn() bool

BlindState Getters

type Competition

type Competition struct {
	UpdateSerial int64             `json:"update_serial"` // 更新序列號 (數字越大越晚發生)
	ID           string            `json:"id"`            // 賽事 Unique ID
	Meta         CompetitionMeta   `json:"meta"`          // 賽事固定資料
	State        *CompetitionState `json:"state"`         // 賽事動態資料
	UpdateAt     int64             `json:"update_at"`     // 更新時間 (Seconds)
}

func (*Competition) AsPlayer

func (c *Competition) AsPlayer()

Competition Setters

func (Competition) CurrentBlindData

func (c Competition) CurrentBlindData() (int, int64, int64, int64, int64)

func (Competition) CurrentBlindLevel

func (c Competition) CurrentBlindLevel() BlindLevel

func (Competition) FindPlayerIdx

func (c Competition) FindPlayerIdx(predicate func(*CompetitionPlayer) bool) int

func (Competition) FindTableIdx

func (c Competition) FindTableIdx(predicate func(*pokertable.Table) bool) int

func (Competition) GetJSON

func (c Competition) GetJSON() (string, error)

Competition Getters

func (Competition) IsBreaking

func (c Competition) IsBreaking() bool

func (Competition) IsTableExist added in v0.0.73

func (c Competition) IsTableExist(tableID string) bool

func (Competition) PlayingPlayerCount

func (c Competition) PlayingPlayerCount() int

type CompetitionAdvanceRule added in v0.0.50

type CompetitionAdvanceRule string

type CompetitionAdvanceStatus added in v0.0.50

type CompetitionAdvanceStatus string

type CompetitionEngine

type CompetitionEngine interface {
	// Events
	OnCompetitionUpdated(fn func(competition *Competition))                                         // 賽事更新事件監聽器
	OnCompetitionErrorUpdated(fn func(competition *Competition, err error))                         // 賽事錯誤更新事件監聽器
	OnCompetitionPlayerUpdated(fn func(competitionID string, competitionPlayer *CompetitionPlayer)) // 賽事玩家更新事件監聽器
	OnCompetitionFinalPlayerRankUpdated(fn func(competitionID, playerID string, rank int))          // 賽事玩家最終名次監聽器
	OnCompetitionStateUpdated(fn func(event string, competition *Competition))                      // 賽事狀態監聽器
	OnAdvancePlayerCountUpdated(fn func(competitionID string, totalBuyInCount int) int)             // 賽事晉級人數更新監聽器
	OnCompetitionPlayerCashOut(fn func(competitionID string, competitionPlayer *CompetitionPlayer)) // 現金桌賽事玩家結算事件監聽器
	OnTableCreated(fn func(table *pokertable.Table))                                                // TODO: Test Only

	// Competition Actions
	GetCompetition() *Competition                                                  // 取得賽事
	CreateCompetition(competitionSetting CompetitionSetting) (*Competition, error) // 建立賽事
	UpdateCompetitionBlindInitialLevel(level int) error                            // 更新賽事盲注初始等級
	CloseCompetition(endStatus CompetitionStateStatus) error                       // 關閉賽事
	StartCompetition() (int64, error)                                              // 開始賽事

	// Player Operations
	PlayerBuyIn(joinPlayer JoinPlayer) error                 // 玩家報名或補碼
	PlayerAddon(tableID string, joinPlayer JoinPlayer) error // 玩家增購
	PlayerRefund(playerID string) error                      // 玩家退賽
	PlayerCashOut(tableID, playerID string) error            // 玩家離桌結算 (現金桌)
	PlayerQuit(tableID, playerID string) error               // 玩家棄賽淘汰

	// Others
	UpdateTable(table *pokertable.Table)                                                    // 桌次更新
	UpdateReserveTablePlayerState(tableID string, playerState *pokertable.TablePlayerState) // 更新 Reserve 桌次玩家狀態
	ReleaseTables() error                                                                   // 釋放所有桌次
}

func NewCompetitionEngine

func NewCompetitionEngine(opts ...CompetitionEngineOpt) CompetitionEngine

type CompetitionEngineOpt

type CompetitionEngineOpt func(*competitionEngine)

func WithTableManagerBackend

func WithTableManagerBackend(tmb TableManagerBackend) CompetitionEngineOpt

type CompetitionEngineOptions

type CompetitionEngineOptions struct {
	OnCompetitionUpdated                func(competition *Competition)
	OnCompetitionErrorUpdated           func(competition *Competition, err error)
	OnCompetitionPlayerUpdated          func(competitionID string, competitionPlayer *CompetitionPlayer)
	OnCompetitionFinalPlayerRankUpdated func(competitionID, playerID string, rank int)
	OnCompetitionStateUpdated           func(event string, competition *Competition)
	OnAdvancePlayerCountUpdated         func(competitionID string, totalBuyInCount int) int
	OnCompetitionPlayerCashOut          func(competitionID string, competitionPlayer *CompetitionPlayer)
}

func NewDefaultCompetitionEngineOptions

func NewDefaultCompetitionEngineOptions() *CompetitionEngineOptions

type CompetitionMeta

type CompetitionMeta struct {
	Blind                          Blind           `json:"blind"`                              // 盲注資訊
	MaxDuration                    int             `json:"max_duration"`                       // 比賽時間總長 (Seconds)
	MinPlayerCount                 int             `json:"min_player_count"`                   // 最小參賽人數
	MaxPlayerCount                 int             `json:"max_player_count"`                   // 最大參賽人數
	TableMaxSeatCount              int             `json:"table_max_seat_count"`               // 每桌人數上限
	TableMinPlayerCount            int             `json:"table_min_player_count"`             // 每桌最小開打數
	RegulatorMinInitialPlayerCount int             `json:"regulator_min_initial_player_count"` // 拆併桌每桌至少需要人數
	Rule                           CompetitionRule `json:"rule"`                               // 德州撲克規則, 常牌(default), 短牌(short_deck), 奧瑪哈(omaha)
	Mode                           CompetitionMode `json:"mode"`                               // 賽事模式 (CT, MTT, Cash)
	ReBuySetting                   ReBuySetting    `json:"re_buy_setting"`                     // 補碼設定
	AddonSetting                   AddonSetting    `json:"addon_setting"`                      // 增購設定
	AdvanceSetting                 AdvanceSetting  `json:"advance_setting"`                    // 晉級設定
	ActionTime                     int             `json:"action_time"`                        // 思考時間 (Seconds)
	MinChipUnit                    int64           `json:"min_chip_unit"`                      // 最小單位籌碼量
}

type CompetitionMode

type CompetitionMode string

type CompetitionPlayer

type CompetitionPlayer struct {
	PlayerID       string `json:"player_id"` // 玩家 ID
	CurrentTableID string `json:"table_id"`  // 當前桌次 ID
	CurrentSeat    int    `json:"seat"`      // 當前座位
	JoinAt         int64  `json:"join_at"`   // 加入時間 (Seconds)

	// current info
	Status     CompetitionPlayerStatus `json:"status"`        // 參與玩家狀態
	Rank       int                     `json:"rank"`          // 當前桌次排名
	Chips      int64                   `json:"chips"`         // 當前籌碼
	IsReBuying bool                    `json:"is_re_buying"`  // 是否正在補碼
	ReBuyEndAt int64                   `json:"re_buy_end_at"` // 最後補碼時間 (Seconds)
	ReBuyTimes int                     `json:"re_buy_times"`  // 補碼次數
	AddonTimes int                     `json:"addon_times"`   // 增購次數

	// statistics info
	// best
	BestWinningPotChips int64    `json:"best_winning_pot_chips"` // 贏得最大底池籌碼數
	BestWinningCombo    []string `json:"best_winning_combo"`     // 身為贏家時最大的牌型組合
	BestWinningType     string   `json:"best_winning_type"`      // 身為贏家時最大的牌型類型
	BestWinningPower    int      `json:"best_winning_power"`     // 身為贏家時最大的牌型牌力

	// accumulated info
	// competition/table
	TotalRedeemChips int64 `json:"total_redeem_chips"` // 累積兌換籌碼
	TotalGameCounts  int64 `json:"total_game_counts"`  // 總共玩幾手牌

	// game: round & actions
	TotalWalkTimes        int64 `json:"total_walk_times"`         // Preflop 除了大盲以外的人全部 Fold,而贏得籌碼的次數
	TotalFoldTimes        int   `json:"total_fold_times"`         // 棄牌總次數
	TotalPreflopFoldTimes int   `json:"total_preflop_fold_times"` // Preflop 棄牌總次數
	TotalFlopFoldTimes    int   `json:"total_flop_fold_times"`    // Flop 棄牌總次數
	TotalTurnFoldTimes    int   `json:"total_turn_fold_times"`    // Turn 棄牌總次數
	TotalRiverFoldTimes   int   `json:"total_river_fold_times"`   // River 棄牌總次數
	TotalActionTimes      int   `json:"total_action_times"`       // 下注動作總次數
	TotalRaiseTimes       int   `json:"total_raise_times"`        // 加注/入池總次數(AllIn&Raise、Raise、Bet)
	TotalCallTimes        int   `json:"total_call_times"`         // 跟注總次數
	TotalCheckTimes       int   `json:"total_check_times"`        // 過牌總次數
	TotalProfitTimes      int   `json:"total_profit_times"`       // 總共贏得籌碼次數

	// game: statistics
	TotalVPIPChances            int `json:"total_vpip_chances"`             // 入池總機會
	TotalVPIPTimes              int `json:"total_vpip_times"`               // 入池總次數
	TotalPFRChances             int `json:"total_pfr_chances"`              // PFR 總機會
	TotalPFRTimes               int `json:"total_pfr_times"`                // PFR 總次數
	TotalATSChances             int `json:"total_ats_chances"`              // ATS 總機會
	TotalATSTimes               int `json:"total_ats_times"`                // ATS 總次數
	Total3BChances              int `json:"total_3b_chances"`               // 3-Bet 總機會
	Total3BTimes                int `json:"total_3b_times"`                 // 3-Bet 總次數
	TotalFt3BChances            int `json:"total_ft3b_chances"`             // Ft3B 總機會
	TotalFt3BTimes              int `json:"total_ft3b_times"`               // Ft3B 總次數
	TotalCheckRaiseChances      int `json:"total_check_raise_chances"`      // C/R 總機會
	TotalCheckRaiseTimes        int `json:"total_check_raise_times"`        // C/R 總次數
	TotalCBetChances            int `json:"total_c_bet_chances"`            // C-Bet 總機會
	TotalCBetTimes              int `json:"total_c_bet_times"`              // C-Bet 總次數
	TotalFtCBChances            int `json:"total_ftcb_chances"`             // FtCB 總機會
	TotalFtCBTimes              int `json:"total_ftcb_times"`               // FtCB 總次數
	TotalShowdownWinningChances int `json:"total_showdown_winning_chances"` // Showdown Winning 總機會
	TotalShowdownWinningTimes   int `json:"total_showdown_winning_times"`   // Showdown Winning 總次數
}

func (CompetitionPlayer) IsOverReBuyWaitingTime added in v0.0.78

func (cp CompetitionPlayer) IsOverReBuyWaitingTime() bool

CompetitionPlayer Getters

type CompetitionPlayerStatus

type CompetitionPlayerStatus string

type CompetitionRank

type CompetitionRank struct {
	PlayerID   string `json:"player_id"`   // 玩家 ID
	FinalChips int64  `json:"final_chips"` // 玩家最後籌碼數
}

type CompetitionRule

type CompetitionRule string

type CompetitionSetting

type CompetitionSetting struct {
	CompetitionID string          `json:"competition_id"`
	Meta          CompetitionMeta `json:"meta"`
	StartAt       int64           `json:"start_game_at"`
	DisableAt     int64           `json:"disable_game_at"`
	TableSettings []TableSetting  `json:"table_settings"`
}

type CompetitionState

type CompetitionState struct {
	OpenAt       int64                  `json:"open_at"`       // 賽事建立時間 (可報名、尚未開打)
	DisableAt    int64                  `json:"disable_at"`    // 賽事未開打前,賽局可見時間 (Seconds)
	StartAt      int64                  `json:"start_at"`      // 賽事開打時間 (可報名、開打) (Seconds)
	EndAt        int64                  `json:"end_at"`        // 賽事結束時間 (Seconds)
	BlindState   *BlindState            `json:"blind_state"`   // 盲注狀態
	Players      []*CompetitionPlayer   `json:"players"`       // 參與過賽事玩家陣列
	Status       CompetitionStateStatus `json:"status"`        // 賽事狀態
	Tables       []*pokertable.Table    `json:"tables"`        // 多桌
	Rankings     []*CompetitionRank     `json:"rankings"`      // 停止買入後玩家排名 (陣列 Index 即是排名 rank - 1, ex: index 0 -> 第一名, index 1 -> 第二名...)
	AdvanceState *AdvanceState          `json:"advance_state"` // 晉級狀態
	Statistic    *Statistic             `json:"statistic"`     // 賽事統計資料
}

type CompetitionStateStatus

type CompetitionStateStatus string

type JoinPlayer

type JoinPlayer struct {
	PlayerID    string `json:"player_id"`
	RedeemChips int64  `json:"redeem_chips"`
}

type Manager

type Manager interface {
	Reset()
	ReleaseCompetition(competitionID string)

	// CompetitionEngine Actions
	GetCompetitionEngine(competitionID string) (CompetitionEngine, error)

	// Competition Actions
	CreateCompetition(competitionSetting CompetitionSetting, options *CompetitionEngineOptions) (*Competition, error)
	UpdateCompetitionBlindInitialLevel(competitionID string, level int) error
	CloseCompetition(competitionID string, endStatus CompetitionStateStatus) error
	StartCompetition(competitionID string) (int64, error)

	// Table Actions
	GetTableEngineOptions() *pokertable.TableEngineOptions
	SetTableEngineOptions(tableOptions *pokertable.TableEngineOptions)
	UpdateTable(competitionID string, table *pokertable.Table) error
	UpdateReserveTablePlayerState(competitionID, tableID string, playerState *pokertable.TablePlayerState) error

	// Player Operations
	PlayerBuyIn(competitionID string, joinPlayer JoinPlayer) error
	PlayerAddon(competitionID string, tableID string, joinPlayer JoinPlayer) error
	PlayerRefund(competitionID string, playerID string) error
	PlayerCashOut(competitionID string, tableID, playerID string) error
	PlayerQuit(competitionID string, tableID, playerID string) error
}

func NewManager

func NewManager(tableManagerBackend TableManagerBackend) Manager

type PlayerCache

type PlayerCache struct {
	PlayerID   string
	JoinAt     int64
	PlayerIdx  int // index of Competition.State.Players
	ReBuyTimes int
	TableID    string
}

type RankData

type RankData struct {
	PlayerID string
	Rank     int
	Chips    int64
}

type ReBuySetting

type ReBuySetting struct {
	MaxTime     int `json:"max_time"`     // 最大次數
	WaitingTime int `json:"waiting_time"` // 玩家可補碼時間 (Seconds)
}

type Statistic added in v0.0.50

type Statistic struct {
	TotalBuyInCount int `json:"total_buy_in_count"` // 總買入次數
}

type TableManagerBackend

type TableManagerBackend interface {
	// Events
	OnTableUpdated(fn func(table *pokertable.Table))
	OnTablePlayerReserved(fn func(tableID string, playerState *pokertable.TablePlayerState))

	// TableManager Table Actions
	CreateTable(options *pokertable.TableEngineOptions, setting pokertable.TableSetting) (*pokertable.Table, error)
	PauseTable(tableID string) error
	CloseTable(tableID string) error
	StartTableGame(tableID string) error
	TableGameOpen(tableID string) error
	UpdateBlind(tableID string, level int, ante, dealer, sb, bb int64) error
	UpdateTablePlayers(tableID string, joinPlayers []pokertable.JoinPlayer, leavePlayerIDs []string) (map[string]int, error)

	// TableManager Player Table Actions
	PlayerReserve(tableID string, joinPlayer pokertable.JoinPlayer) error
	PlayerJoin(tableID, playerID string) error // TODO: test only, should remove this
	PlayerRedeemChips(tableID string, joinPlayer pokertable.JoinPlayer) error
	PlayersLeave(tableID string, playerIDs []string) error

	// Others
	UpdateTable(table *pokertable.Table) // TODO: test only, should remove this
	ReleaseTable(tableID string) error
}

func NewNativeTableManagerBackend

func NewNativeTableManagerBackend(manager pokertable.Manager) TableManagerBackend

type TableSetting

type TableSetting struct {
	TableID     string                  `json:"table_id"`
	JoinPlayers []pokertable.JoinPlayer `json:"join_players"`
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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