kinesisanalytics

package
v1.1.4 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2026 License: MIT Imports: 20 Imported by: 0

README

Kinesis Analytics

Parity grade: A · SDK aws-sdk-go-v2/service/kinesisanalytics@v1.30.21 · last audited 2026-07-13 (d6bfd3a1)

Coverage

Metric Value
Operations audited 20 (19 ok, 1 deferred)
Feature families 1 (1 ok)
Known gaps 4
Deferred items 0
Resource leaks clean
Known gaps
  • DiscoverInputSchema returns a fixed canned schema/sample records regardless of input; real schema inference from a live Kinesis/Firehose stream or S3 object requires an actual sampling+type-inference engine this emulator does not have. Documented as an intentional stub in the handler (handleDiscoverInputSchema doc comment); response shape matches the real wire format so SDK consumers parse it without error. (bd: TBD)
  • Application/applicationDetail carry ServiceExecutionRole and RuntimeEnvironment fields that DO NOT EXIST anywhere in the real aws-sdk-go-v2/service/kinesisanalytics@v1.30.21 model (verified: grep for both identifiers across the whole SDK package returns zero hits outside unrelated client-config internals). These are additive/extra JSON keys in our responses; real SDK clients silently ignore unknown fields, so this doesn't break wire compatibility, but it is not a real field either -- ServiceExecutionRole is entirely unreachable from a real client (CreateApplicationInput has no such member) and RuntimeEnvironment is hardcoded to "SQL-1_0" for display only. Left as-is this sweep: removing them would require an Application persistence-shape/version bump and touches ~10 tests for zero real-client-facing benefit (extra fields are harmless). Worth a dedicated cleanup pass. (bd: TBD)
  • statusAutoScaling/statusForceStopping/statusMaintenance/statusRollingBack/statusRolledBack constants in backend.go are marked //nolint:deadcode "AWS status constant" but are NOT part of the real v1 ApplicationStatus enum (only DELETING/STARTING/STOPPING/READY/RUNNING/UPDATING exist per types/enums.go) -- they appear to be copied from the v2 (kinesisanalyticsv2) ApplicationStatus enum, which has more values. Unused dead code today so no functional bug, but the doc comment is misleading; a future pass should either delete them or correct the comment. (bd: TBD)
  • inputUpdate.InputStartingPositionConfiguration is accepted server-side but does not exist on the real InputUpdate shape (real InputUpdate only has InputId/InputParallelismUpdate/InputProcessingConfigurationUpdate/InputSchemaUpdate/Kinesis*InputUpdate/NamePrefixUpdate). Harmless surplus -- no real client ever sends it since the field isn't in their SDK type -- but noted so a future audit doesn't assume it's reachable in practice. (bd: TBD)

More

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound is returned when an application does not exist.
	ErrNotFound = awserr.New("ResourceNotFoundException", awserr.ErrNotFound)
	// ErrAlreadyExists is returned when an application already exists.
	ErrAlreadyExists = awserr.New("ResourceInUseException", awserr.ErrAlreadyExists)
	// ErrConcurrentUpdate is returned when the application version does not match.
	ErrConcurrentUpdate = errors.New("ConcurrentModificationException: application version mismatch")
	// ErrValidation is returned for invalid input parameters.
	ErrValidation = awserr.New("InvalidArgumentException", awserr.ErrInvalidParameter)
	// ErrLimitExceeded is returned when a resource limit is reached.
	ErrLimitExceeded = awserr.New("LimitExceededException", awserr.ErrConflict)
	// ErrTooManyTags is returned when tagging an application would exceed the maximum tag
	// count. AWS models this as a dedicated TooManyTagsException on CreateApplication and
	// TagResource, distinct from the generic LimitExceededException (verified against
	// aws-sdk-go-v2/service/kinesisanalytics deserializers.go per-operation error lists).
	ErrTooManyTags = errors.New("TooManyTagsException: application tag limit exceeded")
	// ErrResourceInUse is returned when the app is in an incompatible state for the requested operation.
	ErrResourceInUse = awserr.New("ResourceInUseException", awserr.ErrAlreadyExists)
)
View Source
var ErrNilAppContext = errors.New("kinesisanalytics: AppContext must not be nil")

ErrNilAppContext is returned by Provider.Init when a nil AppContext is supplied.

Functions

This section is empty.

Types

type Application

type Application struct {
	LastUpdateTimestamp      *time.Time                       `json:"LastUpdateTimestamp,omitempty"`
	Tags                     map[string]string                `json:"Tags,omitempty"`
	CreateTimestamp          *time.Time                       `json:"CreateTimestamp,omitempty"`
	ApplicationARN           string                           `json:"ApplicationARN"`
	ApplicationStatus        string                           `json:"ApplicationStatus"`
	ApplicationDescription   string                           `json:"ApplicationDescription,omitempty"`
	ApplicationCode          string                           `json:"ApplicationCode,omitempty"`
	ApplicationName          string                           `json:"ApplicationName"`
	ServiceExecutionRole     string                           `json:"ServiceExecutionRole,omitempty"`
	RuntimeEnvironment       string                           `json:"RuntimeEnvironment,omitempty"`
	Region                   string                           `json:"region,omitempty"`
	CloudWatchLoggingOptions []CloudWatchLoggingOptionDesc    `json:"CloudWatchLoggingOptions,omitempty"`
	ReferenceDataSources     []ReferenceDataSourceDescription `json:"ReferenceDataSources,omitempty"`
	Outputs                  []OutputDescription              `json:"Outputs,omitempty"`
	Inputs                   []InputDescription               `json:"Inputs,omitempty"`
	ApplicationVersionID     int64                            `json:"ApplicationVersionId"`
}

Application represents a Kinesis Analytics v1 application.

Region is additive: it is never part of the AWS wire format (Application is always converted to applicationDetail/applicationSummary before being marshaled for a response -- see toApplicationDetail in handler.go), so it carries a lowercase JSON tag to distinguish it from the AWS-named fields above. It exists purely so the store.Table keyFn and byRegion/byARN [store.Index]es (see store_setup.go) can derive both halves of the region-scoped identity from the value itself, mirroring how ApplicationName was already a real field. It must still round-trip through JSON (not json:"-") because it is part of the primary key store.Table.Restore rebuilds from a persisted snapshot.

type CSVMappingParameters

type CSVMappingParameters struct {
	RecordColumnDelimiter string `json:"RecordColumnDelimiter"`
	RecordRowDelimiter    string `json:"RecordRowDelimiter"`
}

CSVMappingParameters holds CSV delimiters.

type CloudWatchLoggingOptionDesc

type CloudWatchLoggingOptionDesc struct {
	CloudWatchLoggingOptionID string `json:"CloudWatchLoggingOptionId"`
	LogStreamARN              string `json:"LogStreamARN"`
	RoleARN                   string `json:"RoleARN,omitempty"`
}

CloudWatchLoggingOptionDesc describes a CloudWatch logging option.

type DestinationSchemaDesc

type DestinationSchemaDesc struct {
	RecordFormatType string `json:"RecordFormatType"`
}

DestinationSchemaDesc describes the destination record format.

type ExportedApplication

type ExportedApplication = Application

ExportedApplication is a compatibility alias used by the dashboard package.

type Handler

type Handler struct {
	Backend       StorageBackend
	AccountID     string
	DefaultRegion string
	// contains filtered or unexported fields
}

Handler is the HTTP handler for the Kinesis Analytics v1 API.

func NewHandler

func NewHandler(backend StorageBackend) *Handler

NewHandler creates a new Kinesis Analytics handler.

func (*Handler) ChaosOperations

func (h *Handler) ChaosOperations() []string

ChaosOperations returns all operations that can be fault-injected.

func (*Handler) ChaosRegions

func (h *Handler) ChaosRegions() []string

ChaosRegions returns all regions this handler handles.

func (*Handler) ChaosServiceName

func (h *Handler) ChaosServiceName() string

ChaosServiceName returns the lowercase AWS service name for fault rule matching.

func (*Handler) ExtractOperation

func (h *Handler) ExtractOperation(c *echo.Context) string

ExtractOperation extracts the Kinesis Analytics action from the X-Amz-Target header.

func (*Handler) ExtractResource

func (h *Handler) ExtractResource(c *echo.Context) string

ExtractResource extracts the application name from the request body.

func (*Handler) GetSupportedOperations

func (h *Handler) GetSupportedOperations() []string

GetSupportedOperations returns the list of supported Kinesis Analytics operations.

func (*Handler) Handler

func (h *Handler) Handler() echo.HandlerFunc

Handler returns the Echo handler function.

func (*Handler) MatchPriority

func (h *Handler) MatchPriority() int

MatchPriority returns the routing priority for header-based matching.

func (*Handler) Name

func (h *Handler) Name() string

Name returns the service name.

func (*Handler) Reset

func (h *Handler) Reset()

Reset clears handler state (delegates to backend if supported).

func (*Handler) Restore

func (h *Handler) Restore(ctx context.Context, data []byte) error

Restore implements persistence.Persistable by delegating to the backend.

func (*Handler) RouteMatcher

func (h *Handler) RouteMatcher() service.Matcher

RouteMatcher returns a function that matches Kinesis Analytics requests by X-Amz-Target header.

func (*Handler) Snapshot

func (h *Handler) Snapshot(ctx context.Context) []byte

Snapshot implements persistence.Persistable by delegating to the backend.

type InMemoryBackend

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

InMemoryBackend is the in-memory implementation of StorageBackend.

Applications are keyed by a composite "region#name" key (see applicationKey) inside a single flat store.Table, with secondary [store.Index]es grouping them by region (byRegion, replacing the old per-region map iteration) and by ARN (byARN, replacing the old map[region]map[arn]*Application reverse index) -- see store_setup.go for the full rationale.

func NewInMemoryBackend

func NewInMemoryBackend(region, accountID string) *InMemoryBackend

NewInMemoryBackend creates a new in-memory Kinesis Analytics backend with a background service context.

func NewInMemoryBackendWithContext

func NewInMemoryBackendWithContext(svcCtx context.Context, region, accountID string) *InMemoryBackend

NewInMemoryBackendWithContext creates a new in-memory Kinesis Analytics backend whose background goroutines are bounded by svcCtx. If svcCtx is nil, context.Background is used.

func (*InMemoryBackend) AddApplicationCloudWatchLoggingOption

func (b *InMemoryBackend) AddApplicationCloudWatchLoggingOption(
	ctx context.Context, name string, versionID int64, option CloudWatchLoggingOptionDesc,
) error

AddApplicationCloudWatchLoggingOption adds a CloudWatch logging option to an application.

func (*InMemoryBackend) AddApplicationInput

func (b *InMemoryBackend) AddApplicationInput(
	ctx context.Context, name string, versionID int64, input InputDescription,
) error

AddApplicationInput adds an input configuration to an application.

func (*InMemoryBackend) AddApplicationInputProcessingConfiguration

func (b *InMemoryBackend) AddApplicationInputProcessingConfiguration(
	ctx context.Context, name string, versionID int64, inputID string, config *InputProcessingConfigurationDesc,
) error

AddApplicationInputProcessingConfiguration sets a processing configuration on an existing input.

func (*InMemoryBackend) AddApplicationInternal

func (b *InMemoryBackend) AddApplicationInternal(app *Application)

AddApplicationInternal is a test-only seed helper that stores an application directly. The region is extracted from the application ARN.

func (*InMemoryBackend) AddApplicationOutput

func (b *InMemoryBackend) AddApplicationOutput(
	ctx context.Context, name string, versionID int64, output OutputDescription,
) error

AddApplicationOutput adds an output configuration to an application.

func (*InMemoryBackend) AddApplicationReferenceDataSource

func (b *InMemoryBackend) AddApplicationReferenceDataSource(
	ctx context.Context, name string, versionID int64, ref ReferenceDataSourceDescription,
) error

AddApplicationReferenceDataSource adds a reference data source to an application.

func (*InMemoryBackend) CreateApplication

func (b *InMemoryBackend) CreateApplication(
	ctx context.Context,
	name, description, code, serviceRole string,
	inputs []InputDescription,
	outputs []OutputDescription,
	cwlOptions []CloudWatchLoggingOptionDesc,
	tags map[string]string,
) (*Application, error)

CreateApplication creates a new Kinesis Analytics application.

func (*InMemoryBackend) DeleteApplication

func (b *InMemoryBackend) DeleteApplication(ctx context.Context, name string, createTimestamp *time.Time) error

DeleteApplication marks an application for deletion (DELETING state) then removes it after a delay.

func (*InMemoryBackend) DeleteApplicationCloudWatchLoggingOption

func (b *InMemoryBackend) DeleteApplicationCloudWatchLoggingOption(
	ctx context.Context, name string, versionID int64, loggingOptionID string,
) error

DeleteApplicationCloudWatchLoggingOption removes a CloudWatch logging option from an application.

func (*InMemoryBackend) DeleteApplicationInputProcessingConfiguration

func (b *InMemoryBackend) DeleteApplicationInputProcessingConfiguration(
	ctx context.Context, name string, versionID int64, inputID string,
) error

DeleteApplicationInputProcessingConfiguration removes the processing config from an input.

func (*InMemoryBackend) DeleteApplicationOutput

func (b *InMemoryBackend) DeleteApplicationOutput(
	ctx context.Context, name string, versionID int64, outputID string,
) error

DeleteApplicationOutput removes an output configuration from an application.

func (*InMemoryBackend) DeleteApplicationReferenceDataSource

func (b *InMemoryBackend) DeleteApplicationReferenceDataSource(
	ctx context.Context, name string, versionID int64, referenceID string,
) error

DeleteApplicationReferenceDataSource removes a reference data source from an application.

func (*InMemoryBackend) DescribeApplication

func (b *InMemoryBackend) DescribeApplication(ctx context.Context, name string) (*Application, error)

DescribeApplication returns a copy of the details for a Kinesis Analytics application.

func (*InMemoryBackend) ListApplications

func (b *InMemoryBackend) ListApplications(
	ctx context.Context,
	exclusiveStart string,
	limit int,
) ([]*Application, bool, error)

ListApplications returns paginated applications.

func (*InMemoryBackend) ListTagsForResource

func (b *InMemoryBackend) ListTagsForResource(ctx context.Context, resourceARN string) (map[string]string, error)

ListTagsForResource returns tags for a resource identified by ARN.

func (*InMemoryBackend) Region

func (b *InMemoryBackend) Region() string

Region returns the default region for this backend.

func (*InMemoryBackend) Reset

func (b *InMemoryBackend) Reset()

Reset clears all state and resets the ID counter.

func (*InMemoryBackend) Restore

func (b *InMemoryBackend) Restore(ctx context.Context, data []byte) error

Restore loads backend state from a JSON snapshot. It implements persistence.Persistable.

func (*InMemoryBackend) Snapshot

func (b *InMemoryBackend) Snapshot(ctx context.Context) []byte

Snapshot serialises the backend state to JSON. It implements persistence.Persistable.

func (*InMemoryBackend) StartApplication

func (b *InMemoryBackend) StartApplication(ctx context.Context, name string, inputConfigs []inputConfiguration) error

StartApplication transitions an application to RUNNING via a STARTING transient state.

func (*InMemoryBackend) StopApplication

func (b *InMemoryBackend) StopApplication(ctx context.Context, name string) error

StopApplication transitions an application to READY via a STOPPING transient state.

func (*InMemoryBackend) TagResource

func (b *InMemoryBackend) TagResource(ctx context.Context, resourceARN string, tags map[string]string) error

TagResource adds or updates tags on a resource.

func (*InMemoryBackend) UntagResource

func (b *InMemoryBackend) UntagResource(ctx context.Context, resourceARN string, tagKeys []string) error

UntagResource removes tags from a resource.

func (*InMemoryBackend) UpdateApplication

func (b *InMemoryBackend) UpdateApplication(
	ctx context.Context,
	name string,
	currentVersionID int64,
	update *applicationUpdate,
) (*Application, error)

UpdateApplication updates the application with the full update payload and bumps the version.

type InputDescription

type InputDescription struct {
	InputProcessingConfigurationDescription *InputProcessingConfigurationDesc   `json:"InputProcessingConfigurationDescription,omitempty"`
	InputStartingPositionConfiguration      *InputStartingPositionConfiguration `json:"InputStartingPositionConfiguration,omitempty"`
	InputSchema                             *SourceSchema                       `json:"InputSchema,omitempty"`
	InputParallelism                        *InputParallelism                   `json:"InputParallelism,omitempty"`
	KinesisStreamsInputDescription          *KinesisStreamsInputDesc            `json:"KinesisStreamsInputDescription,omitempty"`
	KinesisFirehoseInputDescription         *KinesisFirehoseInputDesc           `json:"KinesisFirehoseInputDescription,omitempty"`
	InputID                                 string                              `json:"InputId"`
	NamePrefix                              string                              `json:"NamePrefix,omitempty"`
	InAppStreamNames                        []string                            `json:"InAppStreamNames,omitempty"`
}

InputDescription describes an application input configuration.

type InputParallelism

type InputParallelism struct {
	Count int `json:"Count"`
}

InputParallelism describes the in-application stream count for an input.

type InputProcessingConfigurationDesc

type InputProcessingConfigurationDesc struct {
	InputLambdaProcessor *LambdaProcessorDesc `json:"InputLambdaProcessor,omitempty"`
}

InputProcessingConfigurationDesc describes an input processing configuration.

type InputStartingPositionConfiguration

type InputStartingPositionConfiguration struct {
	InputStartingPosition string `json:"InputStartingPosition,omitempty"`
}

InputStartingPositionConfiguration describes where to start reading from an input stream.

type JSONMappingParameters

type JSONMappingParameters struct {
	RecordRowPath string `json:"RecordRowPath"`
}

JSONMappingParameters holds the JSON row path.

type KinesisFirehoseInputDesc

type KinesisFirehoseInputDesc struct {
	ResourceARN string `json:"ResourceARN"`
	RoleARN     string `json:"RoleARN,omitempty"`
}

KinesisFirehoseInputDesc describes a Kinesis Firehose input.

type KinesisFirehoseOutputDesc

type KinesisFirehoseOutputDesc struct {
	ResourceARN string `json:"ResourceARN"`
	RoleARN     string `json:"RoleARN,omitempty"`
}

KinesisFirehoseOutputDesc describes a Kinesis Firehose output.

type KinesisStreamsInputDesc

type KinesisStreamsInputDesc struct {
	ResourceARN string `json:"ResourceARN"`
	RoleARN     string `json:"RoleARN,omitempty"`
}

KinesisStreamsInputDesc describes a Kinesis Streams input.

type KinesisStreamsOutputDesc

type KinesisStreamsOutputDesc struct {
	ResourceARN string `json:"ResourceARN"`
	RoleARN     string `json:"RoleARN,omitempty"`
}

KinesisStreamsOutputDesc describes a Kinesis Streams output.

type LambdaOutputDesc

type LambdaOutputDesc struct {
	ResourceARN string `json:"ResourceARN"`
	RoleARN     string `json:"RoleARN,omitempty"`
}

LambdaOutputDesc describes a Lambda output.

type LambdaProcessorDesc

type LambdaProcessorDesc struct {
	ResourceARN string `json:"ResourceARN"`
	RoleARN     string `json:"RoleARN,omitempty"`
}

LambdaProcessorDesc describes a Lambda input processor.

type MappingParameters

type MappingParameters struct {
	JSONMappingParameters *JSONMappingParameters `json:"JSONMappingParameters,omitempty"`
	CSVMappingParameters  *CSVMappingParameters  `json:"CSVMappingParameters,omitempty"`
}

MappingParameters holds format-specific mapping parameters.

type OutputDescription

type OutputDescription struct {
	KinesisStreamsOutputDescription  *KinesisStreamsOutputDesc  `json:"KinesisStreamsOutputDescription,omitempty"`
	KinesisFirehoseOutputDescription *KinesisFirehoseOutputDesc `json:"KinesisFirehoseOutputDescription,omitempty"`
	LambdaOutputDescription          *LambdaOutputDesc          `json:"LambdaOutputDescription,omitempty"`
	DestinationSchema                *DestinationSchemaDesc     `json:"DestinationSchema,omitempty"`
	OutputID                         string                     `json:"OutputId"`
	Name                             string                     `json:"Name,omitempty"`
}

OutputDescription describes an application output configuration.

type Provider

type Provider struct{}

Provider implements service.Provider for the Kinesis Analytics service.

func (*Provider) Init

Init initializes the Kinesis Analytics service backend and handler.

func (*Provider) Name

func (p *Provider) Name() string

Name returns the provider name.

type RecordColumn

type RecordColumn struct {
	Name    string `json:"Name"`
	SQLType string `json:"SqlType"`
	Mapping string `json:"Mapping,omitempty"`
}

RecordColumn describes a column mapping in the schema.

type RecordFormat

type RecordFormat struct {
	MappingParameters *MappingParameters `json:"MappingParameters,omitempty"`
	RecordFormatType  string             `json:"RecordFormatType"`
}

RecordFormat describes the record format type and mapping.

type ReferenceDataSourceDescription

type ReferenceDataSourceDescription struct {
	S3ReferenceDataSourceDescription *S3ReferenceDataSourceDesc `json:"S3ReferenceDataSourceDescription,omitempty"`
	ReferenceSchema                  *SourceSchema              `json:"ReferenceSchema,omitempty"`
	ReferenceID                      string                     `json:"ReferenceId"`
	TableName                        string                     `json:"TableName,omitempty"`
}

ReferenceDataSourceDescription describes a reference data source.

type S3ReferenceDataSourceDesc

type S3ReferenceDataSourceDesc struct {
	BucketARN        string `json:"BucketARN"`
	FileKey          string `json:"FileKey"`
	ReferenceRoleARN string `json:"ReferenceRoleARN,omitempty"`
}

S3ReferenceDataSourceDesc describes the S3 source for reference data.

The IAM role field is wired as "ReferenceRoleARN" on the wire, not "RoleARN" -- unlike every other role-ARN-bearing shape in this API, S3ReferenceDataSource(Description) uses the ReferenceRoleARN name (verified against aws-sdk-go-v2/service/kinesisanalytics deserializers.go / types.go).

type SourceSchema

type SourceSchema struct {
	RecordFormat   RecordFormat   `json:"RecordFormat"`
	RecordEncoding string         `json:"RecordEncoding,omitempty"`
	RecordColumns  []RecordColumn `json:"RecordColumns"`
}

SourceSchema describes the schema of the input records.

type StorageBackend

type StorageBackend interface {
	CreateApplication(ctx context.Context, name, description, code, serviceRole string,
		inputs []InputDescription, outputs []OutputDescription,
		cwlOptions []CloudWatchLoggingOptionDesc, tags map[string]string) (*Application, error)
	DeleteApplication(ctx context.Context, name string, createTimestamp *time.Time) error
	DescribeApplication(ctx context.Context, name string) (*Application, error)
	ListApplications(ctx context.Context, exclusiveStart string, limit int) ([]*Application, bool, error)
	StartApplication(ctx context.Context, name string, inputConfigs []inputConfiguration) error
	StopApplication(ctx context.Context, name string) error
	UpdateApplication(
		ctx context.Context,
		name string,
		currentVersionID int64,
		update *applicationUpdate,
	) (*Application, error)
	ListTagsForResource(ctx context.Context, resourceARN string) (map[string]string, error)
	TagResource(ctx context.Context, resourceARN string, tags map[string]string) error
	UntagResource(ctx context.Context, resourceARN string, tagKeys []string) error
	AddApplicationCloudWatchLoggingOption(
		ctx context.Context,
		name string,
		versionID int64,
		option CloudWatchLoggingOptionDesc,
	) error
	AddApplicationInput(ctx context.Context, name string, versionID int64, input InputDescription) error
	AddApplicationInputProcessingConfiguration(
		ctx context.Context,
		name string,
		versionID int64,
		inputID string,
		config *InputProcessingConfigurationDesc,
	) error
	AddApplicationOutput(ctx context.Context, name string, versionID int64, output OutputDescription) error
	AddApplicationReferenceDataSource(
		ctx context.Context,
		name string,
		versionID int64,
		ref ReferenceDataSourceDescription,
	) error
	DeleteApplicationCloudWatchLoggingOption(
		ctx context.Context,
		name string,
		versionID int64,
		loggingOptionID string,
	) error
	DeleteApplicationInputProcessingConfiguration(
		ctx context.Context,
		name string,
		versionID int64,
		inputID string,
	) error
	DeleteApplicationOutput(ctx context.Context, name string, versionID int64, outputID string) error
	DeleteApplicationReferenceDataSource(ctx context.Context, name string, versionID int64, referenceID string) error
}

StorageBackend is the interface for the Kinesis Analytics in-memory backend.

Jump to

Keyboard shortcuts

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