Sites

Menu

Concepts glossary

Project

A SpatialOS project is the source code of a game that runs on SpatialOS. We often use this to refer to the directory that contains the source code, too.

A project includes (but isn’t limited to):

Related pages:

Cloud project name

Your cloud project name is a name which is used to label your project. It’s generated for you when you sign up for SpatialOS. It’s usually something like beta_someword_anotherword_000.

Note that your cloud project name is (usually) not the same as the name of the directory your project is in.

You must specify this name when you run a cloud deployment. You can either:

You can find out what your cloud project name is in the Console.

Related pages:

Assembly

An assembly is what’s created when you build. It contains all the files that your game uses.

This includes executable files for the client-worker types and server-worker types, and the assets your worker instances use (like models and textures used by a client to visualize the game).

When you run a cloud deployment, you have to specify an assembly to use.

Related pages:

Structured project layout (SPL)

Directory layout of a SpatialOS project.

Related pages:

Flexible project layout (FPL)

New directory layout of a SpatialOS project designed to replace the structured project layout. Currently in beta.

Related pages:

The SpatialOS CLI

The SpatialOS CLI provides a set of commands that you use to interact with a SpatialOS project. Among other things, you use it to:

Related pages:

Building

When you make changes to the code of a worker type, you need to build those changes before you can try them out in a local or cloud deployment.

You can:

We recommend only building the bits of your project that you’ve changed, to save time. For example, if you’ve only changed the source code of one worker type, you should only build that worker type’s code.

You can build all worker types in your project using the command spatial worker build.

Related pages:

Deploying

SpatialOS hosts the server element of your mulitplayer game. You set up the server hosting via SpatialOS deployments. This means launching your game with its own instance of SpatialOS. This SpatialOS instance sets up the world based on a snapshot, then starts up the worker instances needed to run the game world.

Once the deployment is running, you can connect client-worker instances to it. You can then use these to play the game.

You can run a deployment:

Cloud vs local hosting

In production, you always use cloud hosting, but during development you can test your game with both cloud hosting and local hosting (where your development machine emulates cloud hosting).

Related pages:

Local deployment

A local deployment is a deployment of your game/project on your local development machine.

Before you run a local deployment, you need to:

You can launch a local deployment using the command spatial local launch.

Launching a local deployment runs SpatialOS locally. SpatialOS will start (and stop) the server-worker instances needed by the game world.

Once the deployment is running, you can connect client-worker instances to it in order to play the game (only on your local machine) using the command spatial local worker launch

Related pages:

Cloud deployment

A cloud deployment is a deployment of your game/project in the cloud.

Before you can run a cloud deployment, you need to:

You can launch a cloud deployment using command spatial cloud launch.

When you run the launch command, you specify:

Launching a deployment runs SpatialOS in the cloud. SpatialOS will start (and stop) the server-worker instances needed by the game world.

Once the deployment is running, you can connect client-worker instances to it, using the command spatial cloud connect external <deployment name>

Related pages:

Deployment name

A deployment name is a label to identify a cloud deployment in the Console. You enter this name when you run a cloud deployment.

Deployment run

A deployment run is an instance (running or stopped) of a deployment. Each deployment run of a cloud deployment is assigned an int64 number as a unique identifier, which is called the Run ID. (Local deployment runs don’t have Run IDs.)

Related pages:

Launch configuration file

A launch configuration file contains settings that the SpatialOS CLI uses when it launches a deployment. This includes things like how big the world is, which worker types to use in the deployment, and what permissions to give them.

Easily confused with the launch configuration section in the worker configuration file (worker.json).

Related pages:

Inspector

The Inspector is a web-based tool that you use to explore the internal state of a SpatialOS world. It gives you realtime view of what’s happening in a deployment, locally or in the cloud. Among other things, it displays:

Related pages:

Launcher

You use the Launcher to connect client-worker instances to a cloud deployment. You can run the Launcher from the Console, or (from the Console) generate share links so anyone with the link can join.

The Launcher gets the executable for the client-worker type from the assembly you uploaded.

Related pages:

Locator

The Locator is the SpatialOS service responsible for connecting a client-worker instance to a deployment.

From SpatialOS 13.5 onwards, client-worker instances can connect to both cloud and local deployments using the Locator. Previously, it was only possible to connect to cloud deployments.

Console

The Console (console.improbable.io) is the main landing page for managing cloud deployments. It shows you:

  • your cloud project name
  • running and previous cloud deployments using that cloud project name
  • all the assemblies you’ve uploaded using that cloud project name
  • a page for each deployment, which shows its status, and gives you access to the Inspector, Logs, and Metrics pages for that deployment.

Related pages:

Worker types and worker instances

Worker instances are the programs that connect a SpatialOS world. Server-worker instances are server-side programs that do most of the computation for the world. A client-worker instance is the client-side program in a game player’s game client, through which the game player interacts with the world. There are as many concurrent client-worker instances are there are concurrent game players.

A worker type is a template for a worker instance. Each worker type has a worker configuration file (<worker_type>.worker.json) where you define how SpatialOS should build, launch, and interact with instances of this worker type.

For example, you could create a server-worker type called PhysicsWorker, and your deployment could have many worker instances of this worker type simulating the physics of the game world.

When a worker type has write access permission on an entity component (via the entity’s EntityAcl), worker instances of that type could potentially have write access authority over the component and make changes to its value. However, only one worker instance can have write access authority over an entity component at any one time. Which worker instance this is depends on your load balancing strategy and on the position of the entity in the world.

Worker instances also have interest, which means they want to receive updates about specific entity components from the entity database.

You can set up worker types using:

Related pages:

Server-worker

Also known as “managed worker”, “server-side worker”.

A server-worker instance has its lifecycle managed by SpatialOS. That means in a running deployment, SpatialOS is in charge of starting it up and stopping it, as part of load balancing - unlike a client-worker instance.

Server-worker instances are usually tasked with implementing game logic and physics simulation.

You might have just one server-worker instance connecting to a SpatialOS world, or dozens, depending on the size of the world.

You tell SpatialOS how to launch a worker instance as a server-worker instance in its worker configuration file (worker.json).

Related pages:

Unmanaged worker

If you want to test what would usually be a server-worker instance by stopping and starting it manually in your game development environment, you can make that worker instance unmanaged in a local deployment or cloud deployment of your game.

Note that these worker instances are not client-worker instances (external worker instances), even though client-worker instances are also not managed by SpatialOS. Unmanaged server-worker instances access the deployment in a different way to client-worker instances.

Server-side worker

See server-worker.

Managed worker

See server-worker.

Unity Worker

Also known as “UnityWorker” A term sometimes used for a server-worker instance in the GDK for Unity.

Unreal Worker

Also known as “UnrealWorker” A term sometimes used for a server-worker instance in the GDK for Unreal.

Client-worker

Also known as “external worker”, “client-side worker”, or “client”.

A client-worker instance is part of a player’s game client; that is, their game executable program. The game client starts and stops a client-worker instance when the player starts and stops the game client. The game client interacts with the game world via the client-worker instance it starts up.

You tell SpatialOS how to launch a worker instance as a client-worker instance in its worker configuration file (worker.json).

Unlike a server-worker instance, a client-worker instance’s lifecycle is not managed by SpatialOS. In a running deployment, there will be one client-worker instance per player, and the players start and stop their client-worker instance.

Client-worker instances are mostly tasked with visualising what’s happening in the world. You’d also use them for dealing with player input. In general, you want to give client-worker instances write access authority to as few components as possible, to make cheating difficult.

Related pages:

Client

See client-worker.

Client-side worker

See client-worker.

External worker

See client-worker.

Unity Client

Also known as “UnityClient” A term sometimes used for a client-worker type in the GDK for Unity.

Unreal Client

Also known as “UnrealClient” A term sometimes used for a client-worker type in the GDK for Unreal.

Worker attribute sets

In its bridge configuration, each worker type specifies an attribute that says what layer it belongs to, for example “physics”. This attribute is used in access control lists, which specify which attribute a worker type must have in order for instances of that worker type to get active read access or write access authority to a component.

Related pages:

Worker ID

Each worker instance has a worker ID, used to uniquely identify it. Worker instances automatically have an attribute which includes their ID: "workerId:<worker ID>".

Related pages:

Sending an update

If a worker instance has write access authority over a component, it can send an update about it to the entity database in the SpatialOS Runtime. An update can change the value of a property, or trigger an event. You can change multiple properties and trigger multiple events in one update.

Related pages:

Bridge

A bridge is a part of the SpatialOS Runtime. Instances of server-workers and client-workers connect to it so that they can send and receive updates about the game world.

Sometimes you might see the bridge referred to as the ‘connection manager’.

Related pages:

Worker configuration (worker.json)

Each worker type must have a worker configuration file, with the name spatialos.<worker_type>.worker.json: for example, spatialos.MyCSharpWorker.worker.json. This file:

  • sets the process used to build the worker type
  • configures settings to do with how instances of this worker type communicate with SpatialOS, including information like what components the worker instances have interest in
  • sets whether a worker type is a server-worker or a client-worker
  • for server-workers, tells SpatialOS how to run the worker instances in the cloud
  • for client-workers, specifies how to launch the worker instances on the game player’s local computer

Related pages:

Worker scheduler

The worker scheduler is responsible for starting up worker instances according to your load balancing strategy.

For example, if you have a server-worker type called PhysicsWorker for which you’re using the rectangle_grid strategy with two rows and two columns, the worker scheduler starts up four PhysicsWorker instances.

The worker scheduler is also responsible for restoring worker instances if they break, to make sure you always have the right number of worker instances running for each worker type.

Load balancer

The load balancer is part of the SpatialOS Runtime. It is responsible for making sure each server-worker instance has write access authority over the correct components on entities.

For example, if you have a server-worker type called PhysicsWorker for which you’re using the rectangle_grid strategy with two rows and two columns, the load balancer splits the world into four areas and makes sure the correct worker instances get the correct write access authority over each entity component.

Related pages:

Authority and interest

The core idea of SpatialOS is that worker instances have access only to a part of the game world. This access is governed both by what the worker instance has authority over and what it has interest in.

Related pages:

Concepts: Authority and interest

Authority

As there can be more than one worker instance in a SpatialOS world, only the worker instance with write access authority can make changes to an entity component’s value at any one time.

Write access authority depends on write access permission and area of authority.

Write access permission

A worker instance can send updates to the entity database about a component on an entity only if it has permission to do so. We call this “write access permission”, and you set it up in the entity’s access control list.

Having write access permission is necessary but not sufficient for a worker instance to send updates about a SpatialOS component. For more information, see Write access authority.

Write access authority

A worker instance has write access authority over a component on an entity when it is sending updates about that component to the entity database, so that other worker instances can receive updates about the changes to the component.

Related pages:

Write access authority

Area of authority

The area of authority for a worker instance defines the set of entity components that the worker instance can have write access authority over. The Runtime allocates this area for each worker instance based on the load balancing strategy you set up.

Related pages:

Area of authority

Interest

When a worker instance wants to receive updates about entity components from the entity database, we say it has interest. Whether a worker instance does receive these updates depends on certain criteria, but when it does, the worker instance has active read access to the component.

There are two types of interest:

  • query-based interest (QBI)
  • chunk-based interest (CBI)

Related pages:

Read access permission

A worker instance can only receive updates about a particular component on an entity if it has permission to do so. We call this “read access permission”, and you set it up in the entity’s access control list.

Related pages:

EntityAcl

Active read access

A worker instance has active read access to a component on an entity when it is receiving updates about that component from the entity database.

Related pages:

Active read access

Query-based interest (QBI)

This is a precise, granular way to define interest.

You set it up using a component, improbable.Interest, on each entity. This component contains a list of component IDs that map to queries. When a worker instance gains write access authority over one of the components in the list of IDs, it additionally gains interest in any components that match the queries associated with that component.

Related pages:

Query-based interest (QBI)

Chunk-based interest (CBI)

This is a simple way to define interest that is less precise than QBI. All SpatialOS example and starter projects use CBI.

With CBI, a worker instance has default areas of interest based on the components it has write access authority over. You can extend these areas of interest by defining a radius distance around the components it has write access authority over.

Related pages:

Chunk-based interest (CBI)

Streaming queries

Streaming queries are a way to extend chunk-based interest (CBI) so that worker instances can have active read access to distant entity components (for example, entities that are far away, or that don’t have a physical position). If you’re using query-based interest (QBI), you don’t need to use streaming queries.

Streaming queries are useful if you need to get information about an entity periodically - for example, so that a player can see and interact with it.

If you just need information about an entity at one particular time, use queries instead.

Related pages:

Streaming queries

Worker flag

Worker flags let you change values that worker instances use, either at the start of a deployment or dynamically while it’s running. For example, you could vary the walking speed of your entities and see how this affects the world.

Worker flags (and their values) are defined in the launch configuration file.

A worker instance can query the value of a flag at any time. You can set the value of flags for a running deployment from the Console, or using the command-line.

Related pages:

Node

Node refers to a single machine used by a cloud deployment. Its name indicates the role it plays in your deployment. You can see these on the advanced tab of your deployment details in the Console.

SpatialOS world

Also known as “the world” and “the game world”.

The world is a central concept in SpatialOS. It’s the canonical source of truth about your game. All the world’s data is stored within entities - specifically, within their components.

SpatialOS manages the world, keeping track of all the entities and what state they’re in.

Changes to the world are made by worker instances. Each worker instance has a view onto the world (the part of the world that they have interest in), and SpatialOS sends them updates when anything changes in that view.

It’s important to recognise this fundamental separation between the SpatialOS world and the view/representation of that world that a worker instance has locally. This is why worker instances must send updates to SpatialOS when they want to change the world: they don’t control the canonical state of the world, they must use SpatialOS APIs to change it.

Layers

Layers are a concept that organises both the components in your game world, and the worker instances that compute the world.

You can look at layers in two ways:

  • A layer is a group of components on entities in the game world.
  • A layer comprises the worker instances that have write access authority over one of those groups.

For details, see Layers.

Chunk

A world is split up into chunks: the grid squares of the world. A chunk is the smallest area of space the world can be subdivided into. Every entity is in exactly one chunk.

You set the size of chunks for your world in launch configuration files.

Related pages:

World unit

World units are an arbitrary unit that worker instances can interpret as they choose.

Settings in world units:

Related pages:

Queries

Queries allow worker instances to get information about the world outside the area they have interest in.

Entity queries are useful if you need to get information about an entity at a particular time.

If you need regular updates about an entity, use streaming queries instead.

Queries can search for entities with the following attributes:

and any combination of the above, using AND/OR.

Based on the set of entities that match it, a query can return:

  • snapshots of those entities, including all components
  • snapshots of those entities, including only the components you specify
  • the number of entities

You should keep queries as limited as possible. All queries hit the network and cause a runtime lookup, which is expensive even in the best cases. This means you should:

  • always limit queries to a specific sphere of the world
  • only return the information you need from queries: specify which components you need to know about
  • if you’re looking for entities that are within your worker instance’s area of interest, search internally on the worker instance instead of using a query

Related pages:

Entity

All of the objects inside a SpatialOS world are entities: they’re the basic building block of the world. Examples include players, NPCs, and objects in the world like trees.

Entities are made up of components, which store the data associated with that entity.

Worker instances can only see the entities they have interest in. Worker instances can represent these entities locally any way you like.

For example, for worker instances built using Unity, you might want to have a prefab associated with each entity type, and spawn a GameObject for each entity the worker instance has active read access to.

You can have other objects that are not entities locally on worker instances - like UI for a player - but no other worker instance will be able to see them, because they’re not part of the SpatialOS world.

Related pages:

Component

An entity is defined by a set of components. Common components in a game might be things like Health, Position, or PlayerControls. They’re the storage mechanism for data about the world that you want to be shared between worker instances.

Components can contain:

  • properties, which describe persistent values that change over time (for example, Position)
  • events, which are things that can happen to an entity (for example, StartedWalking)
  • commands that another worker instance can call to ask the component to do something, optionally returning a value (for example, Teleport)

An entity can have as many components as you like, but it must have at least Position and EntityAcl. Most entities will have the Persistence and Metadata components.

Components are defined as files in your schema.

Which types of worker can read from or write to which components is governed by access control lists.

Related pages:

Property

Properties are one of the things that can be contained in a component. Properties describe persistent values that change over time.

Property updates can be sent by the worker instance with write access authority to the component. They’re delivered to other worker instances that have interest in this component of the entity.

For entities containing components that they have interest in, worker instances can:

  • Read the current value of a property
  • Watch for changes to the value of a property
  • Send an update to the value of a property (if they have write access authority)

Related pages:

Event

Events are one of the things that can be contained in a component. Unlike a property, an event is not persistent (the data in it isn’t saved).

Events let an entity broadcast a transient message about something that has happened to it. In all other respects, events work the same way as updates to persistent properties.

Events can be triggered by the worker instance with write access authority over the component. They’re delivered to other worker instances that have interest in this component of the entity.

For entities that contain components they have interest in, worker instances can:

  • Watch for an event
  • Send an update that triggers an event (if they have write access authority)

Related pages:

Command

Commands are one of the things that can be contained in a component. They’re essentially a remote procedure call (RPC). Commands facilitate communication in the other direction to events and properties: they allow any worker instance to send a request to the worker instance with write access authority to a specific component. The receiving worker instance can take action and should respond to the request.

Because which worker instance has write access authority over a component can change regularly, and commands must be sent to the worker instance with write access authority, commands can fail if this worker instance changes between the time of sending and the time of receiving. By default, commands are routed through SpatialOS. You can short-circuit commands that you think will be received by the same worker instance that sent them, but it might lead to a worker executing a command despite having just lost authority over the command’s component. See the documentation on commands for more details.

This means that, for communication within a small area, it’s better to model it using properties or events. Commands are best suited when you don’t know where the target entity is, or know that it’s likely to be far away.

Worker instances can:

Related pages:

Short-circuiting

Commands are routed through SpatialOS by default. You can choose to bypass this and short-circuit commands when the worker instance sending the command believes to have write access authority over the target component. However, doing this might lead to a worker executing a command despite having just lost authority over the command’s component.

Related pages:

Standard schema library components

Position (required)

Position is a component in the standard schema library; all entities must have this component. It lets SpatialOS know what the position of an entity in the world is.

This is used by SpatialOS few specific purposes, like load balancing and queries.

Note that there’s no reason that this component must be used to represent entity positions inside, say, worker logic. For example, a 2D simulation could use a custom position component with only two fields, and update improbable.Position at a lower frequency to save bandwidth.

Related pages:

EntityAcl (required)

The access control list (ACL) is a component called EntityAcl that is required on every entity. You use it to define whether a worker type has write access permission and/or read access permission to the components on an entity.

A worker type needs read access permission so that its instances can receive updates about a component, and write access permission so that they can send updates about a component.

An entity’s ACL determines the permissions that worker instances of particular types have:

  • for each component on an entity, which worker types have write access permission
  • for all components on an entity, which worker types have read access permission

Write access permission is a requirement to send updates about components but a worker instance with write access permission to a component cannot necessarily send updates about that component. To do this, it needs write access authority which requires certain conditions are met.

Similarly, read access permission is a requirement to receive updates about components but a worker instance with read access permission to a component does not automatically receive updates about that component. To do this, it needs active read access which requires certain conditions are met.

Related pages:

Persistence (optional)

Persistence is a component in the standard schema library. It’s optional, but all entities that you want to persist in the world must have this component. Persistence means that entities are saved into snapshots.

If an entity doesn’t have this component, it won’t exist in snapshots. This is fine for transient entities. For example, you probably don’t want the entities associated with players to be saved into a snapshot you take of a deployment, because the players won’t be connected when you restart the deployment.

Related pages:

Metadata (optional)

Metadata is a component in the standard schema library.

It has a single property, entity_type, that’s used to label the entity.

Related pages:

Interest (optional)

Interest is a component in the standard schema library. You use it to specify query-based interest.

Related pages:

EntityId

An EntityId uniquely identifies each entity in the world and in a snapshot.

Entity template

An entity template defines what components an entity has. You use this template when you create an entity.

Creating an entity template varies in different programming languages, but, in general, you create a new Entity object, and then add components to it.

Related pages:

  • Creating and deleting entities in:

Entity database

The entity database is a part of the SpatialOS Runtime. It stores the canonical value of component data for entities. Only worker instances that have write access authority over component data can make updates to that data, and only worker instances with active read access can receive updates about that data. SpatialOS starts one Runtime instance as part of each deployment.

Related pages:

Schema

The schema is where you define all the components in your world.

Schema is defined in .schema files, written in schemalang. Schema files are stored in the schema/ directory of your project.

SpatialOS uses the schema to generate code in various languages (including C#, C++, and Java). You can use this generated code in your worker instances to interact with entities in the world.

Related pages:

Schemalang

Schemalang is SpatialOS’s language for writing a component schemas.

Related pages:

Code generation

Use the command spatial worker codegen to compile generated code from the schema (in C#, C++ and Java).

This code is used by workers to interact with entities: to read from their components, and to make changes to them.

Related pages:

Schema descriptor

The schema descriptor is a build artifact of a SpatialOS project assembly. It allows the SpatialOS Runtime to interpret your project’s schema and is necessary for starting a SpatialOS deployment both locally and in the cloud. You can generate a schema descriptor using the schema compiler tool.

Related pages:

Snapshot

A snapshot is a representation of the state of a world at some point in time. It stores each persistent entity and the values of their componentsproperties.

You’ll use a snapshot as the starting point (an initial snapshot) for your world when you deploy, locally or in the cloud.

Related pages:

Initial snapshot

An initial snapshot is a snapshot that you use as the starting point of your world when you deploy, locally or in the cloud.

Related pages:

Taking snapshots

You can take a snapshot from a running cloud deployment, which will capture the current state of all of the persistent entities in the world.

You can take snapshots automatically based on a time interval, or take them manually. You can also use the Platform SDK’s snapshot service to write a script to take snapshots according to your specific use case, and to programmatically download and upload them.

Related pages:

The Runtime

There is a Runtime instance for every game deployment. A Runtime instance holds the canonical store of all SpatialOS entity data.

It handles server-worker and client-worker instance connections, and coordinates each worker instance’s write and read access to entity data.

Related pages:

Worker SDK

Use the Worker SDK to create server-worker types and client-worker types which make your game work as a SpatialOS deployment. You can use these to:

  • extend the functionality of the game development kits for Unity or Unreal.
  • create low-level worker types for game logic that does not require a game engine; these could work without any game engine or with a game engine, complimenting the functionality of worker types in any game engine, including Unity or Unreal.

The Worker SDK is availailable in several programming languages: the C++, C# and Java flavors have a very similar structure; the Worker SDK in C is lower-level and doesn’t include code generation.

Worker SDK in C#

The toolkit for developing C# worker types with SpatialOS. This is a fairly low-level set of APIs for interacting with a SpatialOS world, and with snapshots.

Related pages:

Worker SDK in C++

The toolkit for developing C++ worker types with SpatialOS. This is a fairly low-level set of APIs for interacting with a SpatialOS world, and with snapshots.

Related pages:

Worker SDK in Java

The toolkit for developing Java worker types with SpatialOS. This is a fairly low-level set of APIs for interacting with a SpatialOS world, and with snapshots.

Related pages:

Worker SDK in C

The lowest level took kit for developing SpatialOS worker types.

Platform SDK

You can use the Platform SDK to build tools, workflows and services that integrate with the SpatialOS platform.

You can use its APIs to integrate SpatialOS into your continuous integration process, create debugging tools as game engine plugins, or build matchmaking and inventory systems that use player identity. You can also manage deployments, snapshots, and other parts of a project locally or in the cloud.

Currently, the Platform SDK is only available in C#.

Related pages:

Related pages:

Unity with SpatialOS

GDK for Unity

A Unity-native experience for developing games with SpatialOS. The GDK for Unity is a toolkit for developing worker types using Unity, built on top of the Worker SDK in C#. It includes APIs for interacting with a SpatialOS world. See the GDK for Unity documentation.

SDK for Unity

Superseded by the GDK for Unity. Until SpatialOS 13.0, SpatialOS included the SDK for Unity. From SpatialOS 13.0 onwards, the SDK for Unity has been released separately.

Unreal with SpatialOS

GDK for Unreal

An Unreal-native experience for developing games with SpatialOS. The GDK for Unreal is a toolkit for developing worker types using Unreal, built on top of the Worker SDK in C++. It includes APIs for interacting with a SpatialOS world. See the GDK for Unreal documentation.

SDK for Unreal

Superseded by the GDK for Unreal. Until SpatialOS 13.0, SpatialOS included the SDK for Unreal. From SpatialOS 13.0 onwards, the SDK for Unreal has been released separately.


————
2019-10-23 Page updated with editorial review: Updated “Deployment runs” and “Deploying”
2019-09-11 Page updated with editorial review: Updated definitions of “Bridge”, “Runtime”, and “Entity database”
2019-08-20 Page updated with editorial review: Added “Deployment runs”

Search results

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums