questions

package
v0.0.0-...-8b20b1e Latest Latest
Warning

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

Go to latest
Published: Apr 28, 2024 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package proof implements a field asking for a (structured) proof.

Index

Constants

View Source
const (
	Strict                                = ComparisonLevel(expression.Strict)                // Exacte
	SimpleSubstitutions                   = ComparisonLevel(expression.SimpleSubstitutions)   // Simple
	ExpandedSubstitutions                 = ComparisonLevel(expression.ExpandedSubstitutions) // Complète
	AsLinearEquation      ComparisonLevel = ExpandedSubstitutions + 100
)
View Source
const (
	ExpressionFieldBlockBlKind            = "ExpressionFieldBlock"
	FigureBlockBlKind                     = "FigureBlock"
	FormulaBlockBlKind                    = "FormulaBlock"
	FunctionPointsFieldBlockBlKind        = "FunctionPointsFieldBlock"
	FunctionsGraphBlockBlKind             = "FunctionsGraphBlock"
	GeometricConstructionFieldBlockBlKind = "GeometricConstructionFieldBlock"
	NumberFieldBlockBlKind                = "NumberFieldBlock"
	OrderedListFieldBlockBlKind           = "OrderedListFieldBlock"
	ProofFieldBlockBlKind                 = "ProofFieldBlock"
	RadioFieldBlockBlKind                 = "RadioFieldBlock"
	SetFieldBlockBlKind                   = "SetFieldBlock"
	SignTableBlockBlKind                  = "SignTableBlock"
	SignTableFieldBlockBlKind             = "SignTableFieldBlock"
	TableBlockBlKind                      = "TableBlock"
	TableFieldBlockBlKind                 = "TableFieldBlock"
	TextBlockBlKind                       = "TextBlock"
	TreeBlockBlKind                       = "TreeBlock"
	TreeFieldBlockBlKind                  = "TreeFieldBlock"
	VariationTableBlockBlKind             = "VariationTableBlock"
	VariationTableFieldBlockBlKind        = "VariationTableFieldBlock"
	VectorFieldBlockBlKind                = "VectorFieldBlock"
)
View Source
const (
	FigureBlockFiKind         = "FigureBlock"
	FunctionsGraphBlockFiKind = "FunctionsGraphBlock"
)
View Source
const (
	GFAffineLineGeKind = "GFAffineLine"
	GFPointGeKind      = "GFPoint"
	GFVectorGeKind     = "GFVector"
	GFVectorPairGeKind = "GFVectorPair"
)
View Source
const (
	CoPaKind = "Co"
	InPaKind = "In"
	RpPaKind = "Rp"
)
View Source
const (
	ProofEqualityPrKind  = "ProofEquality"
	ProofInvalidPrKind   = "ProofInvalid"
	ProofNodePrKind      = "ProofNode"
	ProofSequencePrKind  = "ProofSequence"
	ProofStatementPrKind = "ProofStatement"
)

Variables

This section is empty.

Functions

func InstancesToLatex

func InstancesToLatex(questions []EnonceInstance) string

Types

type Block

type Block interface {
	// contains filtered or unexported methods
}

Block form the actual content of a question it is stored in a DB in generic form, but may be instantiated against random parameter values

type BlockWrapper

type BlockWrapper struct {
	Data Block
}

BlockWrapper may be used as replacements for Block when working with JSON

func (BlockWrapper) MarshalJSON

func (item BlockWrapper) MarshalJSON() ([]byte, error)

func (*BlockWrapper) UnmarshalJSON

func (out *BlockWrapper) UnmarshalJSON(src []byte) error

type Co

type Co string

func (Co) String

func (cm Co) String() string

type ComparisonLevel

type ComparisonLevel uint8

type CoordExpression

type CoordExpression struct {
	X, Y string
}

CoordExpression is a pair of valid expression.Expression

type DropDownFieldInstance RadioFieldInstance

type Enonce

type Enonce []Block

func (Enonce) InstantiateWith

func (qu Enonce) InstantiateWith(params ex.Vars) (EnonceInstance, error)

InstantiateWith uses the given values to instantiate the general question

func (Enonce) MarshalJSON

func (list Enonce) MarshalJSON() ([]byte, error)

func (*Enonce) Scan

func (s *Enonce) Scan(src interface{}) error

Scan implements the driver.Scanner interface using JSON

func (*Enonce) UnmarshalJSON

func (list *Enonce) UnmarshalJSON(data []byte) error

func (Enonce) Value

func (s Enonce) Value() (driver.Value, error)

type EnonceInstance

type EnonceInstance []instance

func (EnonceInstance) CheckSyntaxe

CheckSyntaxe returns an error message if the syntaxe is not

func (EnonceInstance) CorrectAnswer

func (qu EnonceInstance) CorrectAnswer() (out client.QuestionAnswersIn)

CorrectAnswer returns the expected answer for the question.

func (EnonceInstance) EvaluateAnswer

EvaluateAnswer check if the given answers are correct, and complete. An empty [answers] is supported, corresponding to the case where the student has left the question.

func (EnonceInstance) ToLatex

func (qu EnonceInstance) ToLatex() string

type ErrParameters

type ErrParameters struct {
	Origin  string
	Details string
}

func (ErrParameters) Error

func (err ErrParameters) Error() string

type ErrQuestionInvalid

type ErrQuestionInvalid struct {
	ErrParameters ErrParameters
	ErrEnonce     errEnonce
	ErrCorrection errEnonce
	Kind          ErrorKind // indicates which field is valid
}

ErrQuestionInvalid is returned by Question.Validate() It is either an error about the random parameters, or the blocks content (enonce or correction).

func (ErrQuestionInvalid) Error

func (e ErrQuestionInvalid) Error() string

type ErrorKind

type ErrorKind uint8
const (
	ErrParameters_ ErrorKind = iota
	ErrEnonce
	ErrCorrection
)

type ExerciceInstance

type ExerciceInstance struct {
	Title       string
	Description string
	Questions   []QuestionInstance
	Id          int64
}

ExerciceInstance is an in memory version of an Exercice, where all random parameters have been generated and substituted

type ExpressionFieldBlock

type ExpressionFieldBlock struct {
	// A valid expression, in the format used by expression.Expression or expression.Compound
	Expression       string
	Label            Interpolated // optional
	ComparisonLevel  ComparisonLevel
	ShowFractionHelp bool // if true an hint for fraction is displayed when applicable
}

func (ExpressionFieldBlock) SyntaxHint

func (f ExpressionFieldBlock) SyntaxHint(params Parameters) (TextBlock, error)

type ExpressionFieldInstance

type ExpressionFieldInstance struct {
	// if not empty, the field is displayed on a new line
	LabelLaTeX string

	Answer          expression.Compound
	ComparisonLevel ComparisonLevel

	// If true an hint for fraction is displayed
	ShowFractionHelp bool

	ID int
}

ExpressionFieldInstance is an answer field where a single mathematical expression if expected

type FigureBlock

type FigureBlock struct {
	Drawings   repere.RandomDrawings
	Bounds     repere.RepereBounds
	ShowGrid   bool
	ShowOrigin bool
}

type FigureInstance

type FigureInstance client.FigureBlock

type FiguresOrGraphs

type FiguresOrGraphs interface {
	// contains filtered or unexported methods
}

type FiguresOrGraphsWrapper

type FiguresOrGraphsWrapper struct {
	Data FiguresOrGraphs
}

FiguresOrGraphsWrapper may be used as replacements for FiguresOrGraphs when working with JSON

func (FiguresOrGraphsWrapper) MarshalJSON

func (item FiguresOrGraphsWrapper) MarshalJSON() ([]byte, error)

func (*FiguresOrGraphsWrapper) UnmarshalJSON

func (out *FiguresOrGraphsWrapper) UnmarshalJSON(src []byte) error

type FormulaBlock

type FormulaBlock struct {
	Parts Interpolated
}

FormulaBlock is a math formula, which should be display using a LaTeX renderer.

type FormulaContent

type FormulaContent []FormulaPart

FormulaContent is a list of chunks, either

  • static math symbols, such as f(x) =
  • valid expression, such as a*x - b, which will be instantiated

when rendering the question

For instance, the formula "f(x) = a*(x + 2)" is represented by two FormulaPart elements:

{ f(x) = } and { a*(x + 2) }

type FormulaDisplayInstance

type FormulaDisplayInstance []string

FormulaDisplayInstance is rendered as LaTeX, in display mode.

type FormulaPart

type FormulaPart struct {
	Content      string
	IsExpression bool // when true, Content is interpreted as an expression.Expression
}

FormulaPart forms a logic chunk of a formula.

type FunctionArea

type FunctionArea struct {
	// reference to function [Label]s, with empty meaning
	// horizontal line
	Bottom, Top Interpolated
	Left, Right string // expression.Expression
	Color       repere.ColorHex
}

type FunctionDecoration

type FunctionDecoration struct {
	Label Interpolated
	Color string
}

type FunctionDefinition

type FunctionDefinition struct {
	Function   string // expression.Expression
	Decoration FunctionDecoration
	Variable   ex.Variable // usually x
	From, To   string      // definition domain, expression.Expression
}

type FunctionPoint

type FunctionPoint struct {
	Function Interpolated // reference to a function [Label]
	X        string       // expression.Expression
	Color    repere.ColorHex
	Legend   Interpolated // legend
}

FunctionPoint draws a point at a given abscice for a given function

type FunctionPointsFieldBlock

type FunctionPointsFieldBlock struct {
	IsDiscrete bool
	Function   string // function or sequence, valid expression.Expression
	Label      string
	Variable   ex.Variable
	XGrid      []string // valid expression.Expression
}

type FunctionPointsFieldInstance

type FunctionPointsFieldInstance struct {
	IsDiscrete bool
	Function   expression.FunctionExpr
	Label      string
	XGrid      []int
	ID         int
	// contains filtered or unexported fields
}

type FunctionSign

type FunctionSign struct {
	Label     Interpolated
	FxSymbols []client.SignSymbol
	Signs     []bool
}

type FunctionsGraphBlock

type FunctionsGraphBlock struct {
	FunctionExprs      []FunctionDefinition
	FunctionVariations []VariationTableBlock
	SequenceExprs      []FunctionDefinition // displayed as discrete sequences
	Areas              []FunctionArea
	Points             []FunctionPoint
}

FunctionsGraphBlock draws a figure with functions curves and colored areas Function are identifier by their [Label]

type FunctionsGraphInstance

type FunctionsGraphInstance struct {
	Functions []functiongrapher.FunctionGraph
	Sequences []functiongrapher.SequenceGraph
	Areas     []client.FunctionArea
	Points    []client.FunctionPoint
}

type GFAffineLine

type GFAffineLine struct {
	Label string
	A     string // valid expression.Expression
	B     string // valid expression.Expression
}

type GFPoint

type GFPoint struct {
	Answer CoordExpression
}

type GFVector

type GFVector struct {
	Answer         CoordExpression
	AnswerOrigin   CoordExpression // optionnal, used when MustHaveOrigin is true
	MustHaveOrigin bool
}

type GFVectorPair

type GFVectorPair struct {
	Criterion VectorPairCriterion
}

type GeoField

type GeoField interface {
	// contains filtered or unexported methods
}

type GeoFieldWrapper

type GeoFieldWrapper struct {
	Data GeoField
}

GeoFieldWrapper may be used as replacements for GeoField when working with JSON

func (GeoFieldWrapper) MarshalJSON

func (item GeoFieldWrapper) MarshalJSON() ([]byte, error)

func (*GeoFieldWrapper) UnmarshalJSON

func (out *GeoFieldWrapper) UnmarshalJSON(src []byte) error

type GeometricConstructionFieldBlock

type GeometricConstructionFieldBlock struct {
	Field      GeoField
	Background FiguresOrGraphs
}

func (GeometricConstructionFieldBlock) MarshalJSON

func (item GeometricConstructionFieldBlock) MarshalJSON() ([]byte, error)

func (*GeometricConstructionFieldBlock) UnmarshalJSON

func (item *GeometricConstructionFieldBlock) UnmarshalJSON(src []byte) error

type GeometricConstructionFieldInstance

type GeometricConstructionFieldInstance struct {
	ID         int
	Field      geoFieldInstance
	Background client.FigureOrGraph
}

type In

type In string

String form on an intrinsic call, validated by expression.ParseIntrinsic

func (In) String

func (it In) String() string

type Interpolated

type Interpolated string

Interpolated is a string with $<static math>$ or &<expression>& delimiters, with && are allowed in $$. Also, $$ ... $$ may be used to define a FormulaBlock, and # ... # to define NumberFieldBlock

type InvalidFieldAnswer

type InvalidFieldAnswer struct {
	ID     int
	Reason string
}

InvalidFieldAnswer is returned for syntactically incorrect answers

func (InvalidFieldAnswer) Error

func (ifa InvalidFieldAnswer) Error() string

type NumberFieldBlock

type NumberFieldBlock struct {
	// a valid expression, in the format used by expression.Expression
	// which is only parametrized by the random parameters
	Expression string
}

type NumberFieldInstance

type NumberFieldInstance struct {
	ID     int
	Answer float64 // expected answer
}

NumberFieldInstance is an answer field where only numbers are allowed. Answers are compared as float values, with a fixed precision.

type OrderedListFieldBlock

type OrderedListFieldBlock struct {
	Label               Interpolated
	Answer              []Interpolated // the order matters
	AdditionalProposals []Interpolated
}

type OrderedListFieldInstance

type OrderedListFieldInstance struct {
	Label               string            // optionnal, LaTeX code displayed in front of the anwser field
	Answer              []client.TextLine // LaTeX code
	AdditionalProposals []client.TextLine // added to Answer when displaying the field
	ID                  int
}

OrderedListFieldInstance asks the student to reorder part of the given symbols

type ParameterEntry

type ParameterEntry interface {
	// Return a user friendly description
	String() string
	// contains filtered or unexported methods
}

ParameterEntry is either a single variable definition, a special function or a (possibly multiline) comment.

type ParameterEntryWrapper

type ParameterEntryWrapper struct {
	Data ParameterEntry
}

ParameterEntryWrapper may be used as replacements for ParameterEntry when working with JSON

func (ParameterEntryWrapper) MarshalJSON

func (item ParameterEntryWrapper) MarshalJSON() ([]byte, error)

func (*ParameterEntryWrapper) UnmarshalJSON

func (out *ParameterEntryWrapper) UnmarshalJSON(src []byte) error

type Parameters

type Parameters []ParameterEntry

Parameters stores the definition of the random parameters, in the order used by the user

func (Parameters) HasTODO

func (pr Parameters) HasTODO() bool

HasTODO returns true if one of the comment has a TODO mention

func (Parameters) MarshalJSON

func (list Parameters) MarshalJSON() ([]byte, error)

func (*Parameters) Scan

func (s *Parameters) Scan(src interface{}) error

Scan implements the driver.Scanner interface using JSON

func (Parameters) ToMap

func (pr Parameters) ToMap() *ex.RandomParameters

ToMap may only be used after `Validate`

func (*Parameters) UnmarshalJSON

func (list *Parameters) UnmarshalJSON(data []byte) error

func (Parameters) Validate

func (pr Parameters) Validate() error

Validate ensure the given `Parameters` are sound, by parsing the expression, checking for duplicate parameters, and detecting definition cycles. It the error is not nil, it will be of type `ErrParameters`. Once called without error, `ToMap` may be safely used.

func (Parameters) Value

func (s Parameters) Value() (driver.Value, error)

type ProofAssertion

type ProofAssertion interface {
	// contains filtered or unexported methods
}

type ProofAssertionWrapper

type ProofAssertionWrapper struct {
	Data ProofAssertion
}

ProofAssertionWrapper may be used as replacements for ProofAssertion when working with JSON

func (ProofAssertionWrapper) MarshalJSON

func (item ProofAssertionWrapper) MarshalJSON() ([]byte, error)

func (*ProofAssertionWrapper) UnmarshalJSON

func (out *ProofAssertionWrapper) UnmarshalJSON(src []byte) error

type ProofAssertions

type ProofAssertions []ProofAssertion

func (ProofAssertions) MarshalJSON

func (list ProofAssertions) MarshalJSON() ([]byte, error)

func (*ProofAssertions) UnmarshalJSON

func (list *ProofAssertions) UnmarshalJSON(data []byte) error

type ProofEquality

type ProofEquality struct {
	Terms string // always interpreted as LaTeX, splitted by equals
}

type ProofFieldBlock

type ProofFieldBlock struct {
	Answer ProofSequence
}

type ProofFieldInstance

type ProofFieldInstance struct {
	Answer proofSequenceIns
	ID     int
}

type ProofInvalid

type ProofInvalid struct{}

Placeholder used when editing the proof

type ProofNode

type ProofNode struct {
	Left, Right ProofAssertion `gomacro-data:"ignore"`
	Op          client.Binary
}

func (ProofNode) MarshalJSON

func (item ProofNode) MarshalJSON() ([]byte, error)

func (*ProofNode) UnmarshalJSON

func (item *ProofNode) UnmarshalJSON(src []byte) error

type ProofSequence

type ProofSequence struct {
	Parts ProofAssertions `gomacro-data:"ignore"`
}

type ProofStatement

type ProofStatement struct {
	Content Interpolated
}

type QuestionInstance

type QuestionInstance struct {
	Enonce     EnonceInstance
	Correction EnonceInstance
}

func (QuestionInstance) ToClient

func (qi QuestionInstance) ToClient() client.Question

ToClient convert the question to a client version, stripping expected answers and converting expressions to LaTeX strings.

type QuestionPage

type QuestionPage struct {
	Enonce     Enonce     `json:"enonce" gomacro-opaque:"dart"`
	Parameters Parameters `json:"parameters" gomacro-opaque:"dart"` // random parameters shared by the all the blocks
	Correction Enonce     `json:"correction" gomacro-opaque:"dart"`
}

QuestionPage is the fundamental object to build exercices. It is mainly consituted of a list of content blocks, which describes the question (description, question, field answer), and are parametrized by random values.

func (QuestionPage) Instantiate

func (qu QuestionPage) Instantiate() (out QuestionInstance, vars ex.Vars)

Instantiate returns a deep copy of `qu`, where all random parameters have been resolved. It assumes that the expressions and random parameters definitions are valid : if an error is encountered, it is returned as a TextInstance displaying the error.

func (QuestionPage) InstantiateErr

func (qu QuestionPage) InstantiateErr() (QuestionInstance, ex.Vars, error)

InstantiateErr is a shortcut to :

  • instantiate Parameters
  • instantiate Enonce with these parameters
  • instantiate [Correction] with these parameters

func (QuestionPage) InstantiateWith

func (qu QuestionPage) InstantiateWith(params ex.Vars) (QuestionInstance, error)

func (QuestionPage) Validate

func (qu QuestionPage) Validate() error

Validate ensure the random parameters and enonce blocks are sound. If not, an `ErrQuestionInvalid` is returned.

type RadioFieldBlock

type RadioFieldBlock struct {
	Answer     string         // must satisfy expression.IsValidIndex
	Proposals  []Interpolated // slice of text parts
	AsDropDown bool
}

type RadioFieldInstance

type RadioFieldInstance struct {
	Proposals []client.TextLine
	ID        int
	Answer    int // index into Proposals, starting at 1
}

RadioFieldInstance is an answer field where one choice is to be made against a fixed list

type Rp

type Rp struct {
	Expression string      `json:"expression"` // as typed by the user, but validated
	Variable   ex.Variable `json:"variable"`
}

func (Rp) String

func (rp Rp) String() string

type SetFieldBlock

type SetFieldBlock struct {
	Answer         string // expression
	AdditionalSets []Interpolated
}

type SetFieldInstance

type SetFieldInstance struct {
	ID     int
	Answer sets.BinarySet
}

type SignSymbol

type SignSymbol uint8
const (
	Nothing        SignSymbol = iota //
	Zero                             // 0
	ForbiddenValue                   // ||
)

func (SignSymbol) MarshalJSON

func (s SignSymbol) MarshalJSON() ([]byte, error)

By default a slice of SignSymbol is marshalled as string by Go, which is not recognized by the PSQL JSON constraints

type SignTableBlock

type SignTableBlock struct {
	Xs        []string // valid expression
	Functions []FunctionSign
}

type SignTableFieldBlock

type SignTableFieldBlock struct {
	Answer SignTableBlock
}

type SignTableFieldInstance

type SignTableFieldInstance struct {
	Answer SignTableInstance
	ID     int
}

type SignTableInstance

type SignTableInstance struct {
	Xs        []*expression.Expr
	Functions []client.FunctionSign
}

type StringOrExpression

type StringOrExpression struct {
	Expression *expression.Expr
	String     string // LaTeX code, rendered in math mode
}

StringOrExpression is either an expression or a static string, usually rendered as LaTeX, in text mode.

func (StringOrExpression) IsEmpty

func (se StringOrExpression) IsEmpty() bool

IsEmpty returns `true` is the struct is the zero value.

type TableBlock

type TableBlock struct {
	HorizontalHeaders []TextPart
	VerticalHeaders   []TextPart
	Values            [][]TextPart
}

type TableFieldBlock

type TableFieldBlock struct {
	HorizontalHeaders []TextPart
	VerticalHeaders   []TextPart
	Answer            [][]string // valid expression.Expression
}

type TableFieldInstance

type TableFieldInstance struct {
	HorizontalHeaders []client.TextOrMath
	VerticalHeaders   []client.TextOrMath
	Answer            client.TableAnswer
	ID                int
}

type TableInstance

type TableInstance client.TableBlock

type TextBlock

type TextBlock struct {
	Parts   Interpolated
	Bold    bool
	Italic  bool
	Smaller bool
}

TextBlock is a chunk of text which may contain maths It support basic interpolation syntax.

type TextInstance

type TextInstance client.TextBlock

TextInstance is a paragraph of text, which may contain expression or math chunks, which is rendered on a single line (eventually wrapped).

type TextKind

type TextKind uint8
const (
	Text       TextKind = iota // Text simple
	StaticMath                 // Code LaTeX
	Expression                 // Expression
)

type TextPart

type TextPart struct {
	Content string
	Kind    TextKind
}

TextPart is either a plain text, a LaTeX code or an expression

func NewPExpr

func NewPExpr(content string) TextPart

func NewPMath

func NewPMath(content string) TextPart

func NewPText

func NewPText(content string) TextPart

type TextParts

type TextParts []TextPart

type TreeBlock

type TreeBlock struct {
	EventsProposals []Interpolated
	AnswerRoot      TreeNodeAnswer
}

type TreeFieldBlock

type TreeFieldBlock struct {
	Answer TreeBlock
}

type TreeFieldInstance

type TreeFieldInstance struct {
	Answer TreeInstance
	ID     int
}

type TreeInstance

type TreeInstance struct {
	EventsProposals []client.TextLine
	AnswerRoot      TreeNodeInstance
}

type TreeNodeAnswer

type TreeNodeAnswer struct {
	Children      []TreeNodeAnswer `gomacro-data:"ignore"`
	Probabilities []string         // edges, same length as Children, valid expression.Expression
	Value         int              // index into the proposals, 0 for the root
}

TreeNodeAnswer is an event, with (optional) children

type TreeNodeInstance

type TreeNodeInstance struct {
	Children      []TreeNodeInstance
	Probabilities []*expression.Expr // expression for edges, same length as Children
	Value         int                // index into the proposals, ignored for the root
}

type VariationTableBlock

type VariationTableBlock struct {
	Label Interpolated
	Xs    []string // expressions
	Fxs   []string // expressions
}

type VariationTableFieldBlock

type VariationTableFieldBlock struct {
	Answer VariationTableBlock
}

type VariationTableFieldInstance

type VariationTableFieldInstance struct {
	Answer VariationTableInstance
	ID     int
}

type VariationTableInstance

type VariationTableInstance struct {
	Label string
	Xs    []evaluatedExpression // sorted expression values for x
	Fxs   []evaluatedExpression // corresponding values for f(x)
}

type VectorFieldBlock

type VectorFieldBlock struct {
	Answer         CoordExpression
	AcceptColinear bool // if true, all vectors colinears to `Answer` are accepted
	DisplayColumn  bool // if true, the field are displayed in column, instead of being on the same line
}

VectorFieldBlock is a two-number field, with option to interpret the answer up to colinearity

type VectorFieldInstance

type VectorFieldInstance struct {
	ID             int
	Answer         repere.Coord
	AcceptColinear bool
	DisplayColumn  bool
}

type VectorPairCriterion

type VectorPairCriterion uint8
const (
	VectorEquals     VectorPairCriterion = iota // Vecteurs égaux
	VectorColinear                              // Vecteurs colinéaires
	VectorOrthogonal                            // Vecteurs orthogonaux
)

Directories

Path Synopsis
Package examples provides a list of Question which may be used for demonstration or testing purposes.
Package examples provides a list of Question which may be used for demonstration or testing purposes.

Jump to

Keyboard shortcuts

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