knf

package
v12.120.0 Latest Latest
Warning

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

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

Documentation

Overview

Package knf provides methods for working with configuration files in KNF format

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrNilConfig  = errors.New("Configuration is nil")
	ErrCantReload = errors.New("Can't reload configuration file: path to file is empty")
	ErrCantMerge  = errors.New("Can't merge configurations: given configuration is nil")
)
View Source
var (
	Millisecond = DurationMod(time.Millisecond)
	Second      = 1000 * Millisecond
	Minute      = 60 * Second
	Hour        = 60 * Minute
	Day         = 24 * Hour
	Week        = 7 * Day
)

Functions

func Alias added in v12.120.0

func Alias(old, new string) error

Alias creates alias for configuration property

It's useful for refactoring the configuration or for providing support for renamed properties

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

// Add alias for renamed property "user:username"
Alias("user:username", "user:name")

fmt.Printf("Value from config: %s\n", GetS("user:name"))
Output:

func GetB

func GetB(name string, defvals ...bool) bool

GetB returns configuration value as boolean

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %t\n", GetB("user:is-admin"))
Output:

func GetD

func GetD(name string, mod DurationMod, defvals ...time.Duration) time.Duration

GetD returns configuration values as duration

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %v\n", GetD("user:timeout", Minute))
Output:

func GetF

func GetF(name string, defvals ...float64) float64

GetF returns configuration value as floating number

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %g\n", GetF("user:priority"))
Output:

func GetI

func GetI(name string, defvals ...int) int

GetI returns configuration value as int

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %d\n", GetI("user:uid"))
Output:

func GetI64

func GetI64(name string, defvals ...int64) int64

GetI64 returns configuration value as int64

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %d\n", GetI64("user:uid"))
Output:

func GetL added in v12.103.0

func GetL(name string, defvals ...[]string) []string

GetL returns configuration value as list

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %v\n", GetL("issue:labels"))
Output:

func GetM

func GetM(name string, defvals ...os.FileMode) os.FileMode

GetM returns configuration value as file mode

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %v\n", GetF("user:default-mode"))
Output:

func GetS

func GetS(name string, defvals ...string) string

GetS returns configuration value as string

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %s\n", GetS("user:name"))
Output:

func GetTD added in v12.103.0

func GetTD(name string, defvals ...time.Duration) time.Duration

GetTD returns configuration value as time duration

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %v\n", GetTD("user:timeout"))
Output:

func GetTS added in v12.103.0

func GetTS(name string, defvals ...time.Time) time.Time

GetTS returns configuration timestamp value as time

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %v\n", GetTS("user:created"))
Output:

func GetTZ added in v12.103.0

func GetTZ(name string, defvals ...*time.Location) *time.Location

GetTS returns configuration value as timezone

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %v\n", GetTZ("service:timezone"))
Output:

func GetU

func GetU(name string, defvals ...uint) uint

GetU returns configuration value as uint

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %d\n", GetU("user:uid"))
Output:

func GetU64

func GetU64(name string, defvals ...uint64) uint64

GetU64 returns configuration value as uint64

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %d\n", GetU64("user:uid"))
Output:

func Global

func Global(file string) error

Global reads and parses configuration file Global instance is accessible from any part of the code

Example
// Load global config
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

// Read string value
GetS("section:string")

// Read integer value
GetI("section:int")

// Read float value
GetF("section:float")

// Read boolean value
GetB("section:boolean")

// Read file mode value
GetM("section:file-mode")

// Read duration as seconds
GetD("section:duration", Second)

// Read duration as minutes
GetD("section:duration", Minute)

// Read time duration
GetTD("section:time-duration")

// Read timestamp
GetTS("section:timestamp")

// Read timezone
GetTZ("section:timezone")

// Read list
GetL("section:list")

// Check section
if HasSection("section") {
	// Section exist
}

// Check property
if HasProp("section:string") {
	// Property exist
}

// Slice of all sections
Sections()

// Slice of all properties in section
Props("section")
Output:

func HasProp

func HasProp(name string) bool

HasProp checks if the property is defined and set

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Is property \"user:name\" exist: %t\n", HasProp("user:name"))
fmt.Printf("Is property \"user:path\" exist: %t\n", HasProp("user:path"))
Output:

func HasSection

func HasSection(section string) bool

HasSection checks if the section exists

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Is section \"main\" exist: %t\n", HasSection("main"))
fmt.Printf("Is section \"user\" exist: %t\n", HasSection("user"))
Output:

func Is added in v12.47.0

func Is(name string, value any) bool

Is checks if given property contains given value

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("user.name == bob: %t\n", Is("user:name", "bob"))
fmt.Printf("user.uid == 512: %t\n", Is("user:uid", 512))
Output:

func Props

func Props(section string) []string

Props returns slice with properties names in some section

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

for index, prop := range Props("user") {
	fmt.Printf("%d: %s\n", index+1, prop)
}
Output:

func Reload

func Reload() (map[string]bool, error)

Reload reloads global configuration file

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

changes, err := Reload()

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

// Print info about changed values
for prop, changed := range changes {
	fmt.Printf("Property %s changed → %t\n", prop, changed)
}
Output:

func Sections

func Sections() []string

Sections returns slice with section names

Example
err := Global("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

for index, section := range Sections() {
	fmt.Printf("%d: %s\n", index+1, section)
}
Output:

func Validate

func Validate(validators []*Validator) []error

Validate executes all given validators and returns slice with validation errors

Types

type Config

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

Config is basic configuration instance

func Parse added in v12.99.0

func Parse(data []byte) (*Config, error)

Parse parses data with KNF configuration

Example
cfg, err := Parse([]byte(`
[service]
	user: john
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %s\n", cfg.GetS("service:user"))
Output:

Value from config: john

func Read

func Read(file string) (*Config, error)

Read reads and parses configuration file

Example
cfg, err := Read("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %s\n", cfg.GetS("service:user"))
Output:

func (*Config) Alias added in v12.120.0

func (c *Config) Alias(old, new string) error

Alias creates alias for configuration property

It's useful for refactoring the configuration or for providing support for renamed properties

Example
cfg, err := Parse([]byte(`
[user]
	username: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

// Add alias for renamed property "user:username"
cfg.Alias("user:username", "user:name")

fmt.Printf("Value from config: %s\n", cfg.GetS("user:name"))
Output:

Value from config: john

func (*Config) File added in v12.45.0

func (c *Config) File() string

File returns path to configuration file

Example
cfg, err := Read("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Path to config: %s\n", cfg.File())
Output:

func (*Config) GetB

func (c *Config) GetB(name string, defvals ...bool) bool

GetB returns configuration value as boolean

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %t\n", cfg.GetB("user:is-admin"))
Output:

Value from config: true

func (*Config) GetD

func (c *Config) GetD(name string, mod DurationMod, defvals ...time.Duration) time.Duration

GetD returns configuration value as duration

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %v\n", cfg.GetD("user:timeout", Minute))
Output:

Value from config: 3m0s

func (*Config) GetF

func (c *Config) GetF(name string, defvals ...float64) float64

GetF returns configuration value as floating number

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %g\n", cfg.GetF("user:priority"))
Output:

Value from config: 3.7

func (*Config) GetI

func (c *Config) GetI(name string, defvals ...int) int

GetI returns configuration value as int

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %d\n", cfg.GetI("user:uid"))
Output:

Value from config: 512

func (*Config) GetI64

func (c *Config) GetI64(name string, defvals ...int64) int64

GetI64 returns configuration value as int64

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %d\n", cfg.GetI64("user:uid"))
Output:

Value from config: 512

func (*Config) GetL added in v12.103.0

func (c *Config) GetL(name string, defvals ...[]string) []string

GetL returns configuration value as list

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %s\n", cfg.GetL("user:labels"))
Output:

Value from config: [system admin]

func (*Config) GetM

func (c *Config) GetM(name string, defvals ...os.FileMode) os.FileMode

GetM returns configuration value as file mode

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %v\n", cfg.GetF("user:default-mode"))
Output:

Value from config: 644

func (*Config) GetS

func (c *Config) GetS(name string, defvals ...string) string

GetS returns configuration value as string

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %s\n", cfg.GetS("user:name"))
Output:

Value from config: john

func (*Config) GetTD added in v12.103.0

func (c *Config) GetTD(name string, defvals ...time.Duration) time.Duration

GetTD returns configuration value as time duration

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %v\n", cfg.GetTD("user:timeout"))
Output:

Value from config: 3m0s

func (*Config) GetTS added in v12.103.0

func (c *Config) GetTS(name string, defvals ...time.Time) time.Time

GetTS returns configuration timestamp value as time

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %v\n", cfg.GetTS("user:created"))
Output:

func (*Config) GetTZ added in v12.103.0

func (c *Config) GetTZ(name string, defvals ...*time.Location) *time.Location

GetTS returns configuration value as timezone

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %s\n", cfg.GetTZ("user:timezone"))
Output:

Value from config: Europe/Madrid

func (*Config) GetU

func (c *Config) GetU(name string, defvals ...uint) uint

GetU returns configuration value as uint

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %d\n", cfg.GetU("user:uid"))
Output:

Value from config: 512

func (*Config) GetU64

func (c *Config) GetU64(name string, defvals ...uint64) uint64

GetU64 returns configuration value as uint64

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config: %d\n", cfg.GetU64("user:uid"))
Output:

Value from config: 512

func (*Config) HasProp

func (c *Config) HasProp(name string) bool

HasProp checks if property is defined and set

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Is property \"user:name\" exist: %t\n", cfg.HasProp("user:name"))
fmt.Printf("Is property \"user:path\" exist: %t\n", cfg.HasProp("user:path"))
Output:

Is property "user:name" exist: true
Is property "user:path" exist: false

func (*Config) HasSection

func (c *Config) HasSection(section string) bool

HasSection checks if section exists

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Is section \"main\" exist: %t\n", cfg.HasSection("main"))
fmt.Printf("Is section \"user\" exist: %t\n", cfg.HasSection("user"))
Output:

Is section "main" exist: false
Is section "user" exist: true

func (*Config) Is added in v12.47.0

func (c *Config) Is(name string, value any) bool

Is checks if given property contains given value

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("user.name == bob: %t\n", cfg.Is("user:name", "bob"))
fmt.Printf("user.uid == 512: %t\n", cfg.Is("user:uid", 512))
Output:

user.name == bob: false
user.uid == 512: true

func (*Config) Merge added in v12.99.0

func (c *Config) Merge(cfg *Config) error

Merge merges two configurations

Example
cfg1, _ := Parse([]byte(`
[service]
	user: john
`))

cfg2, _ := Parse([]byte(`
[service]
	user: bob
`))

fmt.Printf("Value from config (before merge): %s\n", cfg1.GetS("service:user"))

err := cfg1.Merge(cfg2)

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Value from config (after merge): %s\n", cfg1.GetS("service:user"))
Output:

Value from config (before merge): john
Value from config (after merge): bob

func (*Config) Props

func (c *Config) Props(section string) []string

Props returns slice with properties names in some section

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

for index, prop := range cfg.Props("user") {
	fmt.Printf("%d: %s\n", index+1, prop)
}
Output:

1: name
2: uid
3: is-admin
4: priority
5: default-mode
6: timeout
7: created
8: timezone
9: labels

func (*Config) Reload

func (c *Config) Reload() (map[string]bool, error)

Reload reloads configuration file

Example
config, err := Read("/path/to/your/config.knf")

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

changes, err := config.Reload()

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

// Print info about changed values
for prop, changed := range changes {
	fmt.Printf("Property %s changed → %t\n", prop, changed)
}
Output:

func (*Config) Sections

func (c *Config) Sections() []string

Sections returns slice with section names

Example
cfg, err := Parse([]byte(`
[user]
	name: john
	uid: 512
	is-admin: true
	priority: 3.7
	default-mode: 0644
	timeout: 3m
	created: 1654424130
	timezone: Europe/Madrid
	labels: system admin

[log]
	file: /var/log/app/app.log
`))

if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

for index, section := range cfg.Sections() {
	fmt.Printf("%d: %s\n", index+1, section)
}
Output:

1: user
2: log

func (*Config) Validate

func (c *Config) Validate(validators []*Validator) []error

Validate executes all given validators and returns slice with validation errors

type DurationMod added in v12.76.1

type DurationMod int64

DurationMod is type for duration modificator

type IConfig added in v12.104.0

type IConfig interface {
	// GetS returns configuration value as string
	GetS(name string, defvals ...string) string

	// GetI returns configuration value as int
	GetI(name string, defvals ...int) int

	// GetI64 returns configuration value as int64
	GetI64(name string, defvals ...int64) int64

	// GetU returns configuration value as uint
	GetU(name string, defvals ...uint) uint

	// GetU64 returns configuration value as uint64
	GetU64(name string, defvals ...uint64) uint64

	// GetF returns configuration value as floating number
	GetF(name string, defvals ...float64) float64

	// GetB returns configuration value as boolean
	GetB(name string, defvals ...bool) bool

	// GetM returns configuration value as file mode
	GetM(name string, defvals ...os.FileMode) os.FileMode

	// GetD returns configuration values as duration
	GetD(name string, mod DurationMod, defvals ...time.Duration) time.Duration

	// GetTD returns configuration value as time duration
	GetTD(name string, defvals ...time.Duration) time.Duration

	// GetTS returns configuration timestamp value as time
	GetTS(name string, defvals ...time.Time) time.Time

	// GetTS returns configuration value as timezone
	GetTZ(name string, defvals ...*time.Location) *time.Location

	// GetL returns configuration value as list
	GetL(name string, defvals ...[]string) []string
}

IConfig is knf like configuration

type PropertyValidator

type PropertyValidator func(config IConfig, prop string, value any) error

PropertyValidator is default type of property validation function

type Validator

type Validator struct {
	Property string            // Property name
	Func     PropertyValidator // Validation function
	Value    any               // Expected value
}

Validator is configuration property validator struct

Directories

Path Synopsis
Package united provides KNF configuration extended by environment variables and options
Package united provides KNF configuration extended by environment variables and options
Package validators provides basic KNF validators
Package validators provides basic KNF validators
fs
Package fs provides KNF validators for checking file-system items
Package fs provides KNF validators for checking file-system items
network
Package network provides KNF validators for checking items related to network
Package network provides KNF validators for checking items related to network
regexp
Package regexp provides KNF validators with regular expressions
Package regexp provides KNF validators with regular expressions
system
Package system provides KNF validators for checking system items (user, groups, network interfaces)
Package system provides KNF validators for checking system items (user, groups, network interfaces)

Jump to

Keyboard shortcuts

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