wiremessage

package
v0.0.16 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2018 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package wiremessage contains types for speaking the MongoDB Wire Protocol. Since this low level library is meant to be used in the context of a driver and in the context of a server all of the flags and types of the wire protocol are implemented. For each op there are two corresponding implementations. One prefixed with Immutable which can be created by casting a []byte to the type, and another prefixed with Mutable that is a struct with methods to mutate the op.

Index

Constants

View Source
const DefaultZlibLevel = 6

DefaultZlibLevel is the default level for zlib compression

View Source
const OpmsgWireVersion = 6

OpmsgWireVersion is the minimum wire version needed to use OP_MSG

Variables

View Source
var ErrHeaderIncorrectOpCode error = Error{Type: ErrHeader, Message: "invalid header because OpCode is improperly set"}

ErrHeaderIncorrectOpCode is returned when the OpCode on a header is set but is not set to the correct OpCode.

View Source
var ErrHeaderInvalidLength error = Error{Type: ErrHeader, Message: "invalid header because MessageLength is imporperly set"}

ErrHeaderInvalidLength is returned when the MessageLength of a header is set but is not set to the correct size.

View Source
var ErrHeaderTooFewBytes error = Error{Type: ErrHeader, Message: "invalid header because []byte too small"}

ErrHeaderTooFewBytes is returned when a call to ReadHeader does not contain enough bytes to be a valid header.

View Source
var ErrHeaderTooSmall error = Error{Type: ErrHeader, Message: "the header is too small to be valid"}

ErrHeaderTooSmall is returned when the size of the header is too small to be valid.

View Source
var ErrInvalidHeader error = Error{Type: ErrHeader, Message: "invalid header"}

ErrInvalidHeader is returned when methods are called on a malformed Header.

View Source
var ErrInvalidMessageLength = errors.New("the message length is too small, it must be at least 16")

ErrInvalidMessageLength is returned when the provided message length is too small to be valid.

View Source
var ErrUnknownOpCode = errors.New("the opcode is unknown")

ErrUnknownOpCode is returned when the provided opcode is not a valid opcode.

Functions

func CurrentRequestID

func CurrentRequestID() int32

CurrentRequestID returns the current request ID.

func NextRequestID

func NextRequestID() int32

NextRequestID returns the next request ID.

func Validate

func Validate([]byte) error

Validate will validate that data is a valid MongoDB wire protocol message.

Types

type Appender

type Appender interface {
	AppendWireMessage([]byte) ([]byte, error)
}

Appender is the interface implemented by types that can append themselves, as a MongoDB wire protocol message, to the provided slice of bytes.

type Command

type Command struct {
	MsgHeader   Header
	Database    string
	CommandName string
	Metadata    string
	CommandArgs string
	InputDocs   []bson.Reader
}

Command represents the OP_COMMAND message of the MongoDB wire protocol.

func (Command) AppendWireMessage

func (c Command) AppendWireMessage([]byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

func (Command) Len

func (c Command) Len() int

Len implements the WireMessage interface.

func (Command) MarshalWireMessage

func (c Command) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

func (Command) String

func (c Command) String() string

String implements the fmt.Stringer interface.

func (*Command) UnmarshalWireMessage

func (c *Command) UnmarshalWireMessage([]byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (Command) ValidateWireMessage

func (c Command) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type CommandReply

type CommandReply struct {
	MsgHeader    Header
	Metadata     bson.Reader
	CommandReply bson.Reader
	OutputDocs   []bson.Reader
}

CommandReply represents the OP_COMMANDREPLY message of the MongoDB wire protocol.

func (CommandReply) AppendWireMessage

func (cr CommandReply) AppendWireMessage([]byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

func (CommandReply) Len

func (cr CommandReply) Len() int

Len implements the WireMessage interface.

func (CommandReply) MarshalWireMessage

func (cr CommandReply) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

func (CommandReply) String

func (cr CommandReply) String() string

String implements the fmt.Stringer interface.

func (*CommandReply) UnmarshalWireMessage

func (cr *CommandReply) UnmarshalWireMessage([]byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (CommandReply) ValidateWireMessage

func (cr CommandReply) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type Compressed

type Compressed struct {
	MsgHeader         Header
	OriginalOpCode    OpCode
	UncompressedSize  int32
	CompressorID      CompressorID
	CompressedMessage []byte
}

Compressed represents the OP_COMPRESSED message of the MongoDB wire protocol.

func (Compressed) AppendWireMessage

func (c Compressed) AppendWireMessage(b []byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

AppendWireMessage will set the MessageLength property of MsgHeader if it is 0. It will also set the OpCode to OpCompressed if the OpCode is 0. If either of these properties are non-zero and not correct, this method will return both the []byte with the wire message appended to it and an invalid header error.

func (Compressed) Len

func (c Compressed) Len() int

Len implements the WireMessage interface.

func (Compressed) MarshalWireMessage

func (c Compressed) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

func (Compressed) String

func (c Compressed) String() string

String implements the fmt.Stringer interface.

func (*Compressed) UnmarshalWireMessage

func (c *Compressed) UnmarshalWireMessage(b []byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (Compressed) ValidateWireMessage

func (c Compressed) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type CompressorID

type CompressorID uint8

CompressorID is the ID for each type of Compressor.

const (
	CompressorNoOp CompressorID = iota
	CompressorSnappy
	CompressorZLib
)

These constants represent the individual compressor IDs for an OP_COMPRESSED.

type Delete

type Delete struct {
	MsgHeader          Header
	FullCollectionName string
	Flags              DeleteFlag
	Selector           bson.Reader
}

Delete represents the OP_DELETE message of the MongoDB wire protocol.

func (Delete) AppendWireMessage

func (d Delete) AppendWireMessage([]byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

func (Delete) Len

func (d Delete) Len() int

Len implements the WireMessage interface.

func (Delete) MarshalWireMessage

func (d Delete) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

func (Delete) String

func (d Delete) String() string

String implements the fmt.Stringer interface.

func (*Delete) UnmarshalWireMessage

func (d *Delete) UnmarshalWireMessage([]byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (Delete) ValidateWireMessage

func (d Delete) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type DeleteFlag

type DeleteFlag int32

DeleteFlag represents the flags on an OP_DELETE message.

const (
	SingleRemove DeleteFlag = 1 << iota
)

These constants represent the individual flags on an OP_DELETE message.

type Error

type Error struct {
	Type    ErrorType
	Message string
}

Error represents an error related to wire protocol messages.

func (Error) Error

func (e Error) Error() string

Error implements the err interface.

type ErrorType

type ErrorType uint16

ErrorType is the type of error, which indicates from which part of the code the error originated.

const (
	ErrNil ErrorType = iota
	ErrHeader
	ErrOpQuery
	ErrOpReply
	ErrOpCompressed
	ErrOpMsg
	ErrRead
)

These constants are the types of errors exposed by this package.

type GetMore

type GetMore struct {
	MsgHeader          Header
	FullCollectionName string
	NumberToReturn     int32
	CursorID           int64
}

GetMore represents the OP_GET_MORE message of the MongoDB wire protocol.

func (GetMore) AppendWireMessage

func (gm GetMore) AppendWireMessage([]byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

func (GetMore) Len

func (gm GetMore) Len() int

Len implements the WireMessage interface.

func (GetMore) MarshalWireMessage

func (gm GetMore) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

func (GetMore) String

func (gm GetMore) String() string

String implements the fmt.Stringer interface.

func (*GetMore) UnmarshalWireMessage

func (gm *GetMore) UnmarshalWireMessage([]byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (GetMore) ValidateWireMessage

func (gm GetMore) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type Header struct {
	MessageLength int32
	RequestID     int32
	ResponseTo    int32
	OpCode        OpCode
}

Header represents the header of a MongoDB wire protocol message.

func ReadHeader

func ReadHeader(b []byte, pos int32) (Header, error)

ReadHeader reads a header from the given slice of bytes starting at offset pos.

func (Header) AppendHeader

func (h Header) AppendHeader(b []byte) []byte

AppendHeader will append this header to the given slice of bytes.

func (*Header) SetDefaults

func (h *Header) SetDefaults(length int, opcode OpCode) error

SetDefaults sets the length and opcode of this header.

func (Header) String

func (h Header) String() string

type Insert

type Insert struct {
	MsgHeader          Header
	Flags              InsertFlag
	FullCollectionName string
	Documents          []bson.Reader
}

Insert represents the OP_INSERT message of the MongoDB wire protocol.

func (Insert) AppendWireMessage

func (i Insert) AppendWireMessage([]byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

func (Insert) Len

func (i Insert) Len() int

Len implements the WireMessage interface.

func (Insert) MarshalWireMessage

func (i Insert) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

func (Insert) String

func (i Insert) String() string

String implements the fmt.Stringer interface.

func (*Insert) UnmarshalWireMessage

func (i *Insert) UnmarshalWireMessage([]byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (Insert) ValidateWireMessage

func (i Insert) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type InsertFlag

type InsertFlag int32

InsertFlag represents the flags on an OP_INSERT message.

const (
	ContinueOnError InsertFlag = 1 << iota
)

These constants represent the individual flags on an OP_INSERT message.

type KillCursors

type KillCursors struct {
	MsgHeader         Header
	NumberOfCursorIDs int32
	CursorIDs         []int64
}

KillCursors represents the OP_KILL_CURSORS message of the MongoDB wire protocol.

func (KillCursors) AppendWireMessage

func (kc KillCursors) AppendWireMessage([]byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

func (KillCursors) Len

func (kc KillCursors) Len() int

Len implements the WireMessage interface.

func (KillCursors) MarshalWireMessage

func (kc KillCursors) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

func (KillCursors) String

func (kc KillCursors) String() string

String implements the fmt.Stringer interface.

func (*KillCursors) UnmarshalWireMessage

func (kc *KillCursors) UnmarshalWireMessage([]byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (KillCursors) ValidateWireMessage

func (kc KillCursors) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type Marshaler

type Marshaler interface {
	MarshalWireMessage() ([]byte, error)
}

Marshaler is the interface implemented by types that can marshal themselves into a valid MongoDB wire protocol message.

type Msg

type Msg struct {
	MsgHeader Header
	FlagBits  MsgFlag
	Sections  []Section
	Checksum  uint32
}

Msg represents the OP_MSG message of the MongoDB wire protocol.

func (*Msg) AcknowledgedWrite added in v0.0.10

func (m *Msg) AcknowledgedWrite() bool

AcknowledgedWrite returns true if this msg represents an acknowledged write command.

func (Msg) AppendWireMessage

func (m Msg) AppendWireMessage(b []byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

AppendWireMesssage will set the MessageLength property of the MsgHeader if it is zero. It will also set the Opcode to OP_MSG if it is zero. If either of these properties are non-zero and not correct, this method will return both the []byte with the wire message appended to it and an invalid header error.

func (*Msg) GetMainDocument added in v0.0.10

func (m *Msg) GetMainDocument() (*bson.Document, error)

GetMainDocument returns the document containing the message to send.

func (*Msg) GetSequenceArray added in v0.0.10

func (m *Msg) GetSequenceArray() (*bson.Array, string, error)

GetSequenceArray returns this message's document sequence as a BSON array along with the array identifier. If this message has no associated document sequence, a nil array is returned.

func (Msg) Len

func (m Msg) Len() int

Len implements the WireMessage interface.

func (Msg) MarshalWireMessage

func (m Msg) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

func (Msg) String

func (m Msg) String() string

String implements the fmt.Stringer interface.

func (*Msg) UnmarshalWireMessage

func (m *Msg) UnmarshalWireMessage(b []byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (Msg) ValidateWireMessage

func (m Msg) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type MsgFlag

type MsgFlag uint32

MsgFlag represents the flags on an OP_MSG message.

const (
	ChecksumPresent MsgFlag = 1 << iota
	MoreToCome

	ExhaustAllowed MsgFlag = 1 << 16
)

These constants represent the individual flags on an OP_MSG message.

type OpCode

type OpCode int32

OpCode represents a MongoDB wire protocol opcode.

const (
	OpReply OpCode = 1

	OpUpdate OpCode = 2001
	OpInsert OpCode = 2002

	OpQuery        OpCode = 2004
	OpGetMore      OpCode = 2005
	OpDelete       OpCode = 2006
	OpKillCursors  OpCode = 2007
	OpCommand      OpCode = 2010
	OpCommandReply OpCode = 2011
	OpCompressed   OpCode = 2012
	OpMsg          OpCode = 2013
)

These constants are the valid opcodes for the version of the wireprotocol supported by this library. The skipped OpCodes are historical OpCodes that are no longer used.

func (OpCode) String

func (oc OpCode) String() string

String implements the fmt.Stringer interface.

type Query

type Query struct {
	MsgHeader            Header
	Flags                QueryFlag
	FullCollectionName   string
	NumberToSkip         int32
	NumberToReturn       int32
	Query                bson.Reader
	ReturnFieldsSelector bson.Reader
}

Query represents the OP_QUERY message of the MongoDB wire protocol.

func (*Query) AcknowledgedWrite added in v0.0.10

func (q *Query) AcknowledgedWrite() bool

AcknowledgedWrite returns true if this command represents an acknowledged write

func (Query) AppendWireMessage

func (q Query) AppendWireMessage(b []byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

AppendWireMessage will set the MessageLength property of the MsgHeader if it is zero. It will also set the OpCode to OpQuery if the OpCode is zero. If either of these properties are non-zero and not correct, this method will return both the []byte with the wire message appended to it and an invalid header error.

func (Query) Len

func (q Query) Len() int

Len implements the WireMessage interface.

func (Query) MarshalWireMessage

func (q Query) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

See AppendWireMessage for a description of the rules this method follows.

func (Query) String

func (q Query) String() string

String implements the fmt.Stringer interface.

func (*Query) UnmarshalWireMessage

func (q *Query) UnmarshalWireMessage(b []byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (Query) ValidateWireMessage

func (q Query) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type QueryFlag

type QueryFlag int32

QueryFlag represents the flags on an OP_QUERY message.

const (
	TailableCursor QueryFlag
	SlaveOK
	OplogReplay
	NoCursorTimeout
	AwaitData
	Exhaust
	Partial
)

These constants represent the individual flags on an OP_QUERY message.

func (QueryFlag) String

func (qf QueryFlag) String() string

String implements the fmt.Stringer interface.

type ReadWriteCloser

type ReadWriteCloser interface {
	Reader
	Writer
	io.Closer
}

ReadWriteCloser is the interface implemented by types that can read and write WireMessages and can also be closed.

type ReadWriter

type ReadWriter interface {
	Reader
	Writer
}

ReadWriter is the interface implemented by types that can both read and write WireMessages.

type Reader

type Reader interface {
	ReadWireMessage(context.Context) (WireMessage, error)
}

Reader is the interface implemented by types that can have WireMessages read from them.

Implementation must obey the cancellation, timeouts, and deadlines of the provided context.Context object.

type Reply

type Reply struct {
	MsgHeader      Header
	ResponseFlags  ReplyFlag
	CursorID       int64
	StartingFrom   int32
	NumberReturned int32
	Documents      []bson.Reader
}

Reply represents the OP_REPLY message of the MongoDB wire protocol.

func (Reply) AppendWireMessage

func (r Reply) AppendWireMessage(b []byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

AppendWireMessage will set the MessageLength property of the MsgHeader if it is zero. It will also set the OpCode to OpQuery if the OpCode is zero. If either of these properties are non-zero and not correct, this method will return both the []byte with the wire message appended to it and an invalid header error.

func (*Reply) GetMainDocument added in v0.0.10

func (r *Reply) GetMainDocument() (*bson.Document, error)

GetMainDocument returns the main BSON document for this reply.

func (Reply) Len

func (r Reply) Len() int

Len implements the WireMessage interface.

func (Reply) MarshalWireMessage

func (r Reply) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

See AppendWireMessage for a description of the rules this method follows.

func (Reply) String

func (r Reply) String() string

String implements the fmt.Stringer interface.

func (*Reply) UnmarshalWireMessage

func (r *Reply) UnmarshalWireMessage(b []byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (Reply) ValidateWireMessage

func (r Reply) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type ReplyFlag

type ReplyFlag int32

ReplyFlag represents the flags of an OP_REPLY message.

const (
	CursorNotFound ReplyFlag = 1 << iota
	QueryFailure
	ShardConfigStale
	AwaitCapable
)

These constants represent the individual flags of an OP_REPLY message.

func (ReplyFlag) String

func (rf ReplyFlag) String() string

String implements the fmt.Stringer interface.

type Section

type Section interface {
	Kind() SectionType
	Len() int
	AppendSection([]byte) []byte
}

Section represents a section on an OP_MSG message.

type SectionBody

type SectionBody struct {
	PayloadType SectionType
	Document    bson.Reader
}

SectionBody represents the kind body of an OP_MSG message.

func (SectionBody) AppendSection added in v0.0.9

func (sb SectionBody) AppendSection(dest []byte) []byte

AppendSection implements the Section interface.

func (SectionBody) Kind

func (sb SectionBody) Kind() SectionType

Kind implements the Section interface.

func (SectionBody) Len added in v0.0.9

func (sb SectionBody) Len() int

Len implements the Section interface

type SectionDocumentSequence

type SectionDocumentSequence struct {
	PayloadType SectionType
	Size        int32
	Identifier  string
	Documents   []bson.Reader
}

SectionDocumentSequence represents the kind document sequence of an OP_MSG message.

func (SectionDocumentSequence) AppendSection added in v0.0.9

func (sds SectionDocumentSequence) AppendSection(dest []byte) []byte

AppendSection implements the Section interface

func (SectionDocumentSequence) Kind

Kind implements the Section interface.

func (SectionDocumentSequence) Len added in v0.0.9

func (sds SectionDocumentSequence) Len() int

Len implements the Section interface

func (SectionDocumentSequence) PayloadLen added in v0.0.9

func (sds SectionDocumentSequence) PayloadLen() int

PayloadLen returns the length of the payload

type SectionType added in v0.0.9

type SectionType uint8

SectionType represents the type for 1 section in an OP_MSG

const (
	SingleDocument SectionType = iota
	DocumentSequence
)

These constants represent the individual section types for a section in an OP_MSG

type Transformer

type Transformer interface {
	TransformWireMessage(WireMessage) (WireMessage, error)
}

Transformer is the interface implemented by types that can alter a WireMessage. Implementations should not directly alter the provided WireMessage and instead make a copy of the message, alter it, and returned the new message.

type Unmarshaler

type Unmarshaler interface {
	UnmarshalWireMessage([]byte) error
}

Unmarshaler is the interface implemented by types that can unmarshal a MongoDB wire protocol message version of themselves. The input can be assumed to be a valid MongoDB wire protocol message. UnmarshalWireMessage must copy the data if it wishes to retain the data after returning.

type Update

type Update struct {
	MsgHeader          Header
	FullCollectionName string
	Flags              UpdateFlag
	Selector           bson.Reader
	Update             bson.Reader
}

Update represents the OP_UPDATE message of the MongoDB wire protocol.

func (Update) AppendWireMessage

func (u Update) AppendWireMessage([]byte) ([]byte, error)

AppendWireMessage implements the Appender and WireMessage interfaces.

func (Update) Len

func (u Update) Len() int

Len implements the WireMessage interface.

func (Update) MarshalWireMessage

func (u Update) MarshalWireMessage() ([]byte, error)

MarshalWireMessage implements the Marshaler and WireMessage interfaces.

func (Update) String

func (u Update) String() string

String implements the fmt.Stringer interface.

func (*Update) UnmarshalWireMessage

func (u *Update) UnmarshalWireMessage([]byte) error

UnmarshalWireMessage implements the Unmarshaler interface.

func (Update) ValidateWireMessage

func (u Update) ValidateWireMessage() error

ValidateWireMessage implements the Validator and WireMessage interfaces.

type UpdateFlag

type UpdateFlag int32

UpdateFlag represents the flags on an OP_UPDATE message.

const (
	Upsert UpdateFlag = 1 << iota
	MultiUpdate
)

These constants represent the individual flags on an OP_UPDATE message.

type Validator

type Validator interface {
	ValidateWireMessage() error
}

Validator is the interface implemented by types that can validate themselves as a MongoDB wire protocol message.

type WireMessage

type WireMessage interface {
	Marshaler
	Validator
	Appender
	fmt.Stringer

	// Len returns the length in bytes of this WireMessage.
	Len() int
}

WireMessage represents a message in the MongoDB wire protocol.

func ReadFrom

func ReadFrom(io.Reader) (WireMessage, error)

ReadFrom will read a single WireMessage from the given io.Reader. This function will validate the WireMessage. If the WireMessage is not valid, this method will return both the error and the invalid WireMessage. If another type of processing error occurs, WireMessage will be nil.

This function will return the immutable versions of wire protocol messages. The Convert function can be used to retrieve a mutable version of wire protocol messages.

func Unmarshal

func Unmarshal([]byte) (WireMessage, error)

Unmarshal will unmarshal data into a WireMessage.

type Writer

type Writer interface {
	WriteWireMessage(context.Context, WireMessage) error
}

Writer is the interface implemented by types that can have WireMessages written to them.

Implementation must obey the cancellation, timeouts, and deadlines of the provided context.Context object.

Jump to

Keyboard shortcuts

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