Access ELF Documentation Access ELF Tutorials Access ELF On-Line Help Access ELF Downloadable Help File Access ELF FAQ VB ELF Documentation VB ELF Tutorials VB ELF On-Line Help VB ELF Downloadable Help File VB ELF FAQ
Configuration & Licensing Options
Critical Opinions
Our Users Talk Back


Please sign our guestbook!





What's New in Version 2.1


This page contains information about the latest upgrade to VB ELF, version 2.1, November 1999.

Bug Fixes:


1) [Sort Key] field in the Phrases table now functions correctly. The [Sort Key] determines the order in which (string) phrase substitutions are applied. String phrase substitutions are also called "context-sensitive" substitutions in the Help Text; these are the class of phrase substitutions whose [When I Type] column-entry (also called the "trigger") is enclosed in brackets or double-quotes.

Note however that it is also permissable to use string substitutions for simple string replacements which don't require context-sensitivity. For example,
When I Type: [coffee bean]    I Really Mean: coffee
This example use no context. It simply replaces the string "coffee bean" with the string "coffee" in all cases.

The [Sort Key] field is used to control the order of occurrence of these string substitutions. In contrast, phrase definitions which do not have their trigger enclosed in brackets or quotes are performed AFTER all string substitutions, and always occur in left-to-right order as the triggers appear in the user's question.

One additional feature has been added to the [Sort Key] field in the 2.1 release. Prior to this release it was not possible to specify that phrase substitutions were to apply to specific Views. Entries in the Phrase table were applied to all Views created for any given database. With the advent of scripted View selection, it's more likely that a given phrase substitution will be designed for use with a particular View, and invalid for another View. To address this problem, the 2.1 release adopts the convention that any Phrase table entry with a sort key containing !ViewName will not be applied in the corresponding View. Notice that this does not affect your ability to use the Sort Key field for positioning (for the views to which it does apply), since !Viewname can be preceded by any alphabetic sequence.

For example, if we wish to have the above string substitution apply to all views except the INVENTORY view, then we could write:
When I Type: [coffee bean]    I Really Mean: coffee     Sort Key: !Inventory

If it was necessary to position the substitution in relation to another string replacement, we might use a sort key of "Z !Inventory" (delays the replacement) or "A !Inventory" (advances the replacement).

This functionality is a "work-around" which will be addressed in a more general way in future releases. Currently, adding !ViewName to a Sort Key affects ONLY string phrase substitutions (it does not apply if the trigger is not enclosed in brackets or double-quotes).


2) Names of fields used in data-aware context-sensitive phrase triggers are now case-insensitive. Example:
When I Type: [{Category} product]    I Really Mean: {1}
This substitution will now work correctly whether the field is named Category or CATEGORY. Its effect, in the Northwind database, would be to change: "Show me the dairy products" into "Show me the dairy". This is because "dairy" is an entry in the Category field. (Notice also that the string replacement algorithm matches "product" to the pluralized form "products"; so in this sense it is not a "strict" string replacement.)

An enhancement to the data-aware replacement algorithm in v2.1 now permits contextless markers. Prior to version 2.1, only triggers of the form
When I Type: [{Category} product]    or
When I Type: [product {Category}]
were permitted; in other words, something had to appear before or after the {FieldName} marker. Beginning with v2.1, it is permissible to write:

When I Type: [{Category}]
by itself.

In the "I Really Mean" field, you can use {1} to represent whatever string was typed by the user and is an element of the Category field of the underlying database. For example, in our Expedia Web demo, we have the following phrase definitions:
When I Type: !notserious
I Really Mean: Is the Pope Catholic?;Get serious, please
When I Type: [{CityName} a city]    I Really Mean: notserious

If a user types: Is Los Angeles a city?, then the question becomes: Is notserious?
"Notserious" is also a trigger. Since it isn't bracketed, it fires AFTER the second one. The initial "!" defines it as a Custom Error definition, and the user sees the above message.

Beginning with v2.1 it is also possible for Phrase Scripts to get access to the data-element which triggered them. For instance
When I Type: [{CityName}]    I Really Mean: -
Sort Key: -    Script Name: PetsByCity

Any question containing the name of a city will be passed to the PetsByCity script. This script has access to the trigger as a global variable called PhraseTrigger. The data element is available as a global variable called DataTrigger. In this case, the two would have the same value, since there is nothing either before or after the {CityName} trigger. In the preceding example, the PhraseTrigger passed to a script would have the value "Los Angeles a city"; the DataTrigger would have the value "Los Angeles".

Numeric triggers are also available, as the global variable NumberTrigger. Numeric triggers are represented in both the [When I Type] and [I Really Mean] fields of the phrase table by the literal {#} and take on the value of any valid numeric expression.

See the section on Scripting for full documentation of the revised set of global variables available to scripts.


3) An omission has been corrected which caused problems when loading interfaces to Oracle databases. This error occurred when the selection was made by choosing the interface .MDB file associated with the Oracle .UDL (in contrast to selecting the .UDL file directly). Because this is the only way to select an Oracle database programatically, this in effect prevented some Oracle interfaces from being accessible via the ELF Web object.



 

Enhancements:


1) AnswerScripts have been modified to permit their return value to consist not only of a modified SQL expression, but also the name of a pre-existing query within the database. In addition, a global variable QueryParms has been added; this allows you to return the name of a parameterized query as the function result of an AnswerScript, while providing any required parameter values in the QueryParms variable.

The QueryParms variable uses a simple convention: it is a set of paired "ParameterName;Value;" entries. For example, an AnswerScript might return the string "PetFriendlyHotels" which is the name of the following parameterized query:

SELECT HOTELS.HotelName, HOTELS.StreetAddress1, HOTELS.CityName, HOTELS.StateRegionName FROM Amenities INNER JOIN ([Amenity Links] INNER JOIN HOTELS ON [Amenity Links].HotelID = HOTELS.HotelID) ON Amenities.AmenityID = [Amenity Links].AmenityID WHERE (((HOTELS.CityName) Like IIf(Len([CityParm]),[CityParm],"%")) AND ((HOTELS.StateRegionName) Like IIf(Len([StateParm]),[StateParm],"%")) AND ((Amenities.Amenity)="Pets Accepted"));

Prior to returning this value ("PetFriendlyHotels"), the script would be obligated to set the appropriate parameters for the query; for example:
QueryParms = "CityParm;Denver;StateParm;CO"

VB ELF will never set the QueryParms variable by itself. It only uses this variable to transfer parameters specified within a script into the SQL statement which is the final result of a query. It is also possible to use QueryParms directly with the SQL returned by an AnswerScript; without having a pre-existing query in the database. This might be simpler in some cases than creating the complete SQL statement, since SQL created within scripts might also benefit from the modularity of having replaceable parameters.

Notice that the WHERE clause of the above example is written in such a way that if the parameters are not supplied by the script, the conditions revert to being comparisons to wildcard characters (which always succeed). This will often be a good strategy where the parameters are essentially optional.

(The wildcard character is the OLE DB "%" token, rather than the familiar Jet "*" token, because our Web demos connect to Jet data via the OLE DB Provider for Jet.)


2) Custom error messages are no longer restricted to a single row, with an optional header. Prior to version 2.1, custom error messages were a single line. They could be generated in one of two ways -- either by using a !Trigger entry in the phrase table, or using a script to set the QueryResult variable to -8 and the ErrorMessage global variable to "The Error Message;An Optional Error Header".

An example of the first use would be:
When I Type: !age
I Really Mean: Sorry, inquiries about age are restricted;Invalid query

In general, the technique for the second type of usage was as follows: a ViewScript (or SpellCheckScript) would detect an "illegal" word or phrase in a query. It would then set the PrivateErrorCode variable. An AnswerScript would test the value of PrivateErrorCode and in the appropriate cases set the QueryResult and ErrorMessage variables; eg.
    QueryResult = -8
    ErrorMessage = "Sorry, inquiries about age are restricted;Invalid query"

Note that developers using VB ELF to return results via SQL might find it very useful to embed URLs within the ErrorMessage string; for example,
ErrorMessage = "<A HREF='nwdbmap.gif'>Click here;Click below to see tables & relationships"

Beginning with v2.1, the ErrorMessage string can also be a complex object, formatted to enable VB ELF to return arbitrary recordsets based on its literal contents. More simply put, it's now possible to set ErrorMessage to be a list of row values and optional header values. As an example, let's say we set ErrorMessage to the following value:
"({not available;Just a reminder:};{Something else}); ({2nd row 1};{2nd row 2});"

VB ELF would then return a recordset which appeared as:

Just a reminder:     "We regret to say:"
not available          Something else
2nd row 1             2nd row 2

Notice that the formatting convention is to enclose each cell, or field element, within a pair of braces. The first row can also specify the header for the column (also within the braces, and following a semi-colon). If no header is specified, then the default is used. The default custom error header is defined in the Advanced tab of the Settings window.

Rows after the first can specify headers according to the same format, but this information will be ignored (it will not override the headers specified in the initial line).

Among other uses, we expect that this feature will make it easier to customize lists of URLs which can be suggestions to the user for alternate paths, particularly in cases where scripts find that the application is unable to supply the exact information desired. Note that it would also be possible in Internet/Intranet applications to use this feature to present a list of e-mailable addresses, possibly with topics pre-filled, making it easy for the user to reach parties who could provide the specific information desired.


3) The Scripting component, which was introduced in version 2.0, has been significantly extended. Scripts now have the following global variables available:

Public Question As Variant
Public Connection As Variant
Public UserID As Variant
Public Password As Variant ' will act as Static by Session
' - - -
Public PrivateErrorCode As Integer
Public SQL As Variant
Public QueryResult As Integer
Public ExecutionError As Integer
Public ErrorMessage As Variant
Public SpellCheck As Integer
Public SpellCheckIn As Variant
Public SpellCheckOut As Variant
' - - - 10/99 additions:
Public Resource As Variant ' general purpose
Public QueryParms As Variant ' parm-name;parm-value; pairs
Public PhraseTrigger As Variant ' to pass triggers into script
Public DataTrigger As Variant ' to pass data-aware triggers into script
Public NumberTrigger As Variant ' same for numeric value in trigger
Public WarningCode As Integer ' to allow elfClass to display "cautions" in
Public WarningString As Variant ' addition to recordset results

This new version corrects many errors in the initial release. First, note that there was some confusion in the prior release concerning the lifetime of these variables. In the current release, this has been simplified.

Only the Password variable acts as static, meaning that it holds its value between queries. This property is designed to allow you to query a user once (and only once) for a valid password. Subsequently, you can simply validate that the Password variable continues to hold a valid entry.

Each of the other settable variables is reinitialized (either to an empty string or zero) prior to each question, and any script can read or write these values. (This does not apply to the Connection and UserID variables, which should be considered read-only and always provide the same information, namely the current OLE DB connection string, and the ID of the current user.)

The Resource variable has been added as a holder for any information that scripts might need to pass between themselves. For instance, a ViewScript might detect keywords in the question, and use the Resource string to store these keywords for acting on later (in an AnswerScript) depending on the outcome of the translation.

Use of the QueryParms variable is described in Enhancement #1 above. It permits AnswerScripts to return either parameterized SQL statements (a), or the names of parameterized stored queries and procedures (b). The QueryParms variable must be filled in by an AnswerScript prior to returning either (a) or (b) as its function result. VB ELF will then use the "ParmName;ParmValue;" pairs designated in the QueryParms string to replace the names of the SQL parameters with the desired values.

PhraseTriggers, DataTriggers, and NumberTriggers have been added to allow greater customizability of PhraseScripts. PhraseScripts now have access -- in addition to the Question variable itself (which holds the complete text of the user's question) -- to whatever context-sensitive triggers were involved in the process of triggering the script. The PhraseTrigger variable will always contain the full literal text of that part of the question corresponding to the phrase trigger (the [When I Type] part of a phrase definition). The DataTrigger variable will only have a value if the trigger was of a "data-aware" form; that is, containing the name of a field (in curly braces). This part of the trigger is matched by any word contained in the underlying database in the respective field. Similarly, NumberTriggers will have value only for phrase definitions which use the {#} format as an elastic placeholder for any valid numeric value.

WarningCode and WarningString have been provided as another means of passing information back from a script to a client application. Its main purpose is to account for those cases when either a valid recordset or a customized error message is being returned, but additional information may be required by the client. For example, a script may determine that it ought to provide a given recordset as a "best effort" -- even though the meaning of the question may not have been clear. In this case, the WarningCode and WarningString variables could be used to display a cautionary footnote about using the resulting information, or advice on how to create a less ambiguous query.

For example, we use these variables in our Northwind Web demo as follows: an AnswerScript detects the presence of the "PIVOT" keyword in any successful SQL translation. If present, the WarningCode is set to 1 and the WarningString variable is set to a caption explaining that crosstabs are also available in SQL Server and Oracle interfaces. The Web ASP page simply tests for non-zero WarningCodes and displays the WarningString above the result if detected. Although this isn't strictly a "warning", it illustrates the potential for using the additional channel for any auxiliary information.

Like the QueryParms variable, the WarningCode and WarningString variables are never set by the VB ELF application itself. They are only provided as a conduit for developers to pass information back from within scripts to their own client applications.


4) A number of other features have been added which relate to scripting. The initial release was a bit inflexible and missing some basic elements. Many users reported that the script panels were truncating the text typed into them. We still haven't solved this problem, but we have provided a number of extensions which make it less likely to occur.

First, we've added two variants of an "include" statement, one which allows scripts to access text from other panels; and one which allows them to access text from external files.

The include statements are of the form:
#include name = "SomePanelName"
#include file = "c:\path\somefilename.xyz"

Include statements should be used at the top of a given panel, to include information from other locations which will be referenced later in the script.

Note that this allows the creation of global functions, which can be used in common by many different types of script. You might find it effective to create small libraries of these functions. In the original release, each script panel was given a name, which was also the name of the function within the script to call when that script was invoked. Library script panels can have arbitrary names; their names don't have to appear as function names. These names are simply used as identifiers to allow other scripts to get access to their contents.

Depending on your taste, you might prefer to keep all your scripts within external files, and have only references to these files within the script panels. In that case, you can use tried-and-true text editors to manipulate script contents. However, you might also prefer to have the text of these scripts directly available to your users via the script panels. To avoid losing any information due to truncation of text typed directly into the panels, you might want to back up these scripts, which are contained in the elfUserTableTemplates table of the VBELF32.MDA database. You can also edit this table directly, when doing substantial script revisions. One of the truly nice parts about working with scripts is that they stand outside the application -- you can actually modify them while your interface is running and see the results immediately.

While VB ELF has always been a very powerful tool for creating query interfaces, like most natural language systems it had its own built-in wall beyond which "tuning" was difficult, if not impossible. With the addition of scripting in version 2.0, and the substantial modifications made in this v2.1 release, we think VB ELF is reaching a completely new level of customizability.


Last Updated: November, 1999