Documentation ¶
Index ¶
- Constants
- Variables
- type BaseResourceType
- type BaseResourceTypeFactory
- type Build
- type BuildStatus
- type ConfigVersion
- type Conn
- type ContainerFactory
- type ContainerMetadata
- type ContainerStage
- type ContainerState
- type CreatedContainer
- type CreatedVolume
- type CreatingContainer
- type CreatingVolume
- type DestroyingContainer
- type DestroyingVolume
- type ErrResourceTypeNotFound
- type ErrVolumeMarkCreatedFailed
- type Pipeline
- type PipelineFactory
- type PipelinePausedState
- type Resource
- type ResourceCache
- func (cache ResourceCache) FindOrCreateForBuild(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, buildID int) (*UsedResourceCache, error)
- func (cache ResourceCache) FindOrCreateForResource(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, resourceID int) (*UsedResourceCache, error)
- func (cache ResourceCache) FindOrCreateForResourceType(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, ...) (*UsedResourceCache, error)
- type ResourceCacheFactory
- type ResourceConfig
- func (resourceConfig ResourceConfig) FindOrCreateForBuild(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, buildID int) (*UsedResourceConfig, error)
- func (resourceConfig ResourceConfig) FindOrCreateForResource(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, resourceID int) (*UsedResourceConfig, error)
- func (resourceConfig ResourceConfig) FindOrCreateForResourceType(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, ...) (*UsedResourceConfig, error)
- type ResourceConfigFactory
- type ResourceType
- type ResourceTypeFactory
- type Team
- type TeamFactory
- type Tx
- type UsedBaseResourceType
- type UsedResourceCache
- type UsedResourceConfig
- type UsedResourceType
- type UsedWorkerResourceType
- type VolumeFactory
- type VolumeResourceType
- type VolumeState
- type VolumeType
- type Worker
- type WorkerBaseResourceType
- type WorkerFactory
- type WorkerResourceType
- type WorkerState
Constants ¶
const ( ContainerStateCreating = "creating" ContainerStateCreated = "created" ContainerStateDestroying = "destroying" )
const ( ContainerStageCheck = "check" ContainerStageGet = "get" ContainerStageRun = "run" )
const ( VolumeStateCreating = "creating" VolumeStateCreated = "created" VolumeStateDestroying = "destroying" )
const ( VolumeTypeContainer = "container" VolumeTypeResource = "resource" VolumeTypeResourceType = "resource-type" VolumeTypeUknown = "unknown" // for migration to life )
const ( WorkerStateRunning = WorkerState("running") WorkerStateStalled = WorkerState("stalled") WorkerStateLanding = WorkerState("landing") WorkerStateLanded = WorkerState("landed") WorkerStateRetiring = WorkerState("retiring") )
Variables ¶
var ( ErrVolumeMarkDestroyingFailed = errors.New("could-not-mark-volume-as-destroying") ErrVolumeStateTransitionFailed = errors.New("could-not-transition-volume-state") ErrVolumeMissing = errors.New("volume-no-longer-in-db") ErrInvalidResourceCache = errors.New("invalid-resource-cache") )
var ( ErrWorkerNotPresent = errors.New("worker-not-present-in-db") ErrCannotPruneRunningWorker = errors.New("worker-not-stalled-for-pruning") )
var EmptyParamsHash = mapHash(atc.Params{})
var ErrBaseResourceTypeAlreadyExists = errors.New("base-resource-type-already-exists")
var ErrBaseResourceTypeNotFound = errors.New("base resource type not found")
var ErrBuildDisappeared = errors.New("build-disappeared-from-db")
var ErrConfigComparisonFailed = errors.New("comparison-with-existing-config-failed-during-save")
var ErrContainerDisappeared = errors.New("container-disappeared-from-db")
var ErrResourceCacheAlreadyExists = errors.New("resource-cache-already-exists")
var ErrResourceCacheDisappeared = errors.New("resource-cache-disappeared")
var ErrResourceConfigAlreadyExists = errors.New("resource config already exists")
var ErrResourceConfigDisappeared = errors.New("resource config disappeared")
var ErrResourceConfigParentDisappeared = errors.New("resource config parent disappeared")
var ErrSafeRetryCreateOrUpdate = errors.New("failed-to-run-safe-create-or-update-retrying")
var ErrSafeRetryFindOrCreate = errors.New("failed-to-run-safe-find-or-create-retrying")
var ErrTeamDisappeared = errors.New("team-disappeared")
var ErrWorkerBaseResourceTypeAlreadyExists = errors.New("worker base resource type already exists")
var ErrWorkerResourceTypeNotFound = errors.New("worker resource type no longer exists (stale?)")
Functions ¶
This section is empty.
Types ¶
type BaseResourceType ¶
type BaseResourceType struct {
Name string // The name of the type, e.g. 'git'.
}
BaseResourceType represents a resource type provided by workers.
It is created via worker registration. All creates are upserts.
It is removed by gc.BaseResourceTypeCollector, once there are no references to it from worker_base_resource_types.
func (BaseResourceType) Find ¶
func (brt BaseResourceType) Find(tx Tx) (*UsedBaseResourceType, bool, error)
func (BaseResourceType) FindOrCreate ¶
func (brt BaseResourceType) FindOrCreate(tx Tx) (*UsedBaseResourceType, error)
FindOrCreate looks for an existing BaseResourceType and creates it if it doesn't exist. It returns a UsedBaseResourceType.
Note that if the BaseResourceType already existed, there's a chance that it will be garbage-collected before the referencing ResourceConfig can be created and used.
This method can return ErrBaseResourceTypeAlreadyExists if two concurrent FindOrCreates clashed. The caller should retry from the start of the transaction.
type BaseResourceTypeFactory ¶
type BaseResourceTypeFactory interface {
Find(name string) (*UsedBaseResourceType, bool, error)
}
func NewBaseResourceTypeFactory ¶
func NewBaseResourceTypeFactory(conn Conn) BaseResourceTypeFactory
type BuildStatus ¶
type BuildStatus string
const ( BuildStatusPending BuildStatus = "pending" BuildStatusStarted BuildStatus = "started" BuildStatusAborted BuildStatus = "aborted" BuildStatusSucceeded BuildStatus = "succeeded" BuildStatusFailed BuildStatus = "failed" BuildStatusErrored BuildStatus = "errored" )
type ConfigVersion ¶
type ConfigVersion int
ConfigVersion is a sequence identifier used for compare-and-swap
type Conn ¶
type Conn interface { Begin() (Tx, error) Close() error Driver() driver.Driver Exec(query string, args ...interface{}) (sql.Result, error) Ping() error Prepare(query string) (*sql.Stmt, error) Query(query string, args ...interface{}) (*sql.Rows, error) QueryRow(query string, args ...interface{}) *sql.Row SetMaxIdleConns(n int) SetMaxOpenConns(n int) Stats() sql.DBStats }
type ContainerFactory ¶
type ContainerFactory interface { FindContainersMarkedForDeletion() ([]DestroyingContainer, error) MarkContainersForDeletion() error FindHijackedContainersForDeletion() ([]CreatedContainer, error) }
func NewContainerFactory ¶
func NewContainerFactory(conn Conn) ContainerFactory
type ContainerMetadata ¶
type ContainerStage ¶
type ContainerStage string
type ContainerState ¶
type ContainerState string
type CreatedContainer ¶
type CreatedContainer interface { ID() int Handle() string Discontinue() (DestroyingContainer, error) Destroying() (DestroyingContainer, error) WorkerName() string MarkAsHijacked() error }
type CreatedVolume ¶
type CreatedVolume interface { Handle() string Path() string Type() VolumeType CreateChildForContainer(CreatingContainer, string) (CreatingVolume, error) Destroying() (DestroyingVolume, error) Worker() *Worker SizeInBytes() int64 Initialize() error IsInitialized() (bool, error) ContainerHandle() string ParentHandle() string ResourceType() (*VolumeResourceType, error) BaseResourceType() (*WorkerBaseResourceType, error) }
type CreatingContainer ¶
type CreatingContainer interface { ID() int Handle() string Created() (CreatedContainer, error) }
type CreatingVolume ¶
type CreatingVolume interface { Handle() string ID() int Created() (CreatedVolume, error) }
type DestroyingContainer ¶
type DestroyingVolume ¶
type ErrResourceTypeNotFound ¶
type ErrResourceTypeNotFound struct {
// contains filtered or unexported fields
}
func (ErrResourceTypeNotFound) Error ¶
func (e ErrResourceTypeNotFound) Error() string
type ErrVolumeMarkCreatedFailed ¶
type ErrVolumeMarkCreatedFailed struct {
Handle string
}
func (ErrVolumeMarkCreatedFailed) Error ¶
func (e ErrVolumeMarkCreatedFailed) Error() string
type Pipeline ¶
type Pipeline interface { ID() int SaveJob(job atc.JobConfig) error CreateJobBuild(jobName string) (Build, error) CreateResource(name string, config atc.ResourceConfig) (*Resource, error) AcquireResourceCheckingLock( logger lager.Logger, resource *Resource, resourceTypes atc.ResourceTypes, length time.Duration, immediate bool, ) (lock.Lock, bool, error) Destroy() error }
type PipelineFactory ¶
func NewPipelineFactory ¶
func NewPipelineFactory(conn Conn, lockFactory lock.LockFactory) PipelineFactory
type PipelinePausedState ¶
type PipelinePausedState string
const ( PipelinePaused PipelinePausedState = "paused" PipelineUnpaused PipelinePausedState = "unpaused" PipelineNoChange PipelinePausedState = "nochange" )
func (PipelinePausedState) Bool ¶
func (state PipelinePausedState) Bool() *bool
type ResourceCache ¶
type ResourceCache struct { ResourceConfig ResourceConfig // The resource configuration. Version atc.Version // The version of the resource. Params atc.Params // The params used when fetching the version. }
ResourceCache represents an instance of a ResourceConfig's version.
A ResourceCache is created by a `get`, an `image_resource`, or a resource type in a pipeline.
ResourceCaches are garbage-collected by gc.ResourceCacheCollector.
func (ResourceCache) FindOrCreateForBuild ¶
func (cache ResourceCache) FindOrCreateForBuild(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, buildID int) (*UsedResourceCache, error)
func (ResourceCache) FindOrCreateForResource ¶
func (cache ResourceCache) FindOrCreateForResource(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, resourceID int) (*UsedResourceCache, error)
func (ResourceCache) FindOrCreateForResourceType ¶
func (cache ResourceCache) FindOrCreateForResourceType(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, resourceType *UsedResourceType) (*UsedResourceCache, error)
type ResourceCacheFactory ¶
type ResourceCacheFactory interface { FindOrCreateResourceCacheForBuild( logger lager.Logger, buildID int, resourceTypeName string, version atc.Version, source atc.Source, params atc.Params, pipelineID int, resourceTypes atc.ResourceTypes, ) (*UsedResourceCache, error) FindOrCreateResourceCacheForResource( logger lager.Logger, resourceID int, resourceTypeName string, version atc.Version, source atc.Source, params atc.Params, pipelineID int, resourceTypes atc.ResourceTypes, ) (*UsedResourceCache, error) FindOrCreateResourceCacheForResourceType( logger lager.Logger, resourceTypeName string, version atc.Version, source atc.Source, params atc.Params, pipelineID int, resourceTypes atc.ResourceTypes, ) (*UsedResourceCache, error) CleanUsesForFinishedBuilds() error CleanUsesForInactiveResourceTypes() error CleanUsesForInactiveResources() error CleanUpInvalidCaches() error }
func NewResourceCacheFactory ¶
func NewResourceCacheFactory(conn Conn, lockFactory lock.LockFactory) ResourceCacheFactory
type ResourceConfig ¶
type ResourceConfig struct { // A resource type provided by a resource. CreatedByResourceCache *ResourceCache // A resource type provided by a worker. CreatedByBaseResourceType *BaseResourceType // The resource's source configuration. Source atc.Source }
ResourceConfig represents a resource type and config source.
Resources in a pipeline, resource types in a pipeline, and `image_resource` fields in a task all result in a reference to a ResourceConfig.
ResourceConfigs are garbage-collected by gc.ResourceConfigCollector.
func (ResourceConfig) FindOrCreateForBuild ¶
func (resourceConfig ResourceConfig) FindOrCreateForBuild(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, buildID int) (*UsedResourceConfig, error)
FindOrCreateForBuild creates the ResourceConfig, recursively creating its parent ResourceConfig or BaseResourceType, and registers a "Use" for the given build.
An `image_resource` or a `get` within a build will result in a UsedResourceConfig.
ErrResourceConfigDisappeared may be returned if the resource config was found initially but was removed before we could use it.
ErrResourceConfigAlreadyExists may be returned if a concurrent call resulted in a conflict.
ErrResourceConfigParentDisappeared may be returned if the resource config's parent ResourceConfig or BaseResourceType was found initially but was removed before we could create the ResourceConfig.
Each of these errors should result in the caller retrying from the start of the transaction.
func (ResourceConfig) FindOrCreateForResource ¶
func (resourceConfig ResourceConfig) FindOrCreateForResource(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, resourceID int) (*UsedResourceConfig, error)
FindOrCreateForResource creates the ResourceConfig, recursively creating its parent ResourceConfig or BaseResourceType, and registers a "Use" for the given resource.
A periodic check for a pipeline's resource will result in a UsedResourceConfig.
ErrResourceConfigDisappeared may be returned if the resource config was found initially but was removed before we could use it.
ErrResourceConfigAlreadyExists may be returned if a concurrent call resulted in a conflict.
ErrResourceConfigParentDisappeared may be returned if the resource config's parent ResourceConfig or BaseResourceType was found initially but was removed before we could create the ResourceConfig.
Each of these errors should result in the caller retrying from the start of the transaction.
func (ResourceConfig) FindOrCreateForResourceType ¶
func (resourceConfig ResourceConfig) FindOrCreateForResourceType(logger lager.Logger, tx Tx, lockFactory lock.LockFactory, resourceType *UsedResourceType) (*UsedResourceConfig, error)
FindOrCreateForResourceType creates the ResourceConfig, recursively creating its parent ResourceConfig or BaseResourceType, and registers a "Use" for the given resource type.
A periodic check for a pipeline's resource type will result in a UsedResourceConfig.
ErrResourceConfigDisappeared may be returned if the resource config was found initially but was removed before we could use it.
ErrResourceConfigAlreadyExists may be returned if a concurrent call resulted in a conflict.
ErrResourceConfigParentDisappeared may be returned if the resource config's parent ResourceConfig or BaseResourceType was found initially but was removed before we could create the ResourceConfig.
Each of these errors should result in the caller retrying from the start of the transaction.
type ResourceConfigFactory ¶
type ResourceConfigFactory interface { FindOrCreateResourceConfigForBuild( logger lager.Logger, buildID int, resourceType string, source atc.Source, pipelineID int, resourceTypes atc.ResourceTypes, ) (*UsedResourceConfig, error) FindOrCreateResourceConfigForResource( logger lager.Logger, resourceID int, resourceType string, source atc.Source, pipelineID int, resourceTypes atc.ResourceTypes, ) (*UsedResourceConfig, error) FindOrCreateResourceConfigForResourceType( logger lager.Logger, resourceTypeName string, source atc.Source, pipelineID int, resourceTypes atc.ResourceTypes, ) (*UsedResourceConfig, error) CleanConfigUsesForFinishedBuilds() error CleanConfigUsesForInactiveResourceTypes() error CleanConfigUsesForInactiveResources() error CleanUselessConfigs() error }
func NewResourceConfigFactory ¶
func NewResourceConfigFactory(conn Conn, lockFactory lock.LockFactory) ResourceConfigFactory
type ResourceType ¶
type ResourceType struct { atc.ResourceType PipelineID int }
func (ResourceType) Create ¶
func (resourceType ResourceType) Create(tx Tx, version atc.Version) (*UsedResourceType, error)
func (ResourceType) Find ¶
func (resourceType ResourceType) Find(tx Tx) (*UsedResourceType, bool, error)
type ResourceTypeFactory ¶
type ResourceTypeFactory interface { FindResourceType(pipelineID int, resourceType atc.ResourceType) (*UsedResourceType, bool, error) CreateResourceType(pipelineID int, resourceType atc.ResourceType, version atc.Version) (*UsedResourceType, error) }
func NewResourceTypeFactory ¶
func NewResourceTypeFactory(conn Conn) ResourceTypeFactory
type Team ¶
type Team interface { ID() int SavePipeline( pipelineName string, config atc.Config, from ConfigVersion, pausedState PipelinePausedState, ) (Pipeline, bool, error) FindPipelineByName(pipelineName string) (Pipeline, bool, error) CreateOneOffBuild() (Build, error) SaveWorker(worker atc.Worker, ttl time.Duration) (*Worker, error) FindContainerByHandle(string) (CreatedContainer, bool, error) FindResourceCheckContainer(*Worker, *UsedResourceConfig) (CreatingContainer, CreatedContainer, error) CreateResourceCheckContainer(*Worker, *UsedResourceConfig) (CreatingContainer, error) FindResourceGetContainer(*Worker, *UsedResourceCache, string) (CreatingContainer, CreatedContainer, error) CreateResourceGetContainer(*Worker, *UsedResourceCache, string) (CreatingContainer, error) FindBuildContainer(*Worker, int, atc.PlanID, ContainerMetadata) (CreatingContainer, CreatedContainer, error) CreateBuildContainer(*Worker, int, atc.PlanID, ContainerMetadata) (CreatingContainer, error) }
type TeamFactory ¶
type TeamFactory interface { CreateTeam(name string) (Team, error) FindTeam(name string) (Team, bool, error) GetByID(teamID int) Team }
func NewTeamFactory ¶
func NewTeamFactory(conn Conn, lockFactory lock.LockFactory) TeamFactory
type UsedBaseResourceType ¶
type UsedBaseResourceType struct {
ID int // The ID of the BaseResourceType.
}
UsedBaseResourceType is created whenever a ResourceConfig is used, either for a build, a resource in the pipeline, or a resource type in the pipeline.
So long as the UsedBaseResourceType's ID is referenced by a ResourceConfig that is in use, this guarantees that the BaseResourceType will not be removed. That is to say that its "Use" is vicarious.
type UsedResourceCache ¶
type UsedResourceCache struct { ID int ResourceConfig *UsedResourceConfig Version atc.Version }
UsedResourceCache is created whenever a ResourceCache is Created and/or Used.
So long as the UsedResourceCache exists, the underlying ResourceCache can not be removed.
UsedResourceCaches become unused by the gc.ResourceCacheCollector, which may then lead to the ResourceCache being garbage-collected.
See FindOrCreateForBuild, FindOrCreateForResource, and FindOrCreateForResourceType for more information on when it becomes unused.
type UsedResourceConfig ¶
type UsedResourceConfig struct { ID int CreatedByResourceCache *UsedResourceCache CreatedByBaseResourceType *UsedBaseResourceType }
UsedResourceConfig is created whenever a ResourceConfig is Created and/or Used.
So long as the UsedResourceConfig exists, the underlying ResourceConfig can not be removed.
UsedResourceConfigs become unused by the gc.ResourceConfigCollector, which may then lead to the ResourceConfig being garbage-collected.
See FindOrCreateForBuild, FindOrCreateForResource, and FindOrCreateForResourceType for more information on when it becomes unused.
type UsedResourceType ¶
type UsedWorkerResourceType ¶
type UsedWorkerResourceType struct { ID int Worker *Worker UsedBaseResourceType *UsedBaseResourceType }
type VolumeFactory ¶
type VolumeFactory interface { GetTeamVolumes(teamID int) ([]CreatedVolume, error) CreateContainerVolume(int, *Worker, CreatingContainer, string) (CreatingVolume, error) FindContainerVolume(int, *Worker, CreatingContainer, string) (CreatingVolume, CreatedVolume, error) FindBaseResourceTypeVolume(int, *Worker, *UsedBaseResourceType) (CreatingVolume, CreatedVolume, error) CreateBaseResourceTypeVolume(int, *Worker, *UsedBaseResourceType) (CreatingVolume, error) FindResourceCacheVolume(*Worker, *UsedResourceCache) (CreatingVolume, CreatedVolume, error) FindResourceCacheInitializedVolume(*Worker, *UsedResourceCache) (CreatedVolume, bool, error) CreateResourceCacheVolume(*Worker, *UsedResourceCache) (CreatingVolume, error) FindVolumesForContainer(CreatedContainer) ([]CreatedVolume, error) GetOrphanedVolumes() ([]CreatedVolume, []DestroyingVolume, error) FindCreatedVolume(handle string) (CreatedVolume, bool, error) }
func NewVolumeFactory ¶
func NewVolumeFactory(conn Conn) VolumeFactory
type VolumeResourceType ¶
type VolumeResourceType struct { BaseResourceType *WorkerBaseResourceType ResourceType *VolumeResourceType Version atc.Version }
type VolumeState ¶
type VolumeState string
type VolumeType ¶
type VolumeType string
type Worker ¶
type Worker struct { Name string GardenAddr *string State WorkerState BaggageclaimURL *string HTTPProxyURL string HTTPSProxyURL string NoProxy string ActiveContainers int ResourceTypes []atc.WorkerResourceType Platform string Tags []string TeamID int StartTime int64 TeamName string ExpiresIn time.Duration }
type WorkerBaseResourceType ¶
type WorkerFactory ¶
type WorkerFactory interface { GetWorker(name string) (*Worker, bool, error) Workers() ([]*Worker, error) WorkersForTeam(teamName string) ([]*Worker, error) StallWorker(name string) (*Worker, error) StallUnresponsiveWorkers() ([]*Worker, error) DeleteFinishedRetiringWorkers() error LandFinishedLandingWorkers() error SaveWorker(worker atc.Worker, ttl time.Duration) (*Worker, error) LandWorker(name string) (*Worker, error) RetireWorker(name string) (*Worker, error) PruneWorker(name string) error DeleteWorker(name string) error HeartbeatWorker(worker atc.Worker, ttl time.Duration) (*Worker, error) }
func NewWorkerFactory ¶
func NewWorkerFactory(conn Conn) WorkerFactory
type WorkerResourceType ¶
type WorkerResourceType struct { Worker *Worker Image string // The path to the image, e.g. '/opt/concourse/resources/git'. Version string // The version of the image, e.g. a SHA of the rootfs. BaseResourceType *BaseResourceType }
func (WorkerResourceType) FindOrCreate ¶
func (wrt WorkerResourceType) FindOrCreate(tx Tx) (*UsedWorkerResourceType, error)
type WorkerState ¶
type WorkerState string
Source Files ¶
- base_resource_type.go
- base_resource_type_factory.go
- build.go
- container.go
- container_factory.go
- pipeline.go
- pipeline_factory.go
- pipeline_locks.go
- psql.go
- resource.go
- resource_cache.go
- resource_cache_factory.go
- resource_config.go
- resource_config_factory.go
- resource_type.go
- resource_type_factory.go
- safe_find_or_create.go
- scannable.go
- team.go
- team_factory.go
- volume.go
- volume_factory.go
- worker.go
- worker_base_resource_type.go
- worker_factory.go
- worker_resource_type.go
- wrap.go
Directories ¶
Path | Synopsis |
---|---|
This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter
|
This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter This file was generated by counterfeiter |