Parasol Framework
  • Gallery
  • API
  • Wiki
  • GitHub
    • Audio
    • Core
    • Display
    • Fluid
    • Font
    • Network
    • Vector
    • Audio
    • Sound
    • File
    • MetaClass
    • Module
    • StorageDevice
    • Task
    • Thread
    • Time
    • Compression
    • Config
    • Script
    • XML
    • Controller
    • BlurFX
    • ColourFX
    • CompositeFX
    • ConvolveFX
    • DisplacementFX
    • FilterEffect
    • FloodFX
    • ImageFX
    • LightingFX
    • MergeFX
    • MorphologyFX
    • OffsetFX
    • RemapFX
    • SourceFX
    • TurbulenceFX
    • WaveFunctionFX
    • Scintilla
    • ScintillaSearch
    • Bitmap
    • Clipboard
    • Display
    • Document
    • Font
    • Picture
    • Pointer
    • Surface
    • SVG
    • ClientSocket
    • HTTP
    • NetSocket
    • Proxy
    • Vector
    • VectorClip
    • VectorColour
    • VectorEllipse
    • VectorFilter
    • VectorGradient
    • VectorGroup
    • VectorImage
    • VectorPath
    • VectorPattern
    • VectorPolygon
    • VectorRectangle
    • VectorScene
    • VectorShape
    • VectorSpiral
    • VectorText
    • VectorTransition
    • VectorViewport
    • VectorWave

Document Class

Provides document display and editing facilities.

The Document class offers a complete page layout engine, providing rich text display features for creating complex documents and text-based interfaces. Internally, document data is maintained as a serial byte stream and all object model information from the source is discarded. This simplification of the data makes it possible to edit the document in-place, much the same as any word processor. Alternatively it can be used for presentation purposes only, similarly to PDF or HTML formats. Presentation is achieved by building a vector scene graph in conjunction with the Vector module. This means that the output is compatible with SVG and can be manipulated in detail with our existing vector API. Consequently, document formatting is closely integrated with SVG concepts and seamlessly inherits SVG functionality such as filling and stroking commands.

The native document format in Parasol is RIPL. Documentation for RIPL is available in the Parasol Wiki. Other document formats may be supported as sub-classes, but bear in mind that document parsing is a one-way trip and stateful information such as the HTML DOM is not supported.

The Document class does not include a security barrier in its current form. Documents that include scripted code should not be processed unless they originate from a trusted source and are confirmed as such. To mitigate security problems, we recommend that the application is built with some form of sandbox that can prevent the system being compromised by bad actors. Utilising a project such as Win32 App Isolation https://github.com/microsoft/win32-app-isolation is one potential way of doing this.

Structure

The Document class consists of the following fields:

Access
NameTypeComment
  AuthorSTRINGThe author(s) of the document.

If a document declares the names of its author(s) under a head tag, the author string will be readable from this field. This field is always NULL if a document does not declare an author string.

  ClientScriptOBJECTPTRAllows an external script object to be used by a document file.

Set ClientScript with a Script object to allow document content to 'breach the firewall' and access functionality outside of its namespace. This feature is primarily intended for applications that need to interact with their own embedded documents.

If a document defines a default script in its content, it will have priority over the one referenced here.

  CopyrightSTRINGCopyright information for the document.

If a document declares copyright information under a head tag, the copyright string will be readable from this field. This field is always NULL if a document does not declare a copyright string.

  DescriptionSTRINGA description of the document, provided by its author.

If the source document includes a description, it will be copied to this field.

  ErrorERRThe most recently generated error code.

The most recently generated error code is stored in this field.

  EventCallbackFUNCTIONProvides callbacks for global state changes.

Set this field with a function reference to receive event notifications. It must be set in conjunction with EventMask so that notifications are limited to those of interest.

The callback function prototype is ERR Function(*Document, DEF EventFlag, KEYVALUE *EventData).

The EventFlag value will indicate the event that occurred. Please see the EventMask field for a list of supported events and additional details.

Error codes returned from the callback will normally be discarded, however in some cases ERR::Skip can be returned in order to prevent the event from being processed any further.

  EventMaskDEFSpecifies events that need to be reported from the Document object.

To receive event notifications, set EventCallback with a function reference and the EventMask field with a mask that indicates the events that need to be received.

NameDescription
DEF::LINK_ACTIVATEDThe user has interacted with a hyperlink. This event can be cancelled by returning ERR::Skip.
DEF::ON_CLICKThe user has interacted with an element that has an on-click definition.
DEF::ON_CROSSINGSynonym for ON_CROSSING_IN | ON_CROSSING_OUT
DEF::ON_CROSSING_INThe mouse pointer has crossed into an element.
DEF::ON_CROSSING_OUTThe mouse pointer has crossed out of an element.
DEF::ON_MOTIONThe user has triggered a motion event in an element that supports motion monitoring.
DEF::PATHThe source file path has changed. Useful for detecting when the user has left the page.
DEF::WIDGET_STATEThe state value of a widget has changed (e.g. input, checkbox, text). name and value keys will be defined in the event parameters.
  FlagsDCFOptional flags that affect object behaviour.
NameDescription
DCF::DISABLEDThis read-only flag is set if the UI has been disabled through the Disable action.
DCF::EDITAllow direct keyboard input and document editing.
DCF::NO_LAYOUT_MSGTurn off debug output produced during document layout and processing - useful on refresh for example.
DCF::NO_SYS_KEYSSystem-keys provide standard key support for Ctrl-C, Ctrl-X etc. Set this flag to turn them off.
DCF::OVERWRITEThis flag forces overwrite mode when the user enters information through the keyboard. If the flag is not set, then insert mode is used.
DCF::UNRESTRICTEDTurn off all security measures - may only be set prior to initialisation.
  Focus*VectorViewportRefers to the object that will be monitored for user focusing.

By default, a document object will become active (i.e. capable of receiving keyboard input) when its surface container receives the focus. If you would like to change this so that a document becomes active when some other object receives the focus, refer to that object by writing its ID to this field.

  KeywordsSTRINGIncludes keywords declared by the source document.

If a document declares keywords under a head tag, the keywords string will be readable from this field. This field is always NULL if a document does not declare any keywords. It is recommended that keywords are separated with spaces or commas. It should not be assumed that the author of the document has adhered to the accepted standard for keyword separation.

  OriginSTRINGSimilar to the Path field, but does not automatically load content if set.

This field is identical to the Path field, with the exception that it does not update the content of a document object if it is set after initialisation. This may be useful if the location of a loaded document needs to be changed without causing a load operation.

  Page*VectorViewportThe Page contains the document content and is hosted by the View
  PageHeightINTMeasures the page height of the document, in pixels.

The exact height of the document is indicated in the PageHeight field. This value includes the top and bottom page margins.

  PageWidthINTMeasures the page width of the document, in pixels.

The page width indicates the width of the longest document line, including left and right page margins. Although the PageWidth can be pre-defined by the client, a document can override this value at any time when it is parsed. If imposing fixed page dimensions is desired, consider setting the Width and Height values of the View viewport object instead.

  PathSTRINGIdentifies the location of a document file to load.

To load a document file into a document object, set the Path field. Valid string formats for setting the path are:

volume:folder/filename.rpl

#page_name?param1&param2=value

volume:folder/filename.rpl#page_name?param1&param2=value

Setting this field post-initialisation will cause a complete reload unless the path begins with a hash to signal a change to the current page and parameters. Note: if a requested page does not exist in the currently loaded document, a dialog is displayed to bring the error to the user's attention).

To leap to a bookmark in the page that has been specified with the <index> element, use the colon as a separator after the pagename, i.e. #pagename:bookmark.

Other means of opening a document include loading the data manually and passing it via the DataFeed() action.

  PretextSTRINGExecute the XML defined here prior to loading new pages.

Use the Pretext field to execute document code prior to the loading of a new document. This feature is commonly used to configure a document in advance, such as setting default font values and background graphics. It is functionally equivalent to embedding an statement at the top of a document, but with the benefit of guaranteeing continued execution if the user navigates away from the first page.

A Pretext will always survive document unloading and resets. It can be removed only by setting this field with NULL.

  TabFocusOBJECTIDAllows the user to hit the tab key to focus on other GUI objects.

If this field points to a TabFocus object, the user will be able to move between objects that are members of the TabFocus by pressing the tab key. Please refer to the TabFocus class for more details.

  TitleSTRINGThe title of the document.

If a document declares a title under a head tag, the title string will be readable from this field. This field is always NULL if a document does not declare a title.

  View*VectorViewportThe viewing area of the document.

The view is an internally allocated viewport that hosts the document Page. Its main purpose is to enforce a clipping boundary on the page. By default, the view dimensions will always match that of the parent Viewport. If a fixed viewing size is desired, set the Width and Height fields of the View's VectorViewport after the initialisation of the document.

  Viewport*VectorViewportA client-specific viewport that will host the document graphics.

The Viewport field must refer to a VectorViewport that will host the document graphics. If undefined by the client, the nearest viewport container will be determined based on object ownership.

  WorkingPathSTRINGDefines the working path (folder or URI).

The working path for a document is defined here. By default this is defined as the location from which the document was loaded, without the file name. If this cannot be determined, the working path for the parent task is used (this is usually set to the location of the parasol executable).

The working path is always fully qualified with a slash or colon at the end of the string.

The client can manually change the working path by setting the Origin field without affecting the loaded document.

Actions

The following actions are currently supported:

ActivateActivates all child objects of the document.
ERR acActivate(*Object)

Calling the Activate() action on a document object will forward Activate() calls to its child objects.

ClearClears all content from the object.
ERR acClear(*Object)

Using the Clear() action will delete all of the document's content. The UI will be updated to reflect a clear document.

ClipboardFull support for clipboard activity is provided through this action.
ERR acClipboard(*Object, OBJECTID Clipboard, CLIPMODE Mode)
ParameterDescription
ModeThe mode that will be used to shift data between the target object and clipboard system.
DataFeedDocument data can be sent and consumed via feeds.
ERR acDataFeed(*Object, OBJECTID Object, DATA Datatype, APTR Buffer, INT Size)
ParameterDescription
ObjectMust refer to the unique ID of the object that you represent. If you do not represent an object, set this parameter to the current task ID.
DatatypeThe type of data being sent.
BufferThe data being sent to the target object.
SizeThe size of the data in Buffer.

Appending content to an active document can be achieved via the data feed feature. The Document class currently supports the DATA::TEXT and DATA::XML types for this purpose.

Error Codes
OkayOperation successful.
AllocMemoryThe Document's memory buffer could not be expanded.
MismatchThe data type that was passed to the action is not supported by the Document class.
NullArgsFunction call missing argument value(s)
DisableDisables user interactivity.
DrawForce a page layout update (if changes are pending) and redraw to the display.
ERR acDraw(*Object, DOUBLE X, DOUBLE Y, DOUBLE Width, DOUBLE Height)
ParameterDescription
XThe X position of the region to be drawn.
YThe Y position of the region to be drawn.
WidthThe width of the region to be drawn.
HeightThe height of the region to be drawn.
EnableEnables object functionality.
FocusSets the user focus on the document page.
GetKeyRetrieves global variables and URI parameters.
ERR acGetKey(*Object, CSTRING Key, STRING Value, INT Size)
ParameterDescription
KeyThe name of a key value.
ValuePointer to a buffer space large enough to hold the retrieved value.
SizeIndicates the byte size of the Buffer.

Use GetKey() to access the global variables and URI parameters of a document. Priority is given to global variables if there is a name clash.

The current value of each document widget is also available as a global variable accessible from GetKey(). The key-value will be given the same name as that specified in the widget's element.

RefreshReloads the document data from the original source location.
SaveToObjectUse this action to save edited information as an XML document file.
ERR acSaveToObject(*Object, OBJECTID Dest, CLASSID ClassID)
ParameterDescription
DestRefers to an object that will receive the encoded data.
ClassIDCan refer to a sub-class that should be used when encoding the data.
SetKeySet a global key-value in the document.
ERR acSetKey(*Object, CSTRING Key, CSTRING Value)
ParameterDescription
KeyThe name of the target key.
ValueThe string value to associate with Key.

Methods

The following methods are currently supported:

AddListenerAdds a listener to a document trigger for receiving special callbacks.
ERR doc::AddListener(OBJECTPTR Object, DRT Trigger, FUNCTION * Function)
ParameterDescription
TriggerThe unique identifier for the trigger.
FunctionThe function to call when the trigger activates.

Use the AddListener() method to receive feedback whenever a document event is triggered. Triggers are a fundamental part of document page development, accessible through the <trigger/> tag. Triggers are normally configured within the document's page code, however if you need to monitor triggers from outside the loaded document's code, then AddListener() will give you that option.

The following triggers are supported:

NameDescription
BEFORE_LAYOUTDocument layout is about to be processed. C/C++: void BeforeLayout(*Caller, *Document, LONG ViewWidth, LONG ViewHeight)
AFTER_LAYOUTDocument layout has been processed. C/C++: void AfterLayout(*Caller, *Document, LONG ViewWidth, LONG ViewHeight, LONG PageWidth, LONG PageHeight)
USER_CLICKUser has clicked the document.
USER_CLICK_RELEASEUser click has been released.
USER_MOVEMENTUser is moving the pointer over the document.
REFRESHPage has been refreshed. C/C++: void Refresh(*Caller, *Document)
GOT_FOCUSThe document has received the focus. C/C++: void GotFocus(*Caller, *Document)
LOST_FOCUSThe document has lost the focus. C/C++: void LostFocus(*Caller, *Document)
LEAVING_PAGEThe currently loaded page is closing (either a new page is being loaded, or the document object is being freed). C/C++: void LeavingPage(*Caller, *Document)

A listener can be removed by calling RemoveListener(), however this is normally unnecessary. Listeners are removed automatically if a new document source is loaded, or the document object is terminated.

Note that a trigger can have multiple listeners attached to it, so a new subscription will not replace any prior subscriptions, nor is there any handling for multiple copies of a subscription to a trigger.

Error Codes
OkayOperation successful.
NullArgsFunction call missing argument value(s)
CallFunctionExecutes any registered function in the currently open document.
ERR doc::CallFunction(OBJECTPTR Object, CSTRING Function, struct ScriptArg * Args, INT TotalArgs)
ParameterDescription
FunctionThe name of the function that will be called.
ArgsPointer to an optional list of parameters to pass to the procedure.
TotalArgsThe total number of entries in the Args array.

This method will execute any registered function in the currently open document. The name of the function must be specified in the first parameter and that function must exist in the document's default script. If the document contains multiple scripts, then a specific script can be referenced by using the name format script.function where script is the name of the script that contains the function.

Arguments can be passed to the function by setting the Args and TotalArgs parameters. These need to be specially formatted - please refer to the Script class' Exec method for more information on how to configure these parameters.

Error Codes
OkayOperation successful.
NullArgsFunction call missing argument value(s)
EditActivates a user editing section within a document.
ERR doc::Edit(OBJECTPTR Object, CSTRING Name, INT Flags)
ParameterDescription
NameThe name of the edit cell that will be activated.
FlagsOptional flags.

The Edit() method will manually activate an editable section in the document. This results in the text cursor being placed at the start of the editable section, where the user may immediately begin editing the section via the keyboard.

If the editable section is associated with an OnEnter trigger, the trigger will be called when the Edit method is invoked.

Error Codes
OkayOperation successful.
SearchThe cell was not found.
NullArgsFunction call missing argument value(s)
FindIndexSearches the document stream for an index, returning the start and end points if found.
ERR doc::FindIndex(OBJECTPTR Object, CSTRING Name, INT * Start, INT * End)
ParameterDescription
NameThe name of the index to search for.
StartThe byte position of the index is returned in this parameter.
EndThe byte position at which the index ends is returned in this parameter.

Use the FindIndex() method to search for indexes that have been declared in a loaded document. Indexes are declared using the <index/> tag and must be given a unique name. They are useful for marking areas of interest - such as a section of content that may change during run-time viewing, or as place-markers for rapid scrolling to an exact document position.

If the named index exists, then the start and end points (as determined by the opening and closing of the index tag) will be returned as byte indexes in the document stream. The starting byte will refer to an SCODE::INDEX_START code and the end byte will refer to an SCODE::INDEX_END code.

Error Codes
OkayThe index was found and the Start and End parameters reflect its position.
SearchThe index was not found.
NullArgsFunction call missing argument value(s)
HideIndexHides the content held within a named index.
ERR doc::HideIndex(OBJECTPTR Object, CSTRING Name)
ParameterDescription
NameThe name of the index.

The HideIndex() and ShowIndex() methods allow the display of document content to be controlled at code level. To control content visibility, start by encapsulating the content in the source document with an <index> tag and ensure that it is named. Then make calls to HideIndex() and ShowIndex() with the index name to manipulate visibility.

The document layout is automatically updated and pushed to the display when this method is called.

Error Codes
OkayOperation successful.
SearchA search routine in this function failed.
NullArgsFunction call missing argument value(s)
InsertTextInserts new content into a loaded document (raw text format).
ERR doc::InsertText(OBJECTPTR Object, CSTRING Text, INT Index, INT Char, INT Preformat)
ParameterDescription
TextA UTF-8 text string.
IndexReference to a TEXT control code that will receive the content. If -1, the text will be inserted at the end of the document stream.
CharA character offset within the TEXT control code that will be injected with content. If -1, the text will be injected at the end of the target string.
PreformatIf true, the text will be treated as pre-formatted (all whitespace, including consecutive whitespace will be recognised).

Use the InsertText() method to insert new content into an initialised document.

Caution must be exercised when inserting document content. Inserting an image in-between a set of table rows for instance, would cause unknown results. Corruption of the document data may lead to a program crash when the document is refreshed.

The document view will not be automatically redrawn by this method. This must be done manually once all modifications to the document are complete.

Error Codes
OkayOperation successful.
FailedGeneral failure.
OutOfRangeA specified number is outside of the valid range.
NullArgsFunction call missing argument value(s)
InsertXMLInserts new content into a loaded document (XML format).
ERR doc::InsertXML(OBJECTPTR Object, CSTRING XML, INT Index)
ParameterDescription
XMLAn XML string in RIPL format.
IndexThe byte position at which to insert the new content.

Use the InsertXML() method to insert new content into an initialised document.

Caution must be exercised when inserting document content. Inserting an image in-between a set of table rows for instance, would cause unknown results. Corruption of the document data may lead to a program crash when the document is refreshed.

The document view will not be automatically redrawn by this method. This must be done manually once all modifications to the document are complete.

Error Codes
OkayOperation successful.
NoDataNo data is available for use.
OutOfRangeA specified number is outside of the valid range.
CreateObjectA call to CreateObject() failed.
NullArgsFunction call missing argument value(s)
ReadContentReturns selected content from the document, either as plain text or original byte code.
ERR doc::ReadContent(OBJECTPTR Object, DATA Format, INT Start, INT End, STRING * Result)
ParameterDescription
FormatSet to TEXT to receive plain-text, or RAW to receive the original byte-code.
StartAn index in the document stream from which data will be extracted.
EndAn index in the document stream at which extraction will stop.
ResultThe data is returned in this parameter as an allocated string.

The ReadContent() method extracts content from the document stream, covering a specific area. It can return the data as a RIPL binary stream, or translate the content into plain-text (control codes are removed).

If data is extracted in its original format, no post-processing is performed to fix validity errors that may arise from an invalid data range. For instance, if an opening paragraph code is not closed with a matching paragraph end point, this will remain the case in the resulting data.

Error Codes
OkayOperation successful.
ArgsInvalid arguments passed to function.
NoDataOperation successful, but no data was present for extraction.
OutOfRangeThe Start and/or End indexes are not within the stream.
NullArgsFunction call missing argument value(s)
RemoveContentRemoves content from a loaded document.
ERR doc::RemoveContent(OBJECTPTR Object, INT Start, INT End)
ParameterDescription
StartThe byte position at which to start the removal.
EndThe byte position at which the removal ends.

This method will remove all document content between the Start and End indexes provided as parameters. The document layout will also be marked for an update for the next redraw.

Error Codes
OkayOperation successful.
ArgsInvalid arguments passed to function.
OutOfRangeThe area to be removed is outside the bounds of the document's data stream.
NullArgsFunction call missing argument value(s)
RemoveListenerRemoves a previously configured listener from the document.
ERR doc::RemoveListener(OBJECTPTR Object, INT Trigger, FUNCTION * Function)
ParameterDescription
TriggerThe unique identifier for the trigger.
FunctionThe function that is called when the trigger activates.

This method removes a previously configured listener from the document. The original parameters that were passed to AddListener() must be provided.

Error Codes
OkayOperation successful.
NullArgsFunction call missing argument value(s)
SelectLinkSelects links in the document.
ERR doc::SelectLink(OBJECTPTR Object, INT Index, CSTRING Name)
ParameterDescription
IndexIndex to a link (links are in the order in which they are created in the document, zero being the first link). Ignored if the Name parameter is set.
NameThe name of the link to select (set to NULL if an Index is defined).

This method will select a link in the document. Selecting a link will mean that the link in question will take on a different appearance (e.g. if a text link, the text will change colour). If the user presses the enter key when a hyperlink is selected, that link will be activated.

Selecting a link may also enable drag and drop functionality for that link.

Links are referenced either by their Index in the links array, or by name for links that have named references. It should be noted that objects that can receive the focus - such as input boxes and buttons - are also treated as selectable links due to the nature of their functionality.

Error Codes
OkayOperation successful.
OutOfRangeA specified number is outside of the valid range.
NullArgsFunction call missing argument value(s)
ShowIndexShows the content held within a named index.
ERR doc::ShowIndex(OBJECTPTR Object, CSTRING Name)
ParameterDescription
NameThe name of the index.

The HideIndex() and ShowIndex() methods allow the display of document content to be controlled at code level. To control content visibility, start by encapsulating the content in the source document with an <index> tag and ensure that it is named. Then make calls to HideIndex() and ShowIndex() with the index name to manipulate visibility.

The document layout is automatically updated and pushed to the display when this method is called.

Error Codes
OkayOperation successful.
SearchThe index could not be found.
NullArgsFunction call missing argument value(s)
Document class documentation © Paul Manias © 2005-2025

DATA Type

Data codes

NameDescription
DATA::AUDIOAudio file data, recognised by the Sound class
DATA::CONTENTDocument content (between XML tags) - sent by document objects only
DATA::DEVICE_INPUTDevice activity
DATA::FILEFile location (the data will reflect the complete file path)
DATA::IMAGEImage file data, recognised by the Image class
DATA::INPUT_READYDevice input that has been transformed into user input
DATA::RAWRaw unprocessed data
DATA::RECEIPTReceipt for item data, in response to an earlier request
DATA::RECORDDatabase record
DATA::REQUESTMake a request for item data
DATA::TEXTStandard ASCII text
DATA::XMLMarkup based text data. NOTE - For clipboard data, the top-level encapsulating tag must declare the type of XML, e.g. 'html', 'ripple'. For plain XML, use 'xml'
Document module documentation © Paul Manias © 2005-2025

DCF Type

Document flags

NameDescription
DCF::DISABLEDThis read-only flag is set if the UI has been disabled through the Disable action.
DCF::EDITAllow direct keyboard input and document editing.
DCF::NO_LAYOUT_MSGTurn off debug output produced during document layout and processing - useful on refresh for example.
DCF::NO_SYS_KEYSSystem-keys provide standard key support for Ctrl-C, Ctrl-X etc. Set this flag to turn them off.
DCF::OVERWRITEThis flag forces overwrite mode when the user enters information through the keyboard. If the flag is not set, then insert mode is used.
DCF::UNRESTRICTEDTurn off all security measures - may only be set prior to initialisation.
Document module documentation © Paul Manias © 2005-2025

DEF Type

Event flags for selectively receiving events from the Document object.

NameDescription
DEF::LINK_ACTIVATEDThe user has interacted with a hyperlink. This event can be cancelled by returning ERR::Skip.
DEF::ON_CLICKThe user has interacted with an element that has an on-click definition.
DEF::ON_CROSSINGSynonym for ON_CROSSING_IN | ON_CROSSING_OUT
DEF::ON_CROSSING_INThe mouse pointer has crossed into an element.
DEF::ON_CROSSING_OUTThe mouse pointer has crossed out of an element.
DEF::ON_MOTIONThe user has triggered a motion event in an element that supports motion monitoring.
DEF::PATHThe source file path has changed. Useful for detecting when the user has left the page.
DEF::WIDGET_STATEThe state value of a widget has changed (e.g. input, checkbox, text). name and value keys will be defined in the event parameters.
Document module documentation © Paul Manias © 2005-2025

DRT Type

Internal trigger codes

NameDescription
DRT::AFTER_LAYOUT
DRT::BEFORE_LAYOUT
DRT::END
DRT::GOT_FOCUS
DRT::LEAVING_PAGE
DRT::LOST_FOCUS
DRT::PAGE_PROCESSED
DRT::REFRESH
DRT::USER_CLICK
DRT::USER_CLICK_RELEASE
DRT::USER_MOVEMENT
Document module documentation © Paul Manias © 2005-2025