deployments

package
v2.41.1 Latest Latest
Warning

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

Go to latest
Published: May 1, 2024 License: Apache-2.0 Imports: 17 Imported by: 6

Documentation

Index

Constants

View Source
const (
	PackageAcquisitionLocationServer          = "Server"
	PackageAcquisitionLocationExecutionTarget = "ExecutionTarget"
	PackageAcquisitionLocationNotAcquired     = "NotAcquired"
)

Variables

This section is empty.

Functions

func IsNil

func IsNil(i interface{}) bool

Types

type ChannelRule

type ChannelRule struct {
	ActionPackages []packages.DeploymentActionPackage `json:"ActionPackages,omitempty"`
	ID             string                             `json:"Id,omitempty"`
	Tag            string                             `json:"Tag,omitempty"`

	//Use the NuGet or Maven versioning syntax (depending on the feed type)
	//to specify the range of versions to include
	VersionRange string `json:"VersionRange,omitempty"`

	resources.Resource
}

type Control added in v2.37.0

type Control struct {
	Type            string                     `json:"Type"`
	Name            string                     `json:"Name"`
	Label           string                     `json:"Label"`
	Description     string                     `json:"Description"`
	Required        bool                       `json:"Required"`
	DisplaySettings *resources.DisplaySettings `json:"DisplaySettings"`
}

func NewControl added in v2.37.0

func NewControl(controlType, name, label, description string, required bool, displaySettings *resources.DisplaySettings) *Control

type CreateDeploymentResponseV1 added in v2.4.0

type CreateDeploymentResponseV1 struct {
	DeploymentServerTasks []*DeploymentServerTask `json:"DeploymentServerTasks,omitempty"`
}

func CreateDeploymentTenantedV1 added in v2.4.0

func CreateDeploymentTenantedV1(client newclient.Client, command *CreateDeploymentTenantedCommandV1) (*CreateDeploymentResponseV1, error)

func CreateDeploymentUntenantedV1 added in v2.4.0

func CreateDeploymentUntenantedV1(client newclient.Client, command *CreateDeploymentUntenantedCommandV1) (*CreateDeploymentResponseV1, error)

type CreateDeploymentTenantedCommandV1 added in v2.4.0

type CreateDeploymentTenantedCommandV1 struct {
	ReleaseVersion           string   `json:"releaseVersion"`  // required
	EnvironmentName          string   `json:"environmentName"` // required
	Tenants                  []string `json:"tenants,omitempty"`
	TenantTags               []string `json:"tenantTags,omitempty"`
	ForcePackageRedeployment bool     `json:"forcePackageRedeployment"`
	UpdateVariableSnapshot   bool     `json:"updateVariableSnapshot"`
	CreateExecutionAbstractCommandV1
}

func NewCreateDeploymentTenantedCommandV1 added in v2.4.0

func NewCreateDeploymentTenantedCommandV1(spaceID string, projectIDOrName string) *CreateDeploymentTenantedCommandV1

func (*CreateDeploymentTenantedCommandV1) MarshalJSON added in v2.4.0

func (c *CreateDeploymentTenantedCommandV1) MarshalJSON() ([]byte, error)

MarshalJSON adds the redundant 'spaceIdOrName' parameter which is required by the server

type CreateDeploymentUntenantedCommandV1 added in v2.4.0

type CreateDeploymentUntenantedCommandV1 struct {
	ReleaseVersion           string   `json:"releaseVersion"`   // required
	EnvironmentNames         []string `json:"environmentNames"` // required
	ForcePackageRedeployment bool     `json:"forcePackageRedeployment"`
	UpdateVariableSnapshot   bool     `json:"updateVariableSnapshot"`
	CreateExecutionAbstractCommandV1
}

func NewCreateDeploymentUntenantedCommandV1 added in v2.4.0

func NewCreateDeploymentUntenantedCommandV1(spaceID string, projectIDOrName string) *CreateDeploymentUntenantedCommandV1

func (*CreateDeploymentUntenantedCommandV1) MarshalJSON added in v2.4.0

func (c *CreateDeploymentUntenantedCommandV1) MarshalJSON() ([]byte, error)

MarshalJSON adds the redundant 'spaceIdOrName' parameter which is required by the server

type CreateExecutionAbstractCommandV1 added in v2.4.0

type CreateExecutionAbstractCommandV1 struct {
	// also has awkward SpaceIDOrName; see CreateReleaseV1 for explanation
	SpaceID              string            `json:"spaceId"`
	ProjectIDOrName      string            `json:"projectName"`
	ForcePackageDownload bool              `json:"forcePackageDownload"`
	SpecificMachineNames []string          `json:"specificMachineNames,omitempty"`
	ExcludedMachineNames []string          `json:"excludedMachineNames,omitempty"`
	SkipStepNames        []string          `json:"skipStepNames,omitempty"`
	UseGuidedFailure     *bool             `json:"useGuidedFailure"`     // note: nil is valid, meaning 'use default'
	RunAt                string            `json:"runAt,omitempty"`      // contains a datetimeOffset-parseable value
	NoRunAfter           string            `json:"noRunAfter,omitempty"` // contains a datetimeOffset-parseable value
	Variables            map[string]string `json:"variables,omitempty"`
}

type Deployment

type Deployment struct {
	Changes                  []*releases.ReleaseChanges `json:"Changes"`
	ChangesMarkdown          string                     `json:"ChangesMarkdown,omitempty"`
	ChannelID                string                     `json:"ChannelId,omitempty"`
	Comments                 string                     `json:"Comments,omitempty"`
	Created                  *time.Time                 `json:"Created,omitempty"`
	DeployedBy               string                     `json:"DeployedBy,omitempty"`
	DeployedByID             string                     `json:"DeployedById,omitempty"`
	DeployedToMachineIDs     []string                   `json:"DeployedToMachineIds"`
	DeploymentProcessID      string                     `json:"DeploymentProcessId,omitempty"`
	EnvironmentID            string                     `json:"EnvironmentId" validate:"required"`
	ExcludedMachineIDs       []string                   `json:"ExcludedMachineIds"`
	FailureEncountered       bool                       `json:"FailureEncountered"`
	ForcePackageDownload     bool                       `json:"ForcePackageDownload"`
	ForcePackageRedeployment bool                       `json:"ForcePackageRedeployment"`
	FormValues               map[string]string          `json:"FormValues,omitempty"`
	ManifestVariableSetID    string                     `json:"ManifestVariableSetId,omitempty"`
	Name                     string                     `json:"Name,omitempty"`
	ProjectID                string                     `json:"ProjectId,omitempty"`
	QueueTime                *time.Time                 `json:"QueueTime,omitempty"`
	QueueTimeExpiry          *time.Time                 `json:"QueueTimeExpiry,omitempty"`
	ReleaseID                string                     `json:"ReleaseId" validate:"required"`
	SkipActions              []string                   `json:"SkipActions"`
	SpaceID                  string                     `json:"SpaceId,omitempty"`
	SpecificMachineIDs       []string                   `json:"SpecificMachineIds"`
	TaskID                   string                     `json:"TaskId,omitempty"`
	TenantID                 string                     `json:"TenantId,omitempty"`
	TentacleRetentionPeriod  *core.RetentionPeriod      `json:"TentacleRetentionPeriod,omitempty"`
	UseGuidedFailure         bool                       `json:"UseGuidedFailure"`

	resources.Resource
}

func NewDeployment

func NewDeployment(environmentID string, releaseID string) *Deployment

NewDeployment initializes a deployment with a name, environment ID, and release ID.

func (*Deployment) Validate

func (d *Deployment) Validate() error

Validate checks the state of the deployment and returns an error if invalid.

type DeploymentAction

type DeploymentAction struct {
	ActionType                    string                           `json:"ActionType" validate:"required,notblank"`
	CanBeUsedForProjectVersioning bool                             `json:"CanBeUsedForProjectVersioning"`
	Channels                      []string                         `json:"Channels,omitempty"`
	Condition                     string                           `json:"Condition,omitempty"`
	Container                     *DeploymentActionContainer       `json:"Container,omitempty"`
	Environments                  []string                         `json:"Environments,omitempty"`
	ExcludedEnvironments          []string                         `json:"ExcludedEnvironments,omitempty"`
	IsDisabled                    bool                             `json:"IsDisabled"`
	IsRequired                    bool                             `json:"IsRequired"`
	Name                          string                           `json:"Name" validate:"required,notblank"`
	Notes                         string                           `json:"Notes,omitempty"`
	Packages                      []*packages.PackageReference     `json:"Packages,omitempty"`
	GitDependencies               []*gitdependencies.GitDependency `json:"GitDependencies,omitempty"`
	Properties                    map[string]core.PropertyValue    `json:"Properties,omitempty"`
	StepPackageVersion            string                           `json:"StepPackageVersion,omitempty"`
	TenantTags                    []string                         `json:"TenantTags,omitempty"`
	WorkerPool                    string                           `json:"WorkerPoolId,omitempty"`
	WorkerPoolVariable            string                           `json:"WorkerPoolVariable,omitempty"`

	resources.Resource
}

func NewDeploymentAction

func NewDeploymentAction(name string, actionType string) *DeploymentAction

NewDeploymentAction initializes a DeploymentAction with a name.

func (DeploymentAction) Validate

func (d DeploymentAction) Validate() error

Validate checks the state of the channel and returns an error if invalid.

type DeploymentActionContainer

type DeploymentActionContainer struct {
	FeedID string `json:"FeedId,omitempty"`
	Image  string `json:"Image,omitempty"`
}

func NewDeploymentActionContainer

func NewDeploymentActionContainer(feedID *string, image *string) *DeploymentActionContainer

NewDeploymentActionContainer creates and initializes a new Kubernetes endpoint.

type DeploymentPreview added in v2.4.0

type DeploymentPreview struct {
	// Changes []*ReleaseChanges // we don't use this at the moment, and it is large+expensive, so don't de-serialize for now
	// ChangesMarkdown string  // we don't use this at the moment, and it is large+expensive, so don't de-serialize for now
	Form                          *Form                     `json:"Form,omitempty"`
	StepsToExecute                []*DeploymentTemplateStep `json:"StepsToExecute,omitempty"`
	UseGuidedFailureModeByDefault bool                      `json:"UseGuidedFailureModeByDefault"`
}

func GetReleaseDeploymentPreview added in v2.4.0

func GetReleaseDeploymentPreview(client newclient.Client, spaceID string, releaseID string, environmentID string, includeDisabledSteps bool) (*DeploymentPreview, error)

GetReleaseDeploymentPreview gets a preview of a release for a given environment. This is used by the portal to show which machines would be deployed to, and other information about the deployment, before proceeding with it. The CLI uses it to build the selector for picking specific machines to deploy to

func GetReleaseDeploymentPreviews added in v2.37.0

func GetReleaseDeploymentPreviews(client newclient.Client, spaceID string, releaseID string, deploymentPreviewRequests []DeploymentPreviewRequest, includeDisabledSteps bool) ([]*DeploymentPreview, error)

GetReleaseDeploymentPreviews gets a preview of a release for a multiple given environments. This is used by the portal to show which machines, prompted variables and other information about the deployment, before proceeding with it. The CLI uses it to build the prompted variables list for a deployment to a given set of environments

func NewEmptyDeploymentPreview added in v2.37.0

func NewEmptyDeploymentPreview() *DeploymentPreview

type DeploymentPreviewRequest added in v2.37.0

type DeploymentPreviewRequest struct {
	EnvironmentId string `json:"EnvironmentId"`
	TenantId      string `json:"TenantId"`
}

type DeploymentPreviewsBody added in v2.37.0

type DeploymentPreviewsBody struct {
	DeploymentPreviews   []DeploymentPreviewRequest `json:"DeploymentPreviews"`
	IncludeDisabledSteps bool                       `json:"IncludeDisabledSteps"`
	ReleaseId            string                     `json:"ReleaseId"`
	SpaceId              string                     `json:"SpaceId"`
}

For review time - Should DeploymentPreviewRequestBody be an array of pointers to an object?

type DeploymentProcess

type DeploymentProcess struct {
	Branch         string            `json:"-"`
	LastSnapshotID string            `json:"LastSnapshotId,omitempty"`
	ProjectID      string            `json:"ProjectId,omitempty"`
	SpaceID        string            `json:"SpaceId,omitempty"`
	Steps          []*DeploymentStep `json:"Steps,omitempty"`
	Version        int32             `json:"Version"`

	resources.Resource
}

func GetAllDeploymentProcesses added in v2.36.0

func GetAllDeploymentProcesses(client newclient.Client, spaceID string) ([]*DeploymentProcess, error)

GetAllDeploymentProcesses returns all deployment processes. If none can be found or an error occurs, it returns an empty collection.

func GetDeploymentProcessByGitRef added in v2.36.0

func GetDeploymentProcessByGitRef(client newclient.Client, spaceID string, project *projects.Project, gitRef string) (*DeploymentProcess, error)

GetDeploymentProcessByGitRef returns the deployment process that matches the input project and a git reference.

func GetDeploymentProcessByID added in v2.36.0

func GetDeploymentProcessByID(client newclient.Client, spaceID string, ID string) (*DeploymentProcess, error)

GetDeploymentProcessByID fetches a deployment process. This may either be the project level process (template), or a process snapshot from a Release, depending on the value of ID

func NewDeploymentProcess

func NewDeploymentProcess(projectID string) *DeploymentProcess

NewDeploymentProcess initializes a deployment process.

func UpdateDeploymentProcess added in v2.36.0

func UpdateDeploymentProcess(client newclient.Client, deploymentProcess *DeploymentProcess) (*DeploymentProcess, error)

UpdateDeploymentProcess modifies a deployment process based on the one provided as input.

type DeploymentProcessService

type DeploymentProcessService struct {
	services.Service
}

func NewDeploymentProcessService

func NewDeploymentProcessService(sling *sling.Sling, uriTemplate string) *DeploymentProcessService

func (*DeploymentProcessService) Get deprecated

Get returns the deployment process that matches the input project and a git reference. If one cannot be found, it returns nil and an error.

Deprecated: use deployments.GetProcessByGitRef

func (*DeploymentProcessService) GetAll deprecated

GetAll returns all deployment processes. If none can be found or an error occurs, it returns an empty collection.

Deprecated: Use deployments.GetAllDeploymentProcesses

func (*DeploymentProcessService) GetByID deprecated

GetByID returns the deployment process that matches the input ID. If one cannot be found, it returns nil and an error.

Deprecated: Use deployments.GetDeploymentProcessByID

func (*DeploymentProcessService) GetTemplate deprecated added in v2.1.0

func (s *DeploymentProcessService) GetTemplate(deploymentProcess *DeploymentProcess, channelID string, releaseID string) (*DeploymentProcessTemplate, error)

Deprecated: Use deployments.GetDeploymentProcessTemplate

func (*DeploymentProcessService) Update deprecated

func (s *DeploymentProcessService) Update(deploymentProcess *DeploymentProcess) (*DeploymentProcess, error)

Update modifies a deployment process based on the one provided as input.

Deprecated: Use deployments.Update

type DeploymentProcessTemplate added in v2.1.0

type DeploymentProcessTemplate struct {
	DeploymentProcessId            string                            `json:"DeploymentProcessId,omitempty"`
	LastReleaseVersion             string                            `json:"LastReleaseVersion,omitempty"`
	NextVersionIncrement           string                            `json:"NextVersionIncrement,omitempty"`
	VersioningPackageStepName      *string                           `json:"VersioningPackageStepName,omitempty"`
	VersioningPackageReferenceName *string                           `json:"VersioningPackageReferenceName,omitempty"`
	Packages                       []releases.ReleaseTemplatePackage `json:"Packages,omitempty"`

	resources.Resource
}

func GetDeploymentProcessTemplate added in v2.36.0

func GetDeploymentProcessTemplate(client newclient.Client, deploymentProcess *DeploymentProcess, channelID string, releaseID string) (*DeploymentProcessTemplate, error)

type DeploymentProcessesQuery

type DeploymentProcessesQuery struct {
	IDs  []string `uri:"ids,omitempty" url:"ids,omitempty"`
	Skip int      `uri:"skip,omitempty" url:"skip,omitempty"`
	Take int      `uri:"take,omitempty" url:"take,omitempty"`
}

type DeploymentQuery

type DeploymentQuery struct {
	Skip int `uri:"skip,omitempty" url:"skip,omitempty"`
	Take int `uri:"take,omitempty" url:"take,omitempty"`
}

type DeploymentServerTask added in v2.4.0

type DeploymentServerTask struct {
	DeploymentID string `json:"DeploymentId"`
	ServerTaskID string `json:"ServerTaskId"`
}

type DeploymentService

type DeploymentService struct {
	services.CanDeleteService
}

DeploymentService handles communication for any operations in the Octopus API that pertain to deployments.

func NewDeploymentService

func NewDeploymentService(sling *sling.Sling, uriTemplate string) *DeploymentService

NewDeploymentService returns a deploymentService with a preconfigured client.

func (*DeploymentService) Add

func (s *DeploymentService) Add(deployment *Deployment) (*Deployment, error)

Add creates a new deployment.

func (*DeploymentService) GetByID

func (s *DeploymentService) GetByID(id string) (*Deployment, error)

GetByID gets a deployment that matches the input ID. If one cannot be found, it returns nil and an error.

func (*DeploymentService) GetByIDs

func (s *DeploymentService) GetByIDs(ids []string) ([]*Deployment, error)

GetByIDs gets a list of deployments that match the input IDs.

func (*DeploymentService) GetByName

func (s *DeploymentService) GetByName(name string) ([]*Deployment, error)

GetByName performs a lookup and returns instances of a Deployment with a matching partial name.

func (*DeploymentService) GetDeploymentSettings added in v2.3.2

func (s *DeploymentService) GetDeploymentSettings(project *projects.Project, gitRef string) (*DeploymentSettings, error)

GetDeploymentSettings loads the deployment settings for a project. If the project is version controlled you'll need to specify a gitRef such as 'main'

func (*DeploymentService) GetDeployments

func (s *DeploymentService) GetDeployments(release *releases.Release, deploymentQuery ...*DeploymentQuery) (*resources.Resources[*Deployment], error)

func (*DeploymentService) GetProgression

func (s *DeploymentService) GetProgression(release *releases.Release) (*releases.LifecycleProgression, error)

func (*DeploymentService) Update

func (s *DeploymentService) Update(resource Deployment) (*Deployment, error)

Update modifies a Deployment based on the one provided as input.

type DeploymentSettings

type DeploymentSettings struct {
	ChangeDescription               string                       `json:"ChangeDescription,omitempty"`
	ConnectivityPolicy              *core.ConnectivityPolicy     `json:"ProjectConnectivityPolicy,omitempty"`
	DefaultGuidedFailureMode        core.GuidedFailureMode       `json:"DefaultGuidedFailureMode,omitempty"`
	DefaultToSkipIfAlreadyInstalled bool                         `json:"DefaultToSkipIfAlreadyInstalled"`
	DeploymentChangesTemplate       string                       `json:"DeploymentChangesTemplate,omitempty"`
	ProjectID                       string                       `json:"ProjectId"`
	ReleaseNotesTemplate            string                       `json:"ReleaseNotesTemplate,omitempty"`
	SpaceID                         string                       `json:"SpaceId"`
	VersioningStrategy              *projects.VersioningStrategy `json:"VersioningStrategy,omitempty"`

	resources.Resource
}

DeploymentSettings are loaded by the ProjectService because deployment settings are a subresource of Projects

func NewDeploymentSettings

func NewDeploymentSettings() *DeploymentSettings

type DeploymentStep

type DeploymentStep struct {
	Actions            []*DeploymentAction              `json:"Actions,omitempty"`
	Condition          DeploymentStepConditionType      `json:"Condition,omitempty"` // variable option adds a Property "Octopus.Action.ConditionVariableExpression"
	Name               string                           `json:"Name"`
	PackageRequirement DeploymentStepPackageRequirement `json:"PackageRequirement,omitempty"`
	Properties         map[string]core.PropertyValue    `json:"Properties,omitempty"`
	StartTrigger       DeploymentStepStartTrigger       `json:"StartTrigger,omitempty" validate:"required,oneof=StartAfterPrevious StartWithPrevious"`
	TargetRoles        []string                         `json:"-"`

	resources.Resource
}

func NewDeploymentStep

func NewDeploymentStep(name string) *DeploymentStep

NewDeploymentStep initializes a DeploymentStep with a name.

func (DeploymentStep) Validate

func (d DeploymentStep) Validate() error

Validate checks the state of the deployment step and returns an error if invalid.

type DeploymentStepConditionType

type DeploymentStepConditionType string
const (
	DeploymentStepConditionTypeSuccess  DeploymentStepConditionType = "Success"
	DeploymentStepConditionTypeFailure  DeploymentStepConditionType = "Failure"
	DeploymentStepConditionTypeAlways   DeploymentStepConditionType = "Always"
	DeploymentStepConditionTypeVariable DeploymentStepConditionType = "Variable"
)

type DeploymentStepPackageRequirement

type DeploymentStepPackageRequirement string
const (
	DeploymentStepPackageRequirementLetOctopusDecide         DeploymentStepPackageRequirement = "LetOctopusDecide"
	DeploymentStepPackageRequirementBeforePackageAcquisition DeploymentStepPackageRequirement = "BeforePackageAcquisition"
	DeploymentStepPackageRequirementAfterPackageAcquisition  DeploymentStepPackageRequirement = "AfterPackageAcquisition"
)

type DeploymentStepStartTrigger

type DeploymentStepStartTrigger string
const (
	DeploymentStepStartTriggerStartAfterPrevious DeploymentStepStartTrigger = "StartAfterPrevious"
	DeploymentStepStartTriggerStartWithPrevious  DeploymentStepStartTrigger = "StartWithPrevious"
)

type DeploymentTemplateStep added in v2.4.0

type DeploymentTemplateStep struct {
	ActionID                string                         `json:"ActionId,omitempty"`
	ActionName              string                         `json:"ActionName,omitempty"`
	ActionNumber            string                         `json:"ActionNumber,omitempty"`
	Roles                   []string                       `json:"Roles,omitempty"`
	MachineNames            []string                       `json:"MachineNames,omitempty"`
	Machines                []*MachineDeploymentPreview    `json:"Machines,omitempty"`
	CanBeSkipped            bool                           `json:"CanBeSkipped"`
	IsDisabled              bool                           `json:"IsDisabled"`
	HasNoApplicableMachines bool                           `json:"HasNoApplicableMachines"`
	UnavailableMachines     []*resources.ReferenceDataItem `json:"UnavailableMachines,omitempty"`
	ExcludedMachines        []*resources.ReferenceDataItem `json:"ExcludedMachines,omitempty"`
}

type DeploymentsQuery

type DeploymentsQuery struct {
	Channels     string   `uri:"channels,omitempty" url:"channels,omitempty"`
	Environments []string `uri:"environments,omitempty" url:"environments,omitempty"`
	IDs          []string `uri:"ids,omitempty" url:"ids,omitempty"`
	PartialName  string   `uri:"partialName,omitempty" url:"partialName,omitempty"`
	Projects     []string `uri:"projects,omitempty" url:"projects,omitempty"`
	Skip         int      `uri:"skip,omitempty" url:"skip,omitempty"`
	Take         int      `uri:"take,omitempty" url:"take,omitempty"`
	TaskState    string   `uri:"taskState,omitempty" url:"taskState,omitempty"`
	Tenants      []string `uri:"tenants,omitempty" url:"tenants,omitempty"`
}

type Element added in v2.37.0

type Element struct {
	Name            string   `json:"Name"`
	Control         *Control `json:"Control"`
	IsValueRequired bool     `json:"IsValueRequired"`
}

func NewElement added in v2.37.0

func NewElement(name string, control *Control, isValueRequired bool) *Element

type Form added in v2.37.0

type Form struct {
	Values   map[string]string `json:"Values"`
	Elements []*Element        `json:"Elements"`
}

func NewFormWithValuesAndElements added in v2.37.0

func NewFormWithValuesAndElements(values map[string]string, elements []*Element) *Form

type MachineDeploymentPreview added in v2.4.0

type MachineDeploymentPreview struct {
	ID                string `json:"Id,omitempty"`
	Name              string `json:"Name,omitempty"`
	HasLatestCalamari bool   `json:"HasLatestCalamari"`
	HealthStatus      string `json:"HealthStatus,omitempty"` // machines.HealthStatus validate:"omitempty,oneof=HasWarnings Healthy Unavailable Unhealthy Unknown"`
}

type StepUsage

type StepUsage struct {
	ProjectID   string            `json:"ProjectId,omitempty"`
	ProjectName string            `json:"ProjectName,omitempty"`
	ProjectSlug string            `json:"ProjectSlug,omitempty"`
	Steps       []*StepUsageEntry `json:"Steps"`
}

type StepUsageEntry

type StepUsageEntry struct {
	StepID   string `json:"StepId,omitempty"`
	StepName string `json:"StepName,omitempty"`
}

Jump to

Keyboard shortcuts

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