utils

package
v0.9.7 Latest Latest
Warning

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

Go to latest
Published: Dec 14, 2020 License: MIT Imports: 41 Imported by: 25

Documentation

Overview

Package utils is used for common functions and tools used across the codebase.

Index

Constants

View Source
const (
	// FormatBytes encodes the output as bytes
	FormatBytes = "bytes"
	// FormatPreformatted encodes the output, assumed to be hex, as bytes.
	FormatPreformatted = "preformatted"
	// FormatUint256 encodes the output as bytes containing a uint256
	FormatUint256 = "uint256"
	// FormatInt256 encodes the output as bytes containing an int256
	FormatInt256 = "int256"
	// FormatBool encodes the output as bytes containing a bool
	FormatBool = "bool"
)
View Source
const (
	FastN = 2
	FastP = 1
)
View Source
const (
	// DefaultSecretSize is the entroy in bytes to generate a base64 string of 64 characters.
	DefaultSecretSize = 48
	// EVMWordByteLen the length of an EVM Word Byte
	EVMWordByteLen = 32
	// EVMWordHexLen the length of an EVM Word Hex
	EVMWordHexLen = EVMWordByteLen * 2
)

Variables

View Source
var (

	// MaxUint256 represents the largest number represented by an EVM word
	MaxUint256 = &big.Int{}
	// MaxInt256 represents the largest number represented by an EVM word using
	// signed encoding.
	MaxInt256 = &big.Int{}
	// MinInt256 represents the smallest number represented by an EVM word using
	// signed encoding.
	MinInt256 = &big.Int{}
)

"Constants" used by EVM words

DefaultScryptParams is for use in production. It used geth's standard level of encryption and is relatively expensive to decode. Avoid using this in tests.

View Source
var EmptyHash = common.Hash{}

EmptyHash is a hash of all zeroes, otherwise in Ethereum as 0x0000000000000000000000000000000000000000000000000000000000000000

View Source
var FastScryptParams = ScryptParams{N: FastN, P: FastP}

FastScryptParams is for use in tests, where you don't want to wear out your CPU with expensive key derivations, do not use it in production, or your encrypted keys will be easy to brute-force!

View Source
var ZeroAddress = common.Address{}

ZeroAddress is an address of all zeroes, otherwise in Ethereum as 0x0000000000000000000000000000000000000000

Functions

func AddHexPrefix

func AddHexPrefix(str string) string

AddHexPrefix adds the previx (0x) to a given hex string.

func CheckPasswordHash

func CheckPasswordHash(password, hash string) bool

CheckPasswordHash wraps around bcrypt.CompareHashAndPassword for a friendlier API.

func CheckUint256 added in v0.8.2

func CheckUint256(n *big.Int) error

CheckUint256(n) returns an error if n is out of bounds for a uint256

func CombinedContext added in v0.9.3

func CombinedContext(signals ...interface{}) (context.Context, context.CancelFunc)

CombinedContext creates a context that finishes when any of the provided signals finish. A signal can be a `context.Context`, a `chan struct{}`, or a `time.Duration` (which is transformed into a `context.WithTimeout`).

func ConcatBytes

func ConcatBytes(bufs ...[]byte) []byte

ConcatBytes appends a bunch of byte arrays into a single byte array

func ContextFromChan added in v0.9.3

func ContextFromChan(chStop <-chan struct{}) (context.Context, context.CancelFunc)

ContextFromChan creates a context that finishes when the provided channel receives or is closed.

func CopyFileWithMaxPerms added in v0.8.5

func CopyFileWithMaxPerms(srcPath, dstPath string, perms os.FileMode) error

Copies the file at `srcPath` to `dstPath` and ensures that it has permissions that are no more permissive than the given ones.

func DebugPanic added in v0.9.3

func DebugPanic()

func DecodeEthereumTx

func DecodeEthereumTx(hex string) (types.Transaction, error)

DecodeEthereumTx takes an RLP hex encoded Ethereum transaction and returns a Transaction struct with all the fields accessible.

func DurationFromNow

func DurationFromNow(t time.Time) time.Duration

DurationFromNow returns the amount of time since the Time field was last updated.

func EIP55CapitalizedAddress

func EIP55CapitalizedAddress(possibleAddressString string) bool

EIP55CapitalizedAddress returns true iff possibleAddressString has the correct capitalization for an Ethereum address, per EIP 55

func EVMBytesToUint64 added in v0.9.0

func EVMBytesToUint64(buf []byte) uint64

func EVMEncodeBytes

func EVMEncodeBytes(input []byte) []byte

EVMEncodeBytes encodes arbitrary bytes as bytes expected by the EVM

func EVMTranscodeBool

func EVMTranscodeBool(value gjson.Result) ([]byte, error)

EVMTranscodeBool converts a json input to an EVM bool

func EVMTranscodeBytes

func EVMTranscodeBytes(value gjson.Result) ([]byte, error)

EVMTranscodeBytes converts a json input to an EVM bytes array

func EVMTranscodeInt256

func EVMTranscodeInt256(value gjson.Result) ([]byte, error)

EVMTranscodeInt256 converts a json input to an EVM int256

func EVMTranscodeJSONWithFormat

func EVMTranscodeJSONWithFormat(value gjson.Result, format string) ([]byte, error)

EVMTranscodeJSONWithFormat given a JSON input and a format specifier, encode the value for use by the EVM

func EVMTranscodeUint256

func EVMTranscodeUint256(value gjson.Result) ([]byte, error)

EVMTranscodeUint256 converts a json input to an EVM uint256

func EVMWordBigInt

func EVMWordBigInt(val *big.Int) ([]byte, error)

EVMWordBigInt returns a big.Int as an EVM word byte array, with support for a signed representation. Returns error on overflow.

func EVMWordSignedBigInt

func EVMWordSignedBigInt(val *big.Int) ([]byte, error)

EVMWordSignedBigInt returns a big.Int as an EVM word byte array, with support for a signed representation. Returns error on overflow.

func EVMWordUint128 added in v0.8.2

func EVMWordUint128(val *big.Int) ([]byte, error)

EVMWordUint128 returns a uint128 as an EVM word byte array.

func EVMWordUint64

func EVMWordUint64(val uint64) []byte

EVMWordUint64 returns a uint64 as an EVM word byte array.

func EnsureDirAndMaxPerms added in v0.8.5

func EnsureDirAndMaxPerms(path string, perms os.FileMode) error

Ensures that the given path exists, that it's a directory, and that it has permissions that are no more permissive than the given ones.

- If the path does not exist, it is created - If the path exists, but is not a directory, an error is returned - If the path exists, and is a directory, but has the wrong perms, it is chmod'ed

func EnsureFileMaxPerms added in v0.8.5

func EnsureFileMaxPerms(file *os.File, perms os.FileMode) error

Ensures that the given file has permissions that are no more permissive than the given ones.

func EnsureFilepathMaxPerms added in v0.8.5

func EnsureFilepathMaxPerms(filepath string, perms os.FileMode) error

Ensures that the file at the given filepath has permissions that are no more permissive than the given ones.

func FileContents

func FileContents(path string) (string, error)

FileContents returns the contents of a file as a string.

func FileExists

func FileExists(name string) bool

FileExists returns true if a file at the passed string exists.

func FilesInDir

func FilesInDir(dir string) ([]string, error)

FilesInDir returns an array of filenames in the directory.

func FormatJSON

func FormatJSON(v interface{}) ([]byte, error)

FormatJSON applies indent to format a JSON response.

func HasHexPrefix

func HasHexPrefix(str string) bool

HasHexPrefix returns true if the string starts with 0x.

func HashPassword

func HashPassword(password string) (string, error)

HashPassword wraps around bcrypt.GenerateFromPassword for a friendlier API.

func HexToUint256 added in v0.8.2

func HexToUint256(s string) (*big.Int, error)

HexToUint256 returns the uint256 represented by s, or an error if it doesn't represent one.

func ISO8601UTC

func ISO8601UTC(t time.Time) string

ISO8601UTC formats given time to ISO8601.

func IsEmptyAddress

func IsEmptyAddress(addr common.Address) bool

IsEmptyAddress checks that the address is empty, synonymous with the zero account/address. No logs can come from this address, as there is no contract present there.

See https://stackoverflow.com/questions/48219716/what-is-address0-in-solidity for the more info on the zero address.

func IsFileOwnedByChainlink(fileInfo os.FileInfo) (bool, error)

func IsQuoted

func IsQuoted(input []byte) bool

IsQuoted checks if the first and last characters are either " or '.

func JustError

func JustError(_ interface{}, err error) error

JustError takes a tuple and returns the last entry, the error.

func Keccak256

func Keccak256(in []byte) ([]byte, error)

Keccak256 is a simplified interface for the legacy SHA3 implementation that Ethereum uses.

func LogIfError added in v0.9.3

func LogIfError(err *error, msg string)

func LogListeningAddress

func LogListeningAddress(address common.Address) string

LogListeningAddress returns the LogListeningAddress

func MaxBigs added in v0.6.10

func MaxBigs(first *big.Int, bigs ...*big.Int) *big.Int

MaxBigs finds the maximum value of a list of big.Ints.

func MaxInt

func MaxInt(first int, ints ...int) int

MaxInt finds the maximum value of a list of ints.

func MaxUint32

func MaxUint32(first uint32, uints ...uint32) uint32

MaxUint32 finds the maximum value of a list of uint32s.

func MinUint added in v0.8.2

func MinUint(first uint, vals ...uint) uint

MinUint finds the minimum value of a list of uints.

func MustHash

func MustHash(in string) common.Hash

MustHash returns the keccak256 hash, or panics on failure.

func MustUnmarshalToMap added in v0.8.17

func MustUnmarshalToMap(input string) map[string]interface{}

MustUnmarshalToMap performs UnmarshalToMap, panics upon failure

func NewBytes32ID

func NewBytes32ID() string

NewBytes32ID returns a randomly generated UUID that conforms to Ethereum bytes32.

func NewSecret added in v0.6.6

func NewSecret(n int) string

NewSecret returns a new securely random sequence of n bytes of entropy. The result is a base64 encoded string.

Panics on failed attempts to read from system's PRNG.

func NormalizedJSON

func NormalizedJSON(val []byte) (string, error)

NormalizedJSON returns a JSON representation of an object that has been normalized to produce a consistent output for hashing.

NOTE: If this string is unmarshalled again, there is no guarantee that the final representation will be consistent with the string produced by this function due to differences in JSON implementations and information loss. e.g:

JSON does not have a requirement to respect object key ordering.

func NullISO8601UTC

func NullISO8601UTC(t null.Time) string

NullISO8601UTC returns formatted time if valid, empty string otherwise.

func ParseEthereumAddress

func ParseEthereumAddress(addressString string) (common.Address, error)

ParseEthereumAddress returns addressString as a go-ethereum Address, or an error if it's invalid, e.g. if EIP 55 capitalization check fails

func RemoveHexPrefix

func RemoveHexPrefix(str string) string

RemoveHexPrefix removes the prefix (0x) of a given hex string.

func RemoveQuotes

func RemoveQuotes(input []byte) []byte

RemoveQuotes removes the first and last character if they are both either " or ', otherwise it is a noop.

func RetryWithBackoff added in v0.8.3

func RetryWithBackoff(ctx context.Context, fn func() (retry bool))

func ReverseString added in v0.8.11

func ReverseString(s string) string

ReverseString returns its argument string reversed rune-wise left to right.

func Sha256

func Sha256(in string) (string, error)

Sha256 returns a hexadecimal encoded string of a hashed input

func StringToHex

func StringToHex(in string) string

StringToHex converts a standard string to a hex encoded string.

func StripBearer

func StripBearer(authorizationStr string) string

StripBearer removes the 'Bearer: ' prefix from the HTTP Authorization header.

func ToDecimal added in v0.9.3

func ToDecimal(input interface{}) (decimal.Decimal, error)

func TooPermissive added in v0.8.5

func TooPermissive(fileMode, maxAllowedPerms os.FileMode) bool

func Uint256ToBytes added in v0.8.2

func Uint256ToBytes(x *big.Int) (uint256 []byte, err error)

Uint256ToBytes(x) is x represented as the bytes of a uint256

func Uint256ToHex added in v0.8.2

func Uint256ToHex(n *big.Int) (string, error)

Uint256ToHex returns the hex representation of n, or error if out of bounds

func Uint64ToHex

func Uint64ToHex(i uint64) string

Uint64ToHex converts the given uint64 value to a hex-value string.

func UnmarshalToMap added in v0.8.17

func UnmarshalToMap(input string) (map[string]interface{}, error)

UnmarshalToMap takes an input json string and returns a map[string]interface i.e. a raw object

func WaitGroupChan added in v0.8.3

func WaitGroupChan(wg *sync.WaitGroup) <-chan struct{}

WaitGroupChan creates a channel that closes when the provided sync.WaitGroup is done.

func WithJitter added in v0.9.6

func WithJitter(d time.Duration) time.Duration

WithJitter adds +/- 10% to a duration

func WithoutZeroAddresses

func WithoutZeroAddresses(addresses []common.Address) []common.Address

WithoutZeroAddresses returns a list of addresses excluding the zero address.

func WrapIfError added in v0.8.13

func WrapIfError(err *error, msg string)

WrapIfError decorates an error with the given message. It is intended to be used with `defer` statements, like so:

func SomeFunction() (err error) {
    defer WrapIfError(&err, "error in SomeFunction:")

    ...
}

func WriteFileWithMaxPerms added in v0.8.5

func WriteFileWithMaxPerms(path string, data []byte, perms os.FileMode) error

Writes `data` to `path` and ensures that the file has permissions that are no more permissive than the given ones.

Types

type AfterNower

type AfterNower interface {
	After(d time.Duration) <-chan time.Time
	Now() time.Time
}

AfterNower is an interface that fulfills the `After()` and `Now()` methods.

type Afterer

type Afterer interface {
	After(d time.Duration) <-chan time.Time
}

Afterer is an interface that fulfills the After method, following the behavior of time.After.

type BackoffSleeper

type BackoffSleeper struct {
	backoff.Backoff
	// contains filtered or unexported fields
}

BackoffSleeper is a sleeper that backs off on subsequent attempts.

func NewBackoffSleeper

func NewBackoffSleeper() *BackoffSleeper

NewBackoffSleeper returns a BackoffSleeper that is configured to sleep for 0 seconds initially, then backs off from 1 second minimum to 10 seconds maximum.

func (*BackoffSleeper) After

func (bs *BackoffSleeper) After() time.Duration

After returns the duration for the next stop, and increments the backoff.

func (*BackoffSleeper) Duration

func (bs *BackoffSleeper) Duration() time.Duration

Duration returns the current duration value.

func (*BackoffSleeper) Reset

func (bs *BackoffSleeper) Reset()

Reset resets the backoff intervals.

func (*BackoffSleeper) Sleep

func (bs *BackoffSleeper) Sleep()

Sleep waits for the given duration, incrementing the back off.

type Big added in v0.8.2

type Big big.Int

Big stores large integers and can deserialize a variety of inputs.

func NewBig added in v0.8.2

func NewBig(i *big.Int) *Big

NewBig constructs a Big from *big.Int.

func NewBigI added in v0.8.7

func NewBigI(i int64) *Big

func (*Big) Hex added in v0.8.2

func (b *Big) Hex() string

Hex returns the hex encoding of b.

func (*Big) MarshalJSON added in v0.8.2

func (b *Big) MarshalJSON() ([]byte, error)

MarshalJSON marshals this instance to base 10 number as string.

func (*Big) MarshalText added in v0.8.2

func (b *Big) MarshalText() ([]byte, error)

MarshalText marshals this instance to base 10 number as string.

func (*Big) Scan added in v0.8.2

func (b *Big) Scan(value interface{}) error

Scan reads the database value and returns an instance.

func (*Big) String added in v0.8.2

func (b *Big) String() string

String returns the base 10 encoding of b.

func (*Big) ToInt added in v0.8.2

func (b *Big) ToInt() *big.Int

ToInt converts b to a big.Int.

func (*Big) UnmarshalJSON added in v0.8.2

func (b *Big) UnmarshalJSON(input []byte) error

UnmarshalJSON implements encoding.JSONUnmarshaler.

func (*Big) UnmarshalText added in v0.8.2

func (b *Big) UnmarshalText(input []byte) error

UnmarshalText implements encoding.TextUnmarshaler.

func (Big) Value added in v0.8.2

func (b Big) Value() (driver.Value, error)

Value returns this instance serialized for database storage.

type BigFloat added in v0.8.2

type BigFloat big.Float

BigFloat accepts both string and float JSON values.

func (BigFloat) MarshalJSON added in v0.8.2

func (b BigFloat) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface.

func (*BigFloat) UnmarshalJSON added in v0.8.2

func (b *BigFloat) UnmarshalJSON(buf []byte) error

UnmarshalJSON implements the json.Unmarshal interface.

func (*BigFloat) Value added in v0.8.2

func (b *BigFloat) Value() *big.Float

Value returns the big.Float value.

type BigIntSlice added in v0.8.7

type BigIntSlice []*big.Int

BigIntSlice attaches the methods of sort.Interface to []*big.Int, sorting in increasing order.

func (BigIntSlice) Len added in v0.8.7

func (s BigIntSlice) Len() int

func (BigIntSlice) Less added in v0.8.7

func (s BigIntSlice) Less(i, j int) bool

func (BigIntSlice) Max added in v0.8.7

func (s BigIntSlice) Max() *big.Int

Max returns the largest element

func (BigIntSlice) Sort added in v0.8.7

func (s BigIntSlice) Sort()

Sort destructively sorts the slice

func (BigIntSlice) Swap added in v0.8.7

func (s BigIntSlice) Swap(i, j int)

type BoundedPriorityQueue added in v0.8.3

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

func NewBoundedPriorityQueue added in v0.8.3

func NewBoundedPriorityQueue(capacities map[uint]uint) *BoundedPriorityQueue

func (*BoundedPriorityQueue) Add added in v0.8.3

func (q *BoundedPriorityQueue) Add(priority uint, x interface{})

func (*BoundedPriorityQueue) Empty added in v0.8.3

func (q *BoundedPriorityQueue) Empty() bool

func (*BoundedPriorityQueue) Take added in v0.8.3

func (q *BoundedPriorityQueue) Take() interface{}

type BoundedQueue added in v0.8.3

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

FIFO queue that discards older items when it reaches its capacity.

func NewBoundedQueue added in v0.8.3

func NewBoundedQueue(capacity uint) *BoundedQueue

func (*BoundedQueue) Add added in v0.8.3

func (q *BoundedQueue) Add(x interface{})

func (*BoundedQueue) Empty added in v0.8.3

func (q *BoundedQueue) Empty() bool

func (*BoundedQueue) Full added in v0.8.3

func (q *BoundedQueue) Full() bool

func (*BoundedQueue) Take added in v0.8.3

func (q *BoundedQueue) Take() interface{}

type Clock

type Clock struct{}

Clock is a basic type for scheduling events in the application.

func (Clock) After

func (Clock) After(d time.Duration) <-chan time.Time

After returns the current time if the given duration has elapsed.

func (Clock) Now

func (Clock) Now() time.Time

Now returns the current time.

type DependentAwaiter added in v0.8.3

type DependentAwaiter interface {
	AwaitDependents() <-chan struct{}
	AddDependents(n int)
	DependentReady()
}

func NewDependentAwaiter added in v0.8.3

func NewDependentAwaiter() DependentAwaiter

type HTTPRequest added in v0.9.3

type HTTPRequest struct {
	Request *http.Request
	Config  HTTPRequestConfig
}

func (*HTTPRequest) SendRequest added in v0.9.3

func (h *HTTPRequest) SendRequest(ctx context.Context) (responseBody []byte, statusCode int, err error)

type HTTPRequestConfig added in v0.9.3

type HTTPRequestConfig struct {
	Timeout                        time.Duration
	MaxAttempts                    uint
	SizeLimit                      int64
	AllowUnrestrictedNetworkAccess bool
}

HTTPRequestConfig holds the configurable settings for an http request

type HTTPResponseTooLargeError added in v0.9.3

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

func (*HTTPResponseTooLargeError) Error added in v0.9.3

func (e *HTTPResponseTooLargeError) Error() string

type MaxBytesReader added in v0.9.3

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

MaxBytesReader is inspired by https://github.com/gin-contrib/size/blob/master/size.go

func NewMaxBytesReader added in v0.9.3

func NewMaxBytesReader(rc io.ReadCloser, limit int64) *MaxBytesReader

func (*MaxBytesReader) Close added in v0.9.3

func (mbr *MaxBytesReader) Close() error

func (*MaxBytesReader) Read added in v0.9.3

func (mbr *MaxBytesReader) Read(p []byte) (n int, err error)

type Nower

type Nower interface {
	Now() time.Time
}

Nower is an interface that fulfills the Now method, following the behavior of time.Now.

type PausableTicker added in v0.9.0

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

func NewPausableTicker added in v0.9.0

func NewPausableTicker(duration time.Duration) PausableTicker

func (*PausableTicker) Destroy added in v0.9.0

func (t *PausableTicker) Destroy()

func (*PausableTicker) Pause added in v0.9.0

func (t *PausableTicker) Pause()

func (*PausableTicker) Resume added in v0.9.0

func (t *PausableTicker) Resume()

func (PausableTicker) Ticks added in v0.9.0

func (t PausableTicker) Ticks() <-chan time.Time

type RemoteServerError added in v0.9.3

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

func (*RemoteServerError) Error added in v0.9.3

func (e *RemoteServerError) Error() string

type ResettableTimer added in v0.9.0

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

func NewResettableTimer added in v0.9.0

func NewResettableTimer() ResettableTimer

func (*ResettableTimer) Reset added in v0.9.0

func (t *ResettableTimer) Reset(duration time.Duration)

func (*ResettableTimer) Stop added in v0.9.0

func (t *ResettableTimer) Stop()

func (ResettableTimer) Ticks added in v0.9.0

func (t ResettableTimer) Ticks() <-chan time.Time

type ScryptConfigReader added in v0.9.3

type ScryptConfigReader interface {
	InsecureFastScrypt() bool
}

type ScryptParams added in v0.9.3

type ScryptParams struct{ N, P int }

func GetScryptParams added in v0.9.3

func GetScryptParams(config ScryptConfigReader) ScryptParams

type Sleeper

type Sleeper interface {
	Reset()
	Sleep()
	After() time.Duration
	Duration() time.Duration
}

Sleeper interface is used for tasks that need to be done on some interval, excluding Cron, like reconnecting.

type SleeperTask added in v0.9.3

type SleeperTask interface {
	Stop() error
	WakeUp()
}

SleeperTask represents a task that waits in the background to process some work.

func NewSleeperTask added in v0.9.3

func NewSleeperTask(worker Worker) SleeperTask

NewSleeperTask takes a worker and returns a SleeperTask.

SleeperTask is guaranteed to call Work on the worker at least once for every WakeUp call. If the Worker is busy when WakeUp is called, the Worker will be called again immediately after it is finished. For this reason you should take care to make sure that Worker is idempotent. WakeUp does not block.

type SleeperTaskFuncWorker added in v0.9.3

type SleeperTaskFuncWorker func()

func (SleeperTaskFuncWorker) Work added in v0.9.3

func (fn SleeperTaskFuncWorker) Work()

type StartStopOnce added in v0.9.3

type StartStopOnce struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func (*StartStopOnce) OkayToStart added in v0.9.3

func (once *StartStopOnce) OkayToStart() (ok bool)

func (*StartStopOnce) OkayToStop added in v0.9.3

func (once *StartStopOnce) OkayToStop() (ok bool)

func (*StartStopOnce) StartOnce added in v0.9.3

func (once *StartStopOnce) StartOnce(name string, fn func() error) error

func (*StartStopOnce) State added in v0.9.3

func (once *StartStopOnce) State() StartStopOnceState

func (*StartStopOnce) StopOnce added in v0.9.3

func (once *StartStopOnce) StopOnce(name string, fn func() error) error

type StartStopOnceState added in v0.9.3

type StartStopOnceState int
const (
	StartStopOnce_Unstarted StartStopOnceState = iota
	StartStopOnce_Started
	StartStopOnce_Stopped
)

type Worker added in v0.9.3

type Worker interface {
	Work()
}

Worker is a simple interface that represents some work to do repeatedly

Jump to

Keyboard shortcuts

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