New ACM paper, free-tier cloud, and open-source license

TypeDB Console

TypeDB Console hero image


TypeDB Console is a standalone TypeDB client with a command line interface (CLI).

It is the default client distributed with TypeDB, but it can also be installed separately. For a standalone installation, see the Install page.

The GitHub repository with the source code and release notes.

See the TypeDB Console installation guide.

Connect to TypeDB

TypeDB can connect to both TypeDB Cloud and TypeDB Core. Running TypeDB Console initiates a network connection to a TypeDB server. By default, it tries to connect to a TypeDB Core server at the address localhost:1729. Use command line arguments to set connection parameters:

  • Cloud

  • Core

Connect to TypeDB Cloud
$ typedb console --cloud=<server-address> --username=<username> --password --tls-enabled=true

You will be prompted for a password.

On your first login, change the password for the admin account. A TypeDB Cloud deployment will refuse queries until the password is changed from its default value.

Connect to TypeDB Core
$ typedb console --core=<server-address>

The --core argument is used to set the TypeDB Core server IP address and port to connect to, for example, 10.0.0.5:1729.

As a result, you get a welcome message from TypeDB Console followed by a command line prompt.

Welcome to TypeDB Console. You are now in TypeDB Wonderland!
Copyright (C) 2022 Vaticle

>

See full list of available CLI arguments in the Console CLI arguments reference section below.

Interactive mode

TypeDB Console provides two levels of interaction via Read–eval–print loop (REPL): Server level and Transaction level.

At any level you can use common commands: help, clear, exit.

Server level

Server level is the first level of interaction, i.e., first-level REPL. From this level, you can use commands for managing databases and users on the server. You also can open a transaction to a database, which gets you to the second level of REPL.

For a full list of commands on the Server level, see the Server level commands section.

Transaction level

Transaction level is the second level of interaction, i.e., second-level REPL. You can control a transaction and send queries in the transaction.

For a full list of commands on the Transaction level, see the Transaction level reference section.

To send a query, while in Transaction level, type in or insert a TypeQL query and push Enter twice.

When opening a transaction, you can specify transaction options. For a full list of transaction options, see the Transaction options.

Example

The following example illustrates how to create a database, define a schema, and insert some data into the database.

  1. Run Console in the interactive mode and connect it to TypeDB:

    $ typedb console
  2. Now, run the following command to create a database:

    database create sample_db
  3. To define a schema, run the transaction command to open a schema session and write transaction to the database. This command opens a Transaction level REPL. Use it to send the Define query, and commit changes:

    transaction sample_db schema write
    define person sub entity;
    commit

    The Transaction level of REPL is announced by the CLI prompt change to include database name, session type, and transaction type.

    To send a query in the Transaction level, push Enter twice, as a single push of the Enter is recognized as a line break in the query.

  4. Insert data with data session and write transaction:

    transaction sample_db data write
    insert $p isa person;
    commit

The above example creates a database with the name sample_db, defines a simple schema with the single person type, then inserts a single instance of the type into the database.

Non-interactive mode

You can run Console commands using the --command argument:

$ typedb console --command=<command1> --command=<command2>

The following example achieves the same results as the one in the interactive mode via the command line arguments. Run the following command in a terminal to start TypeDB and execute queries:

$ typedb console --command="database create sample_db" \
--command="database list" \
--command="transaction sample_db schema write" \
--command="define person sub entity;" \
--command="commit" \
--command="transaction sample_db data write" \
--command='insert $p isa person;' \
--command="commit"
See the output
Output
+ database create sample_db
Database 'sample_db' created
+ database list
sample_db
+ transaction sample_db schema write
++ define person sub entity;
Concepts have been defined
++ commit
Transaction changes committed
+ transaction sample_db data write
++ insert $p isa person;
{ $p iid 0x826e80017fffffffffffffff isa person; }
answers: 1, total (with concept details) duration: 56 ms
++ commit
Transaction changes committed

Scripting

You can create a script file that contains the list of commands to run. These are the very same commands that are used in the Interactive mode or Non-interactive mode. For the full list of commands, see the References below.

To use a script file with commands, run Console with the --script argument and a path to the script file:

$ typedb console --script=<script-file-path>

Each line in the script file is interpreted as one command, so multiline queries are not available in this mode. You can overcome this limitation, by calling a TypeQL query from a file with the source command. For example, see the Run a query from a file section below.

Prepare the script to run and save it to a local file. For example, let’s try the following script.txt file:

script.txt
database create test
transaction test schema write
    define person sub entity, owns name; name sub attribute, value string;
    commit
transaction test data write
    insert $x isa person, has name "Bob";
    commit
transaction test data read
    match $x isa person, has name $f; fetch $f;
    close
database delete test

Execute the script with TypeDB Console:

Run script.txt
$ typedb console --script=PATH/script.txt

Where PATH/script.txt is the path to the file and the filename.

See the output
Output
+ database create test
Database 'test' created
+ transaction test schema write
++ define person sub entity, owns name; name sub attribute, value string;
Concepts have been defined

++ commit
Transaction changes committed
+ transaction test data write
++ insert $x isa person, has name "Bob";
{
    $_0 Bob isa name;
    $x iid 0x826e80017fffffffffffffff isa person;
}

answers: 1, total duration: 15 ms

++ commit
Transaction changes committed
+ transaction test data read
++ match $x isa person, has name $f; fetch $f;
{ "f": { "value": "Bob", "type": { "label": "name", "root": "attribute", "value_type": "string" } } }

answers: 1, total duration: 10 ms

++ close
Transaction closed
+ database delete test
Database 'test' deleted

Run a query from a file

To run a TypeQL query stored in a file, use the source <filename> command. This command is available from the Transaction level REPL:

Interactive mode source usage example
transaction sample_db schema write
source schema.tql
commit

The schema.tql file should be located in the working directory, when you run TypeDB Console, and contain a valid Define query.

Script using query files examples

To overcome the limitation of a script file for one command per line, you can store multiple multiline queries in a separate file and run them with the source command.

For example, let’s use the following script file to:

  • Create the iam_sample_db database

  • Load the IAM schema form the iam-schema.tql file in a schema session

  • Load sample data from the iam-data.tql file in a data session

  • Run a Fetch query

  • Delete the database to reset the environment

Script file
database create iam_sample_db
transaction iam_sample_db schema write
    source iam-schema.tql
    commit
transaction iam_sample_db data write
    source iam-data.tql
    commit
transaction iam_sample_db data read
    match $p isa person; fetch $p as person: attribute;
    close
database delete iam_sample_db
See the iam-schema.tql
iam-schema.tql
define

credential sub attribute, value string;
full-name sub attribute, value string;
id sub attribute, abstract, value string;
email sub id, value string;
name sub id, value string;
number sub id, value string;
path sub id, value string;
object-type sub attribute, value string;
ownership-type sub attribute, value string;
review-date sub attribute, value datetime;
size-kb sub attribute, value long;
validity sub attribute, value boolean;

access sub relation,
    relates action,
    relates object,
    plays change-request:change,
    plays permission:access;

change-request sub relation,
    relates change,
    relates requestee,
    relates requester;

membership sub relation,
    relates member,
    relates parent;

collection-membership sub membership,
    relates collection as parent;

group-membership sub membership,
    relates group as parent;

set-membership sub membership,
    relates set as parent;

ownership sub relation,
    relates owned,
    relates owner;

group-ownership sub ownership,
    owns ownership-type,
    relates group as owned;

object-ownership sub ownership,
    owns ownership-type,
    relates object as owned;

permission sub relation,
    owns review-date,
    owns validity,
    relates access,
    relates subject;

segregation-policy sub relation,
    owns name,
    relates action,
    plays segregation-violation:policy;

violation sub relation,
    abstract;

segregation-violation sub violation,
    relates object,
    relates policy,
    relates subject;

action sub entity,
    abstract,
    owns name,
    owns object-type,
    plays access:action,
    plays membership:member,
    plays segregation-policy:action;

operation sub action;

operation-set sub action,
    plays set-membership:set;

object sub entity,
    abstract,
    owns object-type,
    plays access:object,
    plays membership:member,
    plays object-ownership:object,
    plays segregation-violation:object;

resource sub object,
    abstract;

file sub resource,
    owns path,
    owns size-kb;

record sub resource,
    owns number;

resource-collection sub object,
    abstract,
    plays collection-membership:collection;

database sub resource-collection,
    owns name;

directory sub resource-collection,
    owns path,
    owns size-kb;

subject sub entity,
    abstract,
    owns credential,
    plays change-request:requestee,
    plays change-request:requester,
    plays membership:member,
    plays ownership:owner,
    plays permission:subject,
    plays segregation-violation:subject;

user sub subject,
    abstract;

person sub user,
    owns email,
    owns full-name;

user-group sub subject,
    abstract,
    plays group-membership:group,
    plays group-ownership:group;

business-unit sub user-group,
    owns name;

user-account sub user-group,
    owns email;

user-role sub user-group,
    owns name;

rule add-view-permission: when {
    $modify isa action, has name "modify_file";
    $view isa action, has name "view_file";
    $ac_modify (object: $obj, action: $modify) isa access;
    $ac_view (object: $obj, action: $view) isa access;
    (subject: $subj, access: $ac_modify) isa permission;
} then {
    (subject: $subj, access: $ac_view) isa permission;
};
See the iam-data.tql
iam-data.tql
# Subjects
insert $p isa person, has full-name "Masako Holley", has email "masako.holley@typedb.com";  # No access
insert $p isa person, has full-name "Pearle Goodman", has email "pearle.goodman@typedb.com";  # Sales manager
insert $p isa person, has full-name "Kevin Morrison", has email "kevin.morrison@typedb.com";  # Full access

# Objects
insert $f isa file, has path "iopvu.java", has size-kb 55;
insert $f isa file, has path "zlckt.ts", has size-kb 143;
insert $f isa file, has path "psukg.java", has size-kb 171;
insert $f isa file, has path "axidw.java", has size-kb 212;
insert $f isa file, has path "lzfkn.java", has size-kb 70;
insert $f isa file, has path "budget_2022-05-01.xlsx", has size-kb 758;
insert $f isa file, has path "zewhb.java";
insert $f isa file, has path "budget_2021-08-01.xlsx", has size-kb 1705;
insert $f isa file, has path "LICENSE";
insert $f isa file, has path "README.md";

# Operations
insert $o isa operation, has name "modify_file";
insert $o isa operation, has name "view_file";

# Potential access types
match $ob isa file, has path "iopvu.java"; $op isa operation, has name "modify_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "zlckt.ts"; $op isa operation, has name "modify_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "psukg.java"; $op isa operation, has name "modify_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "axidw.java"; $op isa operation, has name "modify_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "lzfkn.java"; $op isa operation, has name "modify_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "budget_2022-05-01.xlsx"; $op isa operation, has name "modify_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "zewhb.java"; $op isa operation, has name "modify_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "budget_2021-08-01.xlsx"; $op isa operation, has name "modify_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "LICENSE"; $op isa operation, has name "modify_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "README.md"; $op isa operation, has name "modify_file"; insert $a (object: $ob, action: $op) isa access;

match $ob isa file, has path "iopvu.java"; $op isa operation, has name "view_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "zlckt.ts"; $op isa operation, has name "view_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "psukg.java"; $op isa operation, has name "view_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "axidw.java"; $op isa operation, has name "view_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "lzfkn.java"; $op isa operation, has name "view_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "budget_2022-05-01.xlsx"; $op isa operation, has name "view_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "zewhb.java"; $op isa operation, has name "view_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "budget_2021-08-01.xlsx"; $op isa operation, has name "view_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "LICENSE"; $op isa operation, has name "view_file"; insert $a (object: $ob, action: $op) isa access;
match $ob isa file, has path "README.md"; $op isa operation, has name "view_file"; insert $a (object: $ob, action: $op) isa access;

# Permissions
match $s isa subject, has full-name "Kevin Morrison"; $o isa object, has path "iopvu.java";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Kevin Morrison"; $o isa object, has path "zlckt.ts";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Kevin Morrison"; $o isa object, has path "psukg.java";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Kevin Morrison"; $o isa object, has path "axidw.java";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Kevin Morrison"; $o isa object, has path "lzfkn.java";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Kevin Morrison"; $o isa object, has path "budget_2022-05-01.xlsx";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Kevin Morrison"; $o isa object, has path "zewhb.java";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Kevin Morrison"; $o isa object, has path "budget_2021-08-01.xlsx";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Kevin Morrison"; $o isa object, has path "LICENSE";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Kevin Morrison"; $o isa object, has path "README.md";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Pearle Goodman"; $o isa object, has path "budget_2022-05-01.xlsx";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Pearle Goodman"; $o isa object, has path "zewhb.java";
      $a isa action, has name "view_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Pearle Goodman"; $o isa object, has path "budget_2021-08-01.xlsx";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Pearle Goodman"; $o isa object, has path "LICENSE";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

match $s isa subject, has full-name "Pearle Goodman"; $o isa object, has path "README.md";
      $a isa action, has name "modify_file"; $ac (object: $o, action: $a) isa access;
insert $p (subject: $s, access: $ac) isa permission;

Make sure you have the above script file and tql files saved to the working directory. Run the script with TypeDB Console using the --script argument, as you did before in the script example.

See the output
Output
+ database create iam_sample_db
Database 'iam_sample_db' created
+ transaction iam_sample_db schema write
++ source iam-schema.tql
Concepts have been defined
++ commit
Transaction changes committed
+ transaction iam_sample_db data write
++ source iam-data.tql
++ commit
Transaction changes committed
+ transaction iam_sample_db data read
++ match $p isa person; fetch $p as person: attribute;
{
    "person": {
        "attribute": [
            { "value": "kevin.morrison@typedb.com", "type": { "label": "email", "root": "attribute", "value_type": "string" } },
            { "value": "Kevin Morrison", "type": { "label": "full-name", "root": "attribute", "value_type": "string" } }
        ],
        "type": { "label": "person", "root": "entity" }
    }
}
{
    "person": {
        "attribute": [
            { "value": "masako.holley@typedb.com", "type": { "label": "email", "root": "attribute", "value_type": "string" } },
            { "value": "Masako Holley", "type": { "label": "full-name", "root": "attribute", "value_type": "string" } }
        ],
        "type": { "label": "person", "root": "entity" }
    }
}
{
    "person": {
        "attribute": [
            { "value": "pearle.goodman@typedb.com", "type": { "label": "email", "root": "attribute", "value_type": "string" } },
            { "value": "Pearle Goodman", "type": { "label": "full-name", "root": "attribute", "value_type": "string" } }
        ],
        "type": { "label": "person", "root": "entity" }
    }
}

answers: 3, total duration: 27 ms

++ close
Transaction closed
+ database delete iam_sample_db
Database 'iam_sample_db' deleted

Troubleshooting

Non-ASCII characters

TypeDB can use type and variable labels and store string value attributes that have characters outside the ASCII range, for example, non-English letters, symbols, and emojis. To manipulate them using Console, the Console’s terminal must use a locale with a compatible code set, such as Unicode.

If it doesn’t, these characters will most likely be rendered as ? symbols in Console. If this issue occurs, you can use the following fix:

  • Linux

  • macOS

  • Windows

Use locale -a to list all installed locales, and use export to set the environment. For example, to use en_US.UTF-8 run:

$ bash export LANG=en_US.UTF-8 && export LC_ALL=en_US.UTF-8

Use locale -a to list all installed locales, and use export to set the environment. For example, to use en_US.UTF-8 run:

$ bash export LANG=en_US.UTF-8 && export LC_ALL=en_US.UTF-8

Use Windows Terminal or run chcp in the terminal (e.g., chcp 936 for Chinese text).

Most systems also allow us to set the system-wide locale. However, this impacts the appearance of other applications.

References

Console CLI arguments

The following arguments can be used when you invoke TypeDB Console:

Table 1. Command line arguments
Argument Alias Description

TypeDB Core specific

--core=<address>

Address to which Console will connect to: IP address and IP port separated by colon. Default value: localhost:1729.
(TypeDB Core only)

TypeDB Cloud specific

--cloud=<address>

Address to which Console will connect to.
(TypeDB Cloud only)

--username=<username>

Username
(TypeDB Cloud only)

--password

Enable a password prompt
(TypeDB Cloud only)

--tls-enabled

Whether to connect with TLS encryption
(TypeDB Cloud only)

--tls-root-ca=<path>

Path to the TLS root CA file
(TypeDB Cloud only)

Common

--help

-h

Show help message.

--command=<commands>

Commands to run in the Console, without interactive mode

--script=<script>

Script with commands to run in the Console, without interactive mode.

--version

-V

Print version information and exit.

--diagnostics-disable=true

Disable anonymous error reporting.

Server level commands

Use these commands at the Server level of TypeDB’s REPL:

Table 2. Server level commands (first level of REPL)
Command Description

Database management

database create <db>

Create a database with the name <db> on the server.

database list

List all databases on the server

database delete <db>

Delete a database with the name <db> from the server

database schema <db>

Print the schema of the database with the name <db> on the server

User management

user list

List all users on the server
(TypeDB Cloud only)

user create <username>

Create a user with the name <username> on the server
(TypeDB Cloud only)

user password-update

Update the password for the current user
(TypeDB Cloud only)

user password-set <username>

Set password for the user with the name username
(TypeDB Cloud only)

user delete <username>

Delete a user with the name <username> on the server
(TypeDB Cloud only)

Open a transaction

transaction <db> schema⎮data read⎮writ [options]

Start a transaction to the database with the name <db> with chosen session and transaction types. You can set transaction options.

Common

help

Print help menu

clear

Clear console screen

exit

Exit console

Transaction level commands

Use these commands in the Transaction level of TypeDB Console’s REPL. The prompt at the Transaction level contains the database name, as well as session and transaction types, for example, iam::data::read>.

Table 3. Transaction level commands (second level of REPL)
Command Description

Querying

<query>

Type in TypeQL query directly. Push Enter once for a line break in a query. Push Enter twice (once more on a new line) to send a query.

source <file>

Run TypeQL queries from a file. You can use a relative or absolute path. On Windows escape \ by writing \\.

Transaction control

commit

Commit the changes and close the transaction.

rollback

Rollback the transaction — remove any uncommitted changes, while leaving the transaction open.

close

Close the transaction without committing changes.

Common

help

Print help menu.

clear

Clear console screen.

exit

Exit console.

Transaction options

The following flags can be passed in the transaction command as transaction options, for example:

transaction sample_db data read --infer true
Table 4. Transaction options
Option Allowed values Description

--infer

true⎮false

Enable or disable inference.

--trace-inference

true⎮false

Enable or disable inference tracing.

--explain

true⎮false

Enable or disable inference explanations.

--parallel

true⎮false

Enable or disable parallel query execution.

--batch-size

1..[max int]

Set RPC answer batch size.

--prefetch

true⎮false

Enable or disable RPC answer prefetch.

--session-idle-timeout

1..[max int]

Kill idle session timeout (ms).

--transaction-timeout

1..[max int]

Kill transaction timeout (ms).

--schema-lock-acquire-timeout

1..[max int]

Acquire exclusive schema session timeout (ms).

--read-any-replica

true⎮false

Allow or disallow reads from any replica
(TypeDB Cloud only).

Version Compatibility

TypeDB Console Protocol encoding version TypeDB Core TypeDB Cloud

2.28.0

3

2.28.0

2.28.0

2.27.0

3

2.27.0

2.27.0

2.26.6

3

2.26.6

2.26.6

2.25.7

3

2.25.7

2.25.7

2.24.15

2

2.24.17

2.24.17

2.18.0

1

2.18.0 to 2.23.0

2.18.0 to 2.23.0

2.17.0

N/A

2.17.0

2.17.0

See older versions
TypeDB Console Protocol encoding version TypeDB Core TypeDB Cloud

2.16.1

N/A

2.16.1

2.16.1 to 2.16.2

2.15.0

N/A

2.15.0

2.15.0

2.14.2

N/A

2.14.2 to 2.14.3

2.14.1

2.14.0

N/A

2.14.0 to 2.14.1

2.14.1

2.12.0

N/A

2.12.0 to 2.13.0

2.12.0 to 2.13.0

2.11.0

N/A

2.11.0 to 2.11.1

2.11.1 to 2.11.2

2.10.0

N/A

2.10.0

2.10.0

2.9.0

N/A

2.9.0

2.9.0

2.8.0

N/A

2.8.0 to 2.8.1

2.5.0

2.6.1

N/A

2.6.1 to 2.7.1

2.5.0

2.6.0

N/A

2.6.0

2.5.0

2.5.0

N/A

2.5.0

2.3.0

2.4.0

N/A

2.4.0

2.3.0

2.3.2

N/A

2.3.2 to 2.3.3

2.3.0

2.3.1

N/A

2.3.1

2.3.0

2.3.0

N/A

2.3.0

2.3.0

2.1.3

N/A

2.1.3 to 2.2.0

2.1.2

2.1.2

N/A

2.1.2

2.0.3

2.1.1

N/A

2.1.1

2.0.3

2.1.0

N/A

2.1.0

2.0.3

2.0.1

N/A

2.0.1 to 2.0.2

2.0.1 to 2.0.2

2.0.0

N/A

2.0.0

2.0.0

1.0.8

N/A

1.1.0 to 1.8.4

-

Provide Feedback