| Database Extreme Library Version 1.28 for PDAT 6.0 Professional |
Copyright (C) 2002-2005 Richard R. Sands dba Sands USA |
| Library Overview |
The Database Extreme Library is a share library for PDA Toolbox applications. It provides database manipulation actions.
This library provides higher level actions for database manipulations including advanced filtering, copying, deleting, and exporting records, and calculating fields. There are two primary techniques for advanced filtering: Advanced "In-Place" and "Keyset" filtering. In-place filters are essentially what PDA Toolbox already provides, however, it is limited to one criteria field which is generally a popup filtering a table. Using the .Select action, you can flag and filter records based on nearly any criteria. Keysets are new databases that contain a subset of records from a "master" database and a unique key field. Keyset databases may be edited and the master database updated.
There are several other actions that include clearing fields, deleting records, and exporting to doc files on a database-wide basis. You can also calculate both string, numeric, and date fields with the .Set actions. There are over 40 operators and functions supporting the expression and criteria evaluator.
It is also used as a "Plug-In" to PDAT/Advanced to provide additional Actions to your PDA Toolbox programs.
This manual assumes the reader has familiarity with the PDAT/Advanced application.
The Database Extreme Library is a Shareware Library for the Palm OS® 3.1 and above unless noted (e.g. FmtDate() function). The distribution module requires 40k of storage memory. For more information click here.
| Plugging In The Library |
For PDA Toolbox 6.0 Professional
For PDAT/Advanced Only
Before you can use the actions contained in this library, you must first "plug" it into PDAT/Advanced. Once plugged in and registered, you will be able to use and distribute this library freely.
After successful registration, when you are editing actions, you'll have a second button named "Lib" which pops up a list of all the commands available to you.
| Distribution |
It is recommended that you distribute the runtime version of the library. This is the "PDATDBXLibRT.prc" file. This file is smaller than the development library as it does not include any of the code for compiling your application.
Since you are distributing multiple PRC files that must be installed on the hand-held device, you may want to check out Ecamm's NutShell for the Palm OS at http://www.ecamm.com/palm/nutshell. Nutshell is a unique installer solution, which allows users distribute multiple Palm files and data as a single self-expanding PRC file. With this tool, the user installs a single file onto their hand-held and the first time your app is run, all the libraries, databases, and sub-programs are automatically unpacked and your app runs. A very good solution to a sticky problem.
| Advanced Filtering Techniques |
There are two primary techniques for filtering using the Database Extreme Library: In-place and Keysets. In-place filters are essentially what PDA Toolbox already provides, however, it is limited to one criteria field which is generally a popup filtering a table. Using the .Select action, you can flag and filter records based on nearly any criteria. Keysets are new databases that contain a subset of records from a "master" database and a unique key field. Keyset databases may be edited and the master database updated.
I've provided two working demos which you can load onto your emulator: Animals1 and Animals2. Animals1 demonstrates in-place filtering, and Animals2 demonstrates keyset filters. See the release notes with those two applications for details about databases, etc.
In-Place Filtering - ANIMALS1
The goal of this demo is to demonstrate advanced queries on the primary database using the SELECT action of the Database Extreme Library. Basically, there are two primary databases: The DATA and QURY. You go to the button (Query Animals) and choose the type, # of legs, and skin and tap (Do It!) to perform the query. The records that match will be check-boxed.
The core selection routine is this:
Script 1307 (Do It!) Button
db.Select pets, DATA, CHCK, "mat(DFld({pets}, {QURY}, 0, {LEGS}), 'All', [LEGS]) AND _
mat(DFld({pets}, {QURY}, 0, {SKIN}), 'All', [SKIN]) AND _
mat(DFld({pets}, {QURY}, 0, {CATA}), 'All', [CATA])"
GotoForm 1000
The db.Select will scan the database specified in (pets/DATA) selecting all records that match the criteria (last parameter). The CHCK is the field that recieves the selection status. The criteria is a logical expression that says if the LEGS, SKIN, and CATA fields match the user's query request, then it's selected.
The MAT() function is a matching routine. The first parameter is matched to the rest and if found, returns true. For example, MAT('B', 'A', 'B', 'C') would match 'B' to 'A', 'B', or 'C' and return true since 'B' is in the list.
The DFLD() allows you to access another table's value. This function requires the CreatorID, TypeID, Record Number, and Field to
retrieve. The record number will almost always be 0 (first record).
A word about brackets: A field in the current record is bracketed by [ ] as in [LEGS] - this says "get the value of LEGS and use it" whereas the { } brackets are used to postpone getting the values like "get the field ID itself - not the value". So, the DFLD() method typically uses {LEGS} since you don't want to get the VALUE of LEGS - you want to pass the ID of LEGS. In the MAT() routine, you want to pass the actual value of LEGS so it's bracketed like [LEGS]. Confusing, but it will be clear as you see more examples.
Note that in this script, the expressions can have carriage returns and spaces for clarity (unlike SMBeta). This REALLY helps.
Keyset Filtering - ANIMALS2
Keyset filtering is more complicated because you have to create a temporary database, use it, and then update the master with any potential changes you've made. There are two primary scripts here:
Script 1307 (Do It!) Button
db.KeySet pets, DATA, pets, DAT1,"Animals Data1", "KEY#", " _
mat(DFLD({pets}, {QURY}, 0, {LEGS}), 'All', [LEGS]) AND _
mat(DFLD({pets}, {QURY}, 0, {SKIN}), 'All', [SKIN]) AND _
mat(DFLD({pets}, {QURY}, 0, {CATA}), 'All', [CATA])"
db.Use pets, DAT1, "Animals Data1", 1000, 1001
db.Use pets, DAT1, "Animals Data1", 1100, 0
GotoForm 1000
Script 1308 (All Animals) Button
db.KeySet.Update pets, DATA, pets, DAT1, "KEY#"
db.Use pets, DATA, "Animals Data", 1000, 1001
db.Use pets, DATA, "Animals Data", 1100, 0
GotoForm 1000
In script 1307, a KeySet is created with the db.KeySet action. A KeySet is a database that contains a copy of all the selected records from the a main database. It contains link field (Key Set Field) that identifies the record back to the main database. This allows you to update the main database by locating each of the original records and updating them from the KeySet record.
In this case, the KeySet is created from querying the "Animals Data" (pets,DATA), and any records that match are written into "Animals Data1" (pets,DAT1). In addition, a new field is added, "KEY#", that is the KeySet link field.
The two db.Use actions make the KeySet database specified (pets, DAT1, "Animals Data1") the database that is used by a form and optionally, a table. The first USE changes the main form and table (Form 1000, Table 1001). The second
db.Use makes the animal editor to use the KeySet database.
For Script 1308, the goal is to select all animals and update the main database from the KeySet database so any changes get saved. This uses the
db.KeySet.Update action which basically reads "Update (pets,DATA) from (pets,DAT1) where
KEY#=RecordID".
| Stash File Information |
With DBX version 1.25, you now have the ability to use a Stash File. A stash file is a single-record database that stores misc. data for your use. In a way, it simulates "global" variables. It can also be used as a more effective clipboard. While many developers have been creating their own "home-brewed" version of this feature, the DBX stash file is better:
To delete a stash file, you use the normal delete actions in PDAT. To clear all or individual fields from the stash file, you can use the db.Stash.Clear action.
Stash Files are only available with PDA Toolbox 6.0 SP6 or higher.
| Library Actions Reference |
Each Action in the library will be described here.
Specifying Databases
Since databases can be dynamically changed, there needs to be a "portable" way of specifying the database when an action requires it. For any parameters named CID (creator ID) or TID (type ID) or Filename you can use these two forms:
| db.Alert expression | ||
| Description: | Displays a simple information alert. | |
| Parameters: | expression | Any valid Database Extreme expression. |
| Example: |
db.Alert "[LNAM] & ', ' & [FNAM]" |
|
Among other things, this action is useful for debugging your scripts. If you are having problems with a big expression, use this action to display portions of the expression to ensure that your expressions are returning what you think they are. This will usually show you where your problem is.
You may use the current open record's fields. This action may be used with or without an open database. The alert's caption is always "Information."
| db.Alert.Custom Talt, expression (PDAT Pro 6.0 SP6 or higher) | ||
| Description: | Displays a custom information alert. | |
| Parameters: | Talt | The ID of an Alert. |
| expression | Any valid Database Extreme expression. | |
| Example: |
db.Alert.Custom 1900, "LNAM & ', ' & FNAM" |
|
This will display an alert that you define in your Professional script with data evaluated from the expression. Among other things, this action is useful for debugging your scripts. If you are having problems with a big expression, use this action to display portions of the expression to ensure that your expressions are returning what you think they are.
When it returns, it will branch to the nth line after the db.Alert.Custom: The first button tapped goes to the following line, the second button tapped goes to the 2nd line following, the third goes to the third line, etc. The following example displays a custom alert with three buttons:
Action btnTest
db.Alert.Custom TestAlert, "LNAM & ', ' & FNAM"
Goto +3
Goto +4
Goto +5
au.Alert.Custom ResultAlert, "You tapped OK"
Goto +2
au.ALert.Custom ResultAlert, "You tapped Maybe"
Goto +2
au.ALert.Custom ResultAlert, "You tapped Cancel"
EndAction
|
To properly create the alert so that it accepts the text passed to it, you must
include in the text the placeholder "^1" as in "Do you want to ^1" where the ^1
is replaced with the text in the db.Alert.Custom action.
You may pass "" if you do not require text to be inserted into the alert.
You may use the current open record's fields. This action may be used with or without an open database.
| db.Append sCID, sTID, dCID, dTID, dFName, Criteria | ||
| Description: | Copies all records that match a criteria from one database to another. | |
| Parameters: | sCID: | Creator ID of the source database that is being queried. |
| sTID: | Type ID of the source database. | |
| dCID: | Creator ID of the destination database that is being written to. | |
| dTID: | Type ID of the destination database. | |
| dFName: | Filename of the destination database for use when it needs to be created. | |
| Criteria: | Any expression that evaluates to a boolean value (true/false). | |
| Example: |
db.Append Test, DATA, Test, BkUp, "MyData Backup", "Year(DATE)=2001" |
|
Writes records from (sCID,sTID) to (dCID,dTID,dFName) that match the criteria. This action will create the database if it does not exist. This supports appending an empty (new) record. New records are placed at the end of the database and you are responsible for resorting the database if required.
| db.Append.Rec CID, TID, FName | ||
| Description: | Appends the current record from the primary database to another database. | |
| Parameters: | CID: | Creator ID of the database that the record is being appended to. |
| TID: | Type ID of the database. | |
| dFName: | Filename of the destination database for use when it needs to be created. | |
| Example: |
db.Append.Rec Test, Arch, "MyApp Archive" |
|
Writes the current record to (CID,TID,FName). This action will create the database if it does not exist. If the record is new (blank), then this will generate an error.
| db.Clear CID,TID,Fld, ... | ||
| Description: | Clears one or more fields from the entire database. | |
| Parameters: | CID: | Creator ID of the database to clear the fields from. |
| TID: | Type ID of the database to clear the fields from. | |
| Fld ... | A list of database fields separated by a comma. | |
| Example: |
db.Clear Test, DATA, CRED, DEPO |
|
This will remove one or more fields from the database. It does not matter if the field does not exist.
| db.Clear.If CID,TID,Fld, ..., Criteria | ||
| Description: | Clears one or more fields from the entire database based on a criteria. | |
| Parameters: | CID: | Creator ID of the database to clear the fields from. |
| TID: | Type ID of the database to clear the fields from. | |
| Fld ... | A list of database fields separated by a comma. | |
| Criteria | Any expression that evaluates to a boolean value (true/false). | |
| Example: |
db.Clear.If Test, DATA, CRED, DEPO, "CHCK<>0" |
|
This will remove one or more fields from the database based on a criteria. If the criteria is true, then the fields are cleared. It does not matter if the field does not exist.
| db.Clear.Rec fld, ... | ||
| Description: | Clears one or more fields from the current record. | |
| Parameters: | Fld ... | A list of database fields separated by a comma. |
| Example: |
db.Clear.Rec CRED, DEPO |
|
This will remove one or more fields from the primary (opened) database. This supports clearing data in a new record. New records are placed at the end of the database and you are responsible for resorting the database if required.
| db.Copy.Rec sCID, sTID, Fld..., Criteria | ||
| Description: | Copies specific fields from another database into the current record based on a criteria | |
| Version: |
1.05 |
|
| Parameters: | sCID: | Creator ID of the database to copy the fields. |
| sTID: | Type ID of the database to copy the fields. | |
| sFld ... | A list of database fields from the source database separated by a comma. | |
| Criteria | Any expression that evaluates to a boolean value (true/false). | |
| Example: |
db.Copy.Rec Test, DATA, ADR1, ADR2, CITY, "LNAM='smith'" |
|
Think of this action as a light-weight join. It opens the database (sCID,sTID) and finds the first record that satisfies the Criteria. Then it copies the fields specified into the currently open record. This will not throw an error if the record is new.
| db.Create CID, TID, Filename | ||
| Description: | Creates a new database (empty) | |
| Version: |
1.12 |
|
| Parameters: | CID: | Creator ID of the new database |
| TID: | Type ID of the new database | |
| Filename: | Filename for the new database | |
| Example: |
db.Create Test, DATA, "MyDBData" |
|
This action will create a database using the CID/TID and Filename. If the database is already created this action proceeds normally. If, for some reason, the database could not be created or opened normally, then this action returns an error and the script will stop.
| db.Delete CID,TID, Criteria [,deleteStyle] | ||
| Description: | Removes all records from a database that match a criteria. | |
| Parameters: | CID: | Creator ID of the database to be processed. |
| TID: | Type ID of the database to be processed. | |
| Criteria: | Any expression that evaluates to a boolean value (true/false). | |
| deleteStle: | Optional. If provided, must be a string starting with "R", "D", or "A". | |
| Example: |
db.Delete Test,DATA, "Year([DATE]) < 2002" |
|
This will remove all records from the specified database where the criteria evaluates to True or non-zero. The database remains if all records are deleted.
PDAT Professional Only: The deleteStyle parameter is a string parameter defined as:
"R", "r", "Remove": Physically removes the record from the database. This should only be used if you application does not support conduits.
"D", "d", "Delete": Marks the record for deletion and removes the data. The record becomes "invisible" to the app.
"A", "a", "Archive": Marks the record for deletion, but does not remove the data. The record becomes "invisible" to the app.
NOTE: If you delete the record that is being displayed on your form (e.g. a record edit form), that record may remain defined but in a "new" state.
| db.Delete.Dups CID,TID, KeyField [,deleteStyle] | ||
| db.Delete.DupsNC CID,TID, KeyField [,deleteStyle] | ||
| Description: | Removes all records from a database that match a criteria. | |
| Parameters: | CID: | Creator ID of the database to be processed. |
| TID: | Type ID of the database to be processed. | |
| KeyField: | Key field for duplicate comparisons | |
| deleteStle: | Optional. If provided, must be a string starting with "R", "D", or "A". | |
| Example: |
db.Delete.Dups Test, DATA, SSN# |
|
This will remove all duplicate records from the specified database where the KeyField matches. The first of a set of duplicate records is retained. This is a sequential delete so it will be a lengthy operation, however, record order is maintained. To perform a comparison on multiple fields, you first must make a key field from the concatenated values using the db.Set action.
Example Script for multiple duplicate check:
db.Set Test, DATA, TFLD, text, "LNAM & FNAM" db.Delete.Dups Test, DATA, TFLD db.Clear Test, DATA, TFLD
The above example first creates a test field (TFLD) from the last name (LNAM) and first name (FNAM) fields. Then it deletes duplicates based on the test field (TFLD). Lastly, it deletes the remaining TFLD field.
The db.Delete.DupsNC action is identical to db.Delete.Dups with the exception that when comparing strings, a caseless comparison is performed.
PDAT Professional Only: The deleteStyle parameter is a string parameter defined as:
"R", "r", "Remove": Physically removes the record from the database. This should only be used if you application does not support conduits.
"D", "d", "Delete": Marks the record for deletion and removes the data. The record becomes "invisible" to the app.
"A", "a", "Archive": Marks the record for deletion, but does not remove the data. The record becomes "invisible" to the app.
This operation should be done when not in the primary data editing form.
| db.Delete.Rec | |
| Description: | Deletes the current record without user-intervention. |
| Example: |
db.Delete.Rec |
Silently deletes the current record from the primary (open) database. If the record is new, then this will generate an error. If the the record being deleted is the last record in the database, the new "last" record will become active.
NOTE: Deleting all records in your database will result in a new record being created.
| db.Export.Doc CID, TID, DocNameExpression, TextExpression, Criteria | ||
| Description: | Exports records to DOC file format. | |
| Parameters: | CID: | Creator ID of the database to be processed. |
| TID: | Type ID of the database to be processed. | |
| DocNameExpression: | Any expression that evaluates to a string value. | |
| TextExpression: | Any expression that evaluates to a string value | |
| Criteria: | Any expression that evaluates to a boolean value (true/false). | |
| Example: |
db.Export.Doc Test, DATA, "'Accounts'", |
|
Exports records that match the criteria. For the DocNameExpression, the first record of the database is accessible by field name. If you want to provide a literal name, you will have to double and single quote it as "'My Doc'" since the single-quoted string is a valid string expression. TextExpression is written to the DOC file only if the criteria proves true for that record. A doc file is created regardless of if any records are written to it.
| db.Export.Memo CID, TID, TitleExpression, TextExpression, Criteria | ||
| Description: | Exports records to the Palm MemoPad file format. | |
| Parameters: | CID: | Creator ID of the database to be processed. |
| TID: | Type ID of the database to be processed. | |
| TitleExpression: | Any expression that evaluates to a string value. | |
| TextExpression: | Any expression that evaluates to a string value | |
| Criteria: | Any expression that evaluates to a boolean value (true/false). | |
| Example: |
db.Export.Memo Test, DATA, "'Accounts'", |
|
Exports records that match the criteria. For the TitleExpression, the first record of the database is accessible by field name. If you want to provide a literal name, you will have to double and single quote it as "'My Doc'" since the single-quoted string is a valid string expression. TextExpression is written to the Memo file only if the criteria proves true for that record. A doc file is created regardless of if any records are written to it. NOTE: There is a limit to the size of memos of around 4 thousands bytes per memo however, if your database being exported is larger than that, then this action will create additional memos with the same title following the first one.
| db.Find.Rec Criteria | ||
| db.FindNext.Rec Criteria | ||
| db.Find.RecEx Criteria (PDAT Pro 6.0 SP6 or higher) | ||
| db.FindNext.RecEx Criteria (PDAT Pro 6.0 SP6 or higher) | ||
| db.FindPrev.RecEx Criteria (PDAT Pro 6.0 SP6 or higher) | ||
| Description: | Goes to the record that matches a criteria in the active database. | |
| Parameters: | Criteria: | Any logical expression. |
| Example: |
db.Find.Rec "NAME=popup(1001)" |
|
The db.Find.Rec searches the entire open database matching each record against the criteria specified. If found, then that record is made active. If not found, the current record remains active. db.FindNext.Rec will start searching the database at the record following the current record. db.FindPrev.Rec will start searching the database at the record before the current record.
The db.Find.RecEx and db.FindNext.RecEx / db.FindPrev.RecEx actions support branching. If a record is found, then it branches to the following action. If the record is not found, then it will skip the next action and execute the following action.
Action btnTest
db.Find.RecEx "LNAM = Stash({LNAM})"
Goto +2
Goto +3
au.Alert.Custom ResultAlert, "Name was found"
Goto +2
au.ALert.Custom ResultAlert, "Name was NOT found"
EndAction
|
| db.Goto Expression | ||
| Description: | Evals expression to a jump offset. | |
| Parameters: | Expression: | Any numeric integer expression. |
| Example: |
db.Goto "2" (skips the
next action) |
|
This powerful action will evaluate the expression, and use the integer result of the expression as the new jump target. The result may be negative (branch backwards) or positive (branch forward) and if the value is 0 or out-of-bounds of the number of actions, then the script is effectively halted.
Action btnTest
db.goto "val(USER)"
Goto @Choice0
Goto @Choice1
Goto @Choice2
@Choice0:
db.Alert "Choice 0 was selected"
Goto @Continue
@Choice1:
db.Alert "Choice 1 was selected"
Goto @Continue
@Choice2:
db.Alert "Choice 2 was selected"
Goto @Continue
@Continue:
EndAction
|
| db.GotoForm Expression | ||
| Description: | Jumps to a calculated form destination. | |
| Parameters: | Expression: | Any numeric integer expression. |
| Example: |
db.GotoForm "1000 + 100" (goes
to form 1100) |
|
This powerful action will evaluate the expression, and if the expression evaluates to a positive number greater than zero, will make that the target form ID and jump to that form. This can be used to jump to random forms, jump to forms selected from a popup list, etc.
| db.If Criteria, TaltID | ||
| Description: | Tests a criteria and when false, halts script and displays a message. | |
| Parameters: | Criteria: | Any logical expression. |
| TaltID: | The Alert Resource ID in your application. | |
| Example: |
db.If "NAME=popup(1001)", 1099 |
|
This action will test the criteria and if it evaluates to true, then will continue to execute the script. If the criteria fails, the script is halted and the alert you specified from your application is displayed.
| db.If.False Criteria | ||
| Description: | Tests if criteria evaluates to false and continues the script if so. | |
| Parameters: | Criteria: | Any logical expression. |
| Example: |
db.If.False "NAME=popup(1001)" |
|
Tests if criteria evaluates to false and continues the script if so. If the criteria evaluates to true, then it will stop the script.
| db.If.True
Criteria db.If.TrueEx Criteria (PDAT Pro 6.0 SP6 or higher) |
||
| Description: | Tests if criteria evaluates to true and continues the script if so. | |
| Parameters: | Criteria: | Any logical expression. |
| Example: |
db.If.True "NAME=popup(1001)" |
|
db.If.True will test if criteria evaluates to true and continues the script if so. If the criteria evaluates to false, then it will stop the script.
db.If.TrueEx will test if criteria evaluates to true and branch to the next action if true, of the 2nd action if false. The script does not stop.
The following example displays a the extended db.If.TrueEx:
Action btnTest
db.if.True "FNAM=''"
Goto +2
Goto +3
db.Alert.Custom ResultAlert, "[LNAM]"
Goto +2
db.Alert.Custom ResultAlert, "[LNAM] & ', ' & [FNAM]"
EndAction
|
| db.Keyset sCID, sTID, dCID, dTID, dFName, KID, Criteria | ||
| Description: | Creates a keyset Database from an existing database. | |
| Parameters: | sCID: | Creator ID of the source (master) database |
| sTID: | Type ID of the source (master) database. | |
| dCID: | Creator ID of the keyset (destination) database that is being written to. | |
| dTID: | Type ID of the keyset (destination) database. | |
| dFName: | Filename of the keyset (destination) database for use when it needs to be created. | |
| KID: | The name of the field in the keyset database that should contain the keyset ID (KID). | |
| Criteria: | Any expression that evaluates to a boolean value (true/false). | |
| Example: |
See Animals2.zip |
|
Used to create filtered databases that contain only selected records which can update a master database. If the keyset database exists, it will first be deleted before the query is performed. This is similar to Append, but adds KID, a field you specified to hold the keyset Link ID.
| db.Keyset.Add sCID, sTID, dCID, dTID, dFName, KID, Criteria | ||
| Description: | Appends additional records to a keyset database. | |
| Parameters: | sCID: | Creator ID of the source (master) database |
| sTID: | Type ID of the source (master) database. | |
| dCID: | Creator ID of the keyset (destination) database that is being written to. | |
| dTID: | Type ID of the keyset (destination) database. | |
| dFName: | Filename of the keyset (destination) database for use when it needs to be created. | |
| KID: | The name of the field in the keyset database that should contain the keyset ID (KID). | |
| Criteria: | Any expression that evaluates to a boolean value (true/false). | |
| Example: |
See Animals2.zip |
|
This is identical to db.keyset, but appends records to the keyset database. If the database does not exists then it is created.
| db.Keyset.Update dCID, dTID, sCID, sTID, KID | ||
| Description: | Updates a master database from a keyset database. | |
| Parameters: | dCID: | Creator ID of the destination (MASTER) database that is being written to. |
| dTID: | Type ID of the destination (MASTER) database. | |
| sCID: | Creator ID of the source (KEYSET) database | |
| sTID: | Type ID of the source (KEYSET) database. | |
| KID: | The name of the field in the keyset database that contains the keyset ID (KID). | |
| Example: |
See Animals2.zip |
|
This action reads the keyset database and searches for each record in the master database. If the keyset record is found in the master, then the master is updated with the new value. If the keyset record is not found, then it is assumed to be a new record and is appended to the master database. There is no "delete" detection, so you should handle deletes by marking records for delete, updating the master, then deleting the records from the master (and keyset, if you are wanting to keep it around).
This action will not work if there is no master database. If there is a chance that your master database will not exist, then call the db.Create action before calling this to create a database (if needed).
| db.Renum CID, TID, fld | ||
| Description: | Renumbers a database field based on the physical record number. | |
| Parameters: | CID: | Creator ID of the database to renumber. |
| TID: | Type ID of the database to renumber. | |
| Fld: | The string field to hold the record number. | |
| Example: |
db.Renum TEST, DATA, RECN |
|
Renumbers a database field based on the record number (starting at 1). This is the same as setting a record to the expression "RecNo()"
| db.Renum.Key CID, TID, fld | ||
| Description: | Rekeys a database based on record ID. | |
| Parameters: | CID: | Creator ID of the database to rekey. |
| TID: | Type ID of the database to rekey. | |
| Fld: | The string field to hold the record ID. | |
| Example: |
db.Renum.Key TEST, DATA, RECK |
|
This will renumber a given database using the unique Palm OS record ID. This is a large number that will not change as long as the record does not get deleted. It is the same value returned by the function RecID().
| db.Select CID, TID, fldX, criteria | ||
| Description: | Marks database records as selected based on the criteria. | |
| Parameters: | CID: | Creator ID of the database to query. |
| TID: | Type ID of the database to query. | |
| FldX: | The BOOLEAN field to indicate if the record is selected. | |
| Criteria: | Any expression that evaluates to a boolean value (true/false). | |
| Example: |
db.Select Test, DATA, "CHCK", "NUMB >
10000" |
|
This is used to check-mark records that match a criteria.
| db.Set CID, TID, Fld, Fld-Type, Expression [, Criteria] db.SetEx CID, TID, [Fld, Fld-Type, Expression]... [, Criteria] |
||
| Description: | Sets a field in an entire database to the expression. | |
| Parameters: | CID: | Creator ID of the database to process. |
| TID: | Type ID of the database to process. | |
| Fld: | The field ID that will get the evaluated result of expression. | |
| Fld-Type: | The database field type of FLD (string, number, bool, date, or time) | |
| Expression: | An expression that evaluates to the type specified in Fld-Type. | |
| [Criteria]: | Optional, any expression that evaluates to a boolean value (true/false). | |
| Example: |
db.Set TEST, DATA, FULL, text, "LEFT(FNAM,1) & LNAM" |
|
Sets the "fld" to the value of expression for the entire database. If criteria is provided, then only those records matching Criteria will have the expression set. This action does not clear the existing contents if criteria is provided.
Fld-Type is a string with any of these values:
The db.SetEx action is set up to take multiple sets of Fld, Fld-Type, and Expression parameters so you perform multiple calculations with one action. This reduces both the flicker and increases the speed of the calculations. The speed is increased proportionally with the number of calculations performed. Expressions are calculated left to right so if you calculate a field in the first and use the field in the second expression, then the use will be the value of the calculated value, not the original value. The Criteria parameter, if provided, applies to all the calculations in the action,
NOTE: DINKs fields are not supported.
| db.Set.Rec Fld, Fld-Type, Expression | ||
| Description: | Sets a field in the current record to the value of Expression. | |
| Parameters: | Fld: | The BOOLEAN field to indicate if the record is selected. |
| Fld-Type: | The database field type of FLD (string, number, bool, date, or time) | |
| Expression: | An expression that evaluates to the type specified in Fld-Type. | |
| Example: |
db.Set.Rec FULL, text, "LEFT(FNAM,1) & LNAM" |
|
Sets the "fld" to the value of expression for the current record.
This supports creating a new record. New records are placed at the end of
the database and you are responsible for resorting the database if required.
Fld-Type is a string with any of these values:
The db.Set.RecEx action is set up to take multiple sets of Fld, Fld-Type, and Expression parameters so you perform multiple calculations with one action. This reduces both the flicker and increases the speed of the calculations. The speed is increased proportionally with the number of calculations performed. Expressions are calculated left to right so if you calculate a field in the first and use the field in the second expression, then the use will be the value of the calculated value, not the original value.
NOTE: DINKs fields are not supported.
| db.StackSize size | ||
| Description: | Sets the depth of the evaluation stack. | |
| Parameters: | size: | An integer value for the stack size. |
| Example: |
db.StackSize 30 'The default size |
|
This allows the evaluation stack to be adjusted for more complicated expressions (or simpler ones if adjusting downward). The amount of memory is proportional to the size of the stack. By default, the stack size is set to 30. This is sufficient for 99% of applications. If your expression is VERY complicated, then you may need to increase it. To estimate the size of the stack needed, you must consider the maximum depth of nested terms and all operands and function calls within the nested expression.
Some examples:
| 5+2 | This expression has a nesting of 2 (5, 2, and then it gets evaluated to 7). | |
| (5*(2+1)) | This is nested to 3 (5, 2, 1 then + adds 2 and 1 to 3, then 5 * 3 = 15) | |
| 5*int([FLDX]) | This is nested to 3 (5, int(), FLDX) | |
| iif(x, iif(y, iif(z, 10, 20), 30), 40) | This is nested to 8 (iif(), x, iif(), y, iif(), z, 10, 20 before the inner iff gets evaluated. |
In general, if you are having problems with a big expression with lots of function calls and parans, then increase the stack by 10 at a time. You probably don't want to go over 100.
The StackSize affects all expressions that are executed after it until it is changed.
This action is available only with the PDAT 6.0 Pro Script Compiler due to memory constraints.
| db.Stash.Clear [ fld, ...] (PDAT Pro 6.0 SP6 or higher) | ||
| Description: | Clears all or selected fields from the stash file. | |
| Parameters: | Fld ... | An optional list of database fields separated by a comma. |
| Example: |
db.Stash.Clear CRED, DEPO |
|
If fields are provided, then this will remove those fields from the stash file database. If no fields are provided, then all fields are cleared from the stash file. There are no warnings.
| db.Stash.Data Fld, Fld-Type, Expression [, Fld, Fld-Type, Expression]... (PDAT Pro 6.0 SP6 or higher) | ||
| Description: | Stashes calculated data into the stash file. | |
| Parameters: | Fld: | The field ID that will get the evaluated result of expression. |
| Fld-Type: | The database field type of FLD (string, number, bool, date, or time) | |
| Expression: | An expression that evaluates to the type specified in Fld-Type. | |
| Example: |
db.Stash.Data FULL, text, "LEFT(FNAM,1) & LNAM" |
|
This action will evaluate each of the expressions and assign them to fields in the stash file database. This essentially creates a "global" set of fields or a better clipboard. You must include at least one set of data (Fld, Type, Expression) but you may include more.
You can access any of the stashed data using the Stash( ) function. You do not need to have an open record to use this action. This means you should be able to use it in the eventStartup script or other places where there is no current record active.
Fld-Type is a string with any of these values:
NOTE: DINKs fields are not supported.
| db.Stash.File CID, TID, Filename (PDAT Pro 6.0 SP6 or higher) | ||
| Description: | Opens or creates a new Stash File. | |
| Parameters: | CID: | Creator ID of the new database |
| TID: | Type ID of the new database | |
| Filename: | Filename for the new database | |
| Example: |
db.Stash.File CRID, STSH, "MyApp-STSH" |
|
This action will create a stash file using the CID/TID and Filename. It also ensures that there is a single record defined. If, for some reason, the database could not be created or opened normally, then this action returns an error and the script will stop. This action is best used in the startupEvent, but it may be used anywhere. You may also use it multiple times with different CreatorID/TypeID pairs - though only the last one defined will be the active one.
If there is existing data in the stash file, it remains. To clear out existing data, either delete the stash file before this action, or use the db.Stash.Clear to clear selected fields.
| db.Status colorIndex, "Message" | ||
| Description: | Changes the color and text of the status message. | |
| Parameters: | colorIndex: | An integer value of the color to use. |
| Message: | The text of the message. Maximum length, 32 characters. | |
| Example: |
db.Status 49, "Purging Database..." |
|
All actions in this library that process an entire database display a small, framed, message as the processing is performed. The color of the frame is controlled by colorIndex and is a number between 0 and 250 but it defaults to UIFrameColor (slightly purple). Each action provides a default message which can be overridden with this action. Once set, you must set the original text back by setting the message to "default".
There are a couple of things to keep in mind about this action and status messages in general. If you have turned off redraw in your script, then no status messages will be displayed at all. If you leave it on, then the status messages are display, but there is a flicker as they are being erased for the next action.
| db.Use CID, TID, FName, FormID, TableID | ||
| Description: | Sets a form/table up to use a specific database. | |
| Parameters: | CID: | Creator ID of the database to use. |
| TID: | Type ID of the database to use. | |
| FName: | Filename of the database to use. | |
| FormID: | The ID of the Form you want to make use the database. | |
| TableID: | The ID of the Table you want to make use the database. | |
| Example: |
db.Use TEST, DAT1, "MyApp Data1", 1000, 1001 |
|
Sets a form to use the CID, TID, Filename (FName) for Form ID "FormID" and Table ID "TableID". FormID or TableID may be 0 if there is no table.
| Function and Evaluator Reference |
Here are the conventions I use to use and document the evaluator:
Database Fields
You can reference database and record fields in one of two ways: By value or by reference. The "by value" means that you want the field's value (or contents) from the record or database. The "by reference" means that the field name itself is the value. You'd use "by value" most of the time as it gets you the value you are mostly interested in. However, when you need to pass the name of the field to a function, you would use the "by reference" form.
String Literals
Constants
Operators
Data Types and Calculations
When performing math, two integer values will always have an integer result (e.g. 10 / 3 = 3). If a floating point number is involved in the expression, then the result is always a floating point (e.g. 10 / 3.0 = 3.33333).
The concatenation operation ("&") will convert numbers to a string so 'Rick' & 8 = 'Rick8', also 32 & 5 = '325'. This avoids having to constantly use the STR(x) function to convert numbers to strings. Dates, times, and field references, when implicitly converted to a string are converted as a number, so 1am would be the string '60' (60 minutes since midnite).
For logical operators, both operands must be strings to kick in the string comparisons. You cannot use AND, OR, NOT with strings. For floats, NOT is treated as a negating operator.
MathLib Functions Support
None! I make no claim to knowing anything about the functions contained in MathLib. Your best bet is to consult the MathLib documentation and lookup the functions that are supported here in the MathLib Function Reference.
Functions Parameter and Return Types Notation
|
Logical Functions |
||||||||||||||||||||||||||||||
|
cmp |
i = cmp(s1, s2) |
String compare: i=0 if s1=s2, i=-1 if s1<s2, i=1 if s1>s2 | ||||||||||||||||||||||||||||
| choose |
x = choose(i, x1, x2, x3...) |
Chooses a result based on i. The variable i should be between 0 and x. For example, choose(0, 'red', 'white', 'blue') would result in 'red' (the zero'th choice). Although i must be a numeric value, you can mix any numbers and strings in the resulting list. | ||||||||||||||||||||||||||||
| iif |
x = iif(iTest, xTrue, xFalse) |
Returns value of xTrue if iTest<>0, otherwise xFalse. Both xTrue and xFalse are evaluated and may be any kind of value. | ||||||||||||||||||||||||||||
| mat |
i = mat(xTarget, xTest1, xTest2...) |
Returns true if xTarget matches any of the remaining arguments. | ||||||||||||||||||||||||||||
| missing |
i = missing({vfld})
|
Returns
true if the field specified is not in the record (e.g. it's
missing) Example: FNAM & iif(Missing({MNAM}), ' ', MNAM & '. ') & LNAM |
||||||||||||||||||||||||||||
| def |
i = def({vfld})
|
Returns
true if the field specified exists in the record and it is a
valid value for the field type. Example: FNAM & iif(Def({MNAM}), MNAM & '. ', '') & LNAM |
||||||||||||||||||||||||||||
|
String Functions |
||||||||||||||||||||||||||||||
| char |
s = char(s, i) |
Return i'th character | ||||||||||||||||||||||||||||
| clipboard |
s = clipboard() |
Returns the string (if any) contained in the clipboard. If the clipboard is empty, then the resulting string is "". If the clipboard contains a number, then it is returned in the string form, so if you want it as a number, use Val(Clipboard()). | ||||||||||||||||||||||||||||
| crc |
i = crc(s, i) |
Returns a unsigned integer (0 to 65k) representing the CRC16 of the string s. The parameter i is the "seed value" which modifies the crc of the string. | ||||||||||||||||||||||||||||
| extract |
s = extract(src, target, index) |
Returns the index'th string in src delimited by target. This allows you to treat a string as an array of strings delimited by some string/character. For instance, "extract('ABC#DEFG#HIJ', '#', 1)" would return 'ABC' and a index of 2 would return 'DEFG'. 0 or indexes beyond what's there will result in "" being returned: "extract('ABC#DEFG#HIJ', '#', 4)" would return "". If a "$" is your delimiter, be sure to use '\4' as the embedded code: "extract([AMTS], '\4', 2)" would extract the numeric amount from a currency string (e.g. if [AMTS] was "$1000", then it would return 1000). | ||||||||||||||||||||||||||||
| lcase |
s = lcase(s) |
Returns the string s as all lowercase, for instance lcase('LIB') = 'lib'. This function may not work for non-US English strings. | ||||||||||||||||||||||||||||
| left |
s = left(s, i) |
Leftmost i characters | ||||||||||||||||||||||||||||
| len |
i = len(s) |
Returns the length of the string s. This value may be zero. | ||||||||||||||||||||||||||||
| lpad |
s = lpad(s, x) |
Left justifies s in a field of x spaces. | ||||||||||||||||||||||||||||
| mid |
s = mid(s, iStart, iCount) |
Substr starting at iStart for iCount characters. | ||||||||||||||||||||||||||||
| pos |
i = pos(src, target) |
Returns the character position of target in src. For instance, "pos('Rick@SandsUSA.com', '@')" would equal 5. | ||||||||||||||||||||||||||||
| right |
s = right(s, i) |
Right-most i characters | ||||||||||||||||||||||||||||
| rightTo |
s = rightTo(s, i) |
Right-most starting from i'th position | ||||||||||||||||||||||||||||
| rpad |
s = rpad(s, x) |
Right justifies s in a field of x spaces. | ||||||||||||||||||||||||||||
| spc |
s = spc(x) |
Creates a string of x spaces. | ||||||||||||||||||||||||||||
| ucase |
s = ucase(s) |
Returns the string s as all uppercase, for instance ucase('lib') = 'LIB'. This function may not work for non-US English strings. | ||||||||||||||||||||||||||||
|
Conversion Functions |
||||||||||||||||||||||||||||||
| fix |
s = fix(n, i) |
Attempts to convert any value into a string while formatting the number to i decimal places. If there are more decimal digits than i, the remaining digits are truncated (e.g. fix(1.2345, 2) is fixed to 1.23 and fix(10, 3) is fixed to 10.000) | ||||||||||||||||||||||||||||
| loc |
s = loc(n, cDP, cComma) |
Attempts to convert the number n to a localized number. cDP and cComma are the character values to use, of use the value 'd' to specify the default (system preferences). NOTE: This function should be used for non-calculated fields, for example, when exporting due to PDA Toolbox always assuming no group formatting and a decimal point of '.'. | ||||||||||||||||||||||||||||
| str |
s = str(n) |
Attempts to convert any value into a string | ||||||||||||||||||||||||||||
| val |
n = val(s) |
Attempts to convert any value into a number | ||||||||||||||||||||||||||||
|
Date Functions |
||||||||||||||||||||||||||||||
| fmtDate |
s = FmtDate(s, d) |
This function formats a DATE as you
want it. Any or all components of the date may be used or
ignored. NOTE: This
function requires a minimum of OS 3.5. ^<valueType><formatModifier> Each substring has three components:
The following is an example of a template specification with three substrings: ^0z ^2l ^4r The <valueType> component is show below. Note that the formatted result depends on the <modifier> value.
Here are the values you can specify for the <modifier> component of each template substring.
|
||||||||||||||||||||||||||||
| day |
i = day(d) |
Returns Day value of Date (e.g. 1 to 31) | ||||||||||||||||||||||||||||
| month |
i = month(d) |
Returns Month value of Date (e.g. 1 to 12) | ||||||||||||||||||||||||||||
| year |
i = year(d) |
Returns Year value of Date (e.g. 2002) | ||||||||||||||||||||||||||||
| qtr |
i = qtr(d) |
Returns quarter number from date (e.g. 1-4 (4=4th Quarter)) | ||||||||||||||||||||||||||||
| toDate |
d = toDate(i,i,i) |
Returns date. (e.g. ToDate(2,15,2002) returns value for Feb. 15, 2002) | ||||||||||||||||||||||||||||
| DateStr |
s = DateStr(d) |
Returns date. (e.g. DateStr(d) returns string formatted via sys prefs | ||||||||||||||||||||||||||||
| today |
x = today(i) |
Returns
the current date. The i parameter indicates what "kind" of date you
desire:
|
||||||||||||||||||||||||||||
|
Time Functions |
||||||||||||||||||||||||||||||
| hour |
i = hour(t) |
Returns hours value of Time. This is in 24 hour notation (e.g. 0 to 23). | ||||||||||||||||||||||||||||
| min |
i = min(t) |
Returns minutes value of Time. (e.g. 0 to 59). | ||||||||||||||||||||||||||||
| ToTime |
t = toTime(iHr, iMin) |
Returns a Time value from iHr and iMin. Calculated as minutes since midnite: (iHr * 60) + iMin | ||||||||||||||||||||||||||||
| TimeStr |
s = timeStr(t) |
Returns a time formatted with the system preferences as a string | ||||||||||||||||||||||||||||
| now |
x = now(i) |
Returns
the current time. The i parameter indicates what "kind" of time you
desire:
|
||||||||||||||||||||||||||||
|
Alarm Functions |
||||||||||||||||||||||||||||||
| adate |
d = adate(a) |
Returns a date from an alarm type date/time. PDA Toolbox Alarm Type is actually the number of seconds since 1/1/1904. Use NOW(3) to get the current date/time. | ||||||||||||||||||||||||||||
| atime |
t = atime(a) |
Returns a time from an alarm type date/time. | ||||||||||||||||||||||||||||
|
Database Functions |
||||||||||||||||||||||||||||||
| RecCnt |
i = RecCnt() |
Returns the number of records for the current database. Does not count "deleted (but not removed)", or "archived" records. | ||||||||||||||||||||||||||||
| RecID |
i = RecID() |
Returns the unique record ID of the current record. | ||||||||||||||||||||||||||||
| RecNo |
i = RecNo() |
Returns record number. First record is 1. This is a transient value. | ||||||||||||||||||||||||||||
| DName |
s = dname() |
Returns name of the current database without the .pdb file extension. | ||||||||||||||||||||||||||||
| DCnt |
i = dcnt({vCID},{vTID})
|
Returns record count for specified database (vc,vt). Does not count "deleted (but not removed)", or "archived" records. | ||||||||||||||||||||||||||||
| DFld |
x = dfld({vCID},{vTID},RecNo,{vfld})
|
Returns field's value (vt) from external database (vc,vt) at record #(i). First record is 0. | ||||||||||||||||||||||||||||
| DSum |
x = dsum({vCID},{vTID},{vfld})
|
Returns sum of database field not including NULL fields. | ||||||||||||||||||||||||||||
| DAvg |
x = davg({vCID},{vTID},{vfld})
|
Returns average of database field not including NULL fields. | ||||||||||||||||||||||||||||
| DMin |
x = dmin({vCID},{vTID},{vfld})
|
Returns minimum value of database field not including NULL fields. | ||||||||||||||||||||||||||||
| DMax |
x = dmax({vCID},{vTID},{vfld})
|
Returns maximum value of database field not including NULL fields. | ||||||||||||||||||||||||||||
|
Control Functions |
||||||||||||||||||||||||||||||
| Field |
s = field(id) |
Retrieves the string from the textbox specified by ID. | ||||||||||||||||||||||||||||
| Popup |
s = popup(id) |
Retrieves the string from the popup trigger specified by ID. | ||||||||||||||||||||||||||||
| Checkbox |
i = checkbox(id) |
Retrieves the value (0,1) from the checkbox specified by ID. | ||||||||||||||||||||||||||||
| Radio |
i = radio(id) |
Retrieves the value (0,1) from the radio button specified by ID. | ||||||||||||||||||||||||||||
| List |
s = list(id) |
Retrieves the string from the listbox specified by ID. NOTE: The value cannot be retained as PDAT does not support listboxes. | ||||||||||||||||||||||||||||
| ListI |
i = listI(id) |
Retrieves the selected value (-1 to n-1) from the listbox specified by ID. NOTE: The value cannot be retained as PDAT does not support listboxes. | ||||||||||||||||||||||||||||
| Slider |
i = slider(id) |
Retrieves the selected value (0 to n) from the slider control specified by ID. NOTE: The value cannot be retained as PDAT does not support sliders. | ||||||||||||||||||||||||||||
|
Non-Mathlib Math Functions |
||||||||||||||||||||||||||||||
| Rnd |
i = Rnd(i) |
Returns random number between 0 and (i-1) | ||||||||||||||||||||||||||||
| Abs |
i = Abs(i) z |
Integer absolute value (floating point uses MathLib) | ||||||||||||||||||||||||||||
|
Misc. Functions |
||||||||||||||||||||||||||||||
| FormID | i = FormID() | Returns the current form ID or 0 if the form ID is undefined (e.g. during special scripts). | ||||||||||||||||||||||||||||
| Stash | x = Stash( {vfld} ) | Return a value from the stash file. The field ID passed in must be in curly-brackets { } | ||||||||||||||||||||||||||||
I make no claim to knowing anything about the functions contained in MathLib. Your best bet is to consult the MathLib documentation.
| abs | f = abs(f) | int | f = int(f) |
| acos | f = acos(f) | log | f = log(f) |
| acosh | f = acosh(f) | log10 | f = log10(f) |
| asin | f = asin(f) | log1p | f = log1p(f) |
| asinh | f = asinh(f) | log2 | f = log2(f) |
| atan | f = atan(f) | logb | f = logb(f) |
| atan2 | f = atan2(f1, f2) | nextafter | f = nextafter(f1, f2) |
| atanh | f = atanh(f) | pow | f = pow(f1, f2) |
| cbrt | f = cbrt(f) | remainder | f = remainder(f1, f2) |
| ceil | f = ceil(f) | round | f = round(f) |
| cos | f = cos(f) | scalb | f = scalb(f1, f2) |
| cosh | f = cosh(f) | sin | f = sin(f) |
| drem | f = drem(f1, f2) | sinh | f = sinh(f) |
| exp | f = exp(f) | sqrt | f = sqrt(f) |
| expm1 | f = expm1(f) | tan | f = tan(f) |
| floor | f = floor(f) | tanh | f = tanh(f) |
| fmod | f = fmod(f1, f2) | trunc | f = trunc(f) |
| hypot | f = hypot(f1, f2) |
| Purchasing Information and Support |
This program is not Freeware. It is Shareware. This means that you can, and should, try the demo out before buying. Shortly after you register via PayPal you will receive an unlock key that will enable developing with this library.
The cost of this package is US$12.95.
Primary support for this library is at the PDAT Nuts & Bolts Support Forum at www.PDATNutsAndBolts.com.
You can always contact me at: email: Rick@SandsUSA.com or at my site http://www.SandsUSA.com.
| Warranty and User License Agreement |
"The Software" is "Database Extreme Library" aka "PDATDBXLib.prc" by Richard R. Sands dba Sands USA.
DISCLAIMER #1 - MUST READ
This product is an "After-Market" utility for PDA Toolbox(tm) and as such, is subject to obsolescence by changes in PDA Toolbox or the Palm OS(tm) itself. This cannot be prevented. I may choose to stop or limit development and support of this product if such situation occurs.
USER LICENSE AGREEMENT
This Agreement sets forth your licensed rights to use "The Software" and is
granted to you upon condition that you accept the terms of this license. Your electronic
indication of agreement, or your use of the program constitute acceptance of all of the
terms of this license.
The program copy and documentation are furnished to make "The Software"
available for your use and remain the property of Sands USA.
IF YOU DO NOT AGREE WITH ANY PART OF THIS LICENSE, DO NOT USE THIS SOFTWARE. Delete
"The Software" and all associated files from all media on which it has been
copied.
LICENSE TERMS AND CONDITIONS
THE LICENSED PRODUCT
"The Software" comprises copyrighted computer programs and utilities for the
reporting of Palm OS(tm) application databases (PRC) created by the PDA
Toolbox(tm) Application Generator. The Licensed
Product in its entirety is protected by US and foreign copyright. YOU MAY NOT
DISTRIBUTE THE LICENSE CODE provided to you.
YOUR USE OF THE LICENSED PRODUCT
General Use. You have the right to use "The Software" with PDAT/Advanced
and to distribute the library file "PDATDBXLib.prc" or "PDATDBXLibRT.prc"
but license codes, or other information about this library. For those purposes, you have the right to install the "The Software"
and any associated files on one (1) computer. Use of "The Software" on a network
or any other arrangement by which its functions are accessible to more than one user at a
time is not permitted.
LIMITATIONS ON USE
General Use Limitations. You have no right to reproduce, transfer, publish or otherwise distribute either
the "The Software" software, or any components or documentation provided.
ALL RIGHTS NOT SPECIFICALLY GRANTED BY THIS LICENSE ARE RESERVED BY SANDS USA.
WARRANTIES, WARNING, DISCLAIMER
Warning and Disclaimer of All Warranties. THE PROGRAM IS FURNISHED "AS IS"
WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, IN ALL JURISDICTIONS WHERE ALL
WARRANTIES MAY BE DISCLAIMED IN THE LICENSING OF INTELLECTUAL PROPERTY.