Terminology and Conventions

  • A primitive is a single primitive that may be part of a link-set.
  • An object may be a single primitive or an entire link-set.

Application Programmer Interface

  • The API is written using functions such as wasKeyValueEncode, wasKeyValueGet or wasKeyValueSet which are defined on the key-value data page. In short these functions are (optimised) helper functions that provide POST-data manipulation and you can use in your scripts to communicate with Corrade.
  • The API uses the RFC 4180 compliant LSL functions wasListToCSV and wasCSVToList for which you can find an implementation on the comma separated values page. This is due to the fact that the built-in Linden Lab functions llList2CSV, respectively llCSV2List do not adhere to any standard (for example, llList2CSV yields identical strings to llDumpList2String(string, ", ") which makes the Linden Lab function useless).
  • The API uses application/x-www-form-urlencoded encoding functions wasFormEncode and wasFormDecode (erroneously used synonymously with wasURLEscape and wasURLUnescape) which can be found on the form encoding page.
  • The API provides some examples, but you can do more depending on the parameters supplied. For example, the tell command sent to Corrade can make Corrade talk in local chat, in a group and to avatars depending on the entity parameter and, in case of local chat, the type parameter (whisper, say, normal).
  • Some commands ask for firstname and lastname when you need to refer to an avatar. If firstname and lastname is not known to the script, you can just supply the agent parameter and feed it the key of the designated agent.
  • Groups can also be passed as UUID rather than name - this is particularly useful in cases where a group is hidden and can only be found iff. the UUID of the group is known.
  • Some commands take as parameter a positional vector that is said to pin-point a parcel. In order to understand this, any point-vector on a region can be projected onto the ground-plane. This projection always intersects a parcel.
  • Every command that acts upon a group can also be passed the target parameter with a group name or group UUID as a value in order to act upon a different group.

Case Sensitivity

  • Commands and parameters are case-sensitive in the right context. For example, passing a lower-case avatar name to Corrade is fine because avatar names are not case sensitive. As a counter-example, passing in-world primitive names may be ambiguous if the primitives have a different casing. A good example for this extra complication are roles within a group which are case-sensitive such that passing a lower-case role name to Corrade's roles command may refer to the wrong role.
    • Err on the side of caution and pass data to Corrade exactly as it appears to you.

Callbacks and Returned Data

  • If Corrade refuses to execute a command, install a callback and check Corrade's return. Corrade extensively reports errors such that it becomes easy to track why a command has failed. Furthermore, Corrade tries to perform all the necessary checks such that a command will be successful, however it may happen that Corrade returns successfully but no "usable data" is returned - just the success status. In such cases, it may very well be that there was no data to return in the first place. As such, Corrade's success return refers to whether the command has been executed successfully and does not reflect the fact that there was no data to be returned.
  • There may be cases where Corrade's return will be larger than the 2KB limit of http_request of an LSL script. If that is the case, then the alternative is to run Corrade's internal HTTP server and query the data outside of the grid (for example, with a PHP script). An alternative solution if you have any previous knowledge about the data that is to be returned by Corrade and you really want the result returned in-world is to use sifting.

Referencing In-World Visual Elements

It is important to realize that the grid is not data-driven and that visual elements such as avatars and objects are passed to a viewer on a least-effort basis. There are few to no guarantees that specific objects or avatars will be passed to the viewer.

All commands that are radar-bound are subject to the draw distance, either defined in the configuration file as the Range parameter or passed to the individual command as the range parameter. The range represents the cutoff point after which objects and avatars will not be perceived by the viewer.

Other commands that rely on different subsystems such as directory services, or the map API will often offer better guarantees for finding avatars and objects. For instance, compare the two commands:

The former command, "getprimitivesdata" is radar-bound and will not guarantee that any primitive in particular will be detected by the viewer whilst the latter command "getprimitiveowners" goes through the land and parcel subsystem and the command is guaranteed to return complete results.

The same applies to avatars, for instance, compare the two commands:

The former command, "getavatarsdata" is radar-bound and will not guarantee that any avatar in particular will be detected by the viewer whilst the "getavatarpositions" command goes through the map API such that the command is guaranteed to return complete results.

Note that commands such as "getavatarsdata" and "getavatarpositions" are different in semantics where "getavatarsdata" is supposed to query avatars for various parameters and that "getavatarpositions" will return, as per the command definition, a CSV list of avatars by positions. Nevertheless, if the purpose is to find all avatars on a region reliably then "getavatarpositions" should be used instead of "getavatarsdata" and then the information that is not needed (such as the map position) can be discarded. Otherwise, "getavatarsdata" can be used in a context where incomplete data is acceptable.

Objects

For all API commands, when an item parameter is required by a command, either the primitive (or object) UUID or primitive name can be passed to the item parameter. In case a name is passed to the item parameter, then Corrade will scan all objects in the vicinity and attempt to find the primitive or object by name. In case an UUID is supplied, Corrade will attempt to find the primitive or object by UUID.

In most cases, it is preferable to combine Corrade command with llSensor or llSensorRepeat in order to provide Corrade with the UUID of the item instead of the name. This is due to the fact that objects in Linden-based virtual worlds carry only a limited amount of information and the name of the object is not part of that information such that the command may take a long time to complete. Furthermore, object or primitive names are not distinct such that issuing a command with the item parameter set to an object name might return ambiguous results where a different primitive is returned rather than the one desired.

The Range Parameter

In many cases when interacting with primitives and avatars, you will notice that Corrade takes as parameter a range. range is the search radius in meters from the bot where Corrade will attempt to find a named primitive. Note that Corrade's search functions also include avatar attachments such that range should be kept as low as possible, otherwise very many primitives will be scanned and the command will take longer to complete.

The range parameter corresponds to the Range configuration setting in the configuration file - usually, for all commands, if range is specified, then the parameter will take precedence over the Range configuration setting. Otherwise, if range is not supplied, the search range will be extended to the Range parameter in the configuration file.

Command Interface

Properly Escaping Keys and Values

  • Corrade attempts to unescape both keys and values when it receives a command, and, in turn, escapes keys and values when it sends data back to the callback. For a more complete by-example tutorial, please see the command tutorial page.

Order of Execution

  • The order in which commands execute is not pre-determined. In other words, if you send two commands succinctly, say stand and then sit, there is no guarantee that stand will execute before sit but it may happen that sit will execute before stand! In order to have any sort of guarantee of linearity, you must use a callback and confirm that a command has executed before issuing a follow-up command. In other words, following the previous example: send the stand command and confirm via the callback that stand has executed; after that, send the sit command (and confirm via the callback that the sit command has executed).
    • As a quick mnemonic: if you do not care about the outcome of a command issued to Corrade then do not check the callback. Conversely, if you care about the outcome, then check the callback.
    • A notable example where the result of a command is negligible would be a HUD where Corrade can be made to move around remotely like a ROV using W, S, A, D keys such as one of the scripts found in the drone HUD. The script usesthe nudge command that is spammed continuously to Corrade via llRegionSayTo (in order to avoid the throttling penalty of instant messages) which makes Corrade move incrementally and since it is irrelevant whether a single one of the infinitesimal nudges got executed then the callback is not checked whilst spamming nudge commands.

Structural Semantics

You can read more about key-value pairs and comma separated values on the tutorial page concerning data returned by Corrade.

  • Corrade uses key-value data as the first order structure and comma-separate values (CSV) as a second-order sub-structure. This is due to the minimal syntax that is used for the two structures contrasted to, say JSON or XML that add a very rich syntactical overhead which is impractical given the constraints imposed by LSL scripts (roughly 64KB of memory).
  • The CSV sub-structure is compliant with RFC 4180 - except that table headers are not used. Unfortunately, the LSL functions llCSV2List and llList2CSV cannot be used because they are not RFC 4180 compliant. To illustrate why llCSV2List and llList2CSV will not work, lets take the invite command which takes one or more roles in the role parameters and invites an avatar into a group and places them in the supplied role. Suppose that the role we want to invite an avatar to carries the name: The "Good", Role!. As you can see, there are several problems here. First, the comma , would interfere with CSV and the double-quotes around Good would interfere with an attempt to escape. In such cases, we would send the command as:
llInstantMessage(CORRADE, 
    wasKeyValueEncode(
        [
            "command", "invite",
            "group", GROUP,
            "password", PASSWORD,
            "firstname", "John",
            "lastname", "Steinbeck",
            "role", llEscapeURL("\"The \"\"Good\"\", Role!\""),
            "callback", llEscapeURL(URL)
        ]
    )
);

Notice the role name \"The \"\"Good\"\", Role!\":

  1. First, every double-quote (") must be escaped in order to not interfere with LSL's start and end-of-string delimiters and will be thus written as (\"). This will vary if you are using Corrade's HTTP interface and are using a different language that supports other delimiters. For example, in PHP, you could use single quotes to avoid clashes and the role would be thus escaped in PHP as '"The ""Good"", Role!"'.
  2. The outer quotes \" (beginning and end) escape the entire role name - we need to do this because the role name contains a comma ,.
  3. RFC 4180 states that in order to escape double-quotes we place another quote before it, as in: "". So, that is why in order to successfully pass "Good", we escape the double quotes using another double quote: \"\"Good\"\".

The Permission System Notation

When setting or getting the permissions for an item - either in-world or as an inventory item, Corrade serializes and deserializes permissions from a specially-formatted string which resembles loosely a superset of the UNIX literal permissions. This is due to the fact that all permissions can be expressed unambiguously using Corrade's formatted string as well as making it much easier to deal with.

An example of what a permission string looks like, is the following permission extracted from a newly created object with "copy" and "transfer" set:

c--mvt------------c---vtc--mvt

To dissect these permissions, you can use the following guide:

  • split that string in segments of 6 characters: cdemvt, ------, ------, cdemvt, cdemvt.
  • each segment means, in order: base permissions, everyone permissions, group permissions, next owner permissions, owner permissions.
  • each character means: c (copy), d (damage), e (export), m (modify), v (move), t (transfer).
    • if any of the previously mentioned characters are missing and have a dash (-) instead, that means that those permissions are missing.

Annotating the example, we have:

       everyone    next owner
          |            |
        +-+--+      +--+-+
        |    |      |    |
  cdemvt------------cde-vtcdemvt
  |    |      |    |      |    |
  +-+--+      +--+-+      +-+--+
    |            |          |
   base        group       owner

And interpreting the results, we have:

  • first 6 characters cdemvt indicate that all permissions are set for the base mask are set.
  • next 6 characters ------ indicate that no permissions are granted to the everyone mask.
  • next 6 characters ------ indicate that no permissions are granted to the group mask.
  • next 6 characters cde-vt indicate that the next owner has the ability to copy (c), damage (d), export (e), move (v) and transfer (t) but cannot modify the object (since the m is missing and a dash is there instead).
  • last 6 characters cdemvt indicate that all permissions are set for the owner.

If you take a closer look at the everyone mask, and the group mask you will notice that there are no permissions there. These permissions are used in cases where, for example, you would grant everyone or a group the permission to move the object. All the fields are relevant, but it is highly likely that the next owner mask is the one you would want to change before giving an object away.

Note that in the instances where you have to set permissions, the Export and Damage permissions are special and pertain mostly to OpenSim. As such, setting an item to full-permission will require the string:

c--mvt------------c--mvtc--mvt

The following table summaries all the permissions that are usually set for the next owner on an object:

Next Owner Permissions Required String
Modify, Copy, Transfer c--mvt------------c--mvtc--mvt
Modify, Transfer c--mvt---------------mvtc--mvt
Modify, Copy c--mvt------------c--mv-c--mvt
Copy, Transfer c--mvt------------c---vtc--mvt
Copy c--mvt------------c---v-c--mvt

Note that the permissions summarised in the table above only change the hexa corresponding to the next owner and that the same variations can be applied to the other hexas.

The restriction for each hexa is that only Modify objects (or objects with no permissions) cannot exist in the Linden permission system. Thus, the following permission strings are illegal:

Next Owner Permission Illegal String
Modify c--mvt---------------mv-c--mvt

Corrade will still attempt to set the permissions but most likely the grid will reject the setting of the permissions and Corrade will thus return a script error to the callback. Keep in mind that Corrade can do anything (and more) that a viewer can do such that a large subset of the Linden restrictions apply to Corrade as well.

Referencing Parcels on a Simulator

In order to blend elegantly with LSL semantics, Corrade uses vectors to reference parcels instead of parcel local IDs since local IDs are not recognized by the LSL API. By consequence, most commands that deal with parcels take a position argument that is supposed to represent a point vector that will intersect a single parcel when projected onto the plane.

For instance in the following illustration, when the vector $\overrightarrow{v}$ is projected onto a simulator map, will intersect a given parcel.

          y   ^                                  
                                                 
            /                                    
     255   --------------------------------------
          /region                              / 
                                              /  
        /                                    /   
                       |  -------------     /    
      /         v(x, y)| /           /     /     
                       |/           /     /      
    /                  v    parcel /     /       
                      /-----------/     /        
  /                                    /         
                                      /          
/ - - - - - - - - - - - - - - - - - -/- - - - -> 
                                               x 
                                   255                  

Vector $\overrightarrow{v}$ can then be fed to the position parameter for all commands that interact with parcels.

The getregionparcellocations command can be used to retrieve a CSV list of parcel names by parcel local ID by descriptive vector.

The getparceldata command can also be used to retrieve the AABMin and AABMax parameters for a parcel representing the south-western extremity point respectively the north-eastern extremity point of a parcel. Intuitively, one could then take the arithmetic mean value to determine the midpoint and compute a point vector that would fall within the parcel. However, in Second Life parcels are allowed to be disjoined such that using the AABMin and AABMax parameters from the getparceldata command will fail in certain situations.

As an example where calculating the midpoint using AABMin and AABMax via the getparceldata command would yield erroneous results, let us assume the following land topology:

        
                AABMax
    +----+--+----+
    |(A)-|//|----|
    |----|//|----|
    +----+//+----+
    |//(B)///////|
    +----+//+----+
    |----|//|----|
    |----|//|----|
    +----+--+----+
AABMin

representing a simulator that has been divided into two parcels denoted with A and B. Taking the AABmin and AABMax points for parcel A and calculating the midpoint as the arithmetic mean would produce a point vector (on the diagonal from AABMin to AABMax) that falls within parcel B.

The getregionparcellocations command is designed to always produced valid point vectors to describe parcels and should always be used instead of computing the midpoint via the getparceldata command.

Plurals and Named Plurals

Corrade distinguishes between two types of plural forms:

  • a plural form that will apply to a collection of items given certain delimiters (ie: avatars on a particular parcel),
  • a plural form that will apply to a list of items provided by the user

For example, the command getavatarappearancedata has a plural form getavatarsappearancedata and a named plural form batchgetavatarappearancedata.

The distinction is made due to the way SecondLife offers various properties that have different kind of contexts leading to different ways of handling the command entirely.

In any case, plural forms for commands that return data (all commands with the data suffix) will return the data requested by the user and only the data requested by the user. For example, suppose that the following command is used to query the IsTrial property of two avatars using the plural form command batchgetavatarsappearancedata:

llInstantMessage(CORRADE,
    wasKeyValueEncode(
        [
            "command", "batchgetavatarsappearancedata",
            "group", wasURLEscape(GROUP),
            "password", wasURLEscape(PASSWORD),
            "avatars", wasListToCSV([
                "Juno Resident",
                "Cat Resident"
            ]),
            "data", "IsTrial",
            "callback", wasURLEscape(URL)
        ]
    )
);

The result passed to the callback URL (or other external services if querying via HTTP, MQTT, etc.) will be a CSV list containing two booleans and it will be impossible to determine to which avatar (either Juno Resident or Cat Resident) a particular boolean in the list corresponds to:

IsTrial,false,IsTrial,true

In order to solve the issue, the AvatarAppearanceEventArgs structure contains an AgentID property which can be queried along with the IsTrial property:

llInstantMessage(CORRADE,
    wasKeyValueEncode(
        [
            "command", "batchgetavatarappearancedata",
            "group", wasURLEscape(GROUP),
            "password", wasURLEscape(PASSWORD),
            "avatars", wasListToCSV([
                "Juno Resident",
                "Cat Resident"
            ]),
            "data", wasListToCSV([
                "AgentID",
                "IsTrial"
            ]),
            "callback", wasURLEscape(URL)
        ]
    )
);

The result will now be a CSV list of avatar UUIDs by booleans:

AvatarID,870b5fa9-0b32-491e-8848-465666ae1151,IsTrial,true,AvatarID,ee0af3af-9881-476b-9482-a8048f64b3f5,IsTrial,false

Furthermore, plural forms shall never mangle the order of the properties passed to the data parameter within a subgroup yet subgroup order may be mangled. In other words, the following two results are possible if the previous command were to be issued twice:

AvatarID,870b5fa9-0b32-491e-8848-465666ae1151,IsTrial,true,AvatarID,ee0af3af-9881-476b-9482-a8048f64b3f5,IsTrial,false

is equivalent to:

AvatarID,ee0af3af-9881-476b-9482-a8048f64b3f5,IsTrial,false,AvatarID,870b5fa9-0b32-491e-8848-465666ae1151,IsTrial,true

As you can observe, the avatar IDs and trial flags have been switched for both avatars however, the correct trial flag still corresponds to the correct avatar. In other words, the subgroups:

AvatarID,ee0af3af-9881-476b-9482-a8048f64b3f5,IsTrial,false

and:

AvatarID,870b5fa9-0b32-491e-8848-465666ae1151,IsTrial,true

are interchangeable.

If you are curious why, imagine a table where the columns / column headers are the properties that users supply to the data parameter and the rows of that table are the results. Since there is no way to transfer a 2-dimensional table, Corrade places the column name before each cell, followed by the cell and each row after the other in the same long string. Following the analogy, the order of the rows is not relevant but the contents of each cell in a row is since it corresponds to a column header name.

Command Name Syntax

The following BNF grammar describes the syntax of a Corrade command:

command ::= [ prefix ] <body> [ suffix ]
prefix ::= "batch" | ""
body ::= ( <term> [ plural ] )+
suffix ::= "data" | ""
plural ::= "s" | ""

Additionally the following notes apply universally to all commands:

  • Commands prefixed with batch denote a command that is a named plural of a command. Such commands take a list of specific items and perform an action or retrieve some information on or for the specified items.
  • Commands ending in data are commands that query various properties of itmes. Such commands are expected to return a data key to the callback whose value represents the queried data or the command does not return a data key at all in which case no data was available for the queried property (or the property does not exist).
  • Plurals might appear using the string "s". The string "s" may be placed within the body of a command and may appear multiple times. Many times, such a command represents the plural of a different command. For example a fictive command "banavatars" would be a plural form of a command "banavatar". Plurals using the string "s" are left-associative and pluralize the term that they are placed after. For example, a fictive command "getavatarsnamedata" would not be the same as "getavatarnamesdata" since "getavatarsnamedata" would be a command that queries multiple avatars whereas "getavatarnamesdata" would be a command that queries multiple names of an avatar.

A formation that contains two or more plurals but one and only one named plural is possible. For example, a fictive command "batchgetavatarsnamedata" could possibly be a command that would query the name of multiple avatars (plural avatars) within multiple parcels (named plural grouping).

Different UUIDs in Various Contexts

Although pertaining more to Linden grid design rather than Corrade, the meaning of UUIDs change depending on the executed commands. Items on the grid have different UUIDs, some of which can be accessed using a standard viewer and others that cannot.

For example, all objects in inventory have an inventory UUID that can be used to reference the objects when using inventory Corrade commands or even when sending the object to someone via the give command. However, the same object does not even have an asset UUID because objects do not have asset UUIDs (compared to, say, textures or sounds that can be downloaded via the download command where an asset UUID is required). If the object were to be rezzed in-world, then the grid will generate a random UUID for the in-world object (and the grid does so every time the same object is rezzed such that the UUID changes) and commands like touch require the in-world UUID to be passed to its parameters.

So far, using the example above, we have collected three different contexts where UUID may appear:

  • inventory UUIDs, pertaining to items inside an avatar inventory
  • asset UUIDs, pertaining to assets that can be retrieved via the asset server,
  • in-world object UUIDs, pertaining to objects that are rezzed in world

This list can now be shunted with avatar UUIDs, group UUIDs and others. Whenever a Corrade command is issued that takes (or can take) as parameter an UUID, it is important to ensure that the passed UUID matches the proper context. Doing otherwise, will not find the object that you are looking for, for example, attempting to de-rez an in-world object via its inventory UUID will fail because an in-world object is referred to by its in-world UUID. Commands should mention the type of UUID that is required on their corresponding API pages.

Inventory

All commands that must reference an inventory item, typically via the item parameter, can be referred to by either by inventory UUID or by inventory path.

Specifying Paths

One of the problems with Linden protocols is that inventory items may carry the same name, which is something that filesystems usually do not support, which makes referring to an item by name ambiguous. To overcome this problem, Corrade allows paths to inventory items to be built by name or by UUID or a combination thereof.

As an example, consider the following tree:

   + My Inventory (UUID: 7c38c488-5440-46c2-9f14-d5e3fcd0cc16)
   |
   +- Textures (UUID: 56a54ebe-7d4d-4839-a618-42ee3b307717)
         +
         |
         +- Floors (UUID: b13b0890-fac6-4085-975c-c2f760b185e4)
         |    +
         |    |
         |    +- Deck (UUID: 3e51dd70-9cd8-4dcf-9465-58c7036e673d)
         |
         +- Floors (UUID: c590792b-a724-4bb6-9f0c-81b6e733fad5)
              +
              |
              +- Table (UUID: 6eaffc93-df2a-479b-836b-4778bb917619)

If we wanted to list Deck via the inventory command and supposing that we are currently in My Inventory which is the root, then supplying /My Inventory/Textures/Floors/Deck to the path parameter would be ambiguous since it is uncertain which Floors folder should be browsed. To get rid of the Linden ambiguity, Corrade allows specifying UUIDs in the paths such that we are able to correctly reference Deck by supplying: /My Inventory/Textures/b13b0890-fac6-4085-975c-c2f760b185e4/Deck to the path parameter. Note that it is also possible to specify any of the other path components as UUIDs rather than by names - yet, in this case, that is not necessary: when you supply a name in the path, you are making a weak reference, when you are supplying an UUID you are making a strong reference.

Items that contain a forward-slash that would clash with the forward-slash (/) representing a path component can be escaped using a backslash (\). For instance, suppose that you have a texture named:

// Awesome Texture //

and that you want to reference it - you would then write:

"path" , wasURLEscape("/My Inventory/Textures/\/\/ Awesome Texture \/\/");

Alternatively, you can just use the UUID instead of the name.

Global Parameters

Corrade accepts some parameters that are considered to have a global scoping in that they apply to every command. The following is a list of global parameters that can be passed as part of certain sets of commands and with various effects on the command.

Parameter Value Context Description
timeout an integer (default 60000) all commands this parameter allows overriding the default Corrade timeout of $60s$ for the called command
target a string or UUID commands acting on groups this parameter allows referring to a different group whilst authenticating with a configured group

Supported Texture Image Formats

Grid clients such as Corrade download and upload textures to the grid in the JPEG2000 image format. The JPEG2000 image format is defined with various profiles, such that if the downloaded image is saved to a file and then inspected by the file or exiftool command line utilities, the detected image description should be:

JPEG2000 codestream

which indicates a Profile 0 JPEG2000 which is what the SecondLife grid is using.

The proper file extension for such images is "j2c" which stands for "JPEG2000 codestream". Some tools may not properly implement nor respect the file extension. One tool that manages to correctly convert images to "JPEG2000 codestream" is ImageMagick with the mogrify tool. For instance, supposing that an image x.png exists in the current directroy, then issuing the command:

mogrify -format "J2K" x.png

will result in a new image created x.j2k that, when inspected with the file tool:

file x.j2k

should output:

x.J2K: JPEG 2000 codestream

Other tools, such as ffmpeg will convert an image that when inspected with the file utility will read x.j2k: JPEG 2000 Part 1 (JP2) which will fail to upload with Corrade to SecondLife.

Furthermore, Corrade follows the SecondLife limits on texture uploads without any processing such that the user must ensure that the texture to be uploaded conforms to the specification.

One condition imposed by SecondLife is that the height and width of the image should be a power of 2 otherwise the image will not be uploaded. When uploading with a regular viewer, the viewer disguises a transformation that changes the image such that the width and height are a power of 2. However, when using Corrade, this transformation has to be performed beforehand in order for the upload to succeed.

Supported Sound Formats

Corrade uploads OGG Vorbis files with the same specification that is listed on the official wiki. In case the uploaded sound seems distorted please check that all the parameters have been met. Typically, the audio rate is the culprit for most sound distortions and one must make sure that the rate of the file to be uploaded is $44100Hz$.

The following is a referential example used as a control to check whether sound uploads work properly. First, a sound is downloaded off the grid from the inventory at /My Inventory Sounds/lemmeout using the download command:

curl --location --request POST 'http://CORRADE_HTTP_SERVER:CORRADE_HTTP_PORT' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'command=download' \
  --data-urlencode 'group=Wizardry and Steamworks' \
  --data-urlencode 'password=CORRADE_GROUP_PASSWORD' \
  --data-urlencode 'type=Sound' \
  --data-urlencode 'item=/My Inventory/Sounds/lemmeout'

where:

  • CORRADE_HTTP_SERVER the IP or hostname of the computer running Corrade,
  • CORRADE_HTTP_PORT the port that Corrade opens for HTTP commands,
  • CORRADE_GROUP_PASSWORD the group password for the group

resulting in the output:

command=download&time=2025-10-26T18%3A11%3A42.060396Z&data=T2dnUwACAAAAAAAAAACLpXTGAAAAAFB1DdYBHgF2b3JiaXMAAAAAARErAAAAAAAASHEAAAAAAACZAU9nZ1MAAAAAAAAAAAAAi6V0xgEAAAAUVRa2C0D%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2B1A3ZvcmJpcw0AAABMYXZmNTcuNDEuMTAwAQAAAB8AAABlbmNvZGVyPUxhdmM1Ny40OC4xMDEgbGlidm9yYmlzAQV2b3JiaXMSQkNWAQAAAQAMUhQhJRlTSmMIlVJSKQUdY1BbRx1j1DlGIWQQU4hJGaV7TyqVWErIEVJYKUUdU0xTSZVSlilFHWMUU0ghU9YxZaFzFEuGSQklbE2udBZL6JljljFGHWPOWkqdY9YxRR1jUlJJoXMYOmYlZBQ6RsXoYnwwOpWiQii%2Bx95S6S2FiluKvdcaU%2BsthBhLacEIYXPttdXcSmrFGGOMMcbF4lMogtCQVQAAAQAAQAQBQkNWAQAKAADCUAxFUYDQkFUAQAYAgAAURXEUx3EcR5IkywJCQ1YBAEAAAAIAACiO4SiSI0mSZFmWZVmWpnmWqLmqL%2FuuLuuu7eq6DoSGrAQAyAAAGIYhh95JzJBTkEkmKVXMOQih9Q455RRk0lLGmGKMUc6QUwwxBTGG0CmFENROOaUMIghDSJ1kziBLPejgYuc4EBqyIgCIAgAAjEGMIcaQcwxKBiFyjknIIETOOSmdlExKKK20lkkJLZXWIueclE5KJqW0FlLLpJTWQisFAAAEOAAABFgIhYasCACiAAAQg5BSSCnElGJOMYeUUo4px5BSzDnFmHKMMeggVMwxyByESCnFGHNOOeYgZAwq5hyEDDIBAAABDgAAARZCoSErAoA4AQCDJGmapWmiaGmaKHqmqKqiKKqq5Xmm6ZmmqnqiqaqmqrquqaqubHmeaXqmqKqeKaqqqaqua6qq64qqasumq9q26aq27MqybruyrNueqsq2qbqybqqubbuybOuuLNu65Hmq6pmm63qm6bqq69qy6rqy7Zmm64qqK9um68qy68q2rcqyrmum6bqiq9quqbqy7cqubbuyrPum6%2Bq26sq6rsqy7tu2rvuyrQu76Lq2rsqurquyrOuyLeu2bNtCyfNU1TNN1%2FVM03VV17Vt1XVtWzNN1zVdV5ZF1XVl1ZV1XXVlW%2FdM03VNV5Vl01VlWZVl3XZlV5dF17VtVZZ9XXVlX5dt3fdlWdd903V1W5Vl21dlWfdlXfeFWbd93VNVWzddV9dN19V9W9d9YbZt3xddV9dV2daFVZZ139Z9ZZh1nTC6rq6rtuzrqizrvq7rxjDrujCsum38rq0Lw6vrxrHrvq7cvo9q277w6rYxvLpuHLuwG7%2Ft%2B8axqaptm66r66Yr67ps675v67pxjK6r66os%2B7rqyr5v67rw674vDKPr6roqy7qw2rKvy7ouDLuuG8Nq28Lu2rpwzLIuDLfvK8evC0PVtoXh1XWjq9vGbwvD0jd2vgAAgAEHAIAAE8pAoSErAoA4AQAGIQgVYxAqxiCEEFIKIaRUMQYhYw5KxhyUEEpJIZTSKsYgZI5JyByTEEpoqZTQSiilpVBKS6GU1lJqLabUWgyhtBRKaa2U0lpqKbbUUmwVYxAy56RkjkkopbRWSmkpc0xKxqCkDkIqpaTSSkmtZc5JyaCj0jlIqaTSUkmptVBKa6GU1kpKsaXSSm2txRpKaS2k0lpJqbXUUm2ttVojxiBkjEHJnJNSSkmplNJa5pyUDjoqmYOSSimplZJSrJiT0kEoJYOMSkmltZJKK6GU1kpKsYVSWmut1ZhSSzWUklpJqcVQSmuttRpTKzWFUFILpbQWSmmttVZrai22UEJroaQWSyoxtRZjba3FGEppraQSWympxRZbja21WFNLNZaSYmyt1dhKLTnWWmtKLdbSUoyttZhbTLnFWGsNJbQWSmmtlNJaSq3F1lqtoZTWSiqxlZJabK3V2FqMNZTSYikptZBKbK21WFtsNaaWYmyx1VhSizHGWHNLtdWUWouttVhLKzXGGGtuNeVSAADAgAMAQIAJZaDQkJUAQBQAAGAMY4xBaBRyzDkpjVLOOSclcw5CCCllzkEIIaXOOQiltNQ5B6GUlEIpKaUUWyglpdZaLAAAoMABACDABk2JxQEKDVkJAEQBACDGKMUYhMYgpRiD0BijFGMQKqUYcw5CpRRjzkHIGHPOQSkZY85BJyWEEEIppYQQQiillAIAAAocAAACbNCUWByg0JAVAUAUAABgDGIMMYYgdFI6KRGETEonpZESWgspZZZKiiXGzFqJrcTYSAmthdYyayXG0mJGrcRYYioAAOzAAQDswEIoNGQlAJAHAEAYoxRjzjlnEGLMOQghNAgx5hyEECrGnHMOQggVY845ByGEzjnnIIQQQueccxBCCKGDEEIIpZTSQQghhFJK6SCEEEIppXQQQgihlFIKAAAqcAAACLBRZHOCkaBCQ1YCAHkAAIAxSjknJaVGKcYgpBRboxRjEFJqrWIMQkqtxVgxBiGl1mLsIKTUWoy1dhBSai3GWkNKrcVYa84hpdZirDXX1FqMtebce2otxlpzzrkAANwFBwCwAxtFNicYCSo0ZCUAkAcAQCCkFGOMOYeUYowx55xDSjHGmHPOKcYYc8455xRjjDnnnHOMMeecc845xphzzjnnnHPOOeegg5A555xz0EHonHPOOQghdM455xyEEAoAACpwAAAIsFFkc4KRoEJDVgIA4QAAgDGUUkoppZRSSqijlFJKKaWUUgIhpZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoplVJKKaWUUkoppZRSSimlACDfCgcA%2FwcbZ1hJOiscDS40ZCUAEA4AABjDGISMOSclpYYxCKV0TkpJJTWMQSilcxJSSimD0FpqpaTSUkoZhJRiCyGVlFoKpbRWaymptZRSKCnFGktKqaXWMuckpJJaS622mDkHpaTWWmqtxRBCSrG11lJrsXVSUkmttdZabS2klFprLcbWYmwlpZZaa6nF1lpMqbUWW0stxtZiS63F2GKLMcYaCwDgbnAAgEiwcYaVpLPC0eBCQ1YCACEBAAQySjnnnIMQQgghUoox56CDEEIIIURKMeacgxBCCCGEjDHnIIQQQgihlJAx5hyEEEIIIYRSOucghFBKCaWUUkrnHIQQQgillFJKCSGEEEIopZRSSikhhBBKKaWUUkopJYQQQiillFJKKaWEEEIopZRSSimllBBCKKWUUkoppZQSQgihlFJKKaWUUkIIpZRSSimllFJKKCGEUkoppZRSSgkllFJKKaWUUkopIZRSSimllFJKKaUAAIADBwCAACPoJKPKImw04cIDEAAAAAIAAkwAgQGCglEIAoQRCAAAAAAACAD4AABICoCIiGjmDA4QEhQWGBocHiAiJAAAAAAAAAAAAAAAAARPZ2dTAATAJAAAAAAAAIuldMYCAAAALeyHaiZZX1taX19lWVtiZWNbYWFfYmNeX2BkY2VeXFxaWGZra2lkYmNaVKIdZqS6FQjUfrKz9b%2FE9o03G59vtjiRWGNm3uuYjfZuTp5Zfog2E1jrwGamgzyv623HyfNCQPpnS0SEOy2c4myN0lFjF5FvUXJFlkimfdiOwbioR3r930oDnh4ypr5nvgLwo5J69U6fPvt578cy2dHb1f4OozknaccubsHNZZMgRX8xvCU%2FxBz6Lau7etbXF6cwxJtHCikbmcu2zAo5jBjporwqk2XJtHSpvhgyiFhj2YL7t8fo6QSiH72Y2eWkAaKn0j298tY%2BjHdMjVZ98jzc3qz%2B9TM1nxikugsqIz%2Bn96tVGj0dCsKoFNJpenDYvb4IJENPuZcOEditCOWv2q7t7PPGuSXuyTTzur%2FiedgGqvhLlh%2BUPHUoQWoKwFf7lY3qu8Rx8%2FyVqVC4cMSaz0dypn7a6DQ6uGBOoKuD4Qll9WvcMWNR1FWsc0ocGLN7bagZHUPOd%2FJpSeLj4h9Jbjb1uwQmS2VYNXaE7ooLlu%2B%2BZqOzbAAHEwB1Aeylnz58Zd2%2BNcv%2BP7Yfc0w8fdUU5ezVbnV%2FHasYQjX9dIzRshlRL28eGE1Vazpx6PQra0bbqLZJdojz4OxEBiNkUEu%2BFfirwMDo5UEb554Y3XCecS%2FkB8DwPgCoCVAKgLz4GXmahuay1c7Ot3pjXZPrCjJ0CX67rf3XC5RPCN4o1UU7ISnrod%2FByvI0PmAiZ69j1P33Mv6NwKl2YdjfNkBp0y4kvvAjfeESTa%2BhOivJMqasAa1mLgBA7QB1gwMQcByUzivrizp7tsmGJ48WxSDMZce%2Ff75yyWf6NGtxKnqLhC5%2BfPe%2Bnj3POZ4tu%2FWxRrXZ5Tbse%2BTTH4%2BR6XgYK%2FrUj6474HA%2FLDGJKLCH4tMYxZ1H5K4GnqmE16dxrrE60MAAGgfcMzX6Pevg%2F2UuwqPB4qjVY5LfrQtkF1vNNXx5NFWzeFxMIPPW10%2Fmt2amDQAxaqz%2Fjm%2FS3rW3S2sAlSB%2B%2FhvmJmQ%2Bx4tQ5B%2F%2BjgOaqDTv7ASfFaCLUHssAHpWJKLsOtGxeq1m3S%2FHvMRp6xc%2F0lknjNaawMDzSt3AFDAw8eap%2Fr9OAjGU5%2FUtYnRij5Sg2YyE9%2B%2F%2FH8cMJUjsjN1qC6ssCVE4iI8ApmoPpU%2BQlaD%2FEAAPAFfgcAwAwPmoiwKr2%2BlM1sLO01QLIDkdGWhPbCWAGE5Ol0qOi%2BXvNpnh12QEhJ7rEwLByIoz%2F3HPVAEPGWD4MBiAjw%2BL%2BgOda5052bL7KB%2FR9%2BKRxQCi7FUplIA9D7AfjIEZFKA2QANoTY1KpFv6I0PefLu7oFjtRdD289l2Pxxat58teK1izsLq4suZScWDtJxBRgtU05TU%2BTwk8vWUowM8lk8D9mbONwwAebOsBnaXh75xFNpu7OVRA6Jsa609EOA8sUQDwwGA78d1wRXLg%2FlKG3vb9A4Q%2FEOnWmO1FxVYRRW%2F89%2BLm9TUxETZvtjSE0aJbkeq6ei33cfvJ9sHzmaQghQBseuf3%2F2EdE4TJbRLnIY5y533KZIpOrJMxKKtQSoPgD5XHYAKEAJ4JN1ovR8OXatwNtnpgdHEdnCaKNBGCs9fPwCJYbk%2FM8bXMkp1IkUeTI1W0iV5p7cP5fVYetfJXTMoh9Frq%2BeCnnz1JYvXJHdCqfs1swKabXcSPYuGzyE5HiYBX4Die3sN1AX%2FfRM2%2B5M5Ia33O5qEOzc9wKgj1Nl%2FfQQPlsnJCClJ1dWDP%2FXc4NZaJ%2BdSP%2F7%2B4oZrit%2FGPsuRYTY3izFxG31WIUIJlahiufbWCyUenqlp%2FvLgSTTovgrrAAGoG8AzW6lbBZ%2BmsdA4NyEc3V7ox79JIPYIPtozFXYVqN4ssG6rVEvd6AAChubVbjdX8vmXEd%2BRzWho1g6fc2Gs0rAo1xtQ5%2FtHRXF%2Bf3%2Bj65xxAJ6pofIyzlUIwDrgaWADp4CC3vGttm4MxvDKq621s%2BnTguokwcM1qJ3XtwOYgK9NluNfzRF9SwguKuUwBq296FHyv0ntJrwSumovUyEvHR5vFdrtiMw2HE7JkOq0V2Y8mqmU10pzoSctARkFs8HhB8b5q1c6gz73e4M%2B%2BTeGd4c%2Fpe3dSRcAQ9gfDWH9ny%2F%2FbfdSwkhc5I7zsyZwMpVHWbJd9jgCyQzNw6tvnv7%2BDrdY1Hrb6qUKFi%2B8uRYP78hZFwKWbVekl4CtKiQ1MAKgA9MCB28zLmdLrwmdv6kuYZ2nDkx8HSBYIvhNKvXcfBXaygBOgjrre6mjB2Y%2FtQCa6Vycd1MT3796zybvmGmAWq4Ghzpuqc7Mnw4YMX9LvRnFFZisFBWSrn38JVZVzQQiBaACpJm4dP%2F5hi5P3p2afvdtjsu9pGvMmWpZvLQtQ8rOrwdEQbIuFS3Z5mZ72haTKZmyxzL3yBwohzkrOZ%2FZbhZmJa0UwSlVLRz1YdbTFGwgrRJwkq0dVLOwg5ppBbDJV1b9vzRqeGitkzs8jYm9ZN1a7NAcO6HPxyPJj9FgXQa5rzBf84mi72cXHYRlkVfX%2BWWIQgKA9k6na%2Bn95YbnzfG7E0%2Fl0jL8%2BU%2F%2B7tR3AJQckgCWLAYyXPAJqADqAQeg%2F8GBp72kP143OHT6tG5vRA1aXr1r0swMO5r5sJa5Y2SXiNcF8exlJ7k6Y%2FFOz9A79JMCcVdxj6y%2B478Bh99SRgIQKG2kp30f5m0%2B19MtHavSrg6WriTroK4IwKCDc2DCg5je5uWWWXcxZ26tqR%2BJePogKndESQClUAn8pmdd31tX3eRFF08NYvxIMfO30aqBntg8N29s%2FvZVdYhh16ME1MvY6Xf0HCJHQLlfPzyPn7NNBLFqDqYNkmw19eEdAagwBhsT1LMvn6bPz7j52Nf6Sr%2BEvl2V7rjEJ5ItZEArq8eLIfzbZ8r1cK4W7y65s9sn1bVLiyGDkX7%2BPfnnF2kOyNuml7rIvMOtREN7JT4YhCkdFvO4%2B1hGsHQMlqtxIDXvzKACsDGwIabbOXShrxr29%2Bz6ntiEky1Zy%2BhwOrnz6yBtz2QvLiuLn3yR%2Fp0l2z5f4QvhS0ANWaxJCqgT%2BzR61lmBTNOHgPTRl0rWUV5kkZDbPO5gKrUtNvCF0jNyhgSWa5bElJcdAN8GpJ9%2B7efLPrdias94vF0W89K1GMfM3dES0WFHi8nDqQGRJ51x2oeYmFnv5DthcKkMYN44DfCz0eWxs3g75M66GrWMXr9fvhU1P1ZbuJ0ffvPDFOQDlqcrjQMAvjoDwH523y9WF8PZXZ1M96R71d9sd05s56bITsXcRE6jrCyXkoerPB4eHw87mCM%2B%2B9bpcuX0OnxteQW5n78U8M2pV1rcOvZmqxMufrDGzvjPZfhAUDSOYda0zNLKpSDURLWv0fj1PXVCVI%2Fc68NmMz%2FSymfmHN%2FFeOh22fzlkixduW3i%2FTyHKyL4zsi8AIN7UmpeElQjadE6VaTX%2BVIuKNnk%2FFRNeuga6u3c5mExsOumAJKhqGAcKABfrcw%2BOXK0bxw%2B%2FPD7dkynjL9VoLJEkajaNIOpJoqCXonujf2tlpzIHDWuxM%2F0Yf2vTHr6%2BqIwyc4oaCdH8QGZXgdeHEfiF7bk6NbG7cXGBFw3N5KkB2qWl4M4psoVa%2FefPV9VT%2F1Kn3ii7ef%2ForAe9JZs9GZkVkewuWcdu0fu40%2FVSknKjD3ckVz5O9vS0zAve5xdhF3H1%2Fs5O80D2%2BG4jcD98%2Fup3MWrhRiWKzbLJzTOQAgQmUCzSC8awED3d758ZuvUza1007WknS2jz%2FYN%2FW2FEhNaWCpK79vl%2Fz39s6%2FSfp38fX0yjQ4JDy1od0CNL%2BeNs7sISCPu18KiHE%2BFBrIBNTbpjGLx7KfXZEjH0ACaLXdwSwDq6hyD4QFAA6QGeJ04XWwl0pSR10nR1Ky0NUzG0Xz2V%2FNVr%2BSQWOWT36lHrC0GIJaPG4vkiYnz559%2FrqccnH3Zu%2BUfc9kZVkbPfmzaJqa9fBUwjUiLtfb29XBTyFGx7sd5FnUjE6KqlPfDolHfPQCD8YX4B2y4QgEQO3ft1%2BWRbWbOB3v3HSbfaDBSIcwFBCG0MEx86368sj1fnrR%2F8PmXdw8ZnQuNQAlVYSzt4yvLarz1z8ky4qEHTn19maeQsDwa84KxJ%2F64q9LQwvTMBLkDmmlXmR5qJCpRAAMbvSuKKlj9lD3y8Z9qvVdUFvfdzcVaKi2qUmgBzUuaJ7P1%2Fer%2B%2FYnP%2F3xf%2FPrn5%2B9X7NKsJ5WGt0PHmm39fPdkBABWh2io0D18J95yxjkI5uTz5fIwG2omTuyEunYflmc%2FpCZYajdg68XhTPj%2BbPuTy%2F80XZ968rZ2NHn%2Fa1loZKnQsTwZ6uzPwbHUy1f%2B6I%2BZNiKiyMfK2W7kbrQ5WbS3IhMavPDG6XDwdnJd7tJe4debdJ3u4XsCjIqlpp6uo%2FKJfZrntVay8QDBhgFb36A4UBUA%2Bveug%2BvWo0pqtrNr9iZqccxxLCfz6fNy7fr%2Ftr%2Bubrb%2Bm9oM6Ph8vnbYdRtY1ypMq95M8VngdIlGGi63yCTXD6fL2SzD3PZ2%2Bv3wCSJbxC4NmuQVo94qAaAAcQCXFJZOQPHT78NUtz4ju6gYxO65NvW9SlBkKaKcNPtQi0ib1FHDo9%2BXl5c9S63m3Mn6TEnH4kgtWjLc76OeZXKLMugZYWoRELvGQ3VGlRwdy9wxAdF5OyQNnqSbTYHTOdBAQHG9yZTZnZ%2B9etfl6OHfz17vdzYkWXi85PDhbQvnxrDuiVT9V9J6Q1jsmAxS5f5ykkI3Z2TYT%2F6vjfmtFv1sKc5sZPAw3dlDKY9Iq1UL0d8AiqI%2BUlkDNWNlbP66dvPf7CZ7h6cnJ81nwUms0vnNAhemuc%2Fjdl0yk5J8eWnzJGzCnQDgGAAyu6gfcxG25bKWS%2Fv%2BbgdXshPqbyn4hgkkJMC4vWQx&success=True&name=TestUpload

note that the value of the data key that is supposed to contain the file is first Base64 encoded and then application/x-www-form-urlencoded such that to be able to decode this file, one must first form-unescape the string and then decode the Base64 string. Using the Linux command line, this would be:

alias urldecode='sed "s@+@ @g;s@%@\\\\x@g" | xargs -0 printf "%b"'

followed by:

echo INPUT | urldecode | base64 -d > sound.ogg

where:

  • INPUT is the entire string value of the data key from the download command return.

The file that was downloaded is the following:

The previous command should create the sound.ogg file that can be queried, say with ffprobe:

Input #0, ogg, from 'sound.ogg':
  Duration: 00:00:00.85, start: 0.000000, bitrate: 59 kb/s
    Stream #0:0: Audio: vorbis, 11025 Hz, mono, fltp, 29 kb/s
    Metadata:
      encoder         : Lavc57.48.101 libvorbis

Now, to perform the converse operation, encode the sound with Base64 and form-escape it in order:

curl --location --request POST 'http://CORRADE_HTTP_SERVER:CORRADE_HTTP_PORT' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'command=upload' \
--data-urlencode 'group=Wizardry and Steamworks' \
--data-urlencode 'password=...' \
--data-urlencode 'name=FILENAME' \
--data-urlencode 'type=Sound' \
--data-urlencode 'data=T2dnUwACAAAAAAAAAACLpXTGAAAAAFB1DdYBHgF2b3JiaXMAAAAAARErAAAAAAAASHEAAAAAAACZ
AU9nZ1MAAAAAAAAAAAAAi6V0xgEAAAAUVRa2C0D///////////+1A3ZvcmJpcw0AAABMYXZmNTcu
NDEuMTAwAQAAAB8AAABlbmNvZGVyPUxhdmM1Ny40OC4xMDEgbGlidm9yYmlzAQV2b3JiaXMSQkNW
AQAAAQAMUhQhJRlTSmMIlVJSKQUdY1BbRx1j1DlGIWQQU4hJGaV7TyqVWErIEVJYKUUdU0xTSZVS
lilFHWMUU0ghU9YxZaFzFEuGSQklbE2udBZL6JljljFGHWPOWkqdY9YxRR1jUlJJoXMYOmYlZBQ6
RsXoYnwwOpWiQii+x95S6S2FiluKvdcaU+sthBhLacEIYXPttdXcSmrFGGOMMcbF4lMogtCQVQAA
AQAAQAQBQkNWAQAKAADCUAxFUYDQkFUAQAYAgAAURXEUx3EcR5IkywJCQ1YBAEAAAAIAACiO4SiS
I0mSZFmWZVmWpnmWqLmqL/uuLuuu7eq6DoSGrAQAyAAAGIYhh95JzJBTkEkmKVXMOQih9Q455RRk
0lLGmGKMUc6QUwwxBTGG0CmFENROOaUMIghDSJ1kziBLPejgYuc4EBqyIgCIAgAAjEGMIcaQcwxK
BiFyjknIIETOOSmdlExKKK20lkkJLZXWIueclE5KJqW0FlLLpJTWQisFAAAEOAAABFgIhYasCACi
AAAQg5BSSCnElGJOMYeUUo4px5BSzDnFmHKMMeggVMwxyByESCnFGHNOOeYgZAwq5hyEDDIBAAAB
DgAAARZCoSErAoA4AQCDJGmapWmiaGmaKHqmqKqiKKqq5Xmm6ZmmqnqiqaqmqrquqaqubHmeaXqm
qKqeKaqqqaqua6qq64qqasumq9q26aq27MqybruyrNueqsq2qbqybqqubbuybOuuLNu65Hmq6pmm
63qm6bqq69qy6rqy7Zmm64qqK9um68qy68q2rcqyrmum6bqiq9quqbqy7cqubbuyrPum6+q26sq6
rsqy7tu2rvuyrQu76Lq2rsqurquyrOuyLeu2bNtCyfNU1TNN1/VM03VV17Vt1XVtWzNN1zVdV5ZF
1XVl1ZV1XXVlW/dM03VNV5Vl01VlWZVl3XZlV5dF17VtVZZ9XXVlX5dt3fdlWdd903V1W5Vl21dl
WfdlXfeFWbd93VNVWzddV9dN19V9W9d9YbZt3xddV9dV2daFVZZ139Z9ZZh1nTC6rq6rtuzrqizr
vq7rxjDrujCsum38rq0Lw6vrxrHrvq7cvo9q277w6rYxvLpuHLuwG7/t+8axqaptm66r66Yr67ps
675v67pxjK6r66os+7rqyr5v67rw674vDKPr6roqy7qw2rKvy7ouDLuuG8Nq28Lu2rpwzLIuDLfv
K8evC0PVtoXh1XWjq9vGbwvD0jd2vgAAgAEHAIAAE8pAoSErAoA4AQAGIQgVYxAqxiCEEFIKIaRU
MQYhYw5KxhyUEEpJIZTSKsYgZI5JyByTEEpoqZTQSiilpVBKS6GU1lJqLabUWgyhtBRKaa2U0lpq
KbbUUmwVYxAy56RkjkkopbRWSmkpc0xKxqCkDkIqpaTSSkmtZc5JyaCj0jlIqaTSUkmptVBKa6GU
1kpKsaXSSm2txRpKaS2k0lpJqbXUUm2ttVojxiBkjEHJnJNSSkmplNJa5pyUDjoqmYOSSimplZJS
rJiT0kEoJYOMSkmltZJKK6GU1kpKsYVSWmut1ZhSSzWUklpJqcVQSmuttRpTKzWFUFILpbQWSmmt
tVZrai22UEJroaQWSyoxtRZjba3FGEppraQSWympxRZbja21WFNLNZaSYmyt1dhKLTnWWmtKLdbS
UoyttZhbTLnFWGsNJbQWSmmtlNJaSq3F1lqtoZTWSiqxlZJabK3V2FqMNZTSYikptZBKbK21WFts
NaaWYmyx1VhSizHGWHNLtdWUWouttVhLKzXGGGtuNeVSAADAgAMAQIAJZaDQkJUAQBQAAGAMY4xB
aBRyzDkpjVLOOSclcw5CCCllzkEIIaXOOQiltNQ5B6GUlEIpKaUUWyglpdZaLAAAoMABACDABk2J
xQEKDVkJAEQBACDGKMUYhMYgpRiD0BijFGMQKqUYcw5CpRRjzkHIGHPOQSkZY85BJyWEEEIppYQQ
QiillAIAAAocAAACbNCUWByg0JAVAUAUAABgDGIMMYYgdFI6KRGETEonpZESWgspZZZKiiXGzFqJ
rcTYSAmthdYyayXG0mJGrcRYYioAAOzAAQDswEIoNGQlAJAHAEAYoxRjzjlnEGLMOQghNAgx5hyE
ECrGnHMOQggVY845ByGEzjnnIIQQQueccxBCCKGDEEIIpZTSQQghhFJK6SCEEEIppXQQQgihlFIK
AAAqcAAACLBRZHOCkaBCQ1YCAHkAAIAxSjknJaVGKcYgpBRboxRjEFJqrWIMQkqtxVgxBiGl1mLs
IKTUWoy1dhBSai3GWkNKrcVYa84hpdZirDXX1FqMtebce2otxlpzzrkAANwFBwCwAxtFNicYCSo0
ZCUAkAcAQCCkFGOMOYeUYowx55xDSjHGmHPOKcYYc8455xRjjDnnnHOMMeecc845xphzzjnnnHPO
Oeegg5A555xz0EHonHPOOQghdM455xyEEAoAACpwAAAIsFFkc4KRoEJDVgIA4QAAgDGUUkoppZRS
SqijlFJKKaWUUgIhpZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkop
pZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWU
UkoplVJKKaWUUkoppZRSSimlACDfCgcA/wcbZ1hJOiscDS40ZCUAEA4AABjDGISMOSclpYYxCKV0
TkpJJTWMQSilcxJSSimD0FpqpaTSUkoZhJRiCyGVlFoKpbRWaymptZRSKCnFGktKqaXWMuckpJJa
S622mDkHpaTWWmqtxRBCSrG11lJrsXVSUkmttdZabS2klFprLcbWYmwlpZZaa6nF1lpMqbUWW0st
xtZiS63F2GKLMcYaCwDgbnAAgEiwcYaVpLPC0eBCQ1YCACEBAAQySjnnnIMQQgghUoox56CDEEII
IURKMeacgxBCCCGEjDHnIIQQQgihlJAx5hyEEEIIIYRSOucghFBKCaWUUkrnHIQQQgillFJKCSGE
EEIopZRSSikhhBBKKaWUUkopJYQQQiillFJKKaWEEEIopZRSSimllBBCKKWUUkoppZQSQgihlFJK
KaWUUkIIpZRSSimllFJKKCGEUkoppZRSSgkllFJKKaWUUkopIZRSSimllFJKKaUAAIADBwCAACPo
JKPKImw04cIDEAAAAAIAAkwAgQGCglEIAoQRCAAAAAAACAD4AABICoCIiGjmDA4QEhQWGBocHiAi
JAAAAAAAAAAAAAAAAARPZ2dTAATAJAAAAAAAAIuldMYCAAAALeyHaiZZX1taX19lWVtiZWNbYWFf
YmNeX2BkY2VeXFxaWGZra2lkYmNaVKIdZqS6FQjUfrKz9b/E9o03G59vtjiRWGNm3uuYjfZuTp5Z
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
bgdXshPqbyn4hgkkJMC4vWQx
'

where:

  • CORRADE_HTTP_SERVER the IP or hostname of the computer running Corrade,
  • CORRADE_HTTP_PORT the port that Corrade opens for HTTP commands,
  • CORRADE_GROUP_PASSWORD the group password for the group,
  • FILENAME the name of the asset that will be created inside Corrade's inventory in-world

Note here that cURL has some nifty command line parameters like --data-urlencode that allow encoding and decode of the Base64 string.

If you wonder why the Base64 string has to be escaped, this is due to key-value pairs being used that will break in case Base64 emits equal signs which is part of its language.

Index


secondlife/scripted_agents/corrade/scripting_considerations.txt ยท Last modified: by office

Wizardry and Steamworks

© 2025 Wizardry and Steamworks

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


For the contact, copyright, license, warranty and privacy terms for the usage of this website please see the contact, license, privacy, copyright.