Documente Academic
Documente Profesional
Documente Cultură
2011-2016
Exsys Corvid Knowledge Automation Expert System Development Manual
This manual, as well as the software described in it, is furnished under license and may be used or copied
only in accordance with the terms of such license. The content of this manual is furnished for informational
use only, is subject to change without notice, and should not be construed as a commitment by Exsys Inc.
Exsys Inc assumes no responsibility of or liability for any errors or inaccuracies that may appear in this
documentation. Except as permitted by such license, no part of this publication may be reproduced, stored in
a retrieval system, or transmitted, in any form or by any means, electronic, mechanical, recording, or
otherwise, without the prior written permission of Exsys Inc.
Any references to company names in samples or exercises are for demonstration purposes only and are not
intended to refer to any actual organization.
Exsys, the Exsys logo, Corvid, the Corvid logo, Exsys RuleBook, the Exsys RuleBook logos and WINK
(WHAT I Need to Know) are either registered trademarks or trademarks of Exsys Inc in the United States
and /or other countries.
Notice to U.S. government end users. The software and documentation are “commercial items,” as that term
is defined at 48 C.F.R. §2.101, consisting of “commercial computer software” and “commercial computer
software documentation,” as such terms are used in 48 C.F.R. §12.212 or 48 C.F.R. §227.7202, as applicable.
Consistent with 48 C.F.R. §12.212 or 48 C.F.R. §§227.7202-1 through 227.7202-4, as applicable, the
commercial computer software and commercial computer software documentation are being licensed to U.S.
government end users (A) only as commercial items and (B) with only those rights as are granted to all other
end users pursuant to the terms and conditions set forth in the Exsys standard licensing agreement for this
software. Unpublished rights reserved under the copyright laws of the United States.
Exsys Inc.
6565 America’s Parkway. NE
Suite 200
Albuquerque, NM 87110
U.S.A.
www.exsys.com
All rights reserved.
Chapter 1: Installing Exsys Corvid! 1
Chapter 2: Exsys Corvid Concepts! 9
2.1 Decisions, Decisions! 10
2.2 Expert Systems! 10
2.3 Exsys Corvid! 11
2.4 Capturing the Decision Making Logic! 11
2.5 If / Then Rules! 12
2.6 The Corvid Inference Engine! 13
Chapter 3: Creating and Running Systems! 19
3.1 Corvid Files! 19
3.2 Projects and the CorvidProjects Folder! 20
3.3 Starting and Stopping Apache Tomcat! 23
3.4 Running Systems in Development! 24
Chapter 4: Variables! 27
4.1 Exsys Corvid Variables! 27
4.2 The Corvid Variables Window! 27
4.3 Adding New Variables! 28
4.4 Variable Types! 29
4.5 Setting Other Variable Properties! 33
4.6 Variable Properties by Type! 34
4.7 Other Controls on the Variables Window! 43
4.8 “Options” Tab ! 44
4.9 “Ask With” Tab ! 44
4.10 “Also Ask” Tab ! 45
4.11 Advanced Options! 45
Chapter 5: Expressions! 51
5.1 If /Then Rules! 51
5.2 [Name]! 51
5.3 Static List Variables! 52
5.4 Continuous Variables - Numeric, String, Date! 53
5.5 Confidence Variables! 57
5.6 Collection Variables! 58
5.7 Dynamic List Variables! 59
5.8 Functions! 59
5.9 Double Square Bracket Embedding - [[Name]]! 60
5.10 Variable Properties - [Name.value]! 61
5.11 Expression Syntax Checking! 62
Chapter 6: Forward and Backward Chaining! 65
6.1 Introduction! 65
6.2 Forward Chaining! 65
6.3 Forward Chaining Limitations! 65
6.4 Backward Chaining! 67
6.5 The Big “To Do” List! 69
6.6 Another Example! 70
6.7 Rules and Logic Blocks! 72
Chapter 7: Logic Blocks - Controls! 73
7.1 Rules and Logic Blocks! 73
7.2 Rules as Trees! 73
7.3 Multiple Logic Blocks! 75
7.4 Creating a Logic Block! 76
7.5 Building Rules in the Logic Block! 77
7.6 Adding Nodes! 82
7.7 Selecting and Editing Nodes! 95
7.8 Changing Block Order! 98
7.9 IF THEN IF! 98
7.10 Adding Commands in a Logic Block! 99
7.11 Merge Function! 99
7.12 Printing! 100
Chapter 8: Logic Blocks - Building Rules from Tree Diagrams! 103
8.1 Rules and Logic Blocks! 103
8.2 Building a Simple Tree! 103
8.3 Breaking a Tree into Pieces! 115
8.4 Running with Backward Chaining! 121
Chapter 9: Command Blocks! 127
9.1 What is a Command Block! 127
9.2 Default Command Block! 128
9.3 Adding a Command Block! 128
9.4 Command Nodes! 129
9.5 Command Builder Window! 132
9.6 Variables Tab ! 133
9.7 Blocks Tab ! 138
9.8 Reset Tab ! 142
9.9 External Tab ! 143
9.10 Control Tab ! 150
9.11 Results Tab ! 161
9.12 Title Tab ! 163
9.13 Reports Tab ! 164
9.14 Email Tab ! 164
9.15 IF, WHILE and FOR Nodes! 165
9.16 Typical Command Blocks! 170
Chapter 10: Action Blocks and Smart Questionnaires! 173
10.1 Overview! 173
10.2 Action Block Structure! 173
10.3 Action Block Tutorial! 180
Chapter 11: Controlling the User Interface! 195
11.1 End User Interface! 195
11.2 Setting the Runtime Applet Window Properties! 196
11.3 Corvid Screen Commands! 197
11.4 Question Screens - Asking the End User for Input! 206
11.5 Information Screens - Title, Results! 218
11.6 Resource Files and Multiple Language Support! 224
11.7 Running Systems with Frames! 230
11.8 Making the Applet Fill the Window! 234
11.9 Using Double Square Bracket Embedding! 236
Chapter 12: MetaBlocks - Probabilistic Product Selection! 243
12.1 Overview! 243
12.2 MetaBlocks! 243
12.3 MetaBlock Spreadsheet! 244
12.4 Selecting and Creating a Spreadsheet! 246
12.5 Editing a Spreadsheet! 246
12.6 MetaBlock Logic! 247
12.7 MetaBlock Sample System! 256
12.8 Other MetaBlock Data Sources! 265
Chapter 13: Interfacing to External Programs! 267
13.1 Overview! 267
13.2 Where to Use External Interface Commands! 267
13.3 Types of External Data Commands! 270
13.4 URL / External Program Command Details! 273
13.5 XML Command Details! 277
13.6 Database Command Details! 293
13.7 PARAM Command Details! 315
13.8 APPLET Command Details! 316
Chapter 14: Reports! 321
14.1 Types of Reports! 321
14.2 Creating Report Content! 322
14.3 Displaying the Reports with the Corvid Servlet Runtime! 329
14.4 Displaying Reports with the Corvid Applet Runtime! 336
14.5 Building the Report Commands! 340
14.6 Creating PDF Reports Templates! 344
14.7 Cannot Put .cfg File in WEB-INF! 348
Chapter 15: Running and Fielding Systems! 349
15.1 Running a Corvid System! 349
15.2 Running as a Java Applet! 350
15.3 Corvid Files! 358
15.4 Moving an Applet System to a Web Server! 359
15.5 Running Standalone! 361
15.6 Embedding Corvid Systems in Emails! 362
Chapter 16: Testing and Debugging a System! 365
16.1 Testing! 365
16.2 Check System! 366
16.3 Validation Testing! 366
16.4 Trace! 375
16.5 Using .HOW! 383
16.6 Custom Tracing! 384
Chapter 17: Exsys Corvid Servlet Runtime! 385
17.1 Overview! 385
17.2 System Requirements! 387
17.3 Installing and Starting the Corvid Servlet Runtime! 387
17.4 Moving to the Corvid Servlet Runtime! 391
17.5 Templates! 392
17.6 Templates to Ask Questions! 395
17.7 Advanced Templates to Ask Questions! 406
17.8 Customizing Text Used in Question Templates! 415
17.9 Templates to Display Results! 425
17.10 EMAIL Functions! 433
17.11 Cookies! 436
17.12 Passing Data at Servlet Runtime Startup ! 437
Chapter 18: Integrating Corvid with Adobe Flash! 439
18.1 Overview! 439
18.2 Using Flash for the User Interface! 440
18.3 Exsys / Flash Interaction Overview! 445
18.4 The Action Script Code in Detail! 451
18.5 The XML Data Sent by the Corvid Servlet Runtime! 457
18.6 Specifying the Flash Interface Parameters in Corvid! 466
Appendix A - Expressions and Functions! 469
A.1 Corvid Expressions! 469
A.2 Constants! 471
A.3 Functions! 472
A.4 Numeric Functions! 472
A.5 String Boolean Tests! 477
A.6 String Functions! 477
A.7 Date Boolean Tests! 484
A. 8 Date and Time Functions! 484
A.9 File Functions! 486
Appendix B: Variable Properties and Methods! 487
B.1 What are Properties! 487
B.2 TIME and AGE Properties! 487
B.3 HOW Property! 488
B.4 DISPLAY_WITH_RESULTS Property! 488
B.5 Static List Properties! 488
B.6 Dynamic List Properties! 491
B.8 Continuous Variable Properties! 494
B.9 Confidence Variable Properties! 498
B.10 Collection Variable Properties! 500
B.11 Collection Variable Methods! 505
Chapter 1: Installing Exsys Corvid
Installing Exsys Corvid also installs the other underlying software that Corvid uses. When you first start
Corvid, it will lead you through this process.
Starting with version 6 of Exsys Corvid, a “CorvidProjects” folder approach is used to organize and edit your
Corvid expert system projects. This is different from earlier versions up v5.3 where projects could be kept in
any location, or Corvid v5.4 where projects had to be built in Tomcat’s webapps folder. The new approach is
much easier to install and use.
Also starting with Corvid v6, the Corvid install process installs Exsys Corvid, Apache Tomcat and the Corvid
servlet programs. This greatly simplifies the earlier process where there needed to be separate downloads
for Apache Tomcat and the servlets needed to be installed manually.
3. Open the Corvid v6 Project Manager and move any systems you built with the earlier versions into
the CorvidProject folder
Corvid v5.4 implemented changes in where systems were located and how they were run. This was
due to changes in Java that prevented applets from running the way they had done previously. This
required installing Apache Tomcat and building systems in the Tomcat webapps folder. This is no
longer required in Corvid v6, and while Tomcat is still used, the interactions with Tomcat are handled
automatically and invisibly.
Make sure you are logged in as Administrator and have system administrator privileges. You will not
be able to successfully complete the install without Administrator level privileges.
Program Files\Exsys\Corvid
When the install is done, you will see the Install completed
window.
Just click “Finish” and Exsys Corvid will automatically start for
the license activation and configuration.
Evaluating Corvid
If you are evaluating Corvid or have not purchased a license, just click the “Continue without Activation”
button. Corvid will run for 30 days and allow systems to be built of up to 150 nodes. This is a reasonably
small system, but allows running the Corvid tutorials and building many types of sample systems.
If you are just using the 30 day / 150 node “Demo” version for the class, just click the “Continue without
Activation” button.
1. Install Java
The Exsys Corvid Runtime programs are based on
Java. Many PCs already have Java installed. Corvid
will check to see if your PC has Java installed. If it
finds it, it will move on to step 2 and this section on
installing Java can be skipped.
Accept the Java download defaults for where to install it. The
one exception is the “Ask” Add-on. This is not needed by
Corvid. If you want to add it, it will not cause any problem for
Corvid, but it is not required and can be unselected if you
choose.
You should click the “Agree and Continue” button. You will
also have to click the “Enable” button to allow your browser to
use Java.
At this point, your browser will ask you if you want to allow
a Java Applet to run. (For some reason, currently, this is
called the Java Uninstall Applet” - which seems like an
odd name since it does not uninstall Java)
You will see various messages as the items are installed. Corvid will then start Apache Tomcat to deploy the
servlet files.
The buttons on the right side of the window generally should not be needed. These are only for special
configurations with multiple copies of Tomcat installed.
Quick Start Guide - To get a quick overview of building a small system, there is a Quick Start Tutorial
as a PDF document. This leads you through the key operations needed to build systems with Corvid.
The guide is installed with Corvid and can be reached from the MS Windows Start button:
Start -> Exsys -> Corvid -> Tutorials -> Quick Start Tutorial
The Quick Start is only an overview, but some students find it a good introduction, or refresher, on
using Corvid.
If you take an umbrella with you when you go to lunch, and someone asks “Why?”. You will probably say “It’s
raining”, or “It looks like its going to rain” or “The forecast this morning was for rain”. In If/Then form these become:
IF
It is raining
THEN
Take an umbrella when you go out
IF
It looks like its going to rain
THEN
Take an umbrella when you go out
It is not exactly the way we might say it to another person, but these rules explain how we make the decision,
and they are exactly the type of rule that could be used in Exsys Corvid.
NOTE: When the IF part is TRUE, the THEN part is also taken to be TRUE. However, the
opposite is NOT true. If the IF part is FALSE, that does NOT mean the THEN part is FALSE. It
might not be raining, but we might want to take an umbrella for some other reason. We could add
a rule saying “If it is not raining, then don’t take an umbrella”, but that would be a different rule.
Corvid rules are basically the same rules the expert would use to explain the decision-making steps to
another person. They have to be written in a precise way that the Corvid Inference Engine can understand,
but the rules should still be easy to read and understand.
2.5.1 Probability
Many decisions are not absolute “yes” or “no”, but may be somewhere in between, representing a
“Probability” or “Confidence” value. The Corvid rules can implement this same type of probabilistic or
“uncertain” reasoning. The confidence or certainly in the IF data can be passed through to have the THEN
assignments made with a “Confidence”. A simple example is the above rule:
IF
Rain is forecast
THEN
Take an umbrella when you go out
The forecast of rain will be a percentage. We could pass that percentage through to the decision to take an
umbrella:
IF
Rain is forecast
THEN
The confidence you should take an umbrella is equal to the percent
likelihood of rain
Corvid has many ways to handle confidence or probability and build powerful systems that can capture the
deeper knowledge of experts in making complex decisions when there is uncertainty.
The Corvid Inference Engine allows you to write rules that are easy to read and understand,
but which can still be used by the computer to solve the problem.
The inference engine uses each rule when it is relevant to what it is trying to determine. The rules represent
independent facts and have no explicit links between them. If a specific rule needs to be changed, it can simply
be edited without having to check how it is linked to other rules or where it appears in nested computer code.
Obviously, the inference engine is a complex program. In most systems the default way the inference engine
processes the rules will work well. However, there are many way to control and optimize the inference engine
for a particular system.
Building rules in Exsys Corvid is not difficult and is far more like explaining the steps in a decision-making
process to another person, rather than traditional programming.
For example, a financial advisory expert system might have rules to determine if a particular mutual fund
should be recommended. A typical rule might be something like:
IF
The customer has high risk tolerance
AND: Meeting objectives requires rapid growth
THEN
Mutual Fund X is a good choice
This is a typical Corvid rule. It is a general rule of thumb that the system can use in selecting which mutual
funds to recommend. The rule itself represents high level knowledge. The rule states when Mutual Fund X
should be recommended, but to use the rule, the system will need to know if “The customer has a high risk
tolerance” and “Meeting objectives requires rapid growth”.
The Corvid Inference Engine will automatically recognize that it needs to determine if the statement “The customer
has a high risk tolerance” is TRUE or FALSE. It will look through the rules in the system and might find:
IF
The customer’s age is less than 30
THEN
The customer has high risk tolerance
IF
The customer’s annual income is over $200,000
THEN
The customer has high risk tolerance
These are lower level and more detailed rules about “risk tolerance”. Just the fact that they set a value for
“Risk Tolerance” is enough for the Corvid Inference Engine to recognize that they are relevant to the higher
level rule. These rules will be tested, which may require calling other rules, asking the user for data, going to
databases, etc. This is done automatically by the Corvid Inference Engine and backward chaining.
Corvid will do whatever is needed to determine if “The customer has a high risk tolerance” is TRUE or FALSE.
This will help determine if the top level rule is true, but can also be used anywhere else that any rule needs to
know about “risk tolerance”. The lower level rules are independent of the top, higher level rule. In this
case, they will be used in combination with the top level rule, but that is because they set a value in their
THEN part that applies to the top rule’s IF statement - not because of any “hard code” relationship between
the rules.
If this logic was built by traditional programming techniques, all the If/Then sections would need to be carefully
organized and nested. If some of the lower level factors changed, the entire program might have to be
reorganized to handle the “ripple effects”.
However, the Exsys Corvid Inference Engine is designed to work with the individual rules. It does not care
what order they are in or where they occur in a system. They are just independent rules that will be used
when needed.
With Corvid, all the developer has to do is provide the rules that describe the steps in making the decision. If
only high level rules are provided, the system will ask high level questions - but the logic will still work. When
lower level rules are added, the questions will get more detailed, but the same high level logic will still be
applied. This ability to build systems from high level rules down to detailed ones using backward chaining is
very powerful and enables rapid system development.
Corvid provides “Logic Blocks” which are a way to organize and structure the logic, making it easy to build
and maintain related sets of rules. But since the Corvid Inference Engine really only cares about the rules,
rather than the actual tree structure, there are many equivalent ways to describe the rules for a system. The
best approach is usually the one that matches the way the expert thinks about solving the problem. Corvid
lets you describe the logic in the way that best matches how you think about solving the problem.
Corvid also supports “Forward Chaining” which is a more procedural, order dependent execution of the
rules. This can be combined with Backward Chaining to run top level rules in a particular order, this will
allow backward chaining to be used to derive needed values from other rule modules. It provides the best of
both approaches.
The IF/Then statements in computer programming are just boolean test expressions that determine if a block
of code should be executed. They have no intrinsic relationship to each other. They can be nested, to
produce more complex tests, but they are executed from the outer-most inwards. The outer tests have no
knowledge of the inner tests and no way to determine if the associated code will be used or even if it is
relevant to the main decision. Of course programmers will say “I carefully arrange them so they are relevant
and will be used only when needed.” - and in a good program, that may be true. But in a complex problem,
the dynamic and probabilistic interrelationships can make it almost impossible to code all the dependencies.
Also, when a change in the logic needs to be made, the ripple effects have to be carefully considered and
worked in.
Corvid greatly simplifies this because the rules are processed by the inference engine which automatically
determines the relationship between rules. If one rule needs the value of X, and some other rules anywhere
else in the system can set the value of X, the inference engine will automatically recognizes that the needed
value can be derived from the other rules. It will automatically use the rules to set X and then return to the
original rule. If we add a new rule anywhere else to set X, it will automatically be used when appropriate. It
does not matter where the rules are, if a rule is useful, the inference engine will find and use it. This just does
not happen in procedural computer code, where the programmer would have to carefully define every step.
This ability of the Inference Engine to automatically apply the rules in a logical way makes building systems in
Corvid very simple, but can be a little confusing at first since so much just happens automatically. But once
the Corvid approach is understood, it is a MUCH easier and more effective way to describe a decision-making
process - and the more complex the process, the better the Corvid approach works.
Several of the files will have the same name, but different file extensions. For a system named “MySystem”,
the following 4 files will always be found:
MySystem.CVD
The CVD file is the main system file for development. It is the file that the Corvid editor uses to build
and store all the information on the system variables, rules and logic. Every Corvid project will have
a .CVD file. The CVD file is only used for development and is not needed to field finished systems
and generally should by included with the files used to field a system.
MySystem.CVR
The CVR file is the system Runtime file. It is created automatically by Corvid when a system is saved
or run. The CVR file is read by the runtime program (applet or servlet) and used to run the system.
The CVR file contains the system logic in a more compact form and cannot be used for editing a
system.
MySystem.HTML
The .HTML file is created automatically by Corvid when a system is run with the Applet Runtime. It is
a normal HTML file, but contains an applet tag that calls the Corvid Applet Runtime and passes in
parameters telling the runtime which system .CVR file to use along with other parameters for running
the system. The .HTML file is built automatically by Corvid using a HTML template file. Everything in
the HTML file can be modified in a text or HTML editor except the applet tag that runs the system.
This can be done by editing the HTML template, or creating a custom HTML page to run the system.
ExsysCorvid.jar
The Corvid file ExsysCorvid.jar is the Corvid Applet Runtime. This file is copied into the project by
Corvid and cannot be modified. It is only used to run the system with Corvid Applet Runtime and is
not needed when running with the Corvid Servlet Runtime.
In addition to these files a system can have various other files that may be needed for the end user interface
or special system functions:
Data Files
Some systems use external data files. These may be interface files for connecting to a SQL
database, XML data files, simple “spreadsheet” files for use in MetaBlock systems, resource files for
systems that run in multiple languages, etc.. Except for SQL command files, these are generally kept
in the system project folder.
4: Variables 19
3.2 Projects and the CorvidProjects Folder
Starting with Corvid version 6, a “CorvidProjects” folder approach is used to manage your Corvid expert
systems. When Corvid is installed a “CorvidProjects” folder is created. This will be in “\Users\your_login” or
on Windows XP “\Documents and Settings\your_login” (The exact folder for your computer is displayed in the
Configuration window)
When you select to run a system from the Corvid Development tool:
3. Corvid checks to make sure Apache Tomcat is running. If it is not, Corvid automatically starts it. Corvid
cannot run systems locally unless Tomcat is running.
4. Corvid checks in Tomcat’s webapps folder, and if there is no folder with the same name as the system
project folder, Corvid creates one. This folder will be in a “CorvidProejcts” folder in Tomcat/webapps. This
is not the same as the main CorvidProjects folder. If the folder is already there from a previous run, Corvid
will use it. This folder should always be created by Corvid and should not be created or modified outside of
Corvid.
20 4: Variables
5. Corvid automatically copies all the files in
the system project folder in CorvidProjects
to the folder in the Tomcat webapps folder
with the same name. The system CVD file
is not copied since it is not needed to run.
Any files that the system will need should
be put in the system project folder in
CorvidProjects and Corvid will move them
to Tomcat when needed.
The one exception can be a Corvid database command file can be added to Tomcat, but not in the webapps
folder. This needs to be added directly to Tomcat and is not copied automatically by Corvid.
When you are ready to field your system, you can copy the files from Tomcat’s webapps folder for the system,
or you can copy the files from the CorvidProjects folder. However, for security, it is recommended that the
CVD file not be copied to an online server - this file is not needed to run systems.
which, while perfectly legal, is a little difficult to read. Using a name of “MySystem” (without a space) will
result in a URL that includes:
MySystem/MySystem.CVR
4: Variables 21
3.2.3 Opening an Existing Project
If you select “Open” under the “File” menu, instead of getting a window to browse the computer file structure
for the system CVD file, you are presented with a list of the Projects in the CorvidProjects folder. You can
only “open” one of the systems in the Projects folder. If there are other systems on the computer created with
versions of Corvid prior to version 6, they must be moved into the CorvidProjects folder to open them with
Corvid v6. This is done from the “Project Manager” window.
Delete - Deletes the selected project. The project folder and all its contents are deleted.
22 4: Variables
3.3 Starting and Stopping Apache Tomcat
Running systems with Corvid v6 requires that
Apache Tomcat be running. This is required when
running with either the applet or servlet runtimes.
The current status of Tomcat is displayed at the top of the Corvid window. There will either be a small Tomcat
icon (which indicates the Tomcat is running) or the icon with a red X on it (which indicates Tomcat is not
running)
Clicking on the Tomcat icon opens the Tomcat window. This can
be used to start and stop Tomcat . Just click the Start/Stop
button. This may take a few seconds, for the batch files needed to
be executed.
4: Variables 23
3.4 Running Systems in Development
A Corvid system can be run at any time by clicking
the blue Run triangle in the menu bar. Corvid will
update the CVD, CVR and other files in the project
folder, copy the required files to Tomcat and open a
browser window to run the system.
The Applet Runtime can be convenient for system development since it has a more extensive trace feature
than the Servlet. However, the Servlet Runtime has many more user interface features and options not
available in the Applet. With early versions of Corvid, building Servlet based systems required a good
knowledge of HTML, however with current versions of Corvid, no knowledge of HTML is required unless
advanced customized screens are needed.
Most browsers currently require the end user specifically allow applets and Java to run. This can confuse
users and certainly makes fielding systems more cumbersome. Using the Servlet Runtime avoids these
issues and allows systems to run on all browsers, even those that do not support Java such as iPhones,
iPads and other mobile devices.
Fielding systems with the Corvid Servlet Runtime requires using a server with Apache Tomcat, Glassfish, IBM
Websphere or comparable “Servlet Container”. While not all servers support this, it is becoming much more
common and standard.
Using the Corvid Servlet Runtime is the recommended approach to all system development. The Applet
Runtime is recommended only:
1. During development to use the more advance trace features to find/fix problems in the system logic
2. In cases, such as academic situations, where the system will not actually be fielded and it is known that
the intended end users (often the professor), can run applet based systems
3. If fielding the system requires using a server that does not support Servlets
In addition, for embedded systems, running as a Java application is an option. This runs the system as an
executable Java application (rather than an applet). Systems run this way are not run in a browser window
and have many of the browser Java security restrictions lifted. It is generally only done to interface Corvid
systems with other executable programs.
24 4: Variables
Capability Applet Runtime Servlet Runtime
Screen design language Corvid Screen HTML / CSS / Java Script / Etc.
Commands
Degree of control Control limited to color, Full control of entire screen - anything that can be
position, fonts, images done in HTML
Implement standard site look-and- Set style properties that HTML templates with replaceable parameters
feel apply to all questions
Ease of development Similar to formatting a Sample templates provided that can be edited with an
Word processor HTML editor
document
Complexity of design Limited - though more High - anything that can be done on an HTML page
than enough for most
systems
Security
Database
Browser
End user requirements Must allow / support Any browser including iPhones and iPads (Some
Java Applets browsers may not support advanced capabilities such
as HTML5 or CSS3) Adobe Flash based systems
require browsers that support Flash
Commercial Systems
4: Variables 25
3.4.1 Selecting How to Run a System
A system can be run with either the Applet or Servlet Runtime by simply selecting which to use. While it is
possible to make a system run differently in the two runtime modes, it requires taking special steps in the end
user interface to make this happen. Almost all systems can be run in either mode with the logic, question
order and conclusions exactly the same.
You can also select to run with the trace options turned on by
clicking the “Run with Trace” to select it.
More experienced users intending to field the system with the Servlet Runtime, often prefer to just use the
Servlet Runtime from the start, especially if customized templates for the user interface will be needed.
It is always best to get the system logic working first, using a very simple end user interface. Once the logic is
giving good advice, there are many design options for the end user interface that can be added. Some can
be done by adding simple Corvid screen commands, others may call for more advance HTML, which often
can be done independently of the development of the system logic.
26 4: Variables
Chapter 4: Variables
4.1 Exsys Corvid Variables
Corvid rules are made up of simple statements or algebraic expressions. Corvid provides the bridge between
rules people can read and ones the computer can use. Humans are good at understanding imprecise
statements, and filling in the gaps - computers are not. The rules in a Corvid system must be stated in a precise
way that the computer can use, but Corvid does this in a way that keeps the rules as easy to read as possible.
Corvid uses “Variables” to create the expressions that build a system’s rules. Corvid has various types of
variables depending on the type of data that they will hold. Variables are fundamental to all aspects of
building systems with Exsys Corvid. The logic of a system is defined with IF/THEN rules that use
expressions based on variables in Boolean tests in the IF part and assignments in THEN part. All of the input
values asked of end users, all the intermediate calculations and results, reports and advice will be built using
variables. Understanding variables is key to using Exsys Corvid.
Most of the ways that Corvid uses variables are similar to standard programming languages and algebra. All
Corvid variables have a name. There is no limit on the length of the name, but it must be unique and should
be something that is easy to recognize and remember. The following are examples of typical variable names:
Within Corvid commands and expressions, variables are identified by the variable name in square brackets:
[Price] > 10
[Name] = “Exsys”
[Length_of_beam] < 58
All variables must also have a “Type” that determines what kind of data it can hold and what type of
expressions it can be used in. Selecting the correct Type for your variables will make system development
much easier. The various types and when they should be used are explained in section 4.4
Variables have an associated “Prompt” text that describes what the variable represents, which can be used
when asking the end user to input a value for the variable, or in reports. Variables can also have many other
properties that define limits on their values, how the variables will appear in the end user interface, and
associated external interfaces to other programs and data sources. These provide ways to precisely control
how variables behave in a system.
4: Variables 27
This will display the Variables window.
(This window is also automatically
displayed when a new system is
started by selecting “New” from the
“File” menu.)
28 4: Variables
4.3.1 Variable Names
All variables in Exsys Corvid must have a name.
There is no limit on the length of the name, but it
must be unique and should be something that is
easy to recognize and remember. Names are
NOT case sensitive, so “WEIGHT” and “weight”
are considered the same variable.
To name a variable, enter the name in the “Name” edit box on the “New Variable” window.
Variable names built in non-English character sets can include any characters
EXCEPT:
Within Corvid commands and expressions, variables are identified by the variable name in square brackets:
[Price] > 10
[Name] = “Exsys”
[Length_of_beam] = 58
The name of a variable can be changed after it has been created and used in a system. Corvid will
automatically check all places where it is used internally and make the necessary corrections.
4: Variables 29
Static List Multiple choice list
Numeric Numeric value
String String value
Date Date Value
Collection Value is a list of strings (Used for reports)
Confidence Value combines multiple Confidence values
Dynamic List Multiple choice list (Set at Runtime)
Most of the Types are very similar to variables found in many programming languages, but others are
specialized for building expert systems. Usually the Type for a variable is determined by how the variable will
be used and the types of expressions that will be needed in the logic. Select the Type by clicking the
associated radio button on the “New Variable” window.
Choosing the Type correctly when the variable is created is very important. Unlike Name, the Type of a
variable CANNOT be changed after it is used in a system. (However, it can be changed immediately
after a new variable has been added, but not used in system rules and logic by clicking on the appropriate
“Type” tab.)
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
The value will be one of the items from the list. The value may be input by the user or assigned by rules in
the system logic. Various options control the number of items that can be selected or assigned.
Static lists are one of the most commonly used of all Corvid variable types and should be used
whenever it is possible to specify a fixed list of possible values for a variable.
Static Lists make user input easier since they just select an item from a list rather than entering a text string or
number. It also greatly reduces the need to check user input for correct syntax, valid data, etc.
Using a Static List variables also makes it easier to build structured rules that covers all possible variable values.
[Price] < 10
30 4: Variables
The value of a Numeric is “Continuous” and any value can be assigned to the variable. Options for the
variable allow specifying specific range limits that the value must be in, or that the value must be an integer.
In some cases, a system may need a numeric value, but there are only a few specific possible values (e.g.
Number of people in your car). In these cases, it can be better to use a Static List variable covering the
specific possible values.
String variables can have any string as a value. If the input is being asked of the end user, options allow
specifying “patterns” that the input string must match. This provides some degree of validation before the
value is assigned.
As with Numerics, if there are only a limited number of possible values for a string variable, it is better to use a
Static List variable so that the value is better controlled.
While string values can be parsed and tested, string variables are most often used for information that will not
be analyzed by the system logic (e.g. name, address, phone number), and is primarily used for building
reports or other interfaces where free text is needed.
Dates can be complicated since there are many ways to specify dates (e.g. 8/21/10, Aug 21, 2010, August 21,
2010) and dates are not written the same way in all countries. In some countries the form is month/day/year
and others it is day/month/year. This results in some short forms of a date being ambiguous and determined
by the localization settings of the computer. This can be important for systems that may be run from multiple
countries with different date representations.
Corvid uses the Java date functions which are quite good at handling the many forms that a date can occur in.
However, in some cases where the date value is not going to be analyzed, and is only going to be added to a
report, it can be better to use a String variable which can handle any text the user inputs.
Collection variables are most often used to build complex reports, where various rules in the system add
pieces of content to the report, or the report is built from a “template” file that combines report formatting with
the values of other Corvid variables. This approach makes it easy to build HTML, RTF and PDF reports that
can be displayed at the end of a session.
4: Variables 31
4.4.6 Confidence Variables
Confidence variables are variables whose value is a numeric “Confidence value”. The value is a measure of
how “good” or “likely” the diagnosis, advice or fact represented by the variable is. The Confidence value is
calculated from multiple values assigned to the variable by various rules.
Corvid provides many algorithms and methods to combine the various individual values to produce the overall
value. Simple systems can be used that match the expert’s approach or more mathematically rigorous
techniques can be used when the underlying rules and data allow it.
Often, there will be a set of Confidence variables representing the various possible diagnoses or items of advice
the system could give. The one(s) with the highest Confidence value are the ones most appropriate for, or
consistent with, the user input for a session. Confidence variables allow building systems that weight and compare
competing factors to select the most likely overall solution, and are used in probabilistic or “Fuzzy” systems.
See Section 4.6.4 below for the details of how Confidence variables combine values.
! If the value is to be asked of the end user and is only going to be directly incorporated into reports or
results (not analyzed or processed by the system logic) use a String variable. Strings provide the
maximum flexibility for user input.
! If the value needs to be analyzed using algebraic expressions or assignments that require a numeric
value, use a Numeric variable. Setting limits on the range of the input value can simplify the logic.
Remember that end users can be quite “creative” in their input and the values should be restricted or
checked in the logic to make sure they make sense.
32 4: Variables
! If the value needs to be a date/time to use in expressions or tests on a date, use a Date variable.
When date variables are used, be sure to take into account the various date formats possible. If the
date is not processed and only handled as text, use a String variable instead.
! If the value will be tested or parsed with Corvid’s string parsing functions, use a String variable. This is
also the appropriate option if a string value must be built up from various pieces, however if the
content of the text string is long or multiple items, a Collection variable may be a better option.
! If building a formatted report or a report that will be built up by various sections of logic, use a
Collection variable. Collections are very flexible and powerful variables ideally suited to reports.
! If a system will select the “most likely” solution/recommendation from among a group of possibilities,
use a group of Confidence variables. These will allow building sections of logic that contribute to the
overall probability of each Confidence variable. The one(s) with the highest Confidence value will be
the “best” recommendations.
When a new variable is added, the top group of tabs will be set to
“Prompt”, and the lower group will be set to the variable’s type.
4.5.1 Prompt
In addition to the Name and Type, each variable has a “Prompt”. This typically explains what the variable
represents. Normally the “Name” is relatively short and simple since it will be used in expressions, and the
“Prompt” is a longer detailed description of what the variable means. The Prompt can be any length and can
include any characters. The prompt is not directly used in the system logic, but creating good prompts can
make it faster and easier to build systems.
Generally, if a variable will be asked of the end user, the Prompt is the text that would be used when the
question is asked. It should clearly and precisely explain what is being asked, including any units or limits
that might apply. For example, a variable might be named [Weight], but the prompt could be “The weight of
the material being processed, not including the container, in kilograms. This should be a number less than
100”. Depending on the desired end user interface, the prompt may be phrased as a question, such as “What
is the color of the light?”. Using prompts for the end user question is a quick way to build a system, but is not
required, and there are many other ways to control the end user interface.
4: Variables 33
The prompt can also be used in various other places in a system when something more than just the name of
the variable is needed. Prompts are often used this way when displaying system results and advice or when
building reports to explain a value that has been assigned to the variable. In that case, the prompt will be
more of a statement or explanation than a question.
The Prompt can be any text and can be changed easily any time during system development. When a new
variable is added, the prompt will automatically be set to the name of the variable. It can be left this way and
then changed later when needed. If a prompt is only going to be used to ask for input. It may be best to phrase
it as a question. (e.g. “What is the price?”). If it is going to be used in reports, it may be better to have it be
more a phrase which can be combined with a value to make a statement (e.g. “The total price would be”). There
are many ways to use alternate text in place of the
prompt when needed, or if a system needs to run in
multiple languages.
When a new variable is added, the Prompt tab will be
selected and the Prompt text will be set to the variable’s
name. Normally this is changed to something more
explanatory, but in some cases where the Prompt text
will not appear, the name is sufficient. Often during
initial development, the Prompt can be left as just the
name and changed later when the end user interface is
being created.
34 4: Variables
3. Repeat until all desired values are entered.
For example, a Static List variable [COLOR]
might ask the color of a light. The possible
values are “Red”, “Yellow” and “Green”.
To Reorder the list: Click a value to move. Click the “Up” / “Down” button to move it in the list.
To see where in the rules a value is used: Click it to select it. Click “Where”.
To add a Short Text to a value, when the value is entered, enter the short text in the “Optional Short Text” edit
box before clicking the “Add to List” button.
While the value text can be any characters, the Short Text must follow the same restrictions on characters as
variable names. Spaces cannot be used and will be converted to underscore _. For systems built in English,
the short text should only include:
A-Z a-z 0-9 _ # $ and %
For non-English character sets it can include any characters EXCEPT:
To use part of the full value text for the Short Text: Use the mouse to select the text to use as the Short text
and click the “Use Select” button to copy that text to the Short Text edit box.
4: Variables 35
4.6.2 “Continuous” Tab
If the variable is a Numeric, String or Date
variable, the “Continuous” tab will be selected
in the lower tab group. These 3 types of
variables are “continuous” since they can be
assigned any value in a continuous range.
Numeric Limits
Numeric variables can have an optional lower and/or upper limit specified. Input values below the lower limit
or above the upper limit will be rejected. Just enter the lower and/or upper limits in the edit boxes. To remove
a limit, delete the value or uncheck the checkbox next to it.
There is also an option that the input value must be an integer. If this is checked, the input value must be an
integer. Non-integer values will be rejected - not rounded off. Values can instead be rounded, but this must
be done in the expressions using Corvid functions.
String Limits
String variables can have a “Mask” that the input value must match.
Syntax Matches
Masks are specified by a string that indicates what character(s) are acceptable. This can be used if the input
string has an expected pattern, and input not matching that pattern would be invalid.
All character matching, either individually or by group, is NOT case sensitive. A mask of “a” will match either
“a” or “A”.
36 4: Variables
For example:
Date Limits
Date variables can have limits set that the input is not more than X days in the past or future.
4: Variables 37
4.6.4 Confidence Tab
If the variable is a Confidence variable, the
“Confidence” tab will be selected in the
lower tab group.
During a run, the confidence variable will often be assigned multiple values by various Logic Blocks and rules.
The values assigned may be single values or calculated from formulas. These multiple values will be
combined to calculate an overall confidence value for the variable.
Confidence variables are somewhat unique to expert systems and behave differently than variables in other
programming languages. In most computer languages if a variable has a value X and is assigned a new
value Y, the old value X will be lost and the new value will be Y. That is also the way Corvid string, numeric
and date variables behave. However, Confidence variables combine ALL the values they are assigned during
a session to produce an overall value.
This allows multiple rules to independently contribute to the overall final confidence value. Some rules may
indicate that the variable is a “good” solution and should get a higher value, while other rules may indicate it is
a “poor” solution and should get a lower value. The various rules, along with the weighting they are given,
determines the overall value.
Trying to do this type of calculation using a normal Corvid numeric variable, would be quite difficult.
Confidence variables are designed for it. They keep track of all the individual values assigned, along with an
algorithm for how to combine them together to produce an overall value.
For example, a simple approach to confidence is the “Sum” method which just adds the individual values
assigned together for the overall value. Individual rules can add or subtract from the overall value by
assigning positive or negative values to the collection. If 3 rules assigned values of 4, 7 and -6, the overall
value would be 4 + 7 - 6 = 5. This is a simple approach but it actually works quite well for many situations.
38 4: Variables
When a new confidence variable is added to a system, the algorithm used to combine values must be
selected. Corvid provides 8 ways to combine the individual values along with options to modify each one.
Each variable can have its own way of handling confidence. This allows multiple techniques to be combined
as needed. However, most systems using confidence will have a set of Confidence variables that all use the
same algorithm to combine confidence values.
An algorithm should be selected that matches the approach used by the human expert providing the decision-
making knowledge for the system. This is done on the “Calculation” drop down list.
Calculation
The calculation parameters control how the values assigned to the variable will be combined to a single
overall confidence value.
There are 8 options for how to combine values. Select the one to use from the drop down list.
Sum - The values are added together. Positive values increase the confidence, negative values
decrease the confidence. This is a simple system, but works very well for many systems. Unless there is
valid statistical data on a process, this may be a good way to combine competing factors in a decision.
Average - The values are added together as with “Sum”, and then divided by the number of values. This
provides another simple way to combine competing factors, with individual factors having less influence
when there are many values added.
Independent probability - The values are combined as if they were independent probabilities. If there
are values X and Y, the combined value will be 1 - ((1-X) * (1-Y)) The individual values must be between
0 and 1. This is a statistically more rigorous approach, but requires that there be valid statistical data that
can be applied.
Dependent probability - The values are combined as if they were dependent probabilities. If there are
values X and Y, the combined value will be X * Y. As with the Independent mode, values should be
between 0 and 1, and it requires valid statistical data.
Multiply - The values are multiplied. This is basically the same as the dependent probability mode, but
here there is no assumption that the values actually represent probabilities, and the values can be any
positive value in any range. For example, a rule could lead to doubling the confidence by giving it a value
of 2, or halving the value by giving it a value of .5. Values in this system should be positive values.
MAX - returns the largest value assigned. This is useful for cases where individual rules can indicate a
variable is “good”, regardless of lower values from other rules.
MIN - returns the smallest value assigned. This is the opposite of MAX. It is good when a rule can
eliminate a variable by giving it a low value, regardless of high values given by other rules.
Mycin - This is one of the traditional approaches for combining confidence, often called the Mycin method.
Confidence values are assigned ranging from -1 meaning absolutely certain to not be valid, to 1 meaning
absolutely certain to be valid.
These values are combined by the following formulas:
! If the current confidence is 1 (absolutely certain to be valid) and a -1 is assigned, the result is 0.
! If the current confidence is >= 0 and the value to assign is >= 0 then the new confidence is (value
to assign) + (current confidence * (1 - value to assign)).
4: Variables 39
! If the current confidence is < 0 and the value to assign is < 0 then the new confidence is (value to
assign) + (current confidence * (1 + value to assign)).
! Otherwise, the new confidence is ((value to assign) + (current confidence)) / (1- min(abs(value to
assign), abs(current confidence)).
This confidence mode has a long history and it allows combination of factors that indicate a goal is valid
along with factors that indicate that the goal is not valid. The output is always a number between -1 and 1.
Many find this method counterintuitive and usually one of the other methods will be easier to use.
Calculation Limits
In addition to the algorithm for combining values, minimum and maximum limits can be set for the calculation.
If a calculated value is less than the minimum, the minimum limit will be used. If the value is higher than the
maximum, the maximum will be used. The calculated value can also be rounded to an integer.
! To set a minimum limit, enter the minimum value to accept in the edit box.
! To set a maximum limit, enter the maximum value to accept in the edit box.
! To limit assigned values to integers, check the “Round to Integer” checkbox.
Limits are rarely needed, but can be used for special situations.
Input
There are also three parameters that can be set to limit the values assigned to a Confidence variable:
minimum, maximum and integer.
If a value is assigned to the variable that is less than the minimum, the minimum value will be used. Likewise,
if the assigned value exceeds the maximum, the maximum will be used.
If “Integers only” is specified, the assigned value will be rounded to an integer.
If no limits are specified, any value can be assigned to the variable.
! To set a minimum limit, enter the minimum value to accept in the edit box.
! To set a maximum limit, enter the maximum value to accept in the edit box.
! To limit assigned values to integers, check the “Accept only Integers” checkbox.
Input limits are not normally used if the values assigned are simple values that come directly from the rules.
They are only needed if the values come from external sources or complex calculations that cannot be
guaranteed to provide values in the correct range. For example, if the Independent Probability method is
selected, the value must be between 0 and 1. If it is possible that a calculation or external source might try to
set a value outside these limits, the input limits could be used to prevent this.
Locking Rules
In some cases, it is desirable to lock the confidence value if a particular condition is met. The Locking Rules
allow this to be done.
Locking rules are added in the ”Lock value if” section by writing a Boolean expression with [#] followed by a “:”
and the value to lock to. [#] is replaced with the individual value being assigned to the variable. If the
expression is TRUE, the confidence value for the variable’s value is locked at the specified value and will not
be changed by any further assignments.
For example, if the locking test is:
[#] >= 10 : 10
then any assignment of a value of 10 or greater will lock the confidence value at 10.
If the locking test was:
[#]<0 : -1
40 4: Variables
then any assigned value of 0 or less would lock the confidence value at -1.
NOTE: Locking tests only apply to individual values being assigned. The overall value for the
variable can be any value provided no individual value triggered a locking test.
Locking tests can be used to override previous values for a Confidence variable. This is useful in methods
such as Average where it may be desired to have special meaning given to a specific high value rather than
just averaging it in.
Locking rules are very rarely needed and can only be entered if the “Show Advance Options” checkbox on the
Variables window is checked.
Make Parameters the Default
The same parameters often are used for multiple confidence variables in a system. This allows the
confidence values for that group of variables to be defined and used in a consistent way. To have the
parameters that are set for one Confidence variable be applied to others as they are defined, check the “Make
Parameters the Default” checkbox. As additional Confidence variables are added, the same parameters will
automatically be used. Parameters for existing confidence variables will NOT be changed.
To do this:
Collection Variable
The value list for a Dynamic List can come from the values in a Collection variable. If this is selected, the full
value for the Collection Variable will be derived via backward chaining before the value list is used for the
Dynamic List variable. Any rules that set values for the Collection variable will be used. Once the Collection
variable’s value list is finalized, it will be used for the Dynamic List.
4: Variables 41
External Source
An external program or data source can be used to get the values for the Dynamic List. External Interfaces
are covered in Chapter 13. (NOTE: Using external sources requires checking the “Show Advanced Options”
checkbox on the Variables window.)
42 4: Variables
4.7 Other Controls on the Variables Window
4.7.1 Variable List Order
When there are large numbers of rules in a system, having them sorted
alphabetically may not be the most efficient way to find a variable for
editing, and other sort options can be used. The order of the list of
variables can be controlled by selecting the “Sort” option, allowing the
list to be sorted by:
! Alphabetically.
! The order the variables were created (most recent at the
bottom).
! By variable type (sorted by order created within the Type).
! By variable type (sorted alphabetically within the Type).
The list can also be limited to only variables containing specific text. Enter the search text in the “Limit to
Variables Containing” edit box and click “Update”. Any variable with the search text in its name, prompt or
value list will be displayed.
4: Variables 43
With the “Show Advance Options” unselected the following controls are still available.
44 4: Variables
4.10 “Also Ask” Tab
The Also Ask tab is used to ask multiple
questions at the same time. Some user
interfaces call for multiple related questions to
be asked on the same screen. This can be
done from the Also Ask tab by setting the
properties for the “Controlling” variable. This is
the variable that will be the top variable asked
on the screen. When this variable is asked, the
other variables will be asked on the same
screen, unless they have already been asked
for some other reason - either asked
individually, or a part of an Also Ask with another variable. Variables that already have been asked will NOT
be re-asked even if they are in an “Also Ask” list.
When the controlling variable is asked, other variables will be asked on the same screen. To do this:
! Select the main controlling variable in the variables list (this is the one that will be asked at the top of
the screen).
! Go to the “Also Ask” tab.
! In the lower drop down list, select a variable to ask on the same screen.
! Click Add.
! Continue adding more variables as needed.
! Variables in the Also Ask can be reordered by selecting them and clicking the “Move Up” and “Move
Down” buttons.
Designing screens that ask multiple variables is covered in more detail in chapter 11 on User Interface.
Prompt Tab
With Advanced Options on, the Prompt tab has
options for:
4: Variables 45
To Be Tab
The To Be tab is for compatibility with earlier versions
of Exsys Corvid. Use of the To Be commands is
discouraged since there are now easier, clearer and
more maintainable ways to add the same logic.
Options Tab
With Advanced Options on, the Options
tab has additional controls for setting a
variable’s value and controlling backward
chaining.
! For Static List Variables, skip redundant rules - those are rules that would not provide any additional
information even if they fired, and would only set a value that is already set.
! Do not use backward chaining to derive a value.
The “Stop after first value is set” option will end backward chaining as soon as any rule fires that sets a value
for the variable. This can be very useful and can reduce the number of rules that are tested.
For example, suppose there is a Static List variable that may be set by the rules to any of several values, but
it will only be set to a single one. The default operation of the inference engine and backward chaining with
test all the rules that could set a value for the variable. In many cases, this is what is needed, but the logic of
a problem can be such that only one rule will file for any situation, and after that rule fires the other rules for
the variable can be ignored.
Using the “Stop after first” option will NOT test any other rules to derive a value for the variable after any rule
fires that sets a value for the variable.
“Stop after first” should only be used in cases where:
! The variable will only be assigned a single value.
! The variable (or variables) is not being used to force a group of rules to fire.
! The system is being run in Backward Chaining.
A related option is the “Skip redundant rules” option. This applies only to Static and Dynamic List variables.
A rule is “redundant” if it would not add any information to what is already known about a particular variable.
46 4: Variables
For example, suppose there is a Static List variable, “The color is”, with possible values “red”, “blue” and “green”.
If other rules the system already have set the value “The color is blue”. A rule that only had “The color is blue”
in the THEN part would be redundant. It would not add any new information on [COLOR], so there is no
reason to try to use it. Using the “Skip redundant” option would cause this rule to be skipped when the
system already knows the color is “Blue”. On the other hand, a rule with the “The color is red” in the THEN
part would not be redundant and would be tested. If that rule fired, the [COLOR] would be “red” and “blue”.
“Skip redundant” is generally a good option to set for Static and Dynamic List variables unless they are being
used to control when a block of rules fire. If a variable is being used to force a rule that also sets other
values, then it may be necessary to fire even redundant rules, but that is not a typical situation.
The “Do NOT Derive” option is rarely needed, and is primarily for variables that are incremented in many
places in a system. For example, if there are several rules of the form:
IF
…
THEN
[COUNT] = [COUNT] + 1
where each rule increments the variable [COUNT]. The first rule that fires will try to set [COUNT] to [COUNT]
+1. To do this, it needs the value of [COUNT]. Backward chaining would cause the other rules that could set
a value for [COUNT] to be called. This process would be repeated for each of the rules that fired. This
complex backward chaining is legal, and will eventually unwind to the correct answer, but it is not needed and
may result in questions being asked in an unexpected order.
Using the “Do NOT Derive” option would prevent the chaining and, provided [COUNT] was initialized to 0,
would simply increment it for each rule that fires. This is especially needed for cases where this type of rule is
used in a MetaBlock. Since MetaBlocks can ONLY be called in forward chaining mode, using them for
backward chaining would cause an error.
Remember, if the “Do NOT Derive” option is selected for a variable, it cannot be used as a backward chaining
goal. The command DERIVE [COUNT] would not cause the rules that might set a value for [COUNT] to be
called. Instead, [COUNT] would receive its initial value, or if there is none, it would be asked of the user.
Any backward chaining options that are set apply ONLY to the associated variable. Different variables can be
set with different chaining options.
Initialize
The “Initialize to” control allows setting an initial value for a variables when the system start. This can be used
any time a starting value is needed, such as setting a variable used as a counter to 0 at the start of a run.
Initialization is different than a “Default” value. Default sets the value of a control when it is asked of the end
user. That way, the user can just press the return key to accept the default value, or they can change it.
Default with the “Never Ask” option set is very similar to an initial value, but the default value is set when the
variable would be asked, and overrides the ASK command. The Initial value is set at the start of the run, and
does not override an ASK command (which would ask for a new value.)
4: Variables 47
External Source
To have the value of the variable set by an external source such as a database, XML file, etc. click the “Edit”
button next to the “External Source for Value” edit box. External data sources are covered in chapter 13.
Check for PARAM
The “Check for Param” option is a special type of external data source. It is equivalent to using an PARAM
external data source command with the PARAM name the same as the variable name. If this is selected, the
PARAM data will be automatically check for the variable’s name. PARAM commands are covered in the
external interfaces section 13.7.
Link Tab
The Link tab provides a way to add an HTML link to the
overall variable Prompt text. This is maintained primarily
for compatibility with systems built with early versions of
Exsys Corvid. This approach is not recommended since
Corvid now supports standard HTML tags to add links
into text. This allows a section (or all) of the Prompt text
to be made into a HTML link which will work with both the
Corvid Applet and Servlet Runtimes. See the User
Interface section 11.3.5 for information on using HTML
links in Corvid text.
If a system has links created with the Link tab, this tab will
be active. New systems or systems not using links will not have this tab active.
Servlet Tab
The Servlet tab is used for setting the template file,
replaceable parameters and FLASH code to use for
the variable when running with the Corvid Servlet
Runtime. The Corvid Servlet Runtime is covered in
Chapter 17. Using Corvid with Adobe Flash is covered
in Chapter 18.
48 4: Variables
Static List Tab
With Advanced Options on, the Static List tab has
options for:
! Calling an external program or database that
will return the text to use for the value text.
This is covered in chapter 13 on External
Interfaces.
! Alternate value texts can be used. Up to 5
alternate text strings can be specified to use.
This is primarily for systems that run in
multiple languages and is covered in section
11.6 on designing systems to run in more than
one language or with more than one prompt/
value text.
4: Variables 49
Chapter 5: Expressions
5.1 If /Then Rules
Exsys Corvid rules are structured as If / Then rules.
IF
Boolean Test 1
AND: Boolean Test 2
AND: Boolean Test 3
AND: ....
THEN
Assignment 1
Assignment 2
Assignment 3
....
The IF part can have multiple Boolean tests, but they are always combined with logical AND. This means that
ALL the IF statements in a rule must be individually true for the overall IF part to be true. If any of the
individual IF statements is false, the overall IF part is false. (There are ways to build expressions using OR
and other logical operators in a single expression.)
The THEN part of a rule can contain multiple assignments. When the IF part of a rule is true, ALL of the
assignments are made. (A rule can also have commands in the THEN part).
Each of the 7 Corvid variable types can be used to build specific types of boolean test and assignments.
Using the correct variable types will make it easier to build rules that most closely match the logic and
decision-making process of the human expert.
Before starting to build rules, it is essential to understand Corvid’s syntax and options for the expressions that
will make up the rules. This chapter is designed to explain the types of expressions and logical tests that can
be built in Corvid. In the next chapter, these will be used to build rules.
5.2 [Name]
In Corvid expressions and assignments, variables are identified by their name in square brackets. So an
expression:
[Price] + 1
means add one to the value of the variable whose name is “Price”. Assignments are usually made to a
specific variable identified by the name in square brackets.
The exception to this is Static List variables, where the variable’s name does not use square brackets. The
square brackets are not needed because of the simple syntax of Static List statements and makes the rules
easier to read.
In expressions, [X] means the value of the variable named “X”. The variable’s type will determine what type the
value is - a numeric variable will have a numeric value, a string variable will have a string value, etc. There are
also other properties of variables that can be used in expressions. These are covered later in this chapter.
5: Expressions 51
5.3 Static List Variables
Static List variables are the easiest to use to build Corvid rules and and should be the first choice when possible.
Static List variables have a name, a Prompt text and a fixed list of possible values. The value list should
cover all the possible values that the variable can have. Normally, the combination of the Prompt text plus a
value makes a readable statement.
For example:
Static List statements are the only ones in Corvid that do NOT use square brackets around the
variable name. This both makes them easier to read and makes it easy to identify Static List expressions.
variable_name = value
The syntax of the statement is the same for both IF and THEN, but icons in the Logic Block and the structure
of the rule indicate if the statement is being used in an IF or THEN context.
The values for a Static List are essentially “Flags” that can be set. A variable may be designed to allow only
one, or multiple values to be set. The individual values that are set can come from user input, other rules that
have made assignments to this variable or external data sources such as database interfaces.
Rules in Corvid can be viewed either in the Logic Block or in the Rule View which provides an expanded
version of the individual rule. In Rule View mode, the statement will appear as the Prompt text followed by
the value text. When there are multiple values, they will be combined with “OR”.
If the Static List was given optional “Short Text” for the values, the short text will be used in the Logic Block,
but the full value text will be used in the Rule View.
52 5: Expressions
For example, in the IF part of a rule:
Color = red is true if the value “red” was set for the variable “Color”, otherwise it is
false.
Color = red, yellow is true if the value “red” OR “Yellow” was set for the variable “Color”,
otherwise it is false.
Color = red Assign (set) the value “red” for the variable “Color”.
Color = red, yellow Assign (set) the values “red” and “yellow” for the variable “Color”.
Static List assignments do not replace the current value, but add to it. If the variable “Color” has the
value “Red” selected and it is assigned the value “Blue”, the new value will be “Red AND Blue”. (If in a
system, the new value should replace the old value, use the RESET command to erase the old value before
assigning the new one.)
[X] >= [Y] + [Z] The value of variable X is greater than or equal to Y + Z.
Normally, the left side is a single variable, but it can be any expression.
5.4.2 Type
Both sides of the comparison test must be the same type. Corvid supports 3 types of Continuous variables
(Numeric, String and Date). Only like types can be compared. When an expression is added to a Logic
Block, Corvid will automatically check to make sure the type matches and display a warning if it does not. If
the left and right side expressions do not have the same type, it will lead to a runtime error.
5: Expressions 53
5.4.3 Comparison Tests
The supported comparison tests are:
= Equal
== Numeric: Values are exactly equal.
String: Values match in content and case.
(either form can be used) Date: Values match exactly
Not Equal
Numeric: Values differ.
!= String: Values do not match in content or case.
Date: Values differ.
Greater Than
Numeric: Left side is greater than right side.
> String: Left side is alphabetically greater than right side*.
Date: Left date is chronologically greater (later) than right date.
Less Than
Numeric: left side is less than right side.
< String: Left side is alphabetically less than right side*.
Date: Left date is chronologically less (earlier) than right date.
Less Than
Numeric: left side is less than or equal to right side.
<= String: Left side is alphabetically less than or equal to right side*.
Date: Left date is chronologically less (earlier) than or equal to right
date.
Approximately Equal
Numeric: Values differ by less than .005%.
~= String: Values match in content but case insensitive.
Date: Millisecond time values differ by less than .005% (~15 minutes).
* String comparisons with < and > use the character values in the strings and are case
sensitive. This can be confusing when comparing upper and lower case strings. To compare
strings in a true, case insensitive, alphabetic test use the UCASE() function to force both
sides of the test to upper case. (e.g. UCASE([S1]) > UCASE([S2])
5.4.4 Parenthesis
An expression can (AND SHOULD) use parenthesis as needed. Corvid supports the standard Java order of
precedence of operators, but using parenthesis in an expression is recommended to make evaluation
absolutely clear. Parenthesis can be nested to any degree. For example:
54 5: Expressions
5.4.5 Numbers
Numbers in expressions can be:
5.4.6 Constants
The following constants can be used in expressions:
Constant Value
PI 3.14159...
NOTE: The CR, LF and CRLF constants do NOT cause a line break when displayed on user interface
screens. Use <BR> to do that. These are used for precise control when writing to files or emails to
add specific characters to output.
Operator Meaning
! Logical NOT
For example:
( [X] > 0) & ([Y] > 0) TRUE only if both X and Y are greater than 0.
5: Expressions 55
5.4.8 Arithmetic Operators
The following standard arithmetic operators are supported in expressions:
Operator Meaning
Addition
+ For stings, concatenation
- Subtraction
* Multiplication
/ Division
[varName] = expression
For example:
[X] = 5
[X] = ( [Y] / [Z] )
[S] = “abcd”
[S] = “ABC” + “DEF”
When a Continuous variable is assigned a value, any existing value it has will be overwritten and lost. It is
legal to use the same variable in the left and right side of the expression to include the current value in the
assignment. For example:
[COUNT] = [COUNT] + 1
Date formats vary around the world, and the ones acceptable depend on the localization for the version of
Java being run. (That is Java on the client machine when using the Applet Runtime, and Java on the server
when using the Corvid Servlet Runtime.)
56 5: Expressions
In the US, the formats are:
Month# / Day# / Year 12/31/09
Month short name day, year Jan 5, 10
Month full name, day year January 12, 2010
The formats can also include time. (e.g. January 12, 2010 7:30:12 PM) When time is used, AM or PM must
be included. The time will be assumed to be for the local time zone, unless another time zone is specified.
For example:
[Date1] = “Jan 5, 10”
[Date1] = “August 7, 1970”
[Date1] = “August 7, 1970 10:30 AM”
[Date1] = NOW( ) (Set the current date and time)
[Date1] = NOWMSEC( ) (Set the current date and time using a numeric value)
[Date1] = NOWMSEC( ) + (24 * 60 * 60 * 1000) (Sets the date 24 hours from current time)
[CONF1] > 10 (The confidence value of variable CONF1 is greater than 10)
[CONF1] > [CONF2] (The confidence value of variable CONF1 is greater than CONF2)
[CONF1] > [X] (The confidence value of variable CONF1 is greater than the value of X)
5: Expressions 57
5.6 Collection Variables
A Collection variable has a value that is a list of strings. The other variable types and their expressions are
fairly standard algebra and should certainly be familiar to anyone that has done programming. Collections are
little more unusual, though they do occur in many computer languages. Collection variables are a very useful
and powerful type of variable and are the key to generating most advanced reports.
The Collection’s value is a list. IF statements can test if something is in the list and THEN statements can add
or delete items from the list. The list itself can be made up of simple items (e.g. a shopping list) or it can hold
more complex text such as HTML content making up a report or web page. The individual values in the
Collection’s value list can be set at startup, obtained from external sources and files, or added individually by
rules in the system.
The Collection statements have a very different syntax from other IF/THEN statements since they use
properties and methods of the variable. However, it is not necessary to memorize the syntax, since the
Corvid development environment will build the statements for you. All you will need to do is provide the
content and set options on how to use it.
When a Collection variable is used in a THEN statement, it is to add or remove content from the collection
variable’s value list. There are many options for adding items to the list. THEN statements can:
! Add specific text as an item in the list.
! Add contents from a file.
! Add the value of a variable.
! Add the list from another Collection as multiple items.
! Add items with a “Sort” value, allowing the list to be ordered.
! Adding items as “vectors”, with multiple related items together.
! Removing an item from the list.
! Clearing the entire list.
58 5: Expressions
Many of these Methods have options for where items are added in the list, or to make sure the same item is
not added more than once.
As with the IF statements, it is not necessary to memorize the syntax for each of these commands since
Corvid will help build the command for you.
If “abc” is a value in the variable’s value list, and it has been set by, the test will be true. Likewise the same
statement in the THEN part would set the value “abc” - but this would require that the value “abc” be one of
the values in the variable’s value list.
This inability to know the values until runtime limits how dynamic list variables can be used. However, when
used with MetaBlocks, this is not a problem since the value list can come from the same “spreadsheet” data
as used in the MetaBlock. This allows systems that have complex logic, but which can be modified by just
changing the MetaBlock data file. MetaBlock systems are covered in Chapter 12.
5.8 Functions
Corvid supports a wide range of functions that can be used in IF and THEN expressions. The function list
includes the standard algebraic functions, string parsing and manipulation functions, date functions and some
special Corvid functions. For example, to set the value of X to the sin(y):
[X] = SIN( [Y] )
To set string S2 equal to the left 5 characters of string S1:
5: Expressions 59
There are many specialized
functions, especially for string
manipulation. Most systems only
need simple tests and algebraic
expression, but when more complex
math is needed, or strings need to
be parsed and manipulated
functions are the answer.
When building expressions in the
Logic Blocks, the list of functions
can be displayed by clicking the
“Function” button and selecting one.
This will be added to the expression
and can be edited to set any
required arguments.
The full list of all functions and their details can be found in Appendix A.
When a string is parsed in Corvid, the embedded double square bracket variables are replaced first, and
independent of any other content in the string.
This allows assigning one type of variable to another. For example, if [S] is a string variable and [N] is a
numeric variable, and we want to assign [S] the value of [N] as a string. Using:
[S] = [N]
60 5: Expressions
[S] = “ [N] “
makes both sides of the assignment strings, but it would assign literally “ [N] “ as a string - not the value of
[N]. To solve this use double square bracket embedding:
[S] = “ [[N]] “
This will replace [[N]] with the value before anything else is done. This puts the actual value in the quotes and
makes a valid assignment to a string.
Double square bracket embedding is a very effective way to handle situations where simply putting the
variable name in single square brackets will not work.
When Corvid needs to display the prompt, it immediately needs the value of the variable [NAME]. If there are
no rules that could set the value, it would directly ask the user. This means that if the system logic called for
asking the question about favorite color, it would first ask the user their name, then ask about favorite color
with the name value embedded. This can be very convenient, since the embedding the value automatically
forces the variable to be asked when (and if) it is needed.
However, perhaps [Name] is obtained from a database and the external interface command to get the name
requires the customer’s ID number. Now instead of asking for [Name] when the “favorite color’ value is
needed, Corvid will suddenly ask for “Customer ID” since that is what is needed to get a value for [Name].
That may be unexpected and break the flow of questions. It can be even more complex if the embedded
variable is derived from rules that need multiple other variables to set the value.
Unless the backward chaining of the embedded variables is being used for a specific procedural reason, it is
generally best to derive or set the value of embedded variables before they are used.
In special cases, it may be necessary to embed the immediate value a variable has at that point in the
session, even though the variable value will change later in the session. To do this use:
[[*varname]] or [[*varname.property]]
Putting an asterisk immediately following the “[[“ and before the variable name tells the Corvid inference
engine to embed the value the variable currently has, without doing any backward chaining to derive a value.
If the variable does not have a value, it will not be asked and nothing will be embedded.
[X] = [Y] + 1
5: Expressions 61
However, Corvid variables have many other attributes that are sometimes needed. Variables have
Prompts. When a system runs, there is information on when and how the value was set. The value of the
variable may need to be formatted in different ways. All of these, and many more, are handled by using
Properties of the variable.
A variable’s properties can be used by:
[VarName.property]
[VarName.property arguments]
For example, [X] means the value of the variable, but [X.Full] means the variables prompt plus the value. So if
there is a variable [Temp] with a prompt of “The temperature is” and a value of “75.3”:
The property name is NOT case sensitive, so [Temp.FULL] and [Temp.full] are the same.
All properties can also by put in double square brackets to embed the Property value. To assign the
formatted value of [Temp] with its prompt to a string:
Using properties with double square bracket embedding allows variable data to be used in many special ways.
Some Properties provide information on the actual execution of the system. [X.Age] will return the number of
milliseconds since a the value of [X] was set of changed. [X.Time] will return the exact time that variable [X]
was set. [X.How] will display an explanation of how the value of variable X was set - what rules assigned
values, etc. (This can be useful in documenting system logic and debugging systems.)
The full list of all Properties and their details can be found in Appendix B.
62 5: Expressions
In rare cases, an expression may appear incorrect,
but due to “creative” uses of MetaBlock parameters
or embedded variables, it will be valid at runtime. If
the Syntax Error window is displayed and you are
sure the expression is correct, click the “Use As Is”
button to accept the expression. Be sure to check
any such expressions at runtime to verify that they
are evaluated without problem.
When Corvid parses the expression, it breaks it down to smaller sub-expressions, checks their syntax and
type, and then checks that these types would fit in the overall expression. Normally when an error is found
the error message is quite specific, such as “parenthesis do not match”, or wrong type. However, in some
cases, the expression can be so confusing to the parser that all it can do is report an “Error”. (This can
happen with something as simple as a missing quote, causing the parser to treat what should be text as
functions/operators in the expression.) When this happens, it will convert the sub-expressions to a single
character that represents their type. These are represented by:
The error will include the original expression with the sub-expression replace by the #, $ or @. Usually
this helps narrow the problem down to a part of the original expression, while indicating what parts are
probably correct.
5: Expressions 63
Chapter 6: Forward and Backward Chaining
6.1 Introduction Understanding backward chaining is essential to fully
Most concepts in Corvid are utilizing the power of the Corvid Inference Engine and
similar to other programs. building efficient, well structured systems in Corvid.
Variables, algebraic expressions
and IF/THEN statements are
found in all programming languages and many other contexts. Likewise, diagramming logical processes and
flows of execution are encountered in many places from flow charts and simple diagrams to more specialized
representations. Various ways to define user interface screens and reports are also pretty common. The
details of how Corvid does these things may be slightly different, but the underlying concepts are fairly
standard and generally familiar to most people that use computers frequently.
“Backward Chaining” is the one big exception. Backward chaining is relatively unique to expert systems. It is
a very important concept to fully understand. It can seem confusing at first, but once the principles behind it
are clear, it is easy to understand.
! Rules are made up of IF conditions (boolean expressions) using variables that evaluate to TRUE or
FALSE.
! When a rule has multiple IF conditions, they all must be TRUE for the rule to be TRUE.
! When a rule is TRUE, its THEN conditions will assign a value to a variable(s).
IF
[X] > 0
AND [Y] > 0
THEN
[Z] = 1
IF
[N] > 0
THEN
[Y] = 1
There are 4 Corvid variables [X], [Y], [Z] and [N] and we want to use the rules to determine the value of [Z].
If these are run in order with forward chaining, the first rule would be tested first. The system would ask for
the value of [X] since that is the first IF condition. If that value was greater than 0, it would then ask the value
[Y]. But that is a problem, since the second rule can set the value for [Y]. If there is rule to set the value for
[Y], it would be better to use that rule to derive the value than to ask the user.
One solution would be to move the second rule to be first in the list:
IF
[N] > 0
THEN
[Y] = 1
IF
[X] > 0
AND [Y] > 0
THEN
[Z] = 1
Now the rule to set the value for [Y] occurs first and the value can then be used in the second rule. But this is
a problem if it only makes sense to ask [N] when the “[X] > 0” condition is true. If “[X] > 0” is false, [Y] is not
needed since the rule is automatically false and either asking or deriving [Y] may not make any sense to the
end user, so we do not want to start off by asking [N], as would happen from the reordering.
IF
[X] > 0
AND [N] > 0
THEN
[Y] = 1
Now [N] will only be asked if [X] is greater than 0. But that is not the same rule as before. Setting [Y]
based on the value of [N] may be needed in other rules that are NOT dependent on [X], and were [X] would
not be needed.
IF
[X] > 0
AND [Y] > 0
THEN
[Z] = 1
IF
[N] > 0
THEN
[Y] = 1
With forward chaining we needed to find an order for the rules that ran correctly, and we were not able to do
this. With backward chaining, we use “goals” and do not care about the rule order. Instead of procedurally
running the rules in order, with backward chaining we set the goal to “Find the value of [Z]”. This tells the
inference engine that only rules that can set a value for [Z] are relevant and need to be tested.
Now [X] becomes the top level goal briefly replacing [Z]. The [Z] goal is not forgotten, just temporarily
replaced by [X]. Since there is no rule that can set the value for [X], the end user is asked for the value of [X].
That satisfies the [X] goal and it is dropped, with the [Z] goal again becoming the top level goal.
If [X] was greater than 0 the rule is again a way to satisfy the [Z] goal and the inference engine now needs to
test the second IF condition and needs the value of [Y]. As with [X], [Y] now temporarily becomes the top
level goal, superseding [Z]. Here however, there is a rule that can set that value [Y]. The inference engine
finds that rule and tests its IF condition. Now it needs the value of [N]. At this point the goal list is:
[N]
[Y]
[Z]
Since there are no rules to set [N], it is asked of the end user and [N] is dropped off the goal list, bringing [Y]
to top. If [N] was greater than 0, the second rule will set a value for [Y], and [Y] will be dropped off the goal
list, bringing [Z] back to the top. Now the original rule can fire assigning a value to [Z] and it can be dropped
off the goal list. Since the goal list is then empty, the inference engine is done.
This may seem complicated, but all the complexity was handled by the inference engine and happened
invisibly to the developer. Just provide the rules, in any order and instruct the inference engine to use them.
If [X] had been less then 0 the first IF condition would have been false and [Y] would not have become a goal
and the second rule would never have been needed or tested. If the rules had been in a different order, the
system would have run the same way. The second rule did not need any extra condition to control how it was
used, it just stated a rule that could be used when needed, and the inference engine determined when it was
needed. All of the problems with forward chaining are gone automatically just by running the rules with
backward chaining.
Best of all, even if there were many rules with many levels of interdependencies, it would all still automatically
work correctly.
At first, backward chaining may not seem like an advantage over forward chaining, but the power of backward
chaining is that the “Goal” changes dynamically. If determining the value of the current goal requires the value
of another Corvid variable to evaluate an IF test or THEN assignment, that new variable immediately
becomes the new Goal. The Inference Engine maintains a list of “Goals” and new goals are added to the top
of the list. When a new goal variable is added to the list, the “relevant” rules immediately become the ones
associated with that variable. The Inference Engine then focuses on those rules. When that goal is achieved
by having the goal variable assigned a value, that goal is removed from the goal list and the next one down
again becomes the top level goal that the Inference Engine will focus on.
The adding and removal of goal variables from the Goal stack happens dynamically, and occurs many times
when running a backward chaining system. The rules that are relevant to the immediate goal constantly are
changing and rules are used in an order that may be very different from the way they are ordered in a system.
This can be confusing at first since it is not following the procedural order of the rules - but it is actually
following a very logical and structured approach to using the rules in the system that allows creating and
maintaining much more complex systems.
Backward chaining allows building small sub-sets of rules that form reusable modules to answer portions of a
problem. The variables set in these modules can then be used in higher level rules that describe a more
general solution. Backward chaining will automatically use the modules as needed by the higher level rules.
The Inference Engine will automatically find the “relevant” rules at each step of the process. If the logic is a
module changes, all this is needed is to change the rules in the module and the changes will automatically
apply everywhere the module is used.
This can be confusing at first, but is actually simple. The inference engine uses the rules the way a person
would think about how to solve a problem - high level logic that uses other lower level rules to provide the
values needed in the higher level rules. People don’t consciously think about “goals”, but if an expert is
explaining how they made a decision, and they say “Because of X and Y, I knew...” and you ask “How did you
know X?”, They will explain lower level logic that let them know X. In Corvid terms, X was briefly their “Goal”
and those rules set X. When the rules are structured in Corvid, the goals become more apparent, but they
are actually the same way experts solve most complex problems.
Rule 1:
IF
Weather is COLD
THEN
Wear a Coat
Rule 2:
IF
[Temperature] < 32
THEN
Weather is COLD
! A Static List variable [Weather] that indicates what the weather is.
! A Static List variable [What_to_Wear] that will list the items to wear.
! A numeric Variable [Temperature] that will have the current temperature.
If these rules were run in Forward (Order Driven) Chaining, the Inference Engine would simply test them in
the order they occur. The steps would be:
1. To test the first rule, the system would need the value for the variable [Weather] and would ask the
end user if the weather is cold. If they said it is “cold”, it would assign the value “Coat” to the
[What_to_Wear] variable.
2. It would then ask the variable [Temperature]. If the value entered was less than 32, it would assign
that the [Weather] is cold - regardless of what the user had told it in step 1.
This has a couple of problems. The variable [Weather] is asked of the end user in rule 1, and then potentially
assigned a value in rule 2. It could end up with conflicting values. Also, the criteria intended to define
[Weather] as “cold” in rule 2 is not applied in rule 1 since that rule has not been used.
In this simple case, these problems could be fixed by moving rule 2 to before rule 1. However, backward
chaining is a much better solution, especially as systems get more complex.
If the 2 rules were run in Backward (Goal Driven) Chaining:
1. Instead of instructing the Inference Engine to run specific rules, in Backward Chaining it would be
given a “Goal” to achieve. Here, that Goal would be to determine the value of the Corvid variable
[What_to_Wear].
2. The Inference Engine would examine the rules to determine which rules are relevant to the goal.
That means those were the goal variable [What to Wear] is assigned a value in the THEN part. This
only occurs in rule 1.
3. Since rule 1 is “relevant” to the immediate goal, the Inference Engine checks its IF conditions to see if
they are TRUE. The only IF condition is the one to determine if the “Weather is Cold”. This requires
knowing the value of the variable [Weather]
4. Unlike Forward Chaining where the [Weather] variable would immediately be asked of the end user,
in Backward Chaining [Weather] becomes the new top level Goal, temporarily superseding the
[What_to_Wear] goal. The variable [What_to_Wear] remains in the Goal list, but as the second item.
! Use any specified external sources for the variable (database, etc).
! Ask the end user for the value.
8. Here there are no external sources, so the variable would be asked of the end user.
9. Once the user provides input, the goal of getting a value for [Temperature] is met and the variable is
dropped off the Goal list. This makes the goals list:
[Weather]
[What_to_wear]
10. Since [Weather] is the new top level goal, the system goes back to trying to set a value for that
variable by using its relevant rules. This means testing rule 2. Here we will assume that the
temperature value is less than 32, so rule 2 fires and assigns the “cold” value to [Weather].
11. Since [Weather] now has a value, that Goal has been met and [Weather] can be dropped off the Goal
list. This brings [What_to_wear] back as the only item in the Goal list. The Inference Engine now
resumes working on that goal, by testing its relevant rules (Rule 1).
12. The variable [Weather] had been assigned a value of “Cold”, so the IF part of rule 1 is TRUE and
“coat” can be assigned to [What_to_wear]. This is the only relevant rule, and the top level goal has
been assigned a value, so it can be removed from the goal list. The Goal list is now empty and the
Backward Chaining process is finished.
Clearly the Backward Chaining process was more complex and had more steps, but the complexity was
handled automatically by the Inference Engine. The rules were used in a more effective manner when the
heuristic in rule 2 was needed, it was automatically used regardless of the rule order. In fact, the system would
run the same regardless of rule order. Even if Rule 2 had been first, it would use the rules in the same way.
With Backward Chaining, If/Then rules should not be viewed as “code” to be executed in a particular order,
but instead as individual facts that will be used when, and if, needed. Developers with a background in more
procedural programming may find this somewhat “free-form” approach disconcerting at first, but it is the key to
building complex systems. Actually following the Goal list and the “relevant” rules is not generally necessary.
Once the Backward Chaining approach is understood, it becomes easy to build modules of rules that
integrate together to handle complex problems.
Logic Blocks are used to organize and provide high-level structure to the rules so that complete, maintainable
sets of rules can be created - but the Corvid Inference Engine focuses on the rules, not the Logic Block
structure. Equivalent sets of rules can be created by many different Logic Block designs. Some designers
like large Logic Blocks that contain many rules, others like many smaller Logic Blocks that each contain fewer
rules. Both approaches are correct as long as they generate all the rules needed by the system. It is even
possible to just have one rule in each Logic Block, but that is usually poor design.
The Inference Engine does keep track of what Logic or Action Block a rule came from and the order of the
rules in that Logic Block. This allows referencing rules by their associated Logic or Action Block. This is used
primarily in forward chaining, where the rule order is more important. It is also used in commands that reset
rules or limit chaining using the name of the associated Logic Block, and to describe the rules that set a
variable’s value.
Corvid Logic Blocks are where the rules are actually created in a system. Logic Blocks enable you to
organize and structure rules so that they cover all relevant situations. They should be easily understood and
maintainable. A full system may have only one Logic Block, or many. It all depends on how the approach to
the problem is structured.
Logic Blocks are typically made up of tree structured diagrams that organize a group of related rules. A Logic
Block may have multiple trees, or trees and rules. A Logic Block can be anything from an entire knowledge
base to a single rule - it all depends on what the problem calls for.
Typically a single Logic Block contains all the rules relevant for a specific “aspect” of the decision. What makes
up an “aspect” depends on how the developer wants to structure the decision-making task. Normally, a subtask
that makes up part of a decision will be in its own Logic Block - but that is not required. For any realistic
problem, there are MANY ways to structure the Logic Blocks, and as long as they give the correct results, they
are all valid.
In most cases, the Logic Blocks should try to organize the rules in a way that matches the decision-making
knowledge that the system is based on. There may be existing decision-trees, SOPs or other documentation
of the decision-making process, or the knowledge may come directly from a human expert. It is best to try to
have the Logic Blocks match the approach used in solving the problem. This is not a requirement, but will
make building the system faster, easier and more maintainable.
If the Logic Block and rules follow the same sequence and approach as existing documentation, it will be much
easier to match Corvid rules with specific approved steps. This speeds development and review of the system.
Rules are related if they share common IF statements. For example, suppose the expert says that one of the
heuristics to make a decision is:
IF
Test 1 = True
THEN
Result = A
IF
Test 1 = False
AND Test 2 = True
THEN
Result = B
IF
Test 1 = False
AND Test 2 = False
THEN
Result = C
These rules are related since they share common IF statements, and those
IF statements are based on the same Corvid Variables (Test 1 and Test 2).
They can be diagrammed as a tree. In a Corvid Logic Block, they would
appear as:
The green angle brackets indicate a group of related values for a single
variable, or related expressions. Having a group indented under another
line, indicates those conditions are combined with AND. The arrows
indicate THEN statements.
IF
Test 1 = True
THEN
Result = A
Lines 3-5 are equivalent to:
IF
Test 1 = False
AND Test 2 = True
THEN
Result = B
Lines 6 and 7 are equivalent to:
IF
Test 1 = False
AND Test 2 = False
THEN
Result = C
This is because any indented sections are combined with the IF statements
that they are indented below. In a Logic Block, this can be seen more easily
by clicking on a line in the tree to select it and the associated lines that build
that rule will be highlighted. Clicking on the last line will highlight the
associate IF statements making it easy to see the rule.
IF
The customer has high risk tolerance
AND: Meeting objectives requires rapid growth
THEN
Mutual Fund X is a good choice
This could be part of a Logic Block that described the selection logic at this level, using “risk tolerance”,
“objectives” and other criteria. A separate Logic Block could have just the rules related to determining the
customer’s “risk tolerance”. This might be a few rules in a single tree, or might be more complicated and use
values set by yet other Logic Blocks. Another Logic Block could set “objectives”.
These Logic Blocks are just a way to organize the rules related to an aspect of the decision-making task. The
inference Engine will make use of all the blocks and rules, to create a logical process that is equivalent to a
very large single tree, if it was programmed by procedural techniques, but the Corvid approach is far easier to
build and maintain.
The “risk tolerance” Logic Block rules would apply anywhere the higher level logic needed to consider “risk
tolerance”. If the logic related to determining “risk tolerance” changed, all that would be needed is a change
in that Logic Block and the change would automatically be used anywhere “risk tolerance” was needed.
The number of Logic Blocks in a system and their organization is very flexible. There are many ways to build
equivalent systems. Some developers like many small Logic Blocks, others prefer a smaller number of larger
ones. The Logic Block structure should be designed so that it matches the approach and process of the
human expert. This makes structure makes it easier to translate the expert’s heuristics into the form the
Corvid inference Engine can use.
There will also be a “Rule View” window opened with the Logic
Block. This Rule View will show the full text of the IF/THEN rule
associated with content in the Logic Block. The Rule View is easier
to read than the shortened form of the rules in the Logic Block, but it
only shows one rule at a time.
Logic lock names can be any text, but must be unique. They should be fairly short and easy to recognize.
A tree is made up of “nodes” that correspond to IF or THEN statements in a rule. The tree structure is created
by adding related IF nodes in groups, such as the various possible values for a variable. These form the
branches in the tree. The way groups of nodes are indented indicated their relationship with other nodes in
the tree. When an IF node is indented, it is ANDed with the parent node above it.
In this simple tree, the two “Test 1” IF nodes are a group that cover the
possible values for “Test 1” (True and False.) When “Test 1 = True”, it has a
THEN node under it. (THEN nodes are indicated by an arrow icon.) The first
2 lines make a complete rule.
IF
Test 1 = True
THEN
Result = A
The “Test 1 = False” node, requires additional tests. The two “Test 2” nodes
make a group that covers all the possible values (True and False). These are indented under the “Test 1 =
False” node, indicating that they are IF nodes which are combined with that “parent” node using AND. The
“Test 2 = False” node is also combined with the same parent node, because it is indented, even though there
are other nodes between them. The “Test 2” nodes and their associated THEN nodes become the rules:
IF
Test 1 = False
AND Test 2 = True
THEN
Result = B
IF
Test 1 = False
AND Test 2 = False
THEN
Result = C
Trees always start with at least one IF node. Normally, nodes are added
in groups that cover the possible values of a variable. This may be a
group of nodes that cover the possible values for a Static List variable, or
it may be a group of expressions that cover possible numeric, string or
date variable values.
For example, suppose a system has logic that needs to know if it is a weekday or the weekend. This could be
a static list variable [Today] with prompt “Today is a” and values “weekday” and “weekend”. The first rule being
added to the Logic Block might be:
IF
Today = weekday
AND ...
THEN ...
This rule actually only needs the node for “weekday”, but since that is not always the case, the node for
“weekend” should be added at the same time. This provides a “placeholder” and reminder in the tree that
rules need to be added for that value too.
The actual mechanics for adding nodes will be covered shortly, but once
the nodes are added the Logic Block would be:
This has one node for each value. The brackets joining the nodes
indicate that they form a group of related nodes, The brackets are red
because there is an IF node with no associated THEN node. With no THEN nodes, it cannot be a valid rule.
When a THEN node is added, the bracket for that IF node will become green. It is easy to tell what parts of a
Logic Block are incomplete just by looking at the color of the brackets.
IF-AND-Above
“Above” will add a parent node that is above, and indented out from, the group that the currently
selected node is in. The group will be a sub node of the first node added.
Same Level
The “Same Level” group has “Below” and “Above” buttons, which add nodes that are at the same
level with the currently selected node and either before or after it.
For example, using with the [Today] variable above and a second Static List variable, [Weather]
Today is a
1 Weekday
2 Weekend
The weather is
1 Sunny
2 Cloudy
Using the 2 nodes added for [Today] with the top node selected.
1. Clicking the IF-AND-Below button will add nodes that are ANDed below the selected node. The [Weather]
nodes would also be added as a group covering both values, with the “Weather =Sunny” node first.
Notice that both new nodes are indented below “Today = Weekday”. These nodes will build the IF statements
for the rules
IF
Today = Weekday
AND Weather = Sunny
THEN ....
IF
Today = Weekday
AND Weather = Cloudy
THEN ....
IF
Today = Weekend
THEN ....
These rules do not yet have any THEN nodes, as indicated by the red brackets.
The IF-AND-Above button adds the FIRST new node as the new parent
node to the selected node, and adds the other new nodes at the same level
as that node. In this case, the order of the nodes that are added makes a
difference. The first node added will be the new parent node ANDed with
the selected node. The other nodes added will not be in the same rule as
the node that had been selected. The rules are now:
IF
Weather = Sunny
AND Today = Weekday
THEN ....
IF
Weather = Sunny
AND Today = Weekday
THEN ....
IF
Weather = Cloudy
THEN ...
3. Going back to the original “Today” nodes once again. This time click
Same Level - Above and add the same group of 2 “Weather” nodes.
The “Same Level” buttons add the new nodes at the same level in the tree
as the selected node. The “Above” button adds the before the selected
node and the “Below” button adds them below the selected node. They
will not be indented relative to the selected node. They can be used to add
nodes that have the same parent node(s) as the selected nodes, but are
unrelated to the selected node.
Notice that the new node has an arrow icon indicating it is a THEN node.
Also notice that the red bracket on “Today = Weekend” has become
green. This indicates that the node is now part of a full IF/THEN rule.
IF
Weather = Sunny
AND Today = Weekend
THEN
Go to the beach
The bracket for “Weather = Sunny” is still red because while this is a full rule, the node for “Today = Weekday” is
not complete. Anytime an IF node has an uncompleted rule (IF with no THEN) under it, the bracket will be red.
The color of the THEN arrow indicates the type of variable that is being assigned a value:
Yellow Confidence
Magenta Collection
List of Variables: The variable to use is selected from the list. When a variable is selected, the
Prompt is displayed under the list. There are controls to limit the variables displayed in the list. When
a system has large numbers of variables, it can be more convenient to limit the list to only a specific
subset of variables
Node Building Controls: Depending on the selected variable’s type, there are 3 tabbed controls for
building individual nodes. There are special tabs for Static List and Collection variables. All others are
built as “Expressions”.
Nodes to Add: As nodes are built, they are added to the Nodes to Add list. All of these nodes will be
added to the Logic Block when “Done” is clicked. This may be a group of related IF nodes or a group
of THEN nodes that all apply to the same rule.
To add a node for each value, click the “Add Each Individually”
button.
This will create a node for each of the values. These will be displayed in the “Nodes
to Add” list. These are the nodes that will be added to the Logic Block when “Done”
is clicked.
One node for each value will be added to the Logic Block.
To build a node:
1. Select one or more values from the list. (Use Shift Click to
select a block of values or Ctrl Click to select multiple
separate items.)
Here the values “Sat” and “Sun” have been selected to add into a
single node. When the values are selected, the lower display shows
the full text of the node being built to assist in making sure that this is
the intended node. This is built using the full variable prompt and full
text of the values selected.
Clicking “Add to List” will add the node with the selected values.
To add Mon, Tues and Wed as another single node, select the 3 values.
Clicking the “Add All in One Item” will add all the remaining
values into one node.
The three “Add..” buttons allows quickly building groups of nodes to cover all
possibilities.
Using NOT
The “Not” check box allows building nodes that are true if the
selected value(s) are NOT set. This is actually equivalent to a node
that checks if the others are set, but can be more convenient if there
are large numbers of values and a rule only needs to check that a
particular value is not set.
To use “NOT”, select the value as above. Then click the “NOT” check
box.
This will build a node in the Logic Block using “!=” indicating “NOT”.
NOTE: When “NOT” is used, it is often to create a single node, and all possible values may not
be covered. When there are multiple NOT nodes, they may not be mutually exclusive and
more than one can simultaneously be true. It is never required to use “NOT” since equivalent
nodes can always be created without “NOT”, but it can be a convenient and more readable way
to build some rules. To build more complex logical tests on values, use “Expressions” with the
properties of the Static List variable.
(The Edit button is not used for Static List variables. It applies to Expression
and Collection variable nodes, allowing the node to be edited rather than just
removed.)
When the node is added, it will appear in the Logic Block with an arrow icon
indicating it is a THEN node.
Building out the other THEN nodes in the Logic Block with other Static
List value assignments.
(It should now be fairly easy to read this Logic Block and the rules it will
convert into.)
In the “Add to Block” window, if a variable is selected in the left variable list
that is NOT a static list or collection variable, the “Expression tab will be
selected.
A boolean expression is entered in the edit box, and then added to the
“Nodes to Add” list by clicking on the “Add to List” button. This process
which is true if the value of the variable [WEIGHT] is greater than 100.
While there are other ways to build nodes with Static List variables, they can also be used in expressions. If
there was a Static List variable named FAVORITES, and the logic needed to know if 3 or more value items
had been selected, it could use:
[FAVORITES.COUNT] >= 3
The property “COUNT” is used which returns how many values are selected in the variable’s value list.
Expressions can include multiple variables and any of the Corvid functions (see Appendix A), operators and
parenthesis as need. For example:
Building an Expression
An expression can be built simply by typing in the expression, but Corvid can help you by providing lists of
variables, properties, functions and MetaBlock parameters.
There are 3 buttons under the Expression edit box, “Variables”, “Functions” and, when working in a Logic
Block that is set to be a MetaBlock, a “MetaBlock” button.
Variables Button
Clicking on the “Variable” button under the
“Expression” tab, will display a list of all the
variables in the system.
Click on a variable in the list on the left side.
All of the properties for that variable will be
displayed on the right, along with a brief
description of the property. If a property is
desired, click on it. Then click “OK”. If no
property is required, just click “OK” or double
click on the variable.
MetaBlock Parameters
If the node is being added to a Logic Block that is a MetaBlock, and the associated MetaBlock file is specified,
clicking on the “MetaBlock” button will bring up a list of the active MetaBlock parameters (spreadsheet column
OR XML headings) that can be used in formulas. Selecting one will add it to the expression. For information
on MetaBlocks, see the “Working with MetaBlocks” Chapter 12.
Groups of Nodes
Normally expression IF nodes will be added in a group that covers all
possible variable values (or at least all values in the variables allowed
range). For example, a system needs to check to see if the numeric
variable [Temp] is:
! Over 100
! Between 50 and 100
! Less then 50
First the expression checking if [Temp] is over 100 would be added.
Enter:
[Temp] > 100
and click the “Add to List” button clicked.
This adds that expression to the “Nodes to Add” list.
Enter the expression:
( [Temp] > 50) & ( [Temp] <= 100 )
and click “Add to List”.
NOTE: When building expressions, be sure to have groups of tests
cover all possible values. If this expression had been [Temp] < 100,
there would have been no node that covers the case where [Temp]
was exactly at 100.
[varName] = expression
The variable is selected by clicking on it in the variable list of the “Add to Block” window. This will copy the
variable’s name to the expression window, followed by the “=”. (when the node is built, if the variable being
assigned a value is not the selected variable, Corvid will report this as an error.)
The expression created must match the type of the variable:
! Numeric variables must be assigned numeric values - any expression or function that returns a number.
! String variables must be assigned strings - either other string variables, expressions that evaluate to
strings or text in quotes. Other variables can be forced to strings with double square bracket
embedding in quotes.
! Date variables must be assigned date values - either date variables, functions that return a date or a
date expressed as a string.
! Confidence variables must be assigned numeric values consistent with the confidence mode and limits
- any expression or function that returns a number.
For example, if there are numeric variables [X] and [Y], String variables [S] and [S2] and Date variable [D] and
[D2], the following are legal assignments:
Node Meaning
[D] = [D2] Assign [D] the same date and time as [D2]
[D] = CREATEDATE( [D2], 0, 0, 30) Assign [D] a date 30 days after date [D2]
[D] = “Jan 5, 2010” Assign [D] The date “Jan 5, 2010” (Must be in
quotes)
Node Problem
Multiple Nodes
When adding Then Nodes, either one or more nodes can be added, but normally, a specific variable will only
be assigned a single value. Just build the individual nodes and add them to the “Nodes to Add” list. All the
nodes will be added when “Done” is clicked.
It is legal to assign the same variable multiple values in a single THEN block, but numeric, string and date
variables will have the last value overwrite the earlier ones. Confidence and Collection variables retain all
values that are assigned, and sometimes are assigned multiple values in the same THEN.
Properties Meaning
TRUE if the first item in the value list for [COL] is str
[COL.FIRST] = “str” (NOTE: quotes are not needed)
TRUE if the last item in the value list for [COL] is str
[COL.LAST]= “str” (NOTE: quotes are not needed)
The properties .INCLUDES and .NOTINCL are NOT case sensitive. If the test string matches, regardless of
case, the test will return true. The .FIRST and .LAST properties just return the specified item from the value
list and the comparison is a standard Corvid string comparison, which is case sensitive. (To do a case
insensitive comparison, use an expression: UCASE ([COL.FIRST] ) = “STR” This will make both strings
upper case for the test.)
The IF expressions built by the Collections tab could also be built in the Expressions tab using the properties
for the Collection variable. This allows more complex expressions to be built along with some that cannot be
built directly from the Collections tab such as the .COUNT property which returns the number of items in the
value list (e.g. [COL.COUNT] > 10 ). The full list of Collection variable properties and methods can be found
in Appendix B.
Enter the text to be added to the collection in the edit box. The item
will be added as the last item in the list unless “Add as the first item”
is checked. The text can be any text and can include the value of
other variables by using double square bracket embedding.
If the list should only have an item once, and other rules may have
already added the item, check the “Do NOT add if an identical item
already in the list”.
If the rule fires, the collection variable will have the text added. This
provides a very convenient way to dynamically build up text that can
be used for many purposes in reports, to track the rules that fired or to build up lists of values to be used in
other parts of the system.
The entire file will be added unless the optional key is used to
specify only part of the file.
Adding a file is a very good way to build reports. The file can be a
report “template” that has the structure of the report, but uses
double square bracket embedding to include the value of Corvid
variables. The file can be text, HTML, RTF or other formats.
When Corvid adds the file to the Collection variable, the double
square bracket variables will be replaced by their actual values.
This produces a full formatted report in the Collection variable that
can then be displayed in various ways.
The variables in the “Available” list can be controlled by selecting the controls in the “Restrict to” box. The list
can be limited to one or more types of variables by checking associated Type check boxes. Only variables of
the types checked will be included in the “Available” list.
The list can also be limited to variables whose prompt or value includes certain text. Enter the text in the
“Limit to Variables containing the text”.
To include all variables, click the “Allow All Variables” button. This will reset to include all types and remove
any text limitation.
Once a group of variables have been moved to the selected list, this list can be saved for later use. Click the
“Save Current List” button. You will be asked for a name for the list. This can be any unique, descriptive
name. To recall the list, just select the name entered in the “Save/Recover” drop down list. To delete a list
name no longer needed, select it from the drop down list and click “Delete”.
Variables in the “Selected” list can be sorted alphabetically or by “Order entered”. A specific variable in the
“Selected list” can be located by entering text in the “Find” edit box and clicking “Find”. Variables with the text
in the prompt or value will be highlighted. To search again, click the “Again” button.
When the list of variables to display is correct, click the “Done” button. This list will become the new display
list when adding nodes.
Left Click Selects the node and deselects all other nodes.
Shift – Left Click Selects the node and all its sub-nodes.
Shift – Ctrl – Left Click Selects the node and all its sub-nodes without
deselecting other selected nodes.
Deletes all selected nodes. This operation also removes all selected nodes
Delete and sub-nodes off the selected nodes. If the sub-nodes are to be saved,
first Copy them, delete the parent node, and paste the sub-nodes back in.
Deletes all selected nodes and sub-nodes. The deleted nodes are saved
Cut
for pasting.
Pastes any saved nodes under the selected node, at the same level in
Paste Below
the tree.
Pastes any saved nodes above the selected node, at the same level in
Paste Above
the tree.
Paste Indented Pastes any saved nodes as sub-nodes to the selected node.
Redoes the last step that was removed via undo. This can only be done
Redo
to one level of undo.
Undo and Redo can also be accessed from the Logic Block menu.
7.9 IF THEN IF
One additional feature of the structure in Logic Blocks is the ability to add a THEN node and still continue the
tree with more IF nodes. This is a very convenient way to include a THEN node once, rather than putting it in
many branches of a tree. For example, suppose on the weekend, you wear a tee shirt regardless of the
weather, this could be added as:
The blue arrow next to “Wear Tee Shirt” indicates it is a THEN node. However,
IF nodes continue off it. To do this:
1. Build the “Today =” branches and add the “Business Suit” node as you
did before.
2. Select the “Today = Weekend” node and click “Variable” under THEN.
3. Add a single THEN node assigning “Wear = Tee Shirt”.
4. Select the “Wear = Tee Shirt” node and click the “IF:Below” button.
5. Add the 2 values for “Weather = Sunny” and “Weather=Cloudy” and
complete these nodes as before.
The “Wear = Tee Shirt “ is included only once, but it will apply to all the rules built off it. Clicking on “Wear =
Jeans” displays the Rule View:
The “Wear Tee Shirt” condition is marked with “>>>” indicating that it does
not depend on all of the IF conditions, and is part of an IF/THEN/IF tree.
NOTE: When an IF/THEN/IF is used in a backward chaining system,
the middle THEN part will fire only if one of the variables in the middle
THEN nodes needs to be derived. The middle THEN nodes will NOT
automatically fire just because the final THEN nodes fire. In a forward
chaining system, the middle THEN nodes will fire if the final THEN
nodes fire.
! Make copies of the initial system for each developer to use as a starting point. There should be a
defined objective for each developer, such as derive the value for a particular shared variable,
implement a particular part of a procedure, or create a Logic Block to perform particular actions.
! Each developer can now add their own variables, Logic Blocks and Command Blocks to their copy of the
system. A specific naming convention should be used for any Variables or Blocks that the developer adds
to make sure they have a different name from any that other developers may add. The variable that each
developer adds should be used only by that developer, since they may have different intended meaning
from a variable of the same name added by another developer. Only the shared variables from the initial
system should be used by all the developers (unless there is consensus among the developers on new
shared variables).
! Each developer will probably have a Command Block for their rules. If these are all the same block, it
is easy to convert this to the merged system. If there are multiple different Command Blocks, they will
either need to be called from a main Command Block, or "cut and pasted" to make a single Command
Block.
! Once the systems are merged, they should be tested thoroughly by all developers to make sure any
changes in the Command Block or in Logic Block order has changed the way the system operates.
7.12 Printing
To print the variables, blocks and rules in a system select “Print” under the “File” menu or click on
the print icon. This will display the print dialog:
Variables
To print the variables in a system either click the “All Variables”
radio button or the “Specific Variables” radio button, and select
the variables to print in the list on the right.
The printout will contain the selected variables and all
parameters.
To print one variable per page, check the “One Per Page”
checkbox.
To add a cross reference listing of all the places where the
variable is used in the system, check the “Cross Reference”
checkbox.
The line number of the node in the block is displayed on the left. IF conditions are in black. THEN nodes are
in blue.
The parent nodes that combine to make up a rule are displayed whenever there is a THEN node(s). These
are displayed in light gray prior to the last IF node. The combination of the parent nodes (in gray), the last IF
node (in black), and the THEN nodes (in blue) make up a rule. In a large tree, the parent nodes may be far
up the page or on a earlier page, repeating the parent nodes in gray makes it much easier to read the full set
of IF conditions required for the THEN nodes to fire.
To turn off the display of the parent nodes, uncheck the “Add Full Rule Before THEN” checkbox. This will
make the Logic Block printout smaller, but will not be as easy to read.
Action Blocks
To print the Action Blocks in a system either click the “All Action Blocks” radio button or the “Specific Action
Blocks” radio button, and select the Action Block(s) to print in the list on the right.
Action blocks are printed by showing the variable/value or Boolean expression in the block with associated
action indented under it.
Variable 1
Value 1
Action 1
Action 2
Value 2
Action 1
Expression
Action 1
Command Blocks
To print the Command Blocks in a system click the “All Command Blocks” radio button or the “Specific
Command Blocks” radio button, and select the Command Blocks to print.
Format
The Format box allows a left margin to be set. The “Step Indent” value is the amount each node in a block is
indented from its parent node.
The font size can be selected from the drop down list.
The last branch point in the tree that does not have an
associated variable is the one on “Height”. Since this
only has 2 branches, it could be a Static List with fixed
values, but for this demo a Numeric variable will be
used, to show how algebraic formulas can be
incorporated into the system.
Create a new variable named “Height” and make it a
“Numeric”.
To quickly find specific variables, enter text into the “Limit to Variables
Containing” edit box and click “Update”. Only variables containing the text in
their name, prompt or values will be displayed. (When limiting text is used, be
sure to delete it to again see the full value list. Just delete the text and click
“Update”)
Since the “Horns?” nodes are below the “legs = four” node, the two are
“ANDed” together. Click the “IF-AND-Below” button to add a node and
match the structure of the tree diagram.
The new nodes are added to the block. They are indented under the
“Number_of_legs = Four” indicating they are ANDed with that node.
If the animal has horns, the decision tree indicates the animal is “Cattle”.
To add this into the block, click on the “Horn = Yes” node to select it.
(Remember, when a node is added, it is added relative to the currently
selected node.)
For the sample, just assign a value of 1. Just enter “1” following the
“[Cattle]=”.
Then click “Add to List” .
The single node will appear in the “Nodes to Add” list. When adding
THEN nodes, generally there is only a single node to add, though
when needed, multiple ones can be added at the same time.
Click “Done” to add the node to the block.
The Logic Block now shows the “[Cattle] = 1” node indented under “Horns =
Yes” and “Number_of_legs = 4”. Since the “[Cattle] =1” THEN node is
selected, the associated IF nodes are highlighted in bold magenta making it
easy to see the rule structure.
Select the “Horns = No” node and build out the nodes that correspond to the
left side of the decision tree. Use the “Udder” and “Length_of_legs” variables
to build the IF nodes, creating one node for each value.
When the decision tree conclusions are reached, assign values to the
corresponding Confidence variables (“Cattle”, “Horse” and “Pig” ) in the
THEN nodes.
When this part of the decision tree is built, the Logic Block should look like:
Click on the various THEN nodes to see the associated rules in the Rule
View window.
Notice that the IF brackets are all green except for the top one. This
indicates that the “Number_of_legs = Two” node is not yet complete, but that
the others will build IF/Then rules.
The next step is to finish off the block by adding the nodes for the right side of
the decision tree. Click on “Number_of_legs = Two” to select it and add the
node corresponding to “Height” under it.
The decision point in the tree is based on the height being “less than
or equal to 12” or “greater than 12”. Build the first node as a Boolean
test by entering the expression “[Height] <= 12”
Click the “Add to List” button.
That completes the Logic Block. The rules can be traced by going down the
block to see that it exactly matches the tree diagram.
Logic Blocks can easily represent logic diagrammed as a tree. However, they
can also do much more complex logic required for probabilistic systems which
cannot be diagrammed as a single tree.
Now that the Logic Block is built, the system can be run. However, first it needs a Command Block. Logic
Blocks tell the inference engine the steps to achieve a goal, but the Command Block sets the goal to achieve.
A Corvid system MUST have a Command Block to run. Command Blocks are covered in Chapter 9, but
Corvid can automatically build a simple default Command Block adequate to run this simple logic.
The system can be rerun by clicking the “Restart” button. To go back to the preceding question, click the
“Back” button. It is easy to work with the tree diagram and input answers that go down the various branches.
This type of segmentation is easy to implement in Corvid. All that is needed is to create some “Flow”
variables. These are just Static List variables that are used to control how the flow of execution will go from
the top tree into the other “pages”.
Now to build the Logic Blocks. The first (Main) Logic Block is built exactly like
in the first (single tree) system, but the places where the system goes to page
2 and page 3 are not yet filled in.
Select the “Number_of_legs = Two” node, which is the node that goes to page
2 in the segmented tree. Instead of continuing the tree here, we will set the
“Go to page 2” variable. Click the “Then - Variable” button to add the node.
(NOTE: Be sure to make this a THEN node, rather than an IF node.)
This will add the “Go to page 2” node to the main tree.
Now select the “Udder = No” node to do the same thing for the “Go to page
3” node. This time select the “Go to page 3” variable and set the value to
“Yes”.
This completes the main tree. It exactly matches the structure of the first of the 3 trees.
This will build a singe node that applies to all the rules in the Logic Block and that
only lets them be used if “Go to page 2” is set to “Yes”. This may be set in the first
tree, and if that does not set “Go_to_page_2” to “yes” it will automatically be set to
“No” - blocking the rules in this Logic Block.
The rest of this block is the logic that is in “Page 2” of the tree diagram. It is built
the same way as was done in the first demo.
The rules are built UNDER the single top node, so click the “IF-AND-Below”
button to add the nodes and build out the tree.
That is all that is needed for the “Page 2” Logic Block. The only difference between the Logic Block and tree
representation is the top node to indicate that this should be used only if “page 2” is needed. The rule part
matches the “Page 2” tree.
Now do the same thing for “Page 3”.
Create a new Logic Block and name it “Page 3”
Add a top level IF node “Go_to_page_3 = Yes” and then build the
associated rules under it.
That is all there is to it. There are now 3 Logic Blocks that match the
3 trees and they will automatically flow together to work as one.
To see this run the new system, click the blue “Run” triangle.
This time when the “No Command Block” window is displayed, select
to backward chain in confidence variables.
[Cattle]
[Pig]
[Chicken]
[Goose]
[Cattle] is the new top level goal, so only rules that set a value for that are tested. There are 2, and both have
a top level IF condition of “Number_of_legs=4”. This time, the variable [Number_of_legs] already has a value,
so it does not need to be derived. Once a variable is assigned a value, that value is immediately used - a
variable will only be asked or have its value derived once (however, it may come back to the top of the list
many times). Here since the value of [Number_of_legs] is 2, all the rules that could set a value for [Cattle] or
[Pig] are false and those 2 confidence variables will be removed from the goal list. It is now:
[Chicken]
[Goose]
The rule for [Chicken] comes from the “Page 2” Logic Block.
IF
Go_to_page_2 = Yes
AND [Height] <= 12
THEN
[Chicken] = 1
[Go_to_page_2 ]
[Chicken]
[Goose]
The rule that can set [Go_to_page_2] is from the “Animal ID” Logic Block:
IF
Number_of_legs = 2
THEN
Go_to_page_2 = Yes
Most Corvid systems have very simple Command Blocks with only a few commands. The logic of the system
and the rules used in making the decision should be in the Logic and Action blocks - not the Command Block.
The Command Block should only be the procedural steps needed to tell the Corvid Inference Engine how to
use the rules in the Logic and Action Blocks.
The Corvid Inference Engine is a very powerful tool for using the rules in a way that will solve problems and
interact with the end user in a way that emulates a conversation with a human expert. Most well built Corvid
systems are designed to run using the Inference Engine’s default approach to using the rules. Usually it only
requires a few Command Block commands to start the Inference Engine on a task, and then control can be
turned over to the Inference Engine to run the rules. This is very different from traditional programming where
every step has to be coded in detail along with the exact procedural flow. Beginning Corvid developers tend
to try to “program” Corvid the same way, spelling out every step in long complex Command Blocks. This can
be made to work, but is not the most effective way to build systems with Corvid.
Building Corvid systems efficiently and effectively requires understanding how the Corvid Inference Engine
works and structuring the rules in a way that takes advantage of the Inference Engine. There are 2 main
ways to run the rules, forward and backward chaining.
Forward chaining (covered in chapters 6 and 7) is a way to run the rules in the order they occur in the Logic
and Action blocks. This is a much more procedural and structured approach and generally easier to get
started with. There are Command Block commands to run the rules in a system in a forward chaining mode,
grouping them in logic and Action Blocks. If the rules are structured this way a FORWARD command will run
the rules in a logic or Action Block. All the decision-making logic should be in the rules - the FORWARD
command just tells the Inference Engine which rules to run.
Backward chaining is a much more powerful way to use the rules in a system and is capable of solving
problems that could not be done with forward chaining. Backward chaining is covered in chapter 6. It is
conceptually simple, but unique to expert systems, so it often takes awhile to get use to it - but it is the key to
efficiently building powerful expert systems. Here a single DERIVE command in the Command Block will start
backward chaining and is often all that is needed to run the rules in a well designed system.
Most Corvid systems will have small Command Blocks with 3 sections:
Starting Commands - These are commands that display a title or explanatory screen on what the
system will do and what is expected of the end user. Sometimes this also asks a few questions
that the developer wants to present at the start, even though they may not directly be used in the
logic. The commands here are to implement a user interface rather than implement decision-
making logic.
Each of these sections is normally only a few commands. If a system has more than that, it is often an
indication that decision-making logic that should be in the rules is being put in the Command Block. It should
never be necessary to write pages of Command Block commands.
Corvid has many Command Block commands and ways to add IF, WHILE and FOR loops in the Command
Blocks. This is to give Corvid the ability to handle even very complex systems that require complex Command
Blocks. If the procedural aspects of a system are complex, it may require a complex Command Block to handle
it. The section on each command indicates if a command is commonly or rarely used. The rarely used
commands are occasionally necessary, but unless a system is unusual in some way they should not be needed.
When building Command Blocks, the goal should always be to make it as simple as possible, letting
the Inference Engine run the logic.
Left Click Selects the node and deselects all other nodes.
Shift – Left Click Selects the node and all its subnodes.
Ctrl – Left Click Selects the node without deselecting other nodes. If the
node is already selected, it is deselected.
Selects the node and all its subnodes without deselecting
Shift – Ctrl – Left Click
other nodes.
Selects the node and deselects all other nodes. Displays a
Right Click popup menu allowing easy access to the editing options
available.
Shift Right Click Selects the node and all its parent nodes.
Redo the last step that was removed via Undo. This
Redo can only be done once to reset one level of Undo.
! To edit an existing command, click on it to select it and click the “Edit” button.
! For a new Command Block, only the “Add” button will be active since there are no commands to add
“before” or “after”.
This table summarizes the commands on each tab and how often they are used.
Tab Use
As the table shows, the commands on the “Variables” “Blocks” and “Results” tabs are the only ones frequently
used. The others are either for special functionality (reports, email, External interfaces) or are rarely needed.
String Variables
String variables must be assigned string values. This can be:
! Text in quotes.
! Another String variable.
! An expression that evaluates to a string.
For example:
SET [S] “This is some text”
SET [S] [AnotherStringVariable]
SET [S] [S] + “Text to add”
SET [S] [COL.CONCAT]
SET [S] “The value of X is [[X]]”
To build a string incorporating numeric values, double square brackets can be used to embed the value of a
variable in quotes.
Collection Variables
When a Collection variable is selected, the “Method” drop
down list becomes active. A method for how the value/
expression will be added to the Collection value list must be
selected. The Methods are the same as when adding to a
Collection in the THEN part of a rule. The methods ending in
“_UNIQUE” will add the new value only if it does not already
exist in the list.
The expression to add depends on the method selected.
For methods that add a string, the expression should be a
text string in quotes or an expression that evaluates to a
string. (Remember double square bracket embedding can be
used to add the value of other variables in the quoted string.)
If the method calls for another Collection variable, that
variable should be entered in the Expression edit box in
square brackets.
If the method is to add with a Sort, enter the text to add in quotes, followed by a comma, followed by the sort value.
Some methods do not require any expression such as CLEAR or DROPFIRST.
Single Variable
Click on the drop down list next the “Variable” radio button. Select the variable to derive.
Syntax Matches
? Matches any character
* Matches the rest of the string, including spaces
Character Matches itself
# Matches any digit 0-9
{abc} Matches any single character in the { }
{X-Z} Matches any single character between X and Z
This allows fairly complex masks to be constructed, but in practice, the best way to use a variable naming
convention with masks in the DERIVE command is to simply start all the variables to be derived with an easily
identified string such as “D_” and use the mask “ D_* “ to select all the variables that start with “D_”.
Simply click the radio button and select the variable from
the drop down list.
Forcing a variable to be asked is most often done at the
start of a system where a desired user interface requires a
specific group of variables to be asked in a defined order. This should be limited to variables that are
ALWAYS needed in the session, rather than variables that are only needed (or relevant) in specific cases -
those will be asked when (and if) the Inference Engine determines they are needed. It can also be used for
variables that will be used in a report, but which are not actually part of the core decision making logic, such
as user name, location, etc.
Logic Block 2:
IF
[Y] > 0
THEN
[X] = [Y] + 1
If the “Allow Backward Chaining” option was selected with forward chaining Logic Block 1:
! The value of [X] would be needed to evaluate the IF part of the Logic Block 1 rules.
! The value of [X] would be derived with Backward Chaining.
! Since the rule in Logic Block 2 can set a value for [X], that rule would be tested.
! To test the Logic Block 2 rule, the value of [Y] would be asked of the user.
! If the value of [Y] was greater than 0, the Logic Block 2 rule would fire and assign a value to [X]. This
would end the backward chaining and the [X] value would be used in Logic Block 1.
! If the value of [Y] was less than or equal to 0, the Logic Block 2 rule would not fire and since there are
no other rules that can set the value for [X], backward chaining would not have been able to derive a
value. Instead the value of [X] would be asked of the end user, and the value used to fire one of the
Logic Block 1 rules.
In the example, it could be run without backward chaining by running Logic Block 2 first and then Logic
Block 1. This could be done with two FORWARD commands in the Command Block or by running all the
Logic Blocks, but making sure the order of the Logic Blocks has Logic Block 2 before Logic Block 1 (See
below on Block Order).
By default the “order” the blocks are run in is the order that they were
added to the system. Whenever there are multiple blocks selected
(either by “All Blocks” or a “Mask”) they will be tested in that order. The
order can be changed. To see or edit the Block order goto “Reorder
Logic Blocks” under the “Run” menu.
A window will be displayed listing the order that blocks will be tested in.
Unless the order has been modified, it will be the order that the blocks
were added to the system.
To change the order, click on the name of a block to select it and use
the “Move Up” and “Move Down” buttons to rearrange the list.
The order for Action Blocks cannot be directly set. Either convert the
Action Block to a Logic Block and use the window to reorder Logic
Blocks, or specify the Action Blocks to run individually with multiple
FORWARD commands.
NOTE: This order is also the order that the blocks will be
checked when using backward chaining to derive a value.
Changes to the order will have an effect on both forward and
backward chaining.
Single Block
To run a specific block in Forward chaining, select the “Block” radio
button and click on the drop down list to select a block to
run. This will run the single block using forward
chaining. If the “Allow backward chaining” check box is
selected, backward chaining will be used to derive
variable values needed in the block.
Often there are a series of FORWARD commands each
running an individual block. This is an alternate way to
control the order that blocks are run in without reordering the blocks. That way there can be one order for
backward chaining and another list in the Command Block for the order that blocks are run in.
When a Command Block is run with the EXEC command it will run until:
! The last command in the called block is reached.
! A RETURN command is executed in the called block. (Entered from the Control tab)
! An EXIT command is executed in the called block. (This will end the session)
This is a very effective way to set the values for multiple variables in a Corvid system. An external program
can write a simple text file with the values, and Corvid will read them.
Data Syntax
The file of data can assign values to any variables in the Corvid system. The file itself is just text. The syntax
for each line in the file is:
[var_name] value
where var_name is the name of the Corvid variable and value is the value to assign. The “value” must match
the variable type, for example if the variable is a numeric, it must be assigned a numeric value, rather than
“abcd”.
The data file can assign values to multiple variables, with one assignment per line. All assignments will be
read and processed until either the end of the data file is reached or a line with just “END” is found.
For example, a variable [COLOR] with values “Red”, “Blue” and “Green”:
[COLOR] 2 would set the value “Blue”
[COLOR] 1 (TAB) 2 would set the values “Red” and “Blue”
[COLOR] green would set the value “Green”
[COLOR} red (TAB) blue would set the values “Red” and “Blue”
[COLOR] 1+1 would evaluate to 2, setting “Blue”
Dynamic List
#
# (TAB) # …
Corvid expression that evaluates to the number of a value
where: # is the number of the value to set, between 1 and the total number of values possible; and (TAB) is
the tab character. The assignments for Dynamic List variables are the same as for Static Lists, but the value
must be referred to by number, rather than name.
Numeric
Number
Corvid expression that evaluates to a number.
For example:
[X] 123 would set the value 123
[X] 3*2 would set the value 6
String
String
Corvid expression that evaluates to a string
For example:
[S] “ABC” would set the value ABC
[S] “ABC” + “DEF” would set the value ABCDEF
Confidence
Number
Corvid expression that evaluates to a number
The value assigned must be in the appropriate range for the confidence mode of the variable. Values
assigned will be combined with any other values that may have been assigned to the confidence variable,
based on the confidence mode selected.
For example:
[Conf] 7 would set the value 7
[Conf] [X] / 2 would set the value based on the value of [X] divided by 2
Collection
String
String (TAB) string (TAB) ….
Multiple assignments, one per line
Multiple values can be added to the Collection either by separating them with a tab character (TAB) or having
multiple assignments in the file. Any assignment to a Collection will be added to any values that the
Collection variable already has. Values are always added to the end of the value list.
For example:
[Coll] abc would add the value “abc” to the Collections value list
[Coll] abc (TAB) def would add 2 values “abc” and “def” as separate values
[Coll] abc
[Coll] def would add 2 values “abc” and “def” as separate values
CLOSE command
When the end of a READ input file is found, the file is automatically closed. However, there may be other
times that the file should be closed for other reasons, or to restart reading the input at the top of the file.
Selecting the CLOSE command can do this. On the External tab, select the “Close the data file” radio button
and enter the name of the file. When this command is executed, the file will be closed. If there is a
subsequent READ command for the same file, it will start with the FIRST batch of data in the file.
The CLOSE command is very rarely be needed. Normally READ commands automatically close the file
when they are done.
The CLOSE command is only needed, when there are READ commands with multiple batches of data and,
either:
If the “Wait for program to terminate” check box is selected the Corvid Runtime will wait for the called program
to terminate before it continues with the next command. This allows the called program to perform some
operation and write data that the next Corvid command can read. Unlike web based programs called as
URLs, external programs do not directly return data to Corvid. Instead they must write the data into files or
databases that later Corvid commands can read.
For example, an EXTERN command might call a program that performed some calculation or custom
interface and wrote the results into a file. The next Corvid command would be a READ which would then
read in that data. To allow multiple sessions, Corvid might pass a unique file name to use for the file or
database record.
For most systems running via the web, it is better to call custom external programs as Java servlets which
can immediately return data without intermediate files, the external program option is the only way to interact
with some older programs, and also is the only option when running in a standalone mode.
Due to Java security restrictions, this can ONLY be done when running Standalone as a Java
Application or when running with the Corvid Servlet Runtime.
Text can be appended to an existing file, or a new file can be created that will overwrite any existing one.
1. Specify the file to write to. This can be either a filename or path relative to the location of the system
CVR file or a full path on the local PC starting with the drive identifier. For example, a filename of just
“MyFile.txt” will be created in the same folder at the system CVR file. A filename of “C:/temp/
MyFIle.txt” will be created in the C:/temp folder.
2. Specify the variable or text to write to the file. This can be any text or a variable/variable property. To
get a list of variables and properties, click the “Property” button. Individual items can be added one at a
time or they can be all put in a single Collection variable, and that written to the file with one command.
To output a text string rather than a variable, enter the text in the edit box. It can be any text, including
HTML code, RTF, XML or any other content that can be represented as text. The text added can
include any variables by double square bracket embedding them in the text. For example, the text “A is
[[A]] and B is [[b]]” would out put the string with the variable value embedded in it.
3. The output will be appended to an existing file if one exists. If there is no file, it will be created. To
always create a new file even if one exists, check the “Start new file” check box.
One very effective way to build reports when running standalone is to use a Collection Variable to create a
report based on a template. The report template can be added to the collection using the ADDFILE method to
read in the template file. The template for the report can conditionally include sections and use double square
bracket embedded Corvid variables. The file can be text, HTML, RTF or other formats that can be read as
text. This is an easy way to build a large formatted report.
Once the template is added to the Collection variable, the replaceable parameters will have been replaced by
actual variable values, This report can then be output to a file, simply by using the WRITE command for the
Collection variable. The file produced can then be displayed by calling an EXTERN program such as a word
processor that can display RTF or a browser to display HTML.
The system would start in “Main” and Ask for the value of the variable [X]. It would then call the
“OtherCommands” Command Block and ask for the value of [Y]. If the value of [Y] was less than 0, the
There are 4 commands that can be used together to specifying certain blocks to exclude.
ALLOW ALL Use all blocks for backward chaining (The default
behavior.)
The commands can be used together to either allow all blocks and then exclude certain ones, or exclude all
blocks and then allow certain ones - whichever will take less commands.
Use in Systems
Very few systems need to use the ALLOW and EXCLUDE commands. Most systems can use the default of
allowing backward chaining to use all blocks, and when some blocks should only be used in certain situations,
top level nodes can be added to the block to automatically block it. For example, suppose there are some
rules in the “California_Rules” Logic Block that only apply to users in California. That Logic Block can be
excluded from the Command Block with an EXCLUDE command:
IF ([State] != “California)
EXCLUDE California_Rules
ENDIF
Other commands in the system
This will exclude the California rules, but if there are many similar tests, the Command Block will get quite
complicated, and will require putting logic in the Command Block that really belongs in the rules.
Command Use
ALLOW_HOW This command saves the data needed to use the .HOW
property. This increases the resources when running a
Parameter: None system. The default is to NOT save HOW data. If .HOW is
needed for debugging or other uses, add the ALLOW_HOW
command as the first command in the Command Block.
DO_NOT_LOOK_AHEAD This runs the inference engine in a way consistent with earlier
versions of Corvid that could in special cases ask unnecessary
Parameter: None questions. This should be used only if that earlier behavior was
used to force certain questions.
NO_RESOURCE_CHECK This command turns off all checking for Resource File links. If
a system uses an external file that may include ""[<"", this
Parameter: None would be interpreted as a link to a Resource File. If the ""[<""
is in the file for other reasons, such as part of a PDF or binary
file, this would lead to errors.
QUIT_MB When a Logic Block uses a MetaBlock, it runs the rules against
each row of the MetaBlock. Normally at the end, the "best"
Parameter: None options are selected based on their score. QUIT_MB will
terminate a MetaBlock without running the remaining rows.
RESOURCE= Allows using external Resource Files for the text in a system.
Very useful for systems running in multiple languages.
Parameter: Resource filename
TERMINATE_IF_INACTIVE: If a session does not have any user activity (e.g. answering a
question) for a certain amount of time, the servlet engine will
Parameter: Number of minutes terminate the session and free the session resources. This
command allows the number of minutes to be specified to
release resources more quickly.
Command Details
Special Command: ALLOW_TABS_IN_COLLECTIONS
Normally when a string that contains tabs is added to a collection variable, the string is broken at the tabs and
each item is added separately For example:
[coll.ADD] aaatabbbbtabccc
here tab is the tab character, would add 3 items to the collection: aaa, bbb and ccc.
However, in some cases, such as dynamically building a tab-delimited file, it is desired to leave the tabs in
place and add only a single item to the collection. To do this, use the special command:
ALLOW_TABS_IN_COLLECTIONS=TRUE
DONE_SCR=filename
and the screen commands will build a screen that will be used in place of the “System Done” screen.
EMPTY_CELL=0
would cause the blank cells to be assigned 0 and [S] would be "102".
The value used for the EMPTY_CELL can be just the string following the =, or it can be a string in quotes " ".
If the value to be set for the empty cell is a space, or has leading/trailing spaces, then it must be in " ".
For example: To have the blank cells replaced by a space, use:
EMPTY_CELL=" "
IF:
Language = Spanish
THEN
RESOURCE=MySystem_Spanish.res
Another more automated approach is to use the language default for the end user’s computer which can be
obtained with the Corvid command to get Java system properties. [[~SYSPROP user.language]] will return
the language setting for the user’s computer. This allows the language to be set automatically by are rule
such as:
IF:
“[[~SYSPROP user.language]]” = “fr”
THEN
RESOURCE=MySystem_French.res
There can be as many TRACE commands as needed in a system. The TRACE command has no meaning
and is ignored if the system is run without the Trace Applet, so the TRACE commands do NOT need to be
removed from a system when it is fielded - they will just be ignored.
The Adobe Flash interface requires the Corvid Servlet Runtime and uses XML specification files to define
what Corvid data should be sent to the Flash SWF file. The RESULTS command can have a XML
specification file associated with it, and that file will automatically be used when running with the Flash
interface. (Details of Corvid Flash Interface are in Chapter 18 on the Adobe Flash).
One problem with using the DISPLAY_HTML command is that the new page may be opened underneath the
page running the system or in a separate tab, and the user will have to take some action to see it. This
behavior depends on the end user’s browser settings and is not controlled by Corvid.
One very useful way to use the DISPLAY_HTML command is with frames. The top level page running the
Corvid system can have named frames in it. Then the content from the DISPLAY_HTML command can be
displayed in another frame on the same page. This allows the HTML content to appear in a portion of the
same page running the system.
9.15.1 IF Controls
An IF control marks a group of nodes that will be executed based on whether a boolean test is true or false.
! If the boolean test is true, the commands in the group will be executed in order and then the first
command after the “IF End” will be executed.
! If the boolean test is false, the commands in the IF control group will be skipped, and the first
command after the “IF End” will be executed.
When the IF control is executed, the boolean test will immediately be evaluated. If the boolean expression
requires the value of any Corvid variables that are not known, Corvid will use backward chaining to attempt to
derive the value(s). If the values cannot be derived or obtained from external sources, the variable will be
asked of the end user. (To suppress backward chaining and force using the current value, double square
bracket embed the variable with an asterisk,[[*varname.value]] . This forces the current value to be used
without backward chaining.)
The IF control marks one or more nodes with an orange bar and ends with an “IF End”. Any Command Block
command or control (IF, WHILE, FOR) can be in the group of nodes associated with the IF control.
To add an IF control:
1. Select the node to add the IF control BELOW by clicking on it. (If there
are no nodes, go on to step 2.)
When the WHILE control is executed, the boolean test will immediately
be evaluated. If the boolean expression requires the value of any Corvid variables that are not known, Corvid
will use backward chaining to attempt to derive the value(s). If the values cannot be derived or obtained from
external sources, the variable will be asked of the end user. (To suppress backward chaining and force using
The FOR and FOR EACH control marks one or more nodes with an light
pink bar and ends with an “FOR End”. Any Command Block command or
control (IF, WHILE, FOR) can be in the group of nodes associated with the
FOR or FOR EACH control.
FOR control groups are added very similarly to IF and
WHILE controls, but when the FOR button is clicked, the
type of FOR control must be selected.
Click the top radio button for a numeric FOR control or
the lower button for a FOR EACH control. The
commands in the control group are entered the same
way as in an IF or WHILE control.
Starting Commands
An initial screen should explain:
! What the system does.
! What the end user will need to do.
! What it will provide the end user (advice, document, report, etc.)
Logic Commands
The logic commands are the ones that tell the Inference Engine how to run the rules. This depends on how
the system is designed, but generally it will be either:
! Using FORWARD commands to run the logic and Action Blocks with forward chaining. This may have
the ALLOW_DERIVE option set to allow backward chaining to be used to derive needed values.
Having multiple FORWARD commands allows running the blocks in a specific order, or the block order
can be set and then a FORWARD ALL can be used to run all the block in that order. This is used
primarily for systems that implement existing procedures, flow charts or regulations that have a
procedural order that should be followed in the system. FORWARD is also always used to run
MetaBlock systems and Action Blocks.
! Using DERIVE commands to start backward chaining to derive the value of one or more variables. A
common situation is to have a set of confidence variables that represent the various possible solutions
or items of advice. They use a DERIVE CONF command to backward chain to derive the values for
all the confidence variables. The ones with highest values will be the solutions presented to the end
user. Another approach is to have a collection variable that builds a report, and using DERIVE to
backward chain to build the report. This is more often used when there are multiple levels in making a
decision (high level rules that call lower level rules to derive or set needed values), highly interrelated
rules that could not be handled in the more linear approach of forward chaining, or decision-making
logic that is being built from various pieces rather than matching existing documentation.
Results Commands
The results commands present the conclusions of the system to the end user. This is usually either done with
a RESULTS command that presents content based on the values of the variables in the systems, or presents
a report, typically built in a collection variable. This data can be presented directly in the Applet Runtime
window or using HTML via the Servlet Runtime. Complex reports using HTML, RTF or PDF formats call for
server-side processing and commands from the “Reports” tab on the command builder. If the system is run
with the Applet Runtime, this requires calling a special servlet program provided with Corvid.
Some systems end each session by writing data to a data base or sending an email. These call for the
commands on the “External” and “Email” tab.
Question The question to ask of the end user. This is the prompt of a standard Corvid variable.
For Static List variables, the possible values for the variable. These may be grouped if
Values several values should produce the same actions. For other variables, this column will list one
or more Boolean expression built using the variable that will evaluate to TRUE or FALSE.
The action to take when the value/expression in the Value column is true. A single value
Action may have multiple associated actions. There are various types of actions, which may
require one or two additional items of data that appear in the “To” and “Content” columns.
If the Action is done to something, it is listed here. For example, an action to execute a
To
Logic Block, would list the Logic Block to run in the To column.
Some actions require both a To and a Content value. For example, if the action is to set
Content the value of a variable, the To column would be the variable and the Content column
would be the value to assign.
To add the first question to the Action Block, click the “Add
Question” button.
When new rows are added, the Action is set to None. Each of the
values can have one or more actions associated with it. The action
is selected by clicking the drop down list in the “Action” column.
Some of the actions require adding values in the “To” and “Content”
columns.
Actions:
No action will be taken if the value is selected. No value for “To” or “Content” is
None
required.
Skip to the specified label. This allows skipping over questions. If the user’s input
indicates some of the following questions are irrelevant, this is a convenient way to
jump over them. You can only use Goto to move down the list – not back to a
Goto Label previous question. The label to go to is selected from a drop down list in the “To”
column. Since the next question in the list is automatically the next one to ask, the
Goto label list only includes questions more than 1 question down in the list.
Nothing is needed in the Content column.
Immediately execute the specified Logic, Action or Command Block. The block to
execute is selected from a drop down list in the “To” column. Nothing is needed in
Exec Block
the “Content” column. This very powerful Action allows doing anything that can be
done with Corvid for analysis, external interfaces, backward chaining, etc.
Assign a value to a variable. This can be used to set the value to any variable in
the system. If a variable has a value set, and the variable appears later in the list,
Set the assigned value will be used rather than asking the user for input. The variable
to assign is entered in the “To” column and the value to assign is entered in the
“Content” column. The value can be an expression using other variables.
Execute a single Corvid command. The command is built with the Command
Command Builder window and entered in the “Content” column. Nothing is needed in the “To”
column.
Exit the Action Block even if there are more questions in the block. Nothing is
needed in the To or Content columns. Only the Action Block is exited – not the
Done - Exit
entire system. Control will go back to the Command Block command that caused
the Action Block to be called.
Question Buttons
Once the Action Block has some questions added, the
“Questions” controls allow adding and editing.
To select a question, click on any of the values/
expressions for the question. The question group will be
selected and highlighted in light blue and the question will
be highlighted in yellow. (These highlight colors can be
selected in the “General” tab of the Properties window. )
Multiple questions can be selected by using Shift-Click to
select each question individually. The questions selected do not have to be consecutive.
The buttons in the “Questions” group are:
Add Add a new question to the end of the list, regardless of what is selected.
Question
Add a new question at the currently selected row in the block, inserted before the
Insert
selected question.
Cut Delete the currently selected question, but keep a copy that can be pasted.
Copy Make a copy of the selected question that can be pasted.
Paste the question from the previous cut or copy. The questions can be pasted above
Paste
or below the selected question. (A window will display these options.)
Open a window to change the grouping of the values. This allows reordering,
combining or splitting up groups of values. The actions associated with the first value
Change
will remain associated with the new first value, the actions with the second value will
Value
remain associated with the new second value, etc. If there are fewer new groupings,
Grouping
extra actions will be deleted. If there are more new groupings, the additional ones will
have “None” as the associated action.
Action Buttons
When a specific value or expression is selected, the actions associated
with that value can be edited. This is done with the “Actions” controls.
To select a specific Action, click on its row.
Add a new action below the currently selected action. It will initially be set to
Add Action
“None”, and can be changed to any Action.
Cut Delete the current Actions, but keep a copy that can be pasted.
Move the selected Action up in the list. This applies only when a Value has more
Up
than one action.
Move the selected Action down in the list. This applies only when a Value has
Down
more than one action.
Applies to all This check box makes the Cut, Copy and Delete buttons apply to all the actions
Action for for the selected Value rather than the specified individual selected Action.
Selected Value
Undo Button
The Undo button allows you to undo your last actions. You can undo up to 5 steps back.
This simple tutorial will go step by step, leading you through building a small Corvid system based on Action
Blocks. The best approach is to follow along using Exsys Corvid to actually build the system. The tutorial
system will give a user advice on their financial status. This will be done using a “smart questionnaire”
approach created with Action Blocks. The tutorial focuses on credit cards, but could be expanded to cover
other areas. With regard to credit cards, the system will consider how many cards the user has, their credit
balance and income. It will generate a report on any potential problem areas.
Starting a System
Open Corvid and select “New” from the “File” menu. Name the system “AB_demo”.
Adding Variables
The system will need some variables to ask questions of the user, perform
calculations and build reports. These are standard Corvid variables and
are exactly the same types of variables that were used to build Logic
Blocks.
Click on the Variables icon on the command bar to display the Variables
window.
The Variables window is used to add and edit variables in the system.
Make sure the “Show Advanced Options” checkbox is NOT selected.
! A Name that describes the variable. Names should be short, but descriptive and clear. Names cannot
include spaces and some other special characters, but Corvid will automatically convert any illegal
characters to underscores. (Underscores are not visible to the systems user.)
! A Prompt to use when asking the user for data or in reports.
! A Type that determines what type of value will be assigned to the variable. For this demo system, the
only types needed are:
- Static List - Has a multiple choice list of values.
- Numeric - Assigns a value that is a number .
- Collection - Assigns pieces of text that will build up a report.
To add a new variable, in the Variables window click the “New” button.
This will open a window to enter the name and type for the
new variable.
[!~!@^&*()-+="?><.,/:;{}|\`]
This will add the variable to the variable window. The Prompt is
automatically set to the variable name. For variables that will be
asked of the end user, the Prompt should be changed to a question
that will be easy to answer. Here change the Prompt text to “Do you
have a credit card?”
Once they are added the variable window should look like:
Open a new Action Block by clicking on the Action Block icon on the command bar.
This will display the window for adding content to both Action
Blocks and Logic Blocks. The variables in the list are ordered
alphabetically. Since the variables were entered in roughly the
order that you plan to use them, it would be more convenient to
arrange them in the order that they were entered.
To do this, in the “Sort” control group in the lower left, click the “Order Entered” radio
button. This will display the list in the order that they were added.
The 2 values are now seen in the “Nodes to Add” list at the bottom right.
Click the “Done” button to add the nodes to the Action Block.
Two lines have been added to the Action Block spreadsheet for the 2 possible answers that the end user may
provide. Now assign the action.
If they don’t have any credit cards, there is no reason to ask more questions about them. So, the action for
the “No” value should be to skip over the questions you will be adding on credit cards in the next section.
Now add the value to assign to the variable Debt_ratio. For this system, the debt ratio is the balance on all
the cards divided by the annual income. The variables Card_balance and Annual_income were already
added to the system to do this calculation.
In Corvid, expressions can include the value of any variable by putting the name of the variable in double
brackets [ ]. Corvid supports standard algebraic operators along with many functions. All that is needed here
is division.
The expression:
! [Card_balance] / [Annual_income]
Click on the Content column in the row for the “Yes” value.
Whenever a row is selected, the lower right section of the
window displays the question, value, action and content.
Click in the Content edit box to put the cursor there. The expression you want to add is:
! [Card_balance] / [Annual_income]
This can be just typed in, but use the window for filling in
the variable’s name.
Hold the Ctrl and Alt keys down and hit the “V” key (Ctrl-
Alt-v). This will display a window that will add the name of
the variable to the expression.
The name of the variable in [ ] will be added to the expression window. Don’t
worry about the red underline of the name, that is the spelling checker, which
will be discussed later.
Notice that any text entered in the Content edit box also appears in the Content cell in the spreadsheet.
You now have the 2 actions for the first question. If the user answers “Yes”, Corvid will evaluate the expression
and assign the result to the variable Debt_ratio. To do this Corvid will need to know the values of the variables
Card_balance and Annual_income. Because these values are needed to do the calculation, Corvid will
automatically ask the user for the values. Whenever the value of a variable is needed, Corvid will do
whatever is necessary to get the value. Here Corvid will ask the user for the information. If you had provided
other rules to derive the value, or provided a way to obtain the information from an external source such as a
database, that would be used instead, but here the user will be asked.
It is important to remember that Corvid will ask the user questions to obtain the data it needs,
when it needs it, but will only ask if it is necessary and can’t get the information from other
sources.
To add a new question at the end of the list, click the “Add
to End button.
This will display the same windows you used before to add
the IF conditions. This time you want to consider the value
of the numeric variable Debt_ratio, and test which range it
falls into.
In order to consider various values of the variable, you will add 3 tests:
[debt_ratio] < .2
([debt_ratio] >= .2) & ([debt_ratio] < .3)
[debt_ratio] >= .3
In Corvid, as with most computer languages, the & is a logical AND. It
combines 2 Boolean tests, and will be true only if both of the individual tests
are true.
You have already added the first. Now to add the second. Go back to edit box under the Expression tab, and
type in the second expression.
Remember: Variables can be added to the expression by clicking the “Variables” button or
using Ctrl-Alt-V to display the variables window.
Once ([debt_ratio] >= .2) & ([debt_ratio] < .3) is entered, click the “Add to List” button.
Now add the third expression, [debt_ratio] >= .3 and click the “Add to
List” button. The list of added nodes should look like:
Click the “Done” button to add the tests to the Action Block.
Now you will start building up a report based on the information provided by the end user.
To do this click on the Action column in line 3
next to [debt_ratio] < .2 and select the Action
“Add to Report/Collection”.
The changes made in the edit box will also appear in the spreadsheet.
NOTE: This text could also be directly entered in the spreadsheet cell, but it is better to use
the edit box for text since it provides spell checking.
Now do the same thing for the next 2 rows, adding Content text to the Report variable.
([debt_ratio] >= .2) & ([debt_ratio] < .3) The amount of credit card debt is a little high, and
should be reduced.
Remember, when this runs, users will be asked: “Do you have a credit card?” first. If they answer “Yes”, they
will be asked for the Card_balance and Annual_income because these are needed to set the value for
Debt_ratio. They will never be asked the debt_ratio directly. If it is needed, it will be calculated.
Click the “Add to End” button and in the window for building test conditions, add 3 tests:
[Number_of_cards] <= 6
[Number_of_cards] > 10
Now for each value expression, add some text to the Report. For each, select the Action “Add to Report/
Collection” and add the text:
[Number_of_cards] > 10 The number of credit cards is quite high. It would be a good
idea to consolidate on a few cards and gradually close the
ones that are not needed.
Headings are a way to divide up the spreadsheet to make it more readable. They do not have
any effect on the logic of the system.
This will display a window asking for the text of the heading
and asking if the heading should be added at the end of the list
of questions or added before the currently selected question.
Enter the text “Checking Account” and select to add to the end
of the list. Click the “OK” button to add the heading to the
Action Block.
The heading appears in the Question column and is the only text on row 9.
This demo does not fill out the section on the Checking Account. It would ask questions about the checking
account and add more text to the Collection variable based on the status. Here the one part not done is the
Goto label for line 2. If the user answers they do not have a credit card, you want to skip the other credit card
questions and go to the Checking_Account question.
The simple Command Block it will build can be later edited if needed. Corvid reminds you that the default
Command Block is not ideal for all systems, but it will work well in this case, so click the OK button.
Now that there is a Command Block, Corvid will build an HTML page that uses the applet runtime to load and
run the system. The HTML page is displayed in a browser window. Actually, this page is the same core
program as in Internet Explorer but without browser navigation buttons.
NOTE: Exsys Corvid systems can be run in any browser that supports Java.
Corvid now asks about the balance on the credit cards. This is needed to set the Debt_ratio variable. Input
5000 and click OK. NOTE: Do not use commas.
The system also needs the annual income to set Debt_ratio, so that is asked next. Input 65000 and click OK.
The last credit card question the system needs to ask is the number of credit cards. Enter 5 and click OK.
The system now moves on to the checking account questions. Since there are not really any rules for this
section, you can select either answer and click OK.
Try running the system with other values to see how the system produces different results based on the input.
While the Results screen has all the data, it is not formatted the way you would want in a system that was
going to be fielded. Corvid screens for Action Blocks and Logic Blocks are formatted the same way. This is
covered in Chapter 11 on user interfaces.
In addition, the Corvid Servlet Runtime allows you to create far more complex end user interfaces that are
created in HTML and CSS. These can incorporate some of the “generic” replaceable parameters of the
default templates or can be highly customized in HTML for individual variable questions or results.
For the most complex user interfaces, it is possible to run a Corvid system under an Adobe Flash user
interface with the Servlet Runtime. This is far more complex and requires knowledge of Flash programming.
This is rarely needed, but for very complex systems provides options not possible in HTML
The recommended approach for system development is to first build the system logic with the standard
defaults for user interface. These are very simple, but work well for getting the system logic worked out.
Once that is working, use the Corvid Screen Commands to enhance the user interface with a better design,
images, etc. This will work with either the applet or servlet runtime, however it is recommended that systems
be moved to the servlet for final release.
If the user interface requires designs or options not possible with the Corvid Screen Commands, add
customized HTML templates to implement the design. These will work only with the Servlet Runtime, though
the logic can still be tested with the applet runtime using the simpler user interface.
Screen Commands are used in many places when building a Corvid system. Screen commands always
control the Applet user interface. They can also be used to control the Servlet user interface with the default
templates that convert the screen commands to HTML and CSS.
Text String
Enter the text into the edit box below “Text”. The text can be any length and can contain any embedded
variables or other embedded data.
Variables
Variables are usually only displayed in a results screen, but they can be
displayed in any screen. Click the drop-down under “Variables” and select
the variable or a type of variables. The drop-down first lists the variable
types (e.g. Confidence, Static list, etc) and then all the variables in the
system arranged alphabetically. If a specific variable is selected, the screen
command will be the variable name in square brackets. If a variable type is
selected, the command will be the type name.
Selecting a type will display ALL of the variables of that type which have a
value. Having a variable displayed does NOT cause the value to be derived
via backward chaining - if the variable has a value it will be displayed. Variables that have not been assigned
a value will not be displayed. (The value for the variable should have been set by other commands before it
is displayed.) Variables embedded with double square brackets will cause backward chaining.
The special type “Variable” will display all variables of all types that have a value set. This is a convenient
way to see the all the variables that were set during a session.
Position
The default is to have text aligned to the left. To change this, select “Center” or “Right” from the “Position”
drop-down list. “Center” will center the text in the applet window (Corvid Runtime Window). “Right” will align
the text with the right border of the applet window.
Indent
To have the text indented from the margin, enter the number of pixels to indent from the left.
Hypertext_color= RBG_color
Hypertext_bg_color= RBG_color
allow the foreground text and background colors to be changed. These should be added in the Command
block somewhere before the screens using the links that are displayed. The RGB_Color is the standard red,
blue and green values separated by commas.
For example:
Hypertext_color=255,0,0
Hypertext_bg_color=128,128,128
would display the links as red text on a gray background.
The hypertext color commands apply until another “Hypertext_color” command is encountered. A system can
change the colors as often as needed.
The HYPERTEXT_COLOR commands can be built from the “Special Command” menu on the “Control” tab of
the Command builder.
Images in Text
The other way to include images is to include them in text using the standard HTML code:
Using:
<IMG SRC=”image”>
allows a graphics image to be included in the text which can be on the same line in the screen. The image
should be a JPG or GIF image including animated GIFs.
For example, the text:
<IMG SRC=”pictures/X123.jpg”> The X123 would be a good choice
would display the image of the X123 followed by the text “The X123 would be a good choice”.
This can be very useful in building the text for Collection variables in MetaBlocks. Collection variables can
only accept text strings as content, but if the string is an IMG SRC command, it will display as an image in the
results screen. This is also an alternate way to use images to ask questions by using an IMG SRC in the
prompt for the variable. (There is also another way to do this by specifying that an image should be used for
the prompt.)
Links on Images
The image displayed with an IMG SRC command can be made into a HTML link by using:
<A HREF=”link”><IMG SRC=”image”></A>
If the end user clicks on the displayed image, the associated link URL will be displayed in a new browser
window (or browser tab - depending on the end user’s browser settings)
<BR>
The HTML <BR> command can be included in text to force the subsequent text to start on a new line. This is
the same as the HTML usage of the <BR> command, so text using <BR> will display consistently in both the
Corvid applet and Servlet runtimes.
A text screen command:
Text "AAA BBB"
would display as:
AAA BBB
However, the command:
Text "AAA <BR>BBB"
would display as:
AAA
BBB
The <BR> command can be added in any text string, either as static text, variable values or files of text to display.
<FORMAT…>
The FORMAT command can be included in text to change the font size, type and style. The format command
applies to all text until the next <FORMAT > command or an ending </FORMAT> command, which will return
the font to the default values. The format command automatically starts the subsequent text on a new line.
The syntax of the format command is:
<FORMAT: options >
where the options are the same as when building a format command from the Format window.
The options can be any combination of:
SIZE=#
The point size of the text, e.g. SIZE=12
NAME=type
The type of font to use. Java applets have very few portable type styles. The type can be "Sanserif",
"Serif" or "Dialog". These will be converted to an appropriate font for the computer running the applet.
e.g NAME=Sanserif
STYLE=Plain
The style of the font. The style can be "Plain", "Bold", "Italic" or "Bold&Italic".
NOTE: "Bold&Italic" has no spaces.
e.g. STYLE=Bold
FCOLOR=#,#,#
The text color stated as an RGB value. For example, to have black text, use FCOLOR=0,0,0. To
have red text, use FCOLOR=255,0,0
would add the title of the report (from the [Rpt_title] variable) and the author (from the variable [Author]).
When displayed in a window, the report would display the title in 18 point, bold, blue, and the author in the
default font for the display.
The question screens ask the end user for the value of specific Corvid variables. Usually a system will only
have a single title or results screen, and it is easy to build them individually. However, a system may ask
many question screens, and it would inconvenient if each had to be designed individually. Most systems
establish a system-wide look for all the question screens, and Corvid will then use this “template”, filling in the
details for the specific variable(s) being asked. This makes it easy to create the user interface even when a
system will ask many different questions and variables. A Corvid system can often be run without adding any
custom screens, using its default settings. These are fine for development, but usually should be customized
to better fit a system before it is fielded.
11.4.5 Prompt
Corvid automatically adds the Prompt text to all question screens. The format will be determined by the
overall Prompt format set on the Variables window and the individual Prompt format set on the “Ask With” tab.
Radio Buttons
This will group the values for the variable as radio buttons. Only one value can be selected
from the group since selecting one will deselect any other value already selected. This is an
excellent way of automatically enforcing Static List variables that can only have a single value.
Checkbox
The check box control is very similar to the radio button, but allows multiple values to be
simultaneously selected.
List
The list control displays a list of values that the user can select among. A number of
values will be displayed and the user can scroll to others in the list. The width is
automatically set in the Corvid Runtime to fit the widest value text. This control
should not be used if the text of the values is very long. The number of values
displayed on the screen is controlled by the Value Format specified for the variable.
Lists allow the end user to select more than one value.
Buttons
Static and Dynamic List variable questions can be asked using buttons.
When buttons are used to ask a question, a click on any of the buttons
immediately sets the associated value and the system continues the
session. This is very effective for many types of systems. However,
buttons should only be used if the value text is fairly short and will easily
fit on the button. When buttons are used, there will be no associated
"OK" button and only a single value can be selected.
The buttons can be arranged like any other control - one per line, all on one line, n per line, etc.
Buttons should generally not be used if there are multiple questions on one screen (built with the "Also Ask"
options). Buttons can be used, but a click on the button will set the value associated with the button and also
any other radio buttons, check boxes, lists or edit regions that also have values set on the screen.
When a question is asked with buttons, there is no "OK" button. This can actually make for a very flexible
screen design and works well for touch-screen devices.
Edit Box
The edit box is a control that allows the user to enter any text as the value
for the variable. This should be used only with Numeric, String and Date
variables. The Corvid Runtime can do some validation of the input data
and additional tests can be specified for the specific variable. The width of
the edit box is controlled by the Value Format commands.
Text edit boxes used to ask for user input can be multiple lines. Use the “Control Rows=” field on the Format
window. The format for the Variable’s value will control the size of the edit box.
Same as Prompt
The value controls will be put immediately
after the prompt on the same line. This is
particularly useful for edit boxes and drop
down lists, but can be used with any control
that does not take up too much space.
N Per Line
This is similar to One per Line, but puts several values on each line. This can be
convenient for saving space when there are many values each with short text.
Entering a value in the edit field specifies the number on the line. The sample shows
setting 2 controls per line.
! Make sure the image is not distorted relative to the formula. Make sure that the space in each region
of the image is correct and that the scale is in the correct place. The formula in the example above is
for linear scales. Non-linear formulas can be used, but the image will need to be modified accordingly.
! Make sure the hot spot box is placed accurately. If the hot spot is not aligned with the scale in the
image, then the return values will not be accurate.
! It is very easy for the user to be off by a few pixels, so design the system the logic to take this into
account.
! Pixels have finite resolution. If the image is small, it will not have high resolution. A 20 pixel image can
only return 20 possible values. To get higher precision, make the images/hot spots large. It is often a
good idea to add a grid on the image to help the user to click a precise value.
The called Command block should be used for functions such as saving
data, or sending data to another program. It should NOT modify the
values of variables currently in use, especially in a backward chaining
system. Normally the called Command block should terminate the system.
The SPECIAL_BUTTON command is built from the “Special Command” menu on the “Control” tab of the
Command builder.
For maximum design flexibility, some developers prefer to use a image editing program such as Adobe
Photoshop to create the title screen as one large image that includes text, images, etc. This allows more
complex designs than would be possible with just Corvid screen commands. If this approach is used, size the
image appropriate for the applet window size and remember that Corvid will automatically add an “OK” button
to the bottom of the screen.
Display Tab
The Display tab provides ways to control when and how a variable will
be displayed. Multiple options may be used simultaneously.
Test Expression
The display can be set to include only variables that pass a Boolean test
of the value.
This is generally used to limit the display when a group of variables is
selected, but it can be used anytime a variable should only be displayed
under certain conditions.
To enter a test, enter a Boolean expression that includes “#” where the
name of the variable should be. The “#” will be replaced with the
variable’s name and the expression will be evaluated. If the test is true,
Format Tab
The same formatting options as any other text are available for the variable
values. These options are set the same way on the Format tab. Clicking
the “Edit” button edit will display the Format dialog.
In addition, when a variable is being displayed the controls in the “For
Variables” box are active. These allow controlling how the variable’s prompt
and value are displayed.
The most common use is to display the Prompt text without the value. This
can be done by checking the “Prompt only” checkbox. This is often used
when the system has selected only certain Confidence variables by giving
them values over a threshold, but the actual confidence value assigned has
no real meaning to the end user. It is better to just display the selected
variable’s Prompt without a value.
To do this:
! Select “Confidence” in the Variables drop-down list.
! To set a threshold: On the “Display” tab, Enter “[#] > 50” for the test (Where 50 is the threshold value)
! To sort the Confidence variables so that the highest confidence variables are at the top of the list: On
the “Display” tab, set “Sort Confidence Variables” to “Descending”.
! On the “Format” tab, select “Prompt Only - no value”.
Link Tab
The Link tab provides a way to associate a URL link with the displayed item.
To add a link, just click on the “Link to URL” radio button and enter the URL in
the edit box.
When the item is displayed and the user clicks on it, it will bring up a new
browser window displaying the URL specified.
This approach links the entire item. To link only specific text in a string use
the <a href=”...”> approach described in section 11.3.5.
IF:
Language = English
THEN
RESOURCE=MySystem_English.res
IF:
Language = Spanish
THEN
RESOURCE=MySystem_Spanish.res
The language default for the user’s computer can be obtained with the Corvid command to get Java system
properties. [[~SYSPROP user.language]] will return the language setting for the user’s computer. This allows
the language to be set automatically by are rule such as:
IF:
“[[~SYSPROP user.language]]” = “fr”
THEN
RESOURCE=MySystem_French.res
NOTE: The // must immediately follow the >]. The “//” and any text following will be ignored, and the
full “[<marker>]// comment” will be replaced by the text from the resource file.
The use of comments allows a developer to include text that will remind them of the meaning of the marker.
It is legal to have more than one marker in a text string, for example:
[<marker1>] and [<marker2>]
In this case, only the last marker on the line can use comments.
You must select at least one of the “Export” options or nothing will be output to the Resource file.
The resource file marker for a variable prompt is:
[<varName>]
where “varName” is the name of the variable.
The resource file marker for a Static List variable value is:
[<varName_valueShortText>]
All exported resources will include the original text as a comment.
Selecting “All String Assignments” will export all value assignments to string variables, or strings added to a
collection variables. The resource marker will be named based on the node number, and will be commented
with the original text.
For example, suppose a system has a variable [Color] with the prompt
“The color is” and values, “red” “blue”, “green”, etc.
[<color>]//The Color is
and the values will have the short text be the original value (“red”, “blue”,
etc) with the full value text be the “variable name_value”:
[<color_red>]//red
[<color_blue>]//blue
etc
[<color>] = El color es
[<color_red>] = rojo
[<color_blue>] = azul
[<color_green>] = verde
[<color_yellow>] = amarillo
[<color_white>] = blanco
In addition to the resources added automatically, any text string in a Corvid system that could use [[..]] can be
made into a resource by using [<..>], and making a corresponding entry in the resource file. The marker name
can be any name not already in use. Changes to the resource file should be made with a plain text editor
such as Notepad. (Do not use MS Word to edit the resource file unless you make sure to save the file as
plain text.)
Key Variable
The key variable indicates which prompt to use when there are multiple prompts. The key variable is selected
by clicking on the drop down list and selecting a variable. The key variable must be either:
! A numeric variable whose value will be an integer value.
! A property of a variable that will return an integer value.
! A Static List variable - in which case the number of the first selected value is used.
The value returned must be between 1 and the total number of prompts.
If a numeric variable is selected, the value of that variable will select the prompt. A value of 1 will use the
Main Prompt. A value of 2, the second prompt (which is the first alternate prompt), etc.
If a static list variable is used as the key variable, the first value set will select the prompt. If value 1 is
selected, the Main Prompt will be used. If value 2 is selected, the second prompt, etc. The use of a Static
List variable makes it easy to have a multiple choice question at the start of a run select the language.
If alternate prompts are used in a system, it is a very good idea to have them all use the same key variable.
Links in Text
Any text or image in a Corvid system can have associated HTML links added with the HTML “<a” tag. If in
that tag, the HREF is changed to “page, frame”, the linked page will be opened in the named frame.
For example, if there is a frame named “Comments”, the link:
<A HREF=”details.html, Comments”>References</A>
would display the page “details.html” in the frame named “Comments”.
NOTE: This is equivalent to a TARGET= command in HTML, but Corvid simplifies the syntax since
by default the Corvid target is always “_blank” unless a frame name is specified.
Once content is displayed in a frame, other links in that frame will display in the same frame unless they use
“TARGET=” to force the content into a different frame. However, do not display a link in the frame that has
the Corvid applet running in it. It is often best to not name the frame running Corvid to avoid this possibility.
Click “OK” to add the command as the “Other Graphics” for the variable.
This can also be used when Corvid is running in a frame to have the applet content completely fill its frame.To
accomplish this effect:
! Run your system. Corvid will automatically build a page named “kb_name.html”, where “kb_name” is
the name of your system.
! Open that page in a text editor (or an HTML editor that lets you edit the HTML code).
<TITLE>
My System
</TITLE>
<style type="text/css"><!--
body {
margin: 0;
}
--></style>
</HEAD>
<BODY>
<APPLET
CODEBASE = "./"
CODE = "Corvid.Runtime.class"
NAME = "CorvidRuntime"
ARCHIVE = "ExsysCorvid.jar"
WIDTH = "100%"
HEIGHT = "100%"
HSPACE = 0
VSPACE = 0
ALIGN = middle
>
<PARAM NAME = "KBBASE" VALUE = "" >
<PARAM NAME = "KBNAME" VALUE = "kb_nam.CVR">
</APPLET>
</BODY>
</HTML>
[[~INPUT]]
This special identifier will be replaced by a tab-delimited list of each variable that the user provided
input for and the variable’s value. The variable is identified by its name. This can be used in UPDATE
commands that store user input in a database. The variables in the list will be in the order that they
were crated in the system (the order they appear in the Variables window).
[[~SORTED_INPUT]]
This is very similar to the [[~INPUT]] command, but the order of the list will be the order that they were
asked of the end user. The variable is identified by its name. This is often preferable if displaying the
input for the end user to review to document how the user ran the system.
[[~DATA]]
This special identifier will be replaced by a tab-delimited list of each Static List, Dynamic List, Numeric,
String or Date variable that has a value. The value can be obtained from the user, assigned in a logic
or Command Block or obtained from an external source. This can be used in UPDATE commands that
store user all current values in a database.
[[~DATA_CR]]
This special identifier is the same as [[~DATA]], but instead of being separated by a tab, the items are
separated by a carriage return. This can be used in situations where the tabs are not syntactically
acceptable.
[[~INPUT_URL]]
This special identifier is the same as [[~INPUT]] but the string will be URL encoded. This can be useful
in some cases where having the [ ] in the string could be a problem.
[[~DATA_URL]]
This special identifier is the same as [[~DATA]] but the string will be URL encoded. This can be useful
in some cases where having the [ ] in the string could be a problem.
For example, if a system has asked the values for numeric variables [X] and [Y], which the user has assigned
values of 5 and 9 respectively. The command:
SET [S] “[[~INPUT]]”
would assign the string variable [S] the string “[X] 5 tab [Y] 9”. This could be used in a database call to store data.
[[*X]<BR>][[*Y]<BR>][[*Z]<BR>]
This will add the <BR> after each variable that has a value, but not include a <BR> when the variable has
no value.
[[var]BEFORE:str]
[[var]BEFORE:str] will be replaced by the value of variable var preceded by the text of string str. If var
has no value, str will not be added.
[[var]BEFORE:str AFTER:str2]
[[var]BEFORE:str AFTER:str2] will be replaced by the value of var preceded by the text of string str and
followed by the text of string str2. If var has no value, str and str2 will not be added.
[[var]AFTER:str]
[[var]AFTER:str] is legal syntax, but the same as [[var] str].
NOTE: [[INPUT] AFTER: ___] will only insert the “AFTER” string specified. If you want a tab
inserted, it must be added to the “AFTER” string as “\t” (e.g [[INPUT] AFTER: <BR>\t] )
Just [[~INPUT]] with no “AFTER” command will separate the variable/value pairs with a tab.
These [[.. ]] options can be used in any text where a standard embedded variable could be used.
In all cases, the var portion can include a property. For example:
For example, a HTML report might want to list the user input, in the order it was provided in a HTML list. To
do this, embed:
[[~SORTED_INPUT] BEFORE: <LI> AFTER:</LI>]
The < and > characters can still be used in most cases. Using “<” and “>” makes it easier to work with
some HTML editors and to edit templates that have embedded Corvid variables.
11.9.6 Checking How Many Confidence Variables are Over a Threshold Value
When building reports that display Confidence variables, it can be very useful to know how many variables
were set to a value over a certain threshold. This can also be used to make sure that at least one
Confidence variable was set and will be displayed. The special embedded variable:
[[~NumConfOver x]]
where X is the threshold value will return the number of confidence variables that have a value greater than
the threshold. (NOTE: This is “greater than” not “greater than or equal to”. Values equal to X will not
be counted.)
If no Confidence variables are over the threshold, the [[~NumConfOver x]] will be replaced by “0”. Otherwise it
will be replaced by the integer number of values over the threshold. This variable can be included in any
expression, or other place where it would be legal to have the [[~NumConfOver x]] replaced by an integer value.
[[~SYSPROP java_system_property_name]] will embed the string for that operating system property. Some
system properties may not be available when running as an applet because the Security Manager will not
allow it.
For example: To have a standalone (Java Application) system write the contents of the collection variable
[NOTES] into a notes.txt file on the users home directory (i.e. MyDocuments) use:
WRITE [[~SYSPROP user.home]][[~SYSPROP file.separator]]notes.txt [NOTES]
You could also have the Applet determine the user’s default language and set a value for the Alternate Prompt
Key Variable
IF “[[~SYSPROP user.language]]” = “en” THEN [Alternate_prompt_key]=1
IF “[[~SYSPROP user.language]]” = “fr” THEN [Alternate_prompt_key]=2
Key Meaning
12.2 MetaBlocks
Any Logic Block can be made a MetaBlock
by clicking on the MetaBlock button on the
Logic Block window.
(If a Logic Block is already defined to be a
MetaBlock, the checkbox next to the
“MetaBlock” button will be checked and
clicking the “MetaBlock” button allows the
properties to be edited.)
This will display the window for setting the
MetaBlock Parameters.
There can be as many “property” columns as needed to describe the product. Each “Property” column must
have a unique column header which will be used in the MetaBlock rules to refer to the data in this column.
Each “product” is a row and all of the data for the product must be in that row.
When using a simple spreadsheet file, the data MUST be stored as “Tab-Delimited” text. This just means that
the file will be a simple text file and there will be a tab character between each of the values. This can be
created and edited with many programs, but the easiest is to use a spreadsheet program such as Excel.
! Build the spreadsheet in Excel.
! Select “Save As” under the File menu.
! In the “Save as Type” drop down list, select “Text (Tab delimited)”.
! Save the file with a unique name in the directory where your Corvid system is being built. (This is
actually not required, but makes it easier when collecting the files to move to the server.)
Many other programs also support building tab-delimited files.
Headings
The first row in the spreadsheet MUST include headings for each column the system will be using. These
headings must be unique and will be used in the Logic Block to indicate what value to take from the
spreadsheet.
In the Logic Block, a heading name in { } will be replaced by the value from the spreadsheet for that columns
in the currently active row. For example, the MetaBlock could have a rule:
IF
{Price} > 14
THEN
....
and a spreadsheet:
Product Price Weight
A123 12.35 1.5
B999 15.97 3.2
The rules in the MetaBlock will be run once for each row of data. Then when the first product row is run,
{Price} will be replaced by the value from the “Price” column in the first data row (12.35) and this condition will
become “12.34 > 14” which will evaluate to FALSE and the rule will not fire.
Once all the rules in the MetaBlock have been tested using the data from the first row, Corvid will repeat the
process with the data from the second row. This time {Price} will be replaced by “15.97” and the condition will
become “15.97 > 14” which is TRUE and that rule will fire, doing whatever actions are in the THEN part.
Data
The data in each column can be numeric or text. However, the data in any individual column should be
consistent. The data values will be replaced into the Corvid rules, so the data must match the way it will be
used in the rules. If a test is numeric (as in the example above) the data should be numeric, without any extra
text that would be syntactically illegal. For example, in the above example, the test is “{Price} > 14”. This
requires that the data in the “Price” column be a simple number, rather than “$12.35”, “Expensive” or “5.00/lb”
The {columnName} is always embedding into the Corvid rules and formulas as a string. This allows it to be
added to both numeric formulas or other Corvid commands. The {columnName} will be replaced with the
exact text in the column and the rules and data must be designed to work together.
String Tests
In addition to numeric data, the spreadsheet can have columns with string data. This can be either properties
that will be used in the IF conditions in the rules or text that can be used in the THEN part of rules to add
product specific text to a report.
Since the value for the column will be used exactly as it occurs in the spreadsheet to replace {columnName},
sometimes the {columnName} must be put in quotes to make it syntactically correct in the MetaBlock rules.
For example, if a spreadsheet on cars had a “Manufacturer” column, an IF condition in the rules might test if
the value in that column was “Ford”. This could be done with:
“{Manufacturer}” = “Ford”
NOTE: The MetaBlock parameter {Manufacturer} must be in “ “ to compare it with the string “Ford”.
The {columnName} will be replaced first - before the expression will be evaluated. The quotes are
needed to make it a syntactically correct expression in Corvid.
Editing Headers
Each column has a header which is used to identify it. The text of the headers can be changed, but can not
be directly edited in the header cell. To change a header, click the header cell and edit the text in the lower
right edit box. The changes made in that edit box will be mirrored in the header text.
IF
{Price} <= [BUDGET]
THEN
....
This rule will be used for each row and will check if the price is less than the budget. If it is, the THEN part of
the rule will do something to increase the ranking score of the product, and perhaps add something to the
comments on that product.
In practice, there would probably be several related rules:
IF
{Price} <= [BUDGET]
THEN
Increase the score for this product
IF
{Price} > [BUDGET]
THEN
Decrease the score for this product
IF
{Price} > 2 * [BUDGET]
THEN
Eliminate this product
A full system would have similar sets of rules for all the different criteria that are going to be used to select a
product, comparing what the end user would like (or need) with the value each product from the spreadsheet.
All the rules MUST be in the same MetaBlock. This means that there will typically be many small trees in the
block. This is done by building the first set of rules on a criteria, then clicking the last top level IF condition
and clicking the “IF - Same Level - Below” button to start the next tree.
IF
Product should be Light
AND: {Weight} <= 2
THEN
Increase the score for this product
This way the end user is only asked if a “light” product is preferred. The rules convert “light” to a value of 2,
but that can be easily changed in the rules if the standards for the product change. If the end user wants a
light product, the ones with a weight less than 2 will get more points and the ones with a weight more than 2
will have points deducted.
There is no need to add rules for the “Weight is not important” value since the user does not care what the
weight is and there is no reason to add or subtract points from the overall score based on weight. Only
factors that have an influence on the decision should be converted to rules.
Just double click the column header to add to the expression (or
click it to select it and click OK) and the header will be added to the
expression in { } at the cursor point. This is the best way to build
expressions in the MetaBlock since it assures that the header
matches the spreadsheet.
If the spreadsheet has been edited external to Corvid and the
headers changed, click the “Reload” button on the MetaBlock
Labels window to update the list.
[Color] = "{productColor}"
or
[Color.value] = "{productColor}"
UCASE([Color.value]) = UCASE("{productColor}")
IF
{Price} > [BUDGET]
THEN
[Score] = -10
IF
{Price} > 2 * [BUDGET]
THEN
[Score] = - 1000
The MetaBlock rules will have similar rules for all the product criteria that the system considers, comparing
the end user’s (customer’s) preferences with the characteristics of each of the items. This will generate the
overall score for the item which can be used to decide what items to display as the “best” recommendations.
On the of the main tasks in building a MetaBlock system is in selecting and “normalizing” the values added to
[Score] in various situation so that the overall rankings correctly considers and balances the importance of the
various factors. Some systems can have more complicated rules that both consider how well the product
matches the user’s preference, but also how important that specific criteria is for different types of users. This
may be a ranking provided by the end user on how important that criteria is for their specific situation, or may
reflect expert knowledge of how the products are typically used by different types of users.
Since each of the factors considered is usually independent of the others, the MetaBlock will typically consist
of many small trees or individual rules. Once the first tree is built, select the top node and use the “IF-Same
Level- Below” button to start the next tree. A MetaBlock can contain as many trees at the same level as
needed for the logic - however, all the trees MUST be in the same MetaBlock. All the rules in the
MetaBlock will be processed for each row, but all the MetaBlock logic must be in the same block. A system
can have multiple MetaBlocks, but they are each independent.
IF
{Price} > 2 * [BUDGET]
THEN
[Score] = - 1000
Notice that the item data can be included as part of the string to add to the report by just putting the {...}
column heading in the text to add. Here the last rule does not need to add content since it is a rule that
eliminates the product for any possible inclusion in the recommendations. (It would be OK to add content into
the report, but it would never be seen by the end user. However, it might be useful for the developer when
building and testing the system.)
Usually the first rules in the MetaBlock will add a line to the report that includes the product identifier so that
each section of report will be associated with a “product”. If the above rules were the first ones in the
MetaBlock, the content added to [productReport] could be expanded to:
IF
{Price} <= [BUDGET]
THEN
[Score] = 10
AND: [productReport.ADD] {Product}: The product is within the budget.
This should also be done in the other 2 mutually exclusive rules so the [productReport] always starts with the
product identifier.
If this product is displayed in the recommendations, clicking on the product name will display the linked URL.
Adding the identifier information can also be done at the end of the MetaBlock before the items are saved in
the overall recommendations.
IF
[Score] >= 20
THEN
[Recommendations.ADDSORTED] [productReprot.CONCAT], [Score]
[Recommendations.TOP 3]
will display only the 3 items in recommendations at the top - which means they had the highest sort score and
are the best recommendations. Since each of the recommendations was the full report on that product
concatenated into a string, the results would display the full report on the 3 products with the highest score.
Restaurants are an excellent example of a product where there can easily be conflicting user requirements,
and “best fit” compromises are often the best solutions. This is an emulation of the advice that would be
given by a concierge on what restaurant to go to based on price, type of food, and type of occasion. It only
considers a few of the factors that a real system would, but shows the concepts for building a MetaBlock
system. These concepts apply to all product selection systems.
NOTE: Remember Corvid variables are in [ ]. Data from the spreadsheet is indicated by the column
heading in { }.
This makes a smooth transition. All restaurants under budget get
100 points. Those slightly over get somewhat less. Until at $20 over
budget, it assigns 0 points. Restaurants more than $20 over budget
get negative points.
The degree to which the system will recommend over budget
restaurants is controlled by how many points are deducted for every dollar over budget. In restaurants the
prices of different items can vary, so it does not severely penalize a restaurant for being somewhat over
budget. (In other types of product selection systems, price might be a very important factor where being over
budget would lead to a greater number of points being deducted.)
Another approach is to use a non-linear formula that will deduct many more points for prices significantly above
budget. One simple way to do this is to deduct the square of the amount above budget. This grows very rapidly.
For this system, use the linear formula above.
! This window displays how the external command will be used, such as “[X]: External source to get
variable value”.
! The text of the command in an edit box. This text is read only and cannot be directly edited. All
command parameters and changes are entered in the edit boxes under each command type tab.
This makes it easier to build commands and reduces the chance for syntax errors.
! The tabs allow selecting the various types of commands.
! Under each tab are the options for building that type of command.
13.3.2 XML
Corvid’s XML interface allows reading item(s) of
data from XML files using XPath commands. XML
provides a powerful and standard way to make
complex data structures available to the Corvid
system, without the overhead of a database
manager. XML data is a common format for data
and XPath is a very effective way to parse the data
for use by Corvid.
The XML “file” is actually just a URL. It can be a
static file or call a server program that dynamically
returns data in an XML form. The same options
found in the URL approach to calling external
programs can be used to call an external XML
resource, however, instead of requiring that the
program return data in Corvid’s format, it should be
returned in the standard XML form and the XPath
command will parse out the data your system
needs.
Corvid supports standard XPath commands, which
are evaluated using the Java XPath command parser. This provides excellent support for current and future
XPath syntax. Corvid adds some special options that make it easier to use the data returned by XPath in
Corvid systems, especially for those not familiar with advanced XPath options.
For command details see Section 13.5.
For example: If there is a data file, MyData.txt, that the system needs, it can be put in the same
folder as the CVR file. In the system, the URL to reference to it is just: MyData.txt
If the file is relative to the system CVR file, Corvid automatically builds the full URL for it. URL addresses that
do NOT start with “http” are automatically taken as relative to the folder that the system CVR file is in. Data
files can also be in a subfolder by including the subfolder name, such as DataFiles/MyData.txt
If the file is not in the same folder or a subfolder of the CVR file, it must be referenced by a full URL address,
starting with “http://”. Any address that starts with “http://” is taken as an absolute address and not relative to the
CVR file. These addresses must be full URL addresses, the same as if they were entered in a browser
program.
In most cases, static files of data needed by a system should be kept in the same folder as the system CVR
file. This makes it easy to keep the files together and to move them between servers or run standalone. Full
URL addresses starting with “http://” are needed for servlet, CGI and other programs on a different server.
When calling server programs such as Java servlets or CGI programs, the URL would be the same as would
be entered in a web browser. The URL can include parameters to pass data to the called program, such as
calling a servlet to get the price of a specific part:
http://www.myServer.com/PriceServlet?part=X123
To pass the value of Corvid variables in the URL, include them in double square brackets, such as:
http://www.myServer.com/PriceServlet?part=[[Selected_Part]]
Any Corvid variable names in double square brackets will be replaced by the variable’s value before the URL
is called. This can be used for parameters passing data, or even part of the base URL address itself.
which would set the value of [X] to 123. Alternatively, it could return
[X] 123
which would also set [X] to 123.
456
[Temp] 77
[Price] 99.99
which would set the values of [X] to 456. Since that data does not have an identifier it would be assigned
to the associated variable. The values of [Temp] and [Price] would also be set.
Date Variables
! A string date value. This can be a full date “July 5, 2010” or shorter forms such as “1/5/99” or the
number of milliseconds since Jan 1, 1970. Dates can also include the time.
Remember: All date values are interpreted by the local settings for dates on the machine running
Corvid. This is the server settings for the Servlet Runtime and the client machine settings for the
Corvid Applet Runtime. Different countries use different formats for dates. Dates such as “1/2/10”
can be ambiguous since the 1 is the month in some countries and the 2 is the month in others. When
assigning dates, the long form (e.g. July 5, 2010 1:23PM) is best to use since it is unambiguous. To
set the variable to the current date, “now()” can be used, but this can also be done in Corvid and does
not require an external call. Using "now()" with the Servlet Runtime will set the time for the server. The
Applet Runtime will set the time for the client PC.
Example: Date variable [Start_date]
! Returning Sets
! July 5, 2010 July 5, 2010
[Start_date] 5/12/10 May 12, 2010 (in the US)
now() The current date and time
Aug 21, 2008 4:52PM Aug 21, 2008 4:52PM
Confidence Variables
! A numeric value consistent with the confidence mode.
! An expression that evaluates to a value consistent with the confidence mode.
Remember: The value assigned must be consistent with the confidence mode settings of the
variable. A variable that expects a value between 0 and 1, must be given a value in that range.
Confidence values assigned will be combined with any other values assigned to the variable based
on the confidence mode settings.
Example: Confidence variable [Conf]
Returning Sets
5 5 combined with any other values
[Conf] .25 .25 combined with any other values
[Conf] 5 + 10 15 combined with any other values
aaa
bbb
ccc (each on a separate line) Adds “aaa” “bbb” and “ccc” to the list
END Marker
When reading a static file of data using the READ command in a Command block, a file can contain multiple
batches of data which will be read and processed sequentially. These batches are separated by the END
command. This ONLY should be used with the READ command and is discussed in the Command Block
chapter section on the READ command.
<part material=”plastic”>
<part_ID>X351</part_ID>
<price> 3.45 </price>
<color> blue </color>
<color> green </color>
<size> 1 inch </size>
</part>
Both provide information on the material, but are referenced in different ways in the XPath command. Also,
the first approach using a tag, would potentially allow adding multiple materials. The second approach would
be better if we wanted to have multiple similar parts, some of plastic and some of some other material, each
with their own <part> tag.
This nesting of tags can get quite complex depending on the nature of the data. The structure can be
recursive, so that there might be a <person> element containing various elements with information on that
person. One of those might be <children> containing a list of other <person> elements for each child, each of
which could also have <children> elements containing more <person> elements, etc. Such a structure could
be very complex, and the concept of “parent”, “child” and “sibling” nodes is key to navigation in such complex
structures. Advanced XPath commands can be used to select data even in complex structures, but here we
will only look at simple XPath commands.
Simple XPath commands look much like a directory path on a computer. In the simplest form, there are
element names separated by “/” traversing the tree-like structure defined by the nested elements.
In the simple part example:
<part>
<part_ID>X351</part_ID>
<price> 3.45 </price>
<color> blue </color>
<color> green </color>
<size> 1 inch </size>
<material> plastic </material>
</part>
The XPath command /part/price would return the value 3.45. /part/size would return “1 inch”. However, /
part/color would return both values “blue green”. This is because multiple values are allowed and the
command does not differentiate between them.
Working with a more complex list of parts:
<part_list>
<part>
....
</part>
<part>
....
</part>
<part>
....
</part>
</part_list>
Any Corvid variable names in double square brackets will be replaced by the variable’s value before the URL
is called. This can be used for parameters passing data, or even part of the base URL address itself.
Remember: Double square bracket embedding can lead to backward chaining to derive
the variable’s value. To use the immediate value without backward chaining, use
[[*varname]]. The asterisk before the name will use the current value without any attempt
to derive or backward chain to get a “final” value.
Any URL that could be entered in a browser window can be used, however, the called URL MUST return data
in an XML form. Corvid does not check the returned data against a schema, but an incorrectly structured file
will probably lead to runtime errors or incorrect operation. It is the developer's responsibility to assure that the
called program is returning syntactically valid XML data.
Edit: To view or edit the XML file, click the
“Edit” button. This will open the file with the
XML editor specified in the Properties window.
The default is to use Notepad, but later
versions of MS Word can be used to display
XML with formatting, or a true XML editor such
as EditiX can be used.
To specify the program to use to view XML, go
to the Properties window “General” tab.
Under “XML Editor Program to Use”, click
“Browse” and select a program. The XML
programs can be used to assist in building
XPath commands, editing data and checking
data against schema as needed.
The data in the <part_ID> tag must NOT have spaces around it. This is particularly important when setting
the value list for a Dynamic List variable from the XML data and then using the value in other boolean tests to
get other tags. Whenever a tag will be used in a boolean expression matching strings, make sure there are
no spaces around the data.
When matching a string, the string must be indicated by the " or ' character. Either:
Note for Advanced XPath Users: Corvid expects the data returned from the XPath command to be
a string. Because of this, Corvid automatically adds “.text()” to the XPath command. Normally this is
correct and allows the developer to just specify the XML elements(s) without needing to explicitly
convert it to a string. However, for complex XPath commands, it may not be valid to just add “.text()”
to the end of the command. Corvid will NOT add the “.text()” to the XPath command if it ends in “)”.
So complex commands not needing “.text()” should be put in parenthesis. For example:
/part_list/part[1]/price
would automatically have “.text()” added and would work correctly.
(/part_list/part[1]/price)
would not work since the “.text()” would not be added, but
(/part_list/part[1]/price.text())
would work correctly.
COUNT
COUNT will return a count of the number of data items returned.
/part_list/part/part_ID COUNT
would return a count of the number of parts in the list.
SEP=”...”
SEP= provides control of the character/string used to separate individual values when multiple values are
returned. This is needed only if the command will return multiple values, and those values are to be used as
a single string. When XML commands are used in a context that expects multiple values, such as defining a
list of values for a dynamic list variable, Corvid does not require the “SEP=” since the context of the use
determines how the values will be used.
The default separation character for multiple values is a new line. To change this to “ & ”, use SEP=” & “.
For example:
/part_list/part/material UNIQUE SEP=" & "
would return a single string, list all the materials in the part list such as:
The separator string is used only between values and does not appear at the end of the string.
Any string can be used in the SEP=” “, but tabs and line feeds cannot be typed into the edit box. To create a
string with a TAB between the values, use SEP=”TAB”. The default separator for multiple values is a new line.
<part>
<part_ID>B222</part_ID>
<price> 7.95 </price>
<color> black </color>
<size> 2 inch </size>
<material> aluminum </material>
</part>
<part>
<part_ID>C333</part_ID>
<price> 9.55 </price>
<color> black </color>
<size> 4 inch </size>
<material> steel </material>
</part>
<part>
<part_ID>D444</part_ID>
<price> 4.55 </price>
<color> blue </color>
<color> green </color>
<size> 2 inch </size>
<material> plastic </material>
</part>
</part_list>
A111
B222
C333
D444
Getting a list of the part_ID of all the parts in the list as a single string separated by &.
/part_list/part/part_ID SEP=" & "
Returns:
plastic
aluminum
steel
plastic
Getting a list of the materials used for parts in the list without repeated items.
/part_list/part/material UNIQUE
Returns:
plastic
aluminum
steel
Returns: 3
Returns: 4
<part_list>
<part>
<part_ID>A111</part_ID>
<price> 3.45 </price>
<color> blue </color>
<material> plastic </material>
</part>
<part>
<part_ID>B222</part_ID>
<price> 7.95 </price>
<color> black </color>
<material> aluminum </material>
</part>
<part>
<part_ID>C333</part_ID>
<price> 9.55 </price>
<color> black </color>
<material> plastic </material>
</part>
</part_list>
In the more standard tab-delimited spreadsheet approach to MetaBlocks, the spreadsheet would look
something like:
part_ID price color material
A111 3.45 blue plastic
B222 7.95 black aluminum
C333 9.55 black plastic
To create the equivalent data using an XML Interface, requires building it one column at a time. The first
column is given a name “part_ID” and the data in that column can be obtained from the XML file by the XPath
command:
/part_list/part/part_ID
This command would return the list of part_ID values in order. The values are used one per line. This builds
the first column of data.
This will return the price of the various parts in the same order as the part_ID column.
The same can be done for the “color” and “material” columns. Note, it is NOT required to have the column
names match the XML element names, but it is easier and more understandable if this is done.
This will build exactly the same MetaBlock data for Corvid to use, but the raw data can be maintained, edited
and stored as XML data.
NOTE: Each of the elements under “part” only have a single value. This makes it much easier to use
the data for a MetaBlock since if one part had multiple “color” elements, the command would return
an extra data element for that column and break the synchronization with the other columns. It is
possible to use XML files with multiple occurrences of an element, but it requires a more advanced
technique discussed below.
Interface File
An interface file needs to be selected or
created. The recommended file extension
for this file is .mbx, but any name can be
used. If there is already a interface file
created, enter the name and click “Load” or
browse to the file and select it. This will
load the file and its parameters. If there is
no file, click “New” and enter a name for the file.
Column Names
Enter the name of the each of the “columns” in the MetaBlock. These can be directly typed into the boxes on
the screen. These will be the column references used in the MetaBlock logic - the names in { }. The names can
be anything clear and unique, but it is often easier if the names match the element names in the XML data.
Columns do NOT need to be created for every element in the XML data, only for the ones that will actually be
needed in the MetaBlock logic and rules.
XPath Commands
Next to each column name enter an XPath command that will return the data for that column. It is VERY
important that the XPath commands return consistent data across the columns. That is, the nth item in each
column MUST all apply to the same product. This is easy to do for simple XML files such as in the example above.
Just make sure the XPath command will return data from the same higher-level elements in the XML data.
In the example, the first column XPath command was
/part_list/part/part_ID
This will return one “part_ID” data item for each part element in the part_list. The other XPath commands
must match. The “price” column uses the XPath command:
/part_list/part/price
This will return also return one “price” data item for each part element in the part_list.
To have the “rows” of data in the MetaBlock all be related and have meaning, it is very
important that this consistency be maintained.
Enter an XPath command to get the data for each of the columns entered.
The XPath command can include embedded Corvid variables and selectors to restrict the data returned such as:
/part_list/part/price
it could return more data items and that data might not be in sync with the part_ID command. This would
cause the MetaBlock to work incorrectly and give incorrect recommendations.
{part_ID}
which will be replaced by the value for the current working “row” in the MetaBlock.
The associated “Color” value might have multiple values. Creating a "color" column would be out of sync with
the other columns. Instead, use an embedded XML expression in the Logic Block expression:
<#<XML "partdata.xml" /part_list/part[ part_ID='{part_ID}' ]/color sep=" " >#>
This will return the color values for that part as a string that may have one or multiple values. This string can
be used in boolean tests to check for particular colors, or can be used as text to add to a collection variable as
part of a report.
This makes the actual MetaBlock logic more complex and difficult to read, but can be an effective way to
handle more complex XML data. As long as at least one column is defined that returns unique single values,
the embedded XML commands can recover any other data in the XML file that is needed.
NOTE: Embedded XML expression for "color" can ONLY be used in the actual MetaBlock
rules in the Logic Block. It CANNOT be used in the XPath commands used to select column
data in the XML MetaBlock specification file.
/part_list/part/
and click “Update”. The XPath commands for each column would become “/part_list/part/” followed by the
column name entered. These would be:
/part_list/part/part_ID
/part_list/part/price
/part_list/part/color
/part_list/part/material
This works ONLY when the column name matches the XML element name and each item only returns single
values; but is a very convenient way to build commands for correctly structured files.
Delete and Move Commands
To delete a row in the XML MetaBlock specification, click on the row to select it and click the “Delete” button.
Rows can be moved and reordered by selecting them and then clicking the “Move Up” and “Move Down”
button - however, the order of the columns has no effect on how a MetaBlock will run.
If more rows are needed in the XML MetaBlock specification file, click the “Add Blank Rows to End” button.
XML Interface System Requirements: The Corvid Applet Runtime will work with virtually any version of
Java, however the XML Interface Applet requires Java v1.6 or higher. When Applet systems using the XML
commands are distributed, the end user must have Java 1.6 or higher or the XML Interface Applet will not
work. For the vast majority of machines, this will not be a problem, but end users with older versions of Java
that have not upgraded may not be able to run systems with XML Commands. If this may be a problem for
your target end users, the best solution is to use the Corvid Servlet Runtime, which puts no limits on the end
user’s machine.
Important Security Concerns: The SQL Command File approach used with the Corvid Applet Runtime
greatly limits the SQL commands that can be executed on your database. However, someone with the
correct knowledge COULD execute the commands in the SQL Command File.
If this presents an unacceptable security problem for your database, you should run
your system with the Corvid Servlet Runtime and not install the Corvid Database
Interface (CorvidDB.war).
The Corvid Servlet Runtime will only execute your Corvid application and cannot be called to execute any
SQL commands directly, even if they are in the SQL command file.
Command File
The first step is to create or open the command file
that will hold the connection information along with
the allowed SQL commands. All the commands
and options will write to this file so the file must be
created or selected before going to the other tabs.
Most systems only have a single command file.
However, multiple command files can be used for
systems that connect to multiple databases using
different DSNs.
Remember, the command file will be moved to the server.
When using the Corvid Applet Runtime, the command file should be put in the
CorvidDB folder created when CorvidDB. war deploys. If using the Corvid Servlet
Runtime, the command file is put in a folder that is secure from browsing.
In most cases, the copy of the file being edited is a local copy. If there is already a file on the server, you
may need to download it to have the latest version of the command file. After changes are made, be sure to
move the edited file up to the server for the changes to take effect.
! To open an existing file, click “Browse” and select it, or enter the name of the file and click “Load
Commands”.
! Once a file is opened, to save it with a different name, click the “Save As” button.
! To create a new file, click “New”. A dialog will be displayed asking for the connection information:
Fill in the connection information as
described below. This information can later
be edited on the Command File tab.
Command files normally have a .cdb file
extension.
Driver
Enter the driver for your database. If you
are using Java 1.8 or higher, this must be a JDBC driver. (Java version up through 1.7 included a JdbcOdbc
driver which allowed an ODBC connection, but that was not included in Java 1.8). Most databases designed
to work with Java will have a “standard” JDBC driver, however, any valid JDBC driver can be used.
At the current time, MS Access does not have an included JDBC driver. The JdbcOdbc driver can be used but
requires a Java version 1.7 or earlier and will not work with Java 1.8 or higher. Since Access is unlikely to be
used as a server database, and is more likely only for local testing, it may be better to switch to MySQL which
is available for free and can be installed locally. There are also some 3rd party JDBC drivers for Access and
more may be available in the future.
Connection
To use an JDBC connection to your database, the database needs to be identified.
Login / Password
If the database requires a login and password, enter them, otherwise leave these fields blank. If a login/
password is entered, it will be stored in the Database Command file. This file will be on the server, and it
should be handled with whatever security limitations and precautions are appropriate for the password.
If there are security concerns about either having the login/password in a file on the server, or in having these
essentially hard coded into the system, you can have the end user provide them. To do this:
1. You must be running the system with the Corvid Servlet Runtime. (This technique will not work
with the Corvid Applet Runtime.)
2. In your system, create Corvid string variables for the login and/or password.
3. In the database connection window, for the login / password enter the name of the string variable
in double square brackets with the .VALUE property.
4. In your system, add a command in the Command Block to force the login / password variables to
be asked before any database calls are made. (If this is not done, the variables will be asked
when the first database call is made, which may not be the order of questions desired for your end
user interface.)
This way, the user will be asked to provide the login and/or password and nothing sensitive is hard coded in
the file. If they cannot provide the password, the database commands will not execute, but the rest of the
system will run.
For example, create Corvid string variables [TheLogin] and [ThePassword] and have these asked of the end
user before any database calls are made. In the connection data window, for the login use [[TheLogin.value]]
and for the password use [[ThePassword.value]]
S String. Allows any alphanumeric characters. Quotes and ticks will not be allowed. The value will
automatically be URL decoded.
N Numeric. Allows only the characters 0-9, '+', '-" and '.'
F Field. Must be a valid syntax for a database field name. The existence of the field in the database is
not checked until the command is actually executed. Allows only alphanumeric characters and ' _').
Some of the letters do not do type checking but instead do some form of conversion:
V Unknown value type. If it contains all numeric characters, it will be handled as a numeric. Otherwise, it
will have ticks ‘ ‘ put around it and handled as a string. If you use V, you must not use a string that
contains only digits or it will think it is a numeric and not tick it. The V is used when you have something
like, "WHERE {F#} ={V#}". Since you do not know what field will be used, you do not know what the field
type will be. By using V it will automatically tick it if it looks like a string value.
Here we can use the String type since the part name is alphanumeric.
Here all that is needed to close the ' around the {S1}.
Replaceable parameters are just replaced by the
value passed. If SQL syntax calls for ticks or
quotes around a value, those must be added in
the command around the replaceable parameter.
To view the command with the Corvid variable(s) directly embedded in it, click the “Display Command with
Variables” button.
Clicking “OK” returns the external data interface command to wherever the interface command was built from:
This time, since the field name is static and does not
come from a variable (although it could), just type in
the field name “Address” and select the “F” validation
type since this is a field name. Click “Add to
Command”. Continue adding the next portion of the
SQL command up to the next replaceable parameter.
After the end user selects the second field they want
to use, the system will ask for the value for that field
and store it in the variable [ID_Data]. This is used for
the last replaceable parameter in the command.
Click OK to add this command to the command list.
CORVID_DB FILE=customerData.cdb&ID=GetField&1=Address&2=[Name]&3=[ID_Type]&4=[ID_Data]
CORVID_DB FILE=customerData.cdb&ID=GetField&1=City&2=[Name]&3=[ID_Type]&4=[ID_Data]
Since the replaceable parameters can be changed as needed, SQL commands can be designed so that they
can be used in multiple ways.
will return 3 fields from the record that is found. To put the 3 values in 3 string variables [ADDR], [CITY] and
[ST], add these 3 Corvid variables to the list. The configuration option added to the command will be:
V=ADDR-CITY-ST
Other Special Options: O=
Special options are a string of characters that cause different pre-programmed behavior.
For example, "O=TQZ" adds 3 behaviors. NOTE: there is no period between individual options.
The available options are:
Q Put quotes around the entire return data string.
T Instead of using line feeds to separate the row/record data use a tab.
N Instead of using a tab to separate the column/field data use a line feed.
Z If the database SELECT statement fails, return an empty string. This will force Corvid to
ask the value of the variable
Configuration Option Line Identifier: R=
The Configuration options line can get fairly long, especially when many items of data are being returned to
multiple variables. An alternative to having the line in the Corvid_DB command is to put it in the SQL
Command File with an identifier string. Then just use R=identifier to add all the Configuration commands on
that line.
This configuration options line can be added to the SQL Command File by:
1. Build a command in the Command Builder with all the required command options.
2. Select and copy the options from the command. Save the command.
3. Start a new command by clicking “Build New Command” on the Command tab.
4. Give the new “command” an identifier and paste the configuration options in as the text of the
“command”. Click OK to save it.
5. Return to the command from step #2 and go to the Options tab.
6. Turn off all configuration options except “Configuration Option Identifier”, which should be set to
the identifier for the option line added to the file in step #4.
! Use the “V=” option on the command to put the return value in the string variable.
Either way, after the value is set, it can be checked in a Logic Block or with an IF in the Command Block.
Unless the return string is “Success”, the SQL command failed. If it fails the string will be an error message,
which may help in determining the cause.
The same window will open that was used to build the
command.
6. Back in the database Command tab, "Build New command" Add a command to select the
needed columns of data from the DB. These must EXACTLY match the columns in the static
sample data header. If the header line defines 3 columns, the SQL command must return 3
items of data for each row. This can be done by a SELECT command listing the field names
of the data needed. (e.g. SELECT Part, Price, Material FROM Table1). The SQL command
can use WHERE with replaceable parameters to limit the data returned if needed. Click OK to
add the new command to the command list.
7. With the command just added selected.
! Click the Options tab. Click "Spreadsheet header line identifier" and enter the header
identifier. This is the identifier name from step #5.
! Still on the Options tab, also click "Use tabs to separate items".
! Click OK to save the command.
The source for the MetaBlock data will be "database" and the edit field will have the CORVID_DB... command.
When the command is executed, the Corvid Runtime will call the SQL command, which will return the
specified fields of data for each applicable record in the database. Corvid will automatically convert the data
returned into the form needed by the MetaBlock. The header row will be added and the values will be
chopped into rows that match the column headers. The number of header columns defines how the data will
be broken into rows, so it is very important that the “Select” identifiers match the column headers.
If PARAM data is used, the HTML page used to run the system must be custom modified. This can be done
by running the system once, and then editing the KBName.HTML page Corvid generates. Edit this to add the
custom PARAM data and save it as a different name. Open the “Properties” window and on the “Test Run”
tab, enter the new HTML page as the “Specific URL”. Corvid will then use that page when test running rather
than the page it generates which would not have the custom PARAM data.
<APPLET
CODEBASE = "./"
CODE = "MyApplet.MyClass.class"
NAME = "CustomApplet"
ARCHIVE = "MyApplet.jar"
WIDTH = 0
HEIGHT = 0
HSPACE = 0
VSPACE = 0
>
</APPLET>
The “Name” for the applet in the Applet tag can be any string. Use this name in the Corvid “Applet Name”
field to call the applet. The case of the characters in the name must match exactly.
Data: This is an optional field, but is generally used. This is the data that will be passed to the applet. This
data will be available in the called applet to tell it what to do. The data is passed as a string and can be any
text data including spaces. Corvid variables in double square brackets can be used to pass Corvid system
data to the called applet. If multiple values are to be passed, pass them in a way that will allow the called
applet to parse out the various items.
For example, an applet to do a table lookup would need to be passed the name of the table and the value to
look up. The name of the table might be static and the value to look up might be in the Corvid variable [X].
The data could be:
“MyDataFile.txt” [[X.VALUE]]
The quotes around the file name make it easy for the called applet to parse that out of the string (even if the
filename contained spaces), and the value of the variable [X] would be embedded in the string.
There is no limit to the length of the string or number of variables passed in it.
Do Not Wait Option: Most called applets will perform some function and return data. In that case, be sure
this option is NOT checked. However, applets can also be used to just display data or store it some custom
way. Corvid does this with its built-in Trace applet which is sent trace data as Corvid runs, but which does not
send anything back.
When the applet first starts, running will be false. The original name of the applet is saved so it can be reset
later, running is set to true and any other initialization code is executed. When Corvid calls the applet, init()
will be called again (by Corvid) and this time since running is true, the processDataRequest() will be executed
to do whatever the applet does to get and return data to Corvid, and the name is reset to the original name.
This last step is important since without it Corvid will not be able to identify the applet for subsequent calls.
The processDataRequest() uses the getName() method to get the data sent from Corvid. Corvid will have
already set this to the “data” string specified by the APPLET command in the Corvid system. When called by
Corvid, the “name” of the applet will actually be the data sent from Corvid. This very simple technique allows
large amounts of data to be sent in a very easy and reliable manner.
This uses essentially the same technique to send data back as was used to pass data in. The
corvidRuntime.setName() sets the data so that Corvid can recover it using a getName() command. The
corvidRuntime.start() methods has a boolean flag that indicates it is waiting for an applet to return data, and
calling it here tells Corvid to read the data and continue processing. Very large amount of data can be passed
back if needed.
123
and [X] would be set to that value.
Note, the type of the variable determines what data is acceptable. If the string “abc” was returned for a
numeric variable, it would produce an error. Static List variables can be set by either the number of the value,
or the short text of the value. So a Static List variable [color] with value “red”, “blue” and “green” could have
return data or either “1” or “red” set the first value. For Static List variables, to set multiple values separate
them with a comma - so “1,2” would set the values red and blue.
To return data for multiple variables, the form:
[varname] value
must be used, and the individual variable/value pairs must be separated by a tab. The return string:
<APPLET
CODEBASE = "./"
CODE = "MyApplet.MyClass.class"
NAME = "CustomApplet"
ARCHIVE = "MyApplet.jar"
WIDTH = 0
HEIGHT = 0
HSPACE = 0
VSPACE = 0
>
</APPLET>
The name is the name used to call the applet from Corvid. The “CODE=” is the main class in the applet. The
Archive is the .jar file for the applet.
The width and height values depend on if the applet will be used to display information, and how the applet
should be displayed on the page. If the applet has no direct user interaction, these values can be “0” and the
applet will be invisible, but will still run. If the applet displays data, or has some user interaction, set these
values appropriately to whatever size is required. The applet can be anywhere on the page.
The HTML page that Corvid generates must be modified in a text editor or HTML editor to add the additional
applet tag. Once a custom page has been created, you can have the system automatically run with this
custom HTML page during development by:
Text Reports
! Allows building reports either incrementally or from a template.
! Can be displayed in the Applet Window or in the browser window the servlets.
! Very limited formatting options, but can be used to generate XML data.
HTML Reports
! Allows building report in HTML either incrementally or from a template.
! Best done using the Corvid Servlet Runtime, but can be done with the Corvid Applet runtime and
the Corvid Report Servlet. Always requires some a server capable of running Java servlets.
! Very wide range of formatting options with HTML, HTML5, CSS, CSS3, JavaScript, etc.
RTF Reports
! Requires building the report in RTF from a template (Building RTF incrementally is difficult)
! Best done using the Corvid Servlet Runtime, but can be done with the Corvid Applet runtime and
the Corvid Report Servlet. Always requires some a server capable of running Java servlets
! Wide range of formatting options comparable to a word processor document.
! Opens report in MS Word or other text editor (depending on browser settings) allowing end user to
modify text. This generally requires that the end user specifically allow this.
! Good for building documents that the end user can modify. If the end user should not be able to
easily edit and modify the report, it is better to use HTML or PRF reports.
The template approach is simple. Just build a file of the correct type (text, HTML, RTF) that has all of the
design and layout. This can be done with any editor appropriate for the file type:
! For text use any text editor and save the file as “text”.
! For HTML, use a HTML editor such as Dreamweaver or any other HTML editor.
! For RTF, use a word processor / editor that can save the file as RTF.
! For PDF, build the report as RTF and it will be converted in a later step.
Use double square bracket embedding of Corvid variables to provide the text and values from the system.
Use the .ADDFILE method to read this template file into a Collection variable. This is typically done in the
Command Block after the main main system logic has run and all the values have been set.
Display the collection (report) in a browser window, which may pass it off to another program depending on
the type of data.
When the template file is read into the collection variable with the ADDFILE method, any embedded double
square bracket variables will be replaced by their value. If the variables have already been assigned a value,
that value will be used, and usually it is a good idea to have commands in the Command Block to derive the
values before the template is used.
If an embedded variable in the template does not have a value, Corvid will use (in order):
! Backward chaining to derive the value.
When the file has been added to the collection variable, all embedded variables will have been replaced by
their final value.
Text Templates
The simplest type of template to start with is a text template.
Suppose a system has variables [X] and [Y] whose value is set by the rules in the system.
A text file, report.txt, could be created in Notepad or any other text editor:
The value of X is [[X.value]]
The value of Y is [[Y.value]]
The template file can be an name, but keeping the extension appropriate to the file will make it easier to edit it
later in the associated editor.
In the rules or Command Block, add the file to a Collection variable [Report]:
[Report.ADDFILE] report.txt
This will read the file and convert the double square bracket embedded variables to their values. (Deriving or
asking the values if needed.) The full report content will now be in the [Report] collection variable which can
then be displayed. Since this is just text, this could be displayed in the Results window by selecting to display
the value of [Report]
The embedded variables in the template can be a variables with a simple individual value set by the rules, or
can be other collection variables that may have a list of values that will all be added to the template when it is
read in. This allows sections of content to be built using rules to incrementally add text, but the overall design
of the report to be handled with a template.
HTML Templates
HTML templates work the same a text templates, but the content is HTML. They can be designed with any
HTML editor. The should appear in the page as displayed text. Just add the embedded Corvid variables in
double square brackets, [[...]], where ever that content should appear. The [[...]] will appear in the displayed
page and can be formatted and styled like any other content. Variables can be embedded with any of the
Properties, and often the .VALUE property is needed to get just the value rather than the prompt plus the vale.
Some embedded variables with multiple values, such as Collection variables may need to use the “Before”
and “After” options (described above) to result in syntactically correct HTML code.
Once the page is built, it is a good idea to open the HTML source in a text editor such as Notepad and check
all the embedded variables. (Just search for “[[“). Sometimes HTML editors can break the embedded
variables by adding formatting or styling tags in them. Since Corvid must find and replace the double square
bracket expressions, it is important that they retain the correct Corvid syntax - even though they must also
display correctly in HTML.
The HTML template should be the full page, with both HEAD and BODY content. If the page uses external
files such as CSS or images, the links to those files will be needed, either as a full link or a relative link. It is
even possible to have formatting options controlled by the embedded variables, so the CSS style could be an
embedded variable, [[StyleToUse]].
Since the page will be created and used by the Corvid Report Servlet or Corvid Servlet Runtime, the “base”
path for the page may be difficult to predict. This can be solved by putting the images, CSS, etc in a folder on
a web server and using a full path (e.g. http://www.exsys.com/MySystems/MySystem.css) This way the file
<head>
<meta charset="UTF-8">
<title>My Report</title>
</head>
<body>
The value of X is <bold> [[X.value]] </bold><br>
The value of Y is <bold> [[Y.value]] </bold>
</body>
</html>
RTF Templates
RTF is another approach to reports where the report formatting is created in a word processor, rather than
HTML editor, and saved as an RTF document. The report based on the template can be displayed to the end
user as either a RTF document that will open in their word processor for editing, or can be converted to a PDF
document that will open in Adobe Acrobat.
RTF is just a way to represent the complex formatting of a word document. The RTF file itself is just text, and
like HTML, can be used as a template for Corvid. To build a RTF template, use a word processor, such as
MS Word, that can save a file as RTF. Create the report template, using double square bracket embedded
Corvid variables for sections of the content. These embedded variables can be formatted and styled like any
other text in the document. The document can also contain any other static content that is needed.
RTF is a more difficult to read syntax than HTML, but is based on documented, standard control codes. For
most reports, understanding the control codes is not required and just building the document in a word
processor will work. For complex reports, or when adding multiple values from a collection, a knowledge of
the control codes can be needed. However, often building a sample of the how a final report should look, and
then opening the RTF file with a simple text editor will provide the codes and structure that is needed.
Once the template is created in the word processor, choose “Save As” and select “RTF” (or in some
programs “Text RTF”). This will create the file that can then be used as a template.
If the optional key string is used, only the section of the file between key
string markers will be added. There can be as many of the Corvid_KEY
markers as needed to divide the file into the required sections.
All text between the marker <!-- Corvid_KEY=key_str --> and the closing
<!-- Corvid_KEY_END=key_str --> will be added to the file. There can be any amount of text between the
markers and it can include multiple lines in the file. Any file content outside of the Corvid_key markers will be
ignored and not added. It is important that the Corvid_key_END marker EXACTLY match the Corvid_key
marker. If they do not match, all text to the end of the file will be added. The key strings should be unique. If
they are not unique, the first one found in the file will be used.
Markers should be in pairs and should match key strings. The start and end markers are associated with a
specific key, and they can overlap. The markers are HTML comments, and often used with HTML, but can be
used in any file. When they are used in a HTML file, and there are overlapping sections the Corvid_KEY
markers will be invisible in HTML.
For example:
<!-- Corvid_KEY=first key -->
aaa
<!-- Corvid_KEY_END=first key -->
<!-- Corvid_KEY=second key -->
bbb
<!-- Corvid_KEY=another key -->
ccc
<!-- Corvid_KEY_END=second key -->
ddd
<!-- Corvid_KEY_END=another key -->
If this was in a file named MyFile.txt and there was a collection variable [Col]:
bbb
<!-- Corvid_KEY=another key -->
ccc
Text in the file added to a Collection variable with the ADDFILE can have blocks that are conditionally include
based on a boolean test express by using:
#Corvid_IF expression
text to include
#Corvid_ENDIF
NOTE: Unless BREAK_ON_CORVID_IF (explained below) is used, the Corvid_IF test expressions
must be on separate lines and be the only text on the line.
The text to include can be any length and any number of lines. All text up to the next “#CORVID_ENDIF” line
will be added to the file.
There can be any number of CORVID_IF expressions. The #CORVID_IF can be used with CORVID_KEY,
but the CORVID_KEY will take precedence. The CORVID_KEY will be used to first select a block of text, and
that text can include #CORVID_IF to include/exclude sections.
The test expression is any Corvid expression that evaluates to TRUE or FALSE, such as:
([X] > 0)
[DAY.CHECK Monday]
[NAMES.INCLUDES Bob]
[X] > [Z]+5
The expression can include Corvid variables and properties. If the value of a variable needed to evaluate a
#CORVID_IF is not known, it will be derived via backward chaining or (if that fails) asked of the end user.
Generally it is best to make sure all variables that will be needed for #CORVID_IF tests are known before the
ADDFILE is done. This will prevent the system from needing to trigger other logic or questions to complete
the ADDFILE.
Inclusion tests can be nested, but each #Corvid_IF must have a matching #Corvid_ENDIF. The
#Corvid_ENDIF corresponds to the first preceding #Corvid_IF that does not have a matching #Corvid_ENDIF.
If a block of text contains other #Corvid_IF tests, the block included/excluded will be all of the text to the point
of the #Corvid_ENDIF that matches the initial #Corvid_IF.
When nested, the lines with #CORVID_IF.. and #CORVID_END if are NOT included in the collection.
For example, if the file to add has:
#Corvid_IF test1
aaa
bbb
#Corvid_IF test2
ccc
#Corvid_ENDIF
ddd
#Corvid_ENDIF
eee
If test1 is TRUE and test2 is TRUE, ADDFILE would included:
aaa
bbb
ccc
ddd
eee
The file to include must be designed so that various sections of text can be included or excluded and still keep
the syntax of the file. This is easy for text files where there is no internal syntax requirements. It can be more
difficult for HTML where tags must match, etc. and can be quite complicated for RTF documents which have a
less readable internal syntax.
HTML Reports
To Corvid, the report content is just text. It does not know if the text is actually HTML, XML, RTF or just
simple descriptive text. It is just a text string that is added to the Collection variable’s value list. However, the
Collection can be used to build reports using HTML, XML and any other text oriented language. This is done
the same way as adding any other content to the report, but to display correctly, the syntactical rules for the
language must be followed when adding content.
Most HTML reports are built using templates (described below) but even there, blocks of content may be built
incrementally and must follow the HTML syntax.
Remember, Corvid treats all the content as just text. If a rule is:
IF
Power light = off
THEN
[Report.ADD] The machine is not getting <b>power</b>.
Corvid will add the text content “The machine is not getting <b>power</b>.” to the Collection. Corvid does not
know that <b> will make the word “power” in a bold font - that is up to the browser that will eventually display
the content as HTML. This makes it very easy to add any HTML content as text, but it requires that the
syntax of HTML be followed. HTML tags must match and be closed, and errors may result in the browser not
displaying the report correctly.
Content can also include CSS styles such as:
[Report.ADD] <p class=”errorMsg”>The machine is not getting <b>power</b>.</p>
provided somewhere on the overall report the CSS style “errorMsg” is defined or imported.
The “Before” and “After” options can be used when adding multiple items to a list and each item must be
wrapped in a tag. For example, to add a Collection variable [Problems] that has had multiple items add to it,
to an overall Collection [Report] as a HTML list:
If you are running on an ISP you may have restricted access and must put your temp report folder in your Tomcat space at
the same level as webapps. This will probably be the lowest level you can access on the server via FTP. Create a folder
at that level. Corvid will need to access this folder by its actual path and you will probably need to ask your ISP for this
information. It may be a complex Unix path such as:
/usr/local/etc/httpd/sites/…./ExsysReports
The CorvidReport.cfg file is just a text file and should be created with a TEXT editor such as Notepad or a “programming
editor”. It should NOT be created or edited with a word processor or other program that may add formatting information.
The text file should have just the location of the report folder (e.g. C:/ExsysReports) on a single line.
Once the CorvidReport.cfg file is created, it must be put where the Corvid Servlet Runtime looks for it. The Corvid
Runtime will look in 2 locations for the CorvidReport.cfg.
1. It will first look in the folder for your individual expert system. This is the same folder as the CVR file for that
system. If you have fielded a system named “MySystem”, there will be a CorvidProjects folder named MySystem
and in that folder a MySystem.CVR. You can put the CorvidReport.cfg file in the same MySystem folder. In this
case, the report folder specified in the CorvidReport.cfg will apply ONLY to reports from MySystem. Other
systems can use a different CorvidReport.cfg specifying a different folder (although they can use the same report
folder if the same CorvidReport.cfg is put in that system’s folder).
Note: when Corvid runs the system, the system files including the CorvidReport.cfg, will be copied to the runtime
Tomcat folders in:
..CorvidProjects/Apache-Tomcat-xx/webapps/MySystem
When Corvid deploys the Servlet Runtime, it puts an empty copy of CorvidReport.cfg in WEB-INF. This empty
file is ignored, but can be replaced by a CorvidReport.cfg that has a folder specified. If the CorvidReport.cfg is
put in WEB-INF, it will apply to ALL Corvid systems that generate reports, UNLESS those systems have a
CorvidReport.cfg in the individual folder for that system.
Putting the CorvidReport.cfg in WEB-INF makes it apply to all systems, but remember that when new copies of
the Corvid Servlet Runtime are deployed, the CorvidReport.cfg may be lost and need to be updated.
In general, putting the CorvidReport.cfg in the individual system folder is a better choice.
CorvidRpt
This servlet provides the ability to save and display reports external to the Corvid Servlet Runtime.
It is needed only for:
The Corvid install program will automatically deploy the CorvidRpt servlet in the CorvidProjects/Apache-Tomcat/webapps
folder. If it is to be used, a CorvidReport.cfg file MUST be added to the CorvidRpt/WEB-INF folder specifying the report
folder. This should be the same CorvidReport.cfg used in the system folder or CORVID/WEB-INF. (Note: with CorvidRpt,
there is only a single CorvidReport.cfg. It does not have access to any CorvidReport.cfg stored in the individual system
folder. All reports using CorvidRpt must be in the same folder and must be consistent with the report folder specified for
the Corvid Servlet Runtime).
The details of testing the CorvidRpt servlet can be found in section 14.4.1.
ExsysFop
The ExsysFop servlet provides the ability to display PDF reports. It is need for any system that will display a PDF report.
The Corvid install program will automatically deploy the ExsysFop servlet in the CorvidProjects/Apache-Tomcat/webapps
folder. If it is to be used, a CorvidReport.cfg file MUST be added to the ExsysFop/WEB-INF folder specifying the report
folder. This should be the same CorvidReport.cfg used in the system folder or CORVID/WEB-INF. (Note: with ExsysFop,
there is only a single CorvidReport.cfg. It does not have access to any CorvidReport.cfg stored in the individual system
folder. All reports using ExsysFop must be in the same folder and must be consistent with the report folder specified for
Corvid).
HTML Reports
There are 3 ways to display HTML template based reports:
In this case, it is not necessary to read the template file into a collection variable.
The displayed report cannot be bookmarked since it is dependent on the Corvid session. The extra functions
of the SaveReport command to limit access are not available, but with this approach there is no “temporary”
report file created to restrict access to, so this should not be a problem.
This approach does not work with the Applet Runtime due to differences in how applets and servlets work. In
the Applet Runtime, the DisplayHTML command does not read in the template file. but instead just opens a
new browser window for the URL without any processing of the URL’s content. Because of this, with the
applet, the embedded variables will not be replaced by their value.
The Command Block for the systems will look something like:
where:
[Report] is a collection variable to build the report in
[Report_ID] is a string variable to hold the report file identifier
The HTML_Report_Template.html is the template file for the report with formatting and double square
bracket embedded variables.
SaveReport saves the report file.
DisplayReport displays it.
If the SaveReport command saved the report ID in a string variable [Report_ID], the link to display the report
with CorvidRpt is:
http://localhost:8080/CorvidRpt/corvidreportservlet?OP=DISPLAY&[[report_ID.value]]
The easiest way to implement this is to use the DISPLAY_HTML command with a redirect page. This page
has no displayed content, but tells the browser to instead open the CorvidRpt page.
<!doctype html>
<html>
<head>
<title>HTML Redirect</title>
<META http-equiv="refresh" content=“0;URL=http://localhost:8080/CorvidRpt/corvidreportservlet?
OP=DISPLAY&[[report_ID.value]]”>
</head>
<body>
</body>
</html>
Alternatively, the URL for CorvidRpt can be added to the displayed HTML page as a standard link with
The Command Block for the systems will look something like:
Instead of a DisplayReport command, the DISPLAY_HTML displays the HTML file with either the redirect
command or a link using the [Report_ID]. To have the report display immediately, use the redirect page
approach since this will automatically switch the browser to the new page.
1. In the normal RESULTS page, include the [Report_ID] as a URL link that is part of the normal
system results page:
<a href="http://localhost:8080/CorvidRpt/corvidreportservlet?
OP=DISPLAY&[[report_ID.value]]">Display Report</a>
This will put a link in the standard results display and clicking on the link will display the report. This
can also be done with PDF reports by changing the servlet called to ExsysFop.
2. Another way to have the called URL redirect to a new page can be done with JavaScript. To
display the report in a pop-up window, change the <body> tag to this:
<body onload='window.open("http://localhost:8080/CorvidRpt/
corvidreportservlet?OP=DISPLAY&[[report_ID.value]] ","_new")'>
RTF Reports
RTF reports are also quite easy to build since they can be formatted in a standard word processor.
1. Create a template for the report and save it as a RTF file. This is done with a standard word
processor. Add any desired formatting and embed Corvid variables in double square brackets.
(Note: Make sure to not have any change of format in the [[..]] or it may not be syntactically valid to
Corvid.)
2. Add the RTF template to a Collection variable with ADDFILE.
3. Call SaveReport for the Collection variable with TYPE set to “rtf” and “Call via Servlet” selected.
No external servlet needs to be specified. Save the report ID in a string variable.
4. Call DisplayReport for the string variable with the report ID. Again, no external servlet needs to be
specified.
The user will be asked if they want to open the resulting RTF report, and what program to open it with. This
will typically be a word processor or whatever program their browser settings use for RTF files.
Once the report opens in the selected program, the user can edit it and save it locally like any other word
The Command Block for the systems will look something like:
The same technique of using a redirect HTML page to CorvidRpt can also be done here, but is generally not
needed since the resulting report is typically saved as a local document, and would not be reopened as a link.
If a system needs to have the RTF report be bookmarkable, use the same approach with a redirect page to
the URL:
http://localhost:8080/CorvidRpt/corvidreportservlet?OP=DISPLAY&[[report_ID.value]]
PDF Reports
PDF reports have the most steps, but are actually not difficult to build once an RTF report is working.
1. Create a RTF template for the report and save it as RTF, just as in a RTF report. (It is a good idea to make
sure that the RTF report works correctly before proceeding since any problem with the RTF report will only be
amplified when moving to a PDF report).
2. Convert the RTF to FO with a conversion program. FO is actually an XML representation of RTF. While
not widely used, it is a standard. Programs such as “RTF_to_XML” ( http://www.rtf-to-xml.com) can be used
to do the conversion. This creates a FO format template.
3. Add the FO template to a Collection variable with ADDFILE.
4. Call SaveReport for the Collection variable with TYPE set to “pdf” and “Call via Servlet” selected, but no
external servlet specified.
5. PDF reports must be displayed with the ExsysFop servlet. This functionality is not built into the Corvid
Servlet Runtime. To do this, use the same redirect approach as was used with HTML reports. Call
DISPLAY_HTML (Not DisplayReport) with a redirect PDF_Redirect.html that will automatically open the
PDF. The redirected link will be to ExsysFop and can be bookmarked. This link will work, even after the
user’s Corvid Servlet session has expired.
http://localhost:8080/ExsysFop/exsysfop[[report_ID.value]]
Note: ExsysFop uses a different syntax from CorvidRpt and there is NO “?” before [[Report_ID.value]].
A simple HTML redirect page can be used to tell the browser to immediately open the PDF:
or the ExsysFop link can be added to a standard HTML page as a link to display the PDF report.
The Command Block for the systems will look something like:
The report will open in Adobe Acrobat which requires that the end user have Acrobat Reader or some other
PDF viewer.
It is highly recommended that systems using the template based reports be run with the Corvid Servlet
Runtime rather than the Applet Runtime. Applets have many, and increasing, Java security issues and will
not run on mobile devices such as iPhones and iPads. Also, displaying reports from the Applet runtime
requires a servlet to save and display the report - so the Corvid Servlet Runtime could be used.
The security applied to Java applets does not allow them to write to the local (client) hard disk or printer. This
prevents an applet from locally writing a report that can be displayed or printed. To solve this, Corvid writes
the report back to the server and then displays it from there in a new browser window or using a “helper”
program for the type of report (e.g. Acrobat Reader for PDF reports).
Writing to a server is allowed by Java security and is a very effective way to handle reports. A formatted report
can be viewed, printed, bookmarked, saved and sent to others when needed.
However, this does require that the server have a program installed that Corvid can use to save and display
the reports. Corvid includes the CorvidRpt.war Java Servlet program which must be installed on a server that
provides support for Java Servlets with Tomcat, Glassfish, IBM Websphere or comparable program. Many
ISPs provide support for servlets, and for development purposes the free “Apache Tomcat” can be installed
on a local PC.
The Corvid Report Servlet needs a folder to store the report files that it creates. This should be a folder that CANNOT be
read from the server using a URL. Since Tomcat is installed locally, you can create a folder outside of the Tomcat folder,
such as “C:/TempCorvidReports”. On a server, check with your system administrator for a location to create the folder
that the servlet can write to, but which cannot be accessed externally with a URL. You will need the full path to the folder,
which on a server may be a long path. DO NOT create the folder in webapps.
Return to the webapps folder in Tomcat. Open the "CorvidRpt" folder that was created, and then open the "WEB-INF"
folder. There should be a "CorvidReport.cfg" file. Open this file with a simple text editor such as Notepad. (If the file does
not exist, create one with Notepad) The file should be 1 line of plain text with the path to the temporary report folder
created in step #6. For example:
C:/TempCorvidReports
On a server, this may be a long and much more complex file path. Notice that the name of the folder does not end with "\"
or "/". Save the CorvidReport.cfg file. If CorvidRpt is being used in conjunction with the Corvid Servlet Runtime to display
a report, the file in CorvidReport.cfg must match the one for the system or in CORVID/WEB-XML
This is one of the few cases where you need to modify a Tomcat file. Normally Corvid handles all Tomcat files
automatically, coping the required files from the system project file in CorivdProjects. If you use the CorvidRpt servlet, you
will need to make this change whenever you delete, install or replace the Tomcat files.
That should be all that is needed. Now to test it, first make sure Tomcat is running.
Corvid will return a HTML page with the name of a file. This will be
“Exsys” followed by a long number and “.html”. This file will have been
created in the folder specified by CorvidReport.cfg.
Click the browser's Back button to return to the URL for the Corvid Report
test form. This time go down to the “Display Report” section:
Type "Exsys" into the 'code 1' slot.
Paste the file name you just copied into the 'code 2' slot.
Click the Submit button.
You should see an HTML page with the text that was entered in the
“Save Report” step. (e.g. "This is a report".)
If you get an error message saying it could not find the
'CorvidReport.cfg' file, note the path to the file in the error message
and put the 'CorvidReport.cfg' file at that location.
When the test works, you are ready to try it in your expert system. In a
Command Block or a THEN command, open the 'Commands' window
and select the 'Reports' tab. In the 'Program to Call' grouping, in the
edit box enter:
http://localhost:8080/CorvidRpt/corvidreportservlet
Select the 'Call via servlet' radio button. Build the rest of the Save Report command. Make sure everything is the same in
the 'Program to Call' grouping when you build the Display Report command and Delete Report commands.
The Corvid Servlet Runtime has this functionality built in and does on need any external servlet to be
specified. If one is added it will be ignored by the Corvid Servlet Runtime, though it would be used by
the Corvid Applet Runtime.
Subfolders
The folder that the Corvid Report Servlet will save the reports in is controlled by the CorvidReport.cfg file. If you
want to have different Corvid expert systems keep their individual reports in separate subfolders in the report
folder, enter the subfolder name in the “Subfolder” edit box. If there are multiple systems running on a server, the
“Subfolder” option can make it easier to keep track of the reports for each system.
Create any referenced subfolders on the server – Corvid expects the subfolder to have already been
created and will report an error if they are not.
Using subfolders is optional and if nothing is specified, the reports will be put in the folders specified by
CorvidReport.cfg.
For example: If CorvidReport.cfg specifies the folder “C:/TempReports” and the subfolder option for a
system is set to “System1”, the reports for that system will be kept in “C:/TempReports/System1”.
Select the report type from the “Type” drop down list when building the command. This "Type" is then used to
build URLs that all current browsers will correctly handle.
The customized version, ExsysFop, passes the passwords created by SaveReport and enforces the other
security options.
The Corvid install automatically deployed the ExsysFop.war file the same way as the CorvidRpt.war file.
After it is deployed, copy the CorvidReport.cfg file to the ExsysFop servlet’s WEB-INF folder (e.g. Tomcat’s
‘webapps/ExsysFop/WEB-INF’ folder). This tells ExsysFop where the saved report files are located.
Since FOP is an open source program, the source code for the Exsys modifications is available should you
need it.
Build the content of the report using double square bracket embedded Corvid variables. Just add the name of
the variable in [[ ]] at the appropriate places and Corvid will replace the [[..]] expression with the variable’s
actual value. For example, below is a very simple report built in WordPad.
Create any referenced subfolders on the server - Corvid expects the subfolder to have already been created
and will report an error if they are not. The subfolder is optional and there is nothing wrong with storing all
reports in one folder.
In the 'Write and Save Report' grouping, select the Collection variable that holds the contents of the report.
Select the String Variable to hold the ID for the report in the "Save ID in" drop down list.
In the "Type" drop down list, select the Type of report. For PDF reports, select "PDF" even though the
report contents so far is FO. (For other types of reports, select the appropriate type).
If you wish to limit access to the URL that Corvid will create, you can limit the access group, but that is
optional. (If you expect end users to send the report URL to others, this should NOT be selected.)
Click on the OK button.
For the Corvid Servlet Runtime, a redirect HTML page must be used to display the PDF report (See Sect
14.3.3 on PDF reports)
Pull down the list for 'ID of report to display' and select the same String variable that was assigned the report
ID in the SaveReport command. The other options are optional. Click on the OK button.
! Java Servlet - This uses the Corvid Servlet Runtime and runs as an HTML form in a browser. This
mode has many advantages and is the recommended mode for fielding systems. It will run in any
browser, even those that do not support Java such as iPhones and iPads
! Java Applet - Corvid will build a HTML page with an Applet tag and run the HTML page using a
browser program. This is convenient for development since it has a more extensive trace feature,
however it is less desirable for fielding systems due to many possible end user browser security issues
with Java and Applets.
! Java Application - Corvid will run the system using Java, but as an executable program. This runs in
a window on the desktop, but not in an HTML page. This is used primarily for embedded systems or
systems that tightly integrate the Corvid runtime with other programs. It is not intended for online
delivery of systems.
A system can be run with either the Applet or Servlet Runtime by simply selecting which to use. While it is
possible to make a system run differently in the two runtime modes, it requires taking special steps in the end
user interface to make this happen. Almost all systems can be run in either mode with the logic, question
order and conclusions exactly the same.
You can also select to run with the trace options turned on by
clicking the “Run with Trace” to select it.
Applet Window
When running as an applet, there is an HTML page which
contains an applet window.
If the content of a screen is larger than the applet window,
Java will display a scroll bar on the right side so the content
can be scrolled up and down.
The default value for the applet window is 700 pixels wide x
400 pixels high with a white background. These value can be
changed from the Properties window. Click the “Properties”
icon to open the window.
KB Default Format
The default format for all text in the system can be set. Clicking on the “Edit” button will display the
standard format editing dialog. The parameters set will override the system defaults. Any format
parameters set in specific display commands will override the values set here.
If all text in the system should be 12 point with blue letters on a yellow background, this is a
convenient place to set these values once for the entire system.
Background Color
Clicking on the “Build” button and selecting a color can set the background for all display windows.
Also, if the RGB value for the color is known, it can be directly entered in the edit box. This color will
be used for the overall background. In addition, each item added has its own background color. If
these are to match, also enter the desired background color in the “KB Default Format”.
kbname.CVR - This is the runtime file for the system. It is created automatically by Corvid every time the
system is run or saved. This file is used by the Corvid Applet and Servlet Runtime programs to execute the
system. The CVR file cannot be opened with the Corvid editor. While it cannot be directly edited with Corvid,
it does still contain some information on the logic such as formulas that could be read by an end user. When
using the Corvid Applet Runtime, the CVR file can be downloaded by the end user. When using the Corvid
Servlet Runtime, the CVR file can be put in a location that is available to the runtime program, but not
available to the end user. If even the limited information in the CVR is sensitive, the Corvid Servlet Runtime
should be used and the CVR file put in a folder that can not be reached by the end user entering a URL.
The CVD file is updated ONLY when the system is saved. The CVR file is updated whenever the system is
run. Consequently, if a system is loaded and modified, but NOT saved - and it is run, the run (CVR) will
include the modifications. If the system is not saved, the modifications will be lost, since the CVD file will not
have been updated. However, the CVR file will still reflect the modifications, and if this CVR was moved to a
Web server, it would contain the modification. Whenever a system is saved, a new CVR file is also created.
Only move a CVR file to a server when it is generated at the same time as the associated CVD file through a
“Save”.
kbname.CVRU - This is an earlier alternate format for the runtime file for the system. This file is no longer
generated or needed. Older systems may still have the CVRU file, but it is not needed and can be deleted.
kbname.HTML - This is the HTML page that would run the system using the Corvid Applet Runtime. This file
is automatically generated from the HTML template associated with the system. It is created in the same
folder as the system CVD and CVR files. The HTML page is only needed when fielding a system with Corvid
Applet Runtime. It should not be put on the server when using the Corvid Servlet Runtime.
ExsysCorvid.jar - This is the Corvid Applet Runtime program. It is required when running systems using the
Applet Runtime or running standalone as a Java application.
The Java applet tag that runs the system requires that a copy of ExsysCorvid.jar be available to the CVR file
and in the same folder. If there is not a copy in the correct location, Corvid will automatically make a copy.
When a system is run, Corvid.exe automatically checks the file creation date of the “official” copy of
ExsysCorvid.jar that is installed in “Program Files/Exsys/Corvid” with the copy in the system folder. If there is
a newer copy in “Program Files/Exsys/Corvid”, it will automatically be copied over the one in the system
folder. When a newer copy of Corvid is installed, it will automatically copy the new ExsysCorvid.jar into the
system folders as they are opened. When fielding an edited system, be sure to move this new
ExsysCorvid.jar with the edited CVR file or a “Version mismatch” error will be displayed when the system is run.
Image and Data Files - A system may optionally use various image or data files. If it does, these need to be
provided when the system is fielded.
</APPLET>
5. Copy ExsysCorvid.jar, the Kbname.CVR, and any other files required by your Corvid system to the
selected directory.
6. Create an HTML email (check your email program for how to do this), and add the modified applet tag.
7. The various parameters for the system can be set as needed. The WIDTH and HEIGHT for your
system may be different and can be changed. These control the size of the applet window in the email.
8. The email can now be sent. When the recipient opens the email they will see a fully functioning expert
system in the applet window, along with any other HTML information or images that were included.
NOTE: if the recipient does not accept HTML in emails, they will not be able to view the
system. In this case, an alternate plain text email can be added that will provide a link to a
Web page to run the system.
! If a numeric variable has a threshold break point in the rules, test above and below it, and be sure to
test on the break point. For example, if the logic has rules bases on “ [X] > 100” , or “[X] <= 100” , test
with values above and below 100, and be sure to test with a value of 100. (A common error is to have
rules that do not cover the actual threshold break point - “[X] < 100” and “[X] > 100” )
! Test typical, expected input, but also test input that would be very unusual. This may not produce a
good recommendation since the situation would be so odd, but the system should work correctly and
produce some answer. Remember, some users will just be “playing” with the system and randomly
answering the questions and it should produce some “reasonable” conclusions for any data.
! If the system is probabilistic and generates the overall likelihood for a conclusion based on various
factors, test with input consistent with a single answer (input that will produce a high confidence value)
and also input that is inconsistent with a single answer. This is a good way to test the relative
weighting of confidence factors to make sure they always provide reasonable advice.
! If the system makes use of databases or other external programs, use input that tests those.
! Test on multiple browsers. Differences between browsers are most often issues of user interface
display, rather than logic, but at least some testing should be done on all browsers that your end users
are expected to have. The more complex the user interface, the more extensive cross browser testing
is needed.
If the system had a “Don’t Know” option for answers, test it extensively to see if the conclusions reflect the
imprecision in user input. If the user answers everything “Don’t know” - what does the system do?
! Try to break the system. Try any input that pushes the capability of the system. Try negative numbers
for variables that cannot be negative, or values out of their expected range. (This should be handled in
the rules or in the properties for the variable to reject negative values.) Try blank values to make sure
they are correctly handled.
Testing can take some effort, but it is necessary. If testing results in needing to change the system in
significant ways, it may be necessary to retest to at least some degree.
Validation helps to check that a system is not producing internal errors and that any
“Warning Tests” are not triggered. However, it does not “understand” the actual
validity and correctness of the rules in the system. It is the responsibility of the
developer to make sure that the actual logic and advice given is correct. The
automated validation testing will greatly simplify performing large numbers of tests,
but only the author and domain expert can assure that a system is giving the correct
answers and advice.
To run validation, select “Validation Tests” under the “Run” menu. This will display the window for setting up
the validation tests.
Running Validation tests requires:
! Selecting the portion(s) of the system to
run.
! Selecting the variable values to test
across.
! Selecting what to output.
! Optionally adding Warning Tests.
These are done in the Validation window. The
settings for a particular test can be saved and
recovered later.
Once the options are chosen, the selected
portion of the system will be tested for every
possible combination of selected variable
values and the output or warnings will be
displayed.
Generally Corvid will run a single test case in
something from a fraction of second to a few seconds depending on the system complexity and computer
hardware. So, about 100 test cases can typically be run in a minute, or 6000 in an hour, 144,000 in a day or
around 300,000 over a weekend. However, for even medium size systems, the number of possible test
cases can get very large, very quickly.
A system with 10 questions that each have 2 values will require 2^10 test cases, or 1024. That can be run in
about 10 minutes. However, if it needed to test across 20 questions that each had 2 values, it would go up to
2^20 or about 1,000,000 test cases and would take around a week.
Being able to test all test cases automatically can be very beneficial, even if it takes a few days. But many
systems would require hundreds of millions of test cases and would be running for years to test every path.
It can be tempting to select to test every path, but in practice it can take an impractically long time. The key to
successful validation testing is to understand the system well so that a subset of the system and variables can
be selected that can be tested in a reasonable numbers of test cases which can be run in a reasonable time.
Subsets of the system are chosen be selecting either only some of the logic/Action Blocks and running in
Static List
When a Static List variables is selected the “List Values” box and “Single Value” drop down list will display all
the possible values.
! A single value can be selected from either the “Single Value” drop down list or by clicking a single
value in the “List Values” box.
! Multiple values to test across can be selected from the “List Values” box by using Shift-Click and Ctrl-
Click to select multiple values in the list.
! All values can be selected by selecting them in the “List Values” box or just clicking the “All Values” button.
Numeric Variables
Numeric variables are assigned either a single value or a sequence of values, from a starting value to an
ending value with an option increment value (an increment of 1 is used if none is specified). When a range of
values is used, the “Test Case” count will be multiplied by number of values in the sequence. This can easily
increase the number of test cases rapidly and ranges should be selected to cover the values of interest
without testing too many values. If a numeric variable is only used in the rules in a limited way such as a
simple test like “[TEMP]>100”. All that is needed is to have values of the variable [TEMP], below, at and
above 100. So a range of 90 to 110 with a step of 10 is all that is needed. If the variable is used in complex
calculations and needs to be tested across a wide range of values, then a wider range will be needed. In
selecting ranges, try to have values across the range of values where it will cause various rules to fire and try
to have the step hit on values that cause the logic trigger different rules.
! A single value is added by entering it in the “Single Value” edit box
! A range of values is selected by entering the “From:”, “To” and “Step” values in the “Numeric Range”
section. The variable will be tested at values of: start value, start value + Step, start value +2*step,
etc until the value is higher than the ending value
Setting Warnings
In addition to the standard output, if Corvid encounters any errors such as “division by zero”, invalid values,
etc. those will also be reported.
While the output file of all input and output data fully documents how the system runs, it may be too
voluminous to be easily worked with – especially if it requires hundreds of thousands of tests to run the
validation. Often it is much more effective to watch for specific possible problems. In place of the normal output
variable list, specific warning tests can be set.
Warnings can be set to check for test cases where:
! No Confidence variable has a value over x.
! A variable has a specific value.
! Any Boolean test involving system variables is true.
For example, if an end user reports that when they were running the system nothing got recommended, but
they can’t remember or duplicate the input that produced this. This could be because no Confidence variable
got a value greater than 0, and the results were set to only display Confidence variables with values greater
than 0. A validation test could be setup to cover many test cases, but with a warning test of “No Confidence
variable with a value greater than 0” and “Only include session if there is a warning”. When the validation
tests finish, the report will show any cases where the input lead to no Confidence variable being assigned a
value greater than 0. These input values could then be used to debug the problem.
16.4 Trace
or
Trace Tab
The Trace tab displays a history of the session.
This is the same trace data as was displayed in
earlier versions of Corvid and which is
displayed when trace is used with the Servlet
Runtime or console window.
The trace displays the steps that the system
executed during the session.
The trace history can be searched for any text.
This can be used to search for any actions that
were taken for a particular variable by
searching on the variable’s name. Enter the
text to search for and click “Find”. To search
again, click the “Again” button.
Since the trace history can get quite long,
especially for MetaBlock systems, the “Clear” button allows clearing the existing text. The subsequent trace
information will be written to the empty window. This can make searching for specific actions easier in
MetaBlock systems.
Variables
The “Variables” list in the center of the
window displays all the variables in the
system.
Goal List
The Goal List is displayed on the left side of the window. This is used for backward chaining systems and
shows the order of the Goal variables being used for the immediate backward chaining. The bottom goal is
the variable actually needed in the top level system logic - typically set by a Command Block command such
as DERIVE. To set the value for this Goal variable, the next highest variable in the list was needed. If that
variable could be derived from other rules, the next variable above that was needed, etc. up to the top
variable in the Goal List which is the one actually being asked or derived. The Goal List changes dynamically
as rules fire and variable values are set.
In a backward chaining system, being able to examine the Goal List provides insight to how the rules are being
used. If a variable is being asked unexpectedly, the Goal List may indicate why that variable is needed, and
how it will be used. If a system is being run in forward chaining, or executing a command that does not require
backward chaining (such as an ASK command), the Goal List may only have a single variable or be empty.
To check on the value and status of any variable in the Goal List, click on it. This will select it in the Variable
list and display the current value and how it was set.
IF / THEN / IF Rules
If a system uses IF/THEN/IF rules (IF nodes added under a THEN node),
the rule display will reflect this. The Trace Applet “Rule” tab will display a
rule for the first THEN node, and subsequent rules for the additional
THEN nodes in the rule. The first THEN will be displayed in the standard
way. The portions of the rule associated with the IF nodes following the
first THEN will include the first THEN node in italic and will a small
“THEN” next to it.
The TRACE command can be added in the THEN part of rules (Logic Blocks), or in Command Blocks.
When
the TRACE command is executed, either due to the
rule firing or the Command Block command being
executed, Corvid will display “TRACE” followed by
the string associated with the command and wait for
the user to click the OK button. At this point the
variables, rules and Logic Blocks can be examined
with the Trace Applet.
There can be as many TRACE commands as needed
in a system. The TRACE command has no meaning
and is ignored if the system is run without the Trace
Applet, so the TRACE commands do NOT need to be
removed from a system when it is fielded - they will
just be ignored.
The CVR_TRACE file should be controlled the same as the CVD file.
It should not be put on the server with the CVR file or made available to anyone that you would not want to
have the system CVD file that allows editing. In practice, the CVR_TRACE does not allow editing the way
the CVD file would, but it does allow examination of the internal structure of the rules and Logic Blocks in a
system.
.HOW Setup
Keeping track internally of the data needed by .HOW both
requires system resources and slows system execution.
Because of this, by default .HOW is disabled and must be
specifically be activated at the start of a run in the starting
Command Block.
This is done by adding an “ALLOW_HOW” command as the
FIRST command in the starting Command Block.
! Open the starting Command Block and add a new
command as the first command. (Select the current
first command and click “Add Above”).
! In the “Commands” window, go to the “Control” tab
and in the “Special Commands” scroll down to
“ALLOW_HOW”.
! Add the command to the block.
This will put the ALLOW_HOW command as the top command
in the block.
This will activate Corvid to save the data needed for the .HOW property.
When the system is finished and fielded, this ALLOW_HOW command should be deleted
unless the system uses .HOW to keep a history that uses it.
! Based on powerful, scalable Java Servlet technology for large numbers of simultaneous users.
! Server-side processing (thin client).
! HTML templates easily implement a consistent look-and-feel.
! Dynamically generated interface based on end user input and system logic.
! Fully interactive online sessions.
! Replaceable parameters and conditional inclusion of blocks of HTML.
! Easy to integrate with other server-side programs.
! Directly generate reports in HTML, RTF or PDF formats.
! Automate email generation.
! Compatible with Corvid systems created for the Exsys Corvid Applet Runtime.
! Build and test in the Corvid Development Environment.
! XML interface to Flash SWF files and other programs when needed.
Since the end user is only sent HTML forms, they can have a thin-client with just a standard browser.
Systems will work on all browsers and all operating systems, with very minimal client-side requirements.
There are no potential issues of the end user’s PC either blocking or not supporting Java Applets. Corvid
Servlet based systems will run on iPhones and iPads which lack Applet and Java support. The Corvid
Servlet Runtime also provides greater system security, tighter integration with other server resources such
as databases and some additional functionality such as automated email.
Screen design language Corvid Screen HTML / CSS / Java Script / Etc.
Commands
Degree of control Control limited to color, Full control of entire screen - anything that can be
position, fonts, images done in HTML
Implement standard site look-and- Set style properties that HTML templates with replaceable parameters
feel apply to all questions
Ease of development Similar to formatting a Sample templates provided that can be edited with an
Word processor HTML editor
document
Complexity of design Limited - though more High - anything that can be done on an HTML page
than enough for most
systems
Security
Database
Browser
End user requirements Must allow / support Any browser including iPhones and iPads (Some
Java Applets browsers may not support advanced capabilities such
as HTML5 or CSS3) Adobe Flash based systems
require browsers that support Flash
Commercial Systems
Suitability Limited due to High - Also ideal for subscription based systems
increasing browser and
Java security issues
Make note of the IP address since that will be needed to get a license file for the server. The Corvid Servlet
Runtime is licensed for a specific server IP address. This is implemented with a file that holds license codes
that allow the servlet to run on a particular server IP address.
The name for the license file is CorvidLicenseCodes.txt. It will have one or more license codes in it. These
are numeric strings similar to:
533367 3072151 563950 511124
The IP license codes are obtained from Exsys Inc. They are provided based on the license(s) purchased.
Contact support@exsys.com to obtain a license file for your server IP address. Temporary licenses can be
provided in some cases allowing the Corvid Servlet Runtime to be tested and evaluated on a server.
When you receive the license code for your server from Exsys Inc. Create a file named
CorvidLicenseCodes.txt with Notepad, and enter the license code(s) one per line in the file. The file name is
2. If you still get the “Could not find the license file” screen, then the CorvidLicenseCodes.txt file is not in
the correct location, or the filename is not spelled correctly.
The “base” will indicate where Corvid is looking for the license file it should be in the folder specified or in
one folder up (“webapps”) Corvid will look in both.
Servlets
Servlets are Java programs that run on the server. In many ways they are similar to CGI programs, but
remove many of the disadvantages presented by CGI. Servlets are run using a servlet engine such as
Tomcat, though there are many other servlet engines. The servlet engine installs the servlet and makes it
available to be called. The user calls the servlet using a special URL address and passes it information. The
servlet processes the information and typically sends back an HTML screen to the user. In the case of the
Corvid Servlet Runtime delivering an expert system, there may be a sequence of screens asking questions or
displaying results. Each screen adds information and continues the session.
Since there may be many users simultaneously running sessions, the servlet is responsible for keeping track
of each user and their data. Java servlets have built-in capabilities to simplify this task and keep track of each
independent session. However, each screen presented to the end user must contain certain information that
allows the data to be sent back to the Corvid servlet with an identification of the individual user session. This
information is automatically added by the template.
Templates
The Corvid Servlet Runtime communicates with the end user via HTML forms that ask the end user for input.
These forms are built using template files that define the page design and tell the system what HTML controls
to use to ask questions or display results.
The Corvid Servlet Runtime processes the data it has and, using the inference engine, determines what
variable to ask next. To ask the user a question, the system must display an HTML page on the user's
browser window. A template file has a specific look-and-feel, but also has replaceable parameters in it that
allow the template to be used to ask a wide range of Corvid variables. The Corvid Servlet Runtime builds a
HTML page by replacing the “generic” parameters with text and options for the specific variable being asked
and the specific user session. When the user responds to the question, the data is sent back to the servlet.
This adds to the information in the session, which then determines the next question to ask. This process
continues until the results are displayed and the session is completed.
17.5 Templates
To make a system work with the Corvid Servlet Runtime requires adding the appropriate templates.
Templates are a very powerful tool and have many options. The first step is to learn how to add a template to
a system. It is easiest to start with the predefined sample templates. The next step is to understand the
syntax for building your own templates. To get the most out of templates requires some knowledge of HTML
and Corvid commands, however many systems can be delivered by minor editing of the sample templates
with a standard HTML editor.
Whenever the Corvid Servlet Runtime needs to ask the user for the value of a variable, it uses a template to
build the screen. In most cases, a single “generic” template will be used for many questions, giving them all
the same look-and-feel and making maintenance easy. In special cases, such as a question asked with an
image map unique to that question, there can be a special template made for that individual question.
A generic template is one that will work for most (or all) of the variables asked of the user. This template is
defined to be the system default template and will be used to ask the end user for the value of any variable
that does not have an associated template that overrides it. Any variables that require a different template
can have a different template associated with them. A specific template associated with a variable will take
precedence over the system default template.
In addition there is an overall Corvid default template that will be used for any system where no template is
specified as the system default and no individual templates are associated with variables. This overall
default provides a very simple and generic interface and is intended to be used only to test a system before
other templates are designed, or if you are having trouble running a system and want to use the simplest
template available.
Order of priority of template use:
1. Template associated with the variable being asked.
2. Knowledge base system default template.
3. The overall Corvid default template screen.
The overall Corvid default template is installed by the CORVID.war file, which installs the Corvid Servlet
Runtime. It will be in the same directory as the Corvid servlet and named “CORVID_Question_Default.html”.
This file should not be modified - it is the last option for asking questions and should remain very generic. To
give a system a different look-and-feel, create or select a template and make it the default template for the
system without changing the overall Corvid default.
Sets of sample templates are provided with Corvid. These illustrate different template styles and approaches.
A quick way to build an attractive template for a system is to select one of the sample templates that you like.
Then open that template in an HTML editor and modify it for your system by adding text or images specific to
your system. This modified template can then be used as the system default for your system.
<FORM> Section
The form section of the template is used to ask the user a question using a variety of controls (radio buttons,
edit boxes, etc). The user's input is sent back to the Corvid Servlet Runtime, which will process the data and
continue the run. The HTML outside of the form section usually does not use Corvid commands and can be
any HTML design.
action="http://www.exsys.com/CORVID/corvidsr;jsessionid=15834833E55A1EBB5"
Since Corvid automatically replaces “CORVID_SERVLET” with the servlet location and session
information, a system can be run from any server without changing the settings,
name="CorvidForm"
The “name” is optional, but used in the JavaScript associated with the form. The name can be
anything, provided it is used consistently in the JavaScript. To just use the standard Corvid
JavaScript, keep the name as “CorvidForm”
When this control in the template is used to build a HTML form for [TEMP], the prompt and name for [TEMP]
will be used, but it can just as easily be used for any other numeric, string or date variable. Corvid will
automatically replace the parameters with the values appropriate for the variable being asked. Also, if the
prompt or name is changed in the system rules, the change will automatically carry over to the HTML form
built from the template.
The parameter “VARIABLE_PROMPT” in the template is just text in the HTML page and can be styled or
formatted with CSS or any other design technique and the styling/formatting will apply to the text that is used
to replace “VARIABLE_PROMPT”.
CORVID_REPEAT
Static and Dynamic List variables need to have multiple values either as a group of radio buttons /check
boxes or in a list. To do this in a generic way that can be applied to variables with different numbers of
values, there is the special Corvid command “CORVID_REPEAT”. This is added in the template as a HTML
comment, “<!--CORVID_REPEAT-->”.
For a Static or Dynamic List, everything between “<!--CORVID_REPEAT-->” and the closing “<!--
REPEAT_END-->” will be repeated for each value in the variable’s value list. The block of code will be used
for the first value, then repeated for the second value, etc. The replaceable parameters
VARIABLE_VALUE_TEXT and VARIABLE_VALUE_NUM will be replaced by the text and number of the
value currently being added.
With CORVID_REPEAT the the controls for [COLOR]:
The color is
<input type=”radio” name=”[COLOR] value=”1”> Red
<input type=”radio” name=”[COLOR] value=”2”> Green
can be rewritten:
VARIABLE_PROMPT <br>
<!--CORVID_REPEAT-->
<input type=”radio” name=”[VARIABLE_NAME]” value=”VARIABLE_VALUE_NUM“>
VARIABLE_VALUE_TEXT
<!--REPEAT_END -->
When this template is applied to [COLOR] it will automatically build the same set of controls in the HTML
form, but will build a set of radio buttons for as many values as the variable has and will automatically match
the prompt and value text in the system. It can also be applied to any other Static or Dynamic List variable.
Since the value can be set by either the number or value short text, the VARIABLE_VALUE_NUM could be
replaced by VARIABLE_VALUE_SHORT
To use CORVID_REPEAT to build a list control in a template, use:
VARIABLE_PROMPT <br>
<select name="[VARIABLE_NAME]">
<!-- CORVID_REPEAT -->
<option value="VARIABLE_VALUE_SHORT"> VARIABLE_VALUE_TEXT
CHARACTER MATCHES
A template file typically will have multiple CORVID_ASK sections, and MUST have a section that applies to
each variable that will be asked using the template. For each variable that is asked using the template, the
first CORVID_ASK section which has a matching VarID will be used and all other CORVID_ASK
sections will be ignored for that variable - even if they would also have matched.
For example, if there were 3 sections in this order:
The variable [COLOR] would use section 1 code, and ignore sections 2 and 3 since section 1 was already a
match. A variable starting with "C", but not [COLOR], would use section 2 and ignore section 1 and 3. All
static list variables that did not start with "C" would use section 3 and ignore section 1 and 2.
One convenient way to make sure a template will work for all variables is to end with a <!-- CORVID_ASK
VARIABLE --> section. This will apply to all variables that have not already matched a CORVID_ASK
command in the page.
Care must be taken since Static List and Numeric variables typically need very different formats and controls
for the questions. If a system has numeric, string, date, Static List and Dynamic List questions, it can be
handled with 2 sections:
Section 1 will be used for all numeric, string and date questions. Section 2 will be used for all variables that
are not Continuous, so it will be used for all Static and Dynamic List variables. Naturally, you might want to
have more variation and have a separate section for each type.
UNDO Button
The UNDO button is optional. It will tell the Corvid Servlet Runtime to step back one question. This is the
same as the BACK button in the Corvid Applet Runtime.
The HTML code for the UNDO button is:
! <input type="submit" name="~UNDO" value=" Back ">
Note that this button also has the type set to “submit” and clicking it will send data back to the Corvid Servlet
Runtime, however, in this case the values selected will be ignored and only the ~UNDO will be used.
The “value” is set to “Back”. This is the button label that will be displayed and can be changed to anything
that is preferred.
RESTART Button
The RESTART button is optional. It will tell the Corvid Servlet Runtime to restart the system from the beginning
of the starting Command Block. This is the same as the RESTART button in the Corvid Applet Runtime.
The HTML code for the UNDO button is:
! <input type="submit" name="~RESTART" value=" Restart ">
Note that this button also has the type set to “submit” and clicking it will send data back to the Corvid Servlet
Runtime, however, in this case the values selected will be ignored and only the ~RESTART will be used.
The “value” is set to “Restart”. This is the button label that will be displayed and can be changed to anything
that is preferred.
The “name” is set to ~ RESTART. This must NOT be changed. The ~RESTART is the special flag to tell the
Corvid Servlet Runtime to process the input as an RESTART action.
The RESTART button can be placed anywhere on the screen. If RESTART is added to a template that will be
used for many questions, Corvid will automatically disable the RESTART button for the first screen since there
is nowhere to step back to. The button will be enabled in all other screens. Do not worry if the first question
screen in a system has the RESTART disabled.
<style type="text/css">
.VariablePrompt {
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
color: #003366;
font-weight: bold;
text-indent: 50px;
}
.VariableValue {
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
color: #003366;
font-weight: bold;
The styles control the font and positions of the prompt (VariablePrompt), font and potions of the Static List
variable values (VariableValue) and size and position of the edit box for other types of variables
(VariableEditBox). An easy way to modify the look of the page is to change the CSS.
Corvid_LINK_BASE
Corvid provides a way to code the address of the linked images using the replaceable parameter
“CORVID_LINK_BASE”. This is another of the replaceable parameters that can be used in the
Corvid only parses its special commands. Anything that does not have syntactical meaning to Corvid is
passed through unchanged. The template can include any HTML commands, HTML5, CSS3, JavaScript,
Ajax, plugins, etc. - anything the browser supports.
If a system asks the variable [COLOR] which has an “Also Ask” list of the variables [INPUTS], [OUTPUTS]
and [COST]. Where [INPUTS] and [OUTPUTS] are static list variables, the screen would have:
CORVID_REPEAT
CORVID_REPEAT can be added to the CORVID_ASK section of HTML code for a Static or Dynamic List to
repeat a section of HTML code for each of the variable’s possible values with:
<!-- CORVID_REPEAT --> … <!-- REPEAT_END -->
The code between the CORVID_REPEAT and REPEAT_END commands will be repeated for each value in
the variable's value list. The parameters VARIABLE_VALUE_TEXT, VARIABLE_VALUE_SHORT and
VARIABLE_VALUE_NUM can be used in the CORVID_REPEAT section. They will be replaced with the
associated value data. The first time through the CORVID_REPEAT, they will be given data from the first
value. The second time through, the second value, etc for each value in the variable's value list.
So if [COLOR] has a prompt "The color is" and values:
Value Short Text Full Value Text
red Reddish
blue Bluish
green Greenish
using:
<!-- CORVID_ASK STATIC_LIST -->
VARIABLE_PROMPT <BR>
<!-- CORVID_REPEAT -->
<input type="checkbox" value="VARIABLE_VALUE_SHORT"
name="[VARIABLE_NAME]">VARIABLE_VALUE_TEXT <BR>
<!-- REPEAT_END -->
<!-- ASK_END -->
would produce:
The color is <BR>
<input type="checkbox" value="red" name="[COLOR]">Reddish <BR>
<input type="checkbox" value="blue" name="[COLOR]">Bluish <BR>
<input type="checkbox" value="green" name="[COLOR]">Greenish <BR>
This same section could be used to ask any Static List variable with any number of values
since all parameters will be obtained from the variable values in the system. This has rather simplistic
formatting, but has all the elements to ask any Static List. If one Static List variable has 2 values and another
There is only a single check box because the HTML editor does not understand the CORVID_REPEAT
command, which in HTML is just a comment. The text VARIABLE_PROMPT or VARIABLE_VALUE_TEXT
could be formatted for color, size, font, style, etc and that formatting would apply when the variable's values
were filled in.
If the template was formatted in the HTML editor, the formatting would be applied to the
actual text.
VALUE #
The CORVID_REPEAT command makes it easy to design templates that include a control for each value in
the list and is very useful when all the values are to be asked the same way. This is normally the case, but if
you wish to apply some different formatting or add HTML code to some values and not others, there is a
second way to build screens for Static and Dynamic List variables.
The code for each specific value can be specified using:
! <!-- VALUE # -->
where # is the number of the value.
All code between <!-- VALUE 1 --> and <!-- VALUE 2 --> will be used to display value number 1. All replaceable
parameters will be set according to the variable's first value. Then all code between <!-- VALUE 2 --> and <!--
VALUE 3 --> will be built according to the second value, etc. until the next HTML comment is reached.
Unlike a CORVID_REPEAT, you must know the maximum number of possible values and design the template
accordingly. The template MUST have as many value # sections as the MAXIMUM number that any variable
asked with that template will have. If a variable does not have as many values as there are value # sections in
the template, the code in the sections that are higher than the number of values for that variable will be ignored.
For example to decrease the font size of the text for each of 3 values value:
Control Layout
To ask for the value of all Static List variables with one value per line, add a <BR> in the
CORVID_REPEAT:
If the <BR> in the CORVID_REPEAT section was removed, the template would put all values on one line.
In this case, the VALUE # approach was used since the <TR> </TR>
that define the rows in the table occur with every second value. When
using CORVID_REPEAT, the same code must occur with every variable
in the same way. Using VALUE # allows formatting into the table easily.
When applied to a variable [COLOR] with 6 values, it would look like:
If [COLOR] was set to only allow a single value, the "checkbox" would
automatically be converted to "radio" and it would look like:
If the same code had the size= parameter changed to size="4", a list control would be
produced:
To allow the end user to select multiple values from the list, "multiple" should be added
after the size= to indicate that multiple values can be selected from the list.
VARIABLE_PROMPT<BR>
<!-- CORVID_REPEAT -->
<input type="submit"
value="[VARIABLE_NAME]=VARIABLE_VALUE_NUM" name="VARIABLE_VALUE_TEXT">
<!-- REPEAT_END -->
For example:
VARIABLE_PROMPT<BR>
<!-- CORVID_REPEAT -->
VARIABLE_VALUE_TEXT
<input type="submit"
value="[VARIABLE_NAME]=VARIABLE_VALUE_NUM" name="X">
<!-- REPEAT_END -->
SECURITY NOTE: Variable values are sent back to the servlet using POST, which is relatively
secure compared to GET which makes the value part of the URL. However, Corvid does NOT
encrypt the information itself and if the user is providing highly sensitive password information, a
secure server connection (https) should be used.
NOTE: Only properties that are defined and known when the question is asked should be used. A
property such as .COUNT is defined during development, however a property such as .VALUE may
only be known after the question is asked and should NOT be used in the screen to ask the question.
This could result in an infinite loop.
The following are NOT legal because they cross CORVID_ASK sections:
<!-- CORVID_IF expr -->
<!-- CORVID_ASK var -->
<!-- END_IF --> …..
<!-- ASK_END -->
If the user clicks on this button, the Command Block “BlockToRun” will be immediately executed.
This can be used to implement special features such as “Save and Exit”. The code:
<input type="submit" name="~EXEC_CMD_BLOCK=SaveAndExit" value="Save And Exit">
would add a “Save and Exit” button to a screen that would call a special Command Block “SaveAndExit”
which could write the input data to a database and exit the run.
Normally, the called Command Block will terminate the run.
This option should be used with care since calling a new Command Block will change the order of operation
of the system, but it can be very useful to implement special functionality.
This servlet portion can be added from the command builder for the RESULTS or DISPLAY command by
entering the template name in the “Servlet Template to Use” edit box or clicking the “Browse” button and
selecting the template. When running with the Servlet runtime, the Corvid Screen Commands will be ignored
and the specified template will be used. If there is no template file specified in a RESULTS command, Corvid
will automatically use a very generic template that displays the values of all variables in the system. This
can be used for testing a system before developing the RESULTS template for the system but generally will
be replaced by a results screen specific to the system before it is finished.. The default template is installed
with the Corvid Servlet Runtime in the CORVID folder named “CORVID_Results_Default.html” and should
NOT be modified since it is the template that the system will use when no other can be found.
HTML Reports
These are built the same for the Corvid Servlet Runtime as the Corvid Applet Runtime, but the “Server
program to use” is not needed and can be left blank. The Corvid Servlet Runtime has the SaveReport and
DisplayReport functionality built in and does not need to call an external program. It is OK to add the Corvid
Report Servlet in the command, it is just not necessary.
The typical commands to display a report are:
set [report.addfile] template.tpt
SaveReport [RportID] [Report] Type="html" IP=4 Servlet=""
DisplayReport [ReportID] Servlet=""
RTF Reports
RTF reports require using the external CorvidRpt servlet. This allows that servlet to be called outside of
Corvid to display the report. The report cannot be displayed directly due to the issue of the browser not
knowing the correct type. This requires using a trick to display the report.
The typical commands to create and display a RTF report are:
set [report.addfile] template.rtf
SaveReport [RportID] [Report] Type="rtf" IP=4 Servlet="http://localhost:8080/CorvidRpt/corvidreportservlet"
RESULTS Servlet=redirect.html
The SaveReport uses the CorvidRpt servlet just like creating a report with the Applet Runtime.
Instead of calling DisplayReport, instead a RESULTS command is used with the Servlet option set to a html
page “redirect.html”. The HTML for this page is:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Your Page Title</title>
<meta http-equiv="REFRESH" content="0;url=[[REPORTID]]">
</head>
<BODY>
</BODY>
</HTML>
PDF Reports
PDF reports are built almost the same way as RTF reports and use the same redirect trick. However, here
the template must be a .fo file (see chapter 14 on PDF reports). In the SaveReport command, instead of
using the CorvidRpt servlet, use the ExsysFop servlet.
set [report.addfile] template.fo
SaveReport [RportID] [Report] Type="pdf" IP=4 Servlet="http://localhost:8080/ExsysFop/exsysfop"
RESULTS Servlet=redirect.html
The redirect.html page is the same as for RTF reports, and will immediately open the PDF report in Adobe
Acrobat.
Replaceable parameters can be used for FOR_EACH. The most useful parameters are:
VARIABLE_PROMPT The prompt of the variable.
[.PROPERTY] Evaluated as [Var.PROPERTY] for any properties of the variable.
Within the FOR_EACH, a CORVID_IF test can be used to select only certain variables.
For example, to display all the Confidence variables that received a value of greater than 20:
When this runs, the code between FOR_EACH and EACH_END will be applied to each Confidence variable
in turn. The Confidence variables will be tested in the order that they are defined in the system.
The first Confidence variable will have [.VALUE] replaced by [ConfVar1.VALUE] and evaluated, where
ConfVar1 is the name of the first Confidence variable. If the value is greater than 20, the [[.FULL]] will be
replaced by [[ConfVar1.FULL]]. This will be replaced by the text of the confidence variable and its assigned
value. The same lines of code will be repeated for each Confidence variable. Each one with a value greater
than 20 will be included in the report. To have the Confidence values sorted with ones with the highest
confidence values displayed at the top, just change "CONFIDENCE" in the FOR_EACH to
"CONFIDENCE_DECENDING".
Within the CORVID_REPEAT for Collection variables, replaceable parameters can be used to obtain the text
of the individual value, the number of the value and the "score" the value was given if the Collection variable
had values added with .ADDSORTED.
For example, to display all the values in a Collection variable [Comment] as a numbered list:
The "FOR_EACH [Comment]" is required even though there is only a single variable to set the context for the
CORVID_REPEAT.
aaa
bbb
ccc
For example, to send a simple email, whose text is stored in a string variable [MESSAGE]. Add the following
commands to a Command Block: (This will require building 6 separate commands from the Email tab.)
EMAIL_SERVER mail.mysite.myserver.net
EMAIL_FROM_ADDRESS me@mysite.com
EMAIL_TO_ADDRESS you@yoursite.com
EMAIL_SUBJECT A message from this Corvid system
EMAIL_CONTENT_TYPE text/plain
EMAIL_SEND [[MESSAGE]]
To send this same message to a second person, all that is needed is another EMAIL_TO_ADDRESS and
EMAIL_SEND command. The other parameters would stay the same.
EMAIL_TO_ADDRESS someone@theirsite.com
EMAIL_SEND [[MESSAGE]]
Emails can be built easily by using templates and the ADDFILE command. The template file added can use
[[ ]] double square bracket replacement for multiple variable and conditional inclusions of sections of text,
based on the values of other variables. This allows a template to build a complex and customized report.
This set of commands will use a report template to set the value for a collection variable and then use that as
the message to send:
17.11 Cookies
Cookies are small packets of data that are passed
invisibly between a servlet and the end user's
browser. They are a very useful way to pass data,
but can also be used to pass sensitive or confidential
user data back to a server.
NOTE: The Corvid Servlet Runtime permits
cookies, but does not require them. If a Corvid
application is part of a larger system that
requires cookies, cookies can be used with
Corvid and they will remain active.
Because cookies can be used in undesirable ways
by some sites, most browsers have an option to
prevent cookies. You cannot be sure that all users
will have their browser configured to accept cookies.
They should only be relied on if you know that your end users will accept cookies, such as an application that
will be distributed only for a standard company browser configuration. Most systems that will allow access to
anyone on the Web should not use cookies to provide maximum compatibility.
All Java servlets that are interactive need to send session information back to the servlet to let it know which
user is returning data. In addition, Corvid has other session data that it needs to send back. The Corvid Servlet
Runtime can do this via cookies, or by adding information to the URL. The default is to NOT use cookies. This
will result in some extra text in the URL, but will not effect the operation of the system.
If you would rather use cookies to send this data, select the "Use Cookies" option on the Properties window
Servlet tab for the system.
18.1 Overview
Exsys Corvid allows Adobe Flash to be used to design the user interface for your expert systems. This allows
the tremendous design, animation and multimedia capabilities of Flash to be used to ask questions, present
results and display information. Flash is the premiere multimedia tool for making web sites “pretty”, now you
can make them pretty and smart. Exsys Corvid systems can interact with the end user as if they were talking
to a human expert, with all the Flash capabilities for graphic design and data presentation. Flash applications
can use the Exsys Inference Engine to perform complex analysis or drive interactive sessions that would not
be practical to “hard code” into a system.
Using Flash for the user interface greatly expands the delivery options beyond what can be done with just the
Exsys Runtime programs, which while more than adequate for most types of interactive expert systems, lack
the ability to do complex graphics, animation or multimedia. Flash based systems can make use of the full
design capabilities of the Adobe Flash IDEs - either Adobe Flash or Adobe Flex. These powerful, proven and
integrated tools are widely used to produce the core part of many web sites.
The underlying Flash programming language, Action Script, makes it easy to connect a Flash application to Exsys.
Action Script is a full and robust language that can be used in conjunction with Exsys to add special interfaces or
program custom functionality into a system. This can allow some aspects of the system such as dynamic
questions and input validation to be handled client-side in Flash, reducing the load of the server-side computation.
An additional benefit is that the Flash SWF file can run in a small window on a page, similar to an applet
window, rather than having the Exsys system fully rebuild an entire page. This allows integrating an expert
system with a complex interface into a larger web page design, while still allowing it to run independent of the
rest of the page. The end user machine need only have the standard Adobe Flash player, which is generally
included with most browsers.
Using Flash for the interface requires having the Adobe Flash development tools and knowledge of how to
build Flash applications. While commonly available, these programs are not provided by Exsys, and the
Exsys/Flash documentation only covers how to connect Exsys systems with Flash - not how to use the Flash
IDEs themselves. If you already are familiar with Flash, you’re all set. If not, the Adobe Flash tutorials and
many introductory books on Flash should get you going quickly. Flash is an interesting and fun program to
learn since it makes it easy to do things that would be very difficult to do otherwise. The Exsys/Flash interface
is based on Action Script commands. You will need to know some Action Script to build your specific system,
but the core code to interface Exsys with Flash is provided and can just be pasted into your system.
To make use of Flash, you will also need the Exsys Corvid Servlet Runtime v5.0 or higher. This can be used
to run Corvid systems with Flash SWF files, or build standard HTML forms and pages. You can mix Flash and
non-Flash systems on the same Corvid Servlet Runtime.
The rules and logic in the Exsys knowledge automation systems you build are the same for Flash and non-
Flash systems. Existing Exsys systems can have a Flash user interface added to them without changing the
core logic - though new systems may be designed to make use of the special Flash capabilities that were not
previously available.
There was only one interaction between Flash and the Corvid Runtime to send the user data. The user’s
action to click on recommended islands is handled internally in the Flash SWF to display the appropriate text
and images. The Corvid system does not retain any information on the session. If the user changes their
activity rankings and re-clicks the “Where should I go” button, a new set of data will be sent to the Corvid
Runtime and new XML returned for Flash to process.
When this type of system runs:
1. The Flash application uses various controls and graphic options to allow the user to provide input.
2. When the user has made their selections, they click a “Submit” button or similar action.
3. Action Script is used to collect the input and format a URL calling the Corvid Servlet Runtime on a
server. This starts a Corvid session and passes the user’s data.
4. The Corvid Runtime loads the appropriate system and uses the rules and logic in the system to
process the input.
5. When complete, the Corvid Runtime system creates XML data that contains the results and
recommendations which is sent back to the Flash application as XML data.
6. The Flash application waits for the Corvid Runtime to return the XML data containing the result.
7. The Flash application reads and parses the XML data to display the results to the user using
whatever capabilities of Flash are needed. This may require various graphics or watching for
additional end user actions to trigger other graphics.
To see this system actually running, go to:
http://www.exsys.com/demomain.html
and run the “Caribbean Vacation Advisor”.
http://www.exsys.com/demomain.html
There may also be many different types of questions that make use of quite different features of Flash. It
would be possible to build a single large SWF, but it could become a development and maintenance issue,
and probably result in an unnecessarily large SWF to load at system startup.
Fortunately this is not necessary, and with just a little Action Script, it is possible to have one SWF file load
another and pass the necessary Exsys data into it, to continue the session. This allows multiple smaller,
simpler SWF files to be used for different questions with a common look-and-feel.
There are 2 main uses for Flash SWF files in a system - to ask for input and to present results. In the
examples above, a single SWF did both, but it may be easier to have a dedicated SWF for questions and a
different one to present the results.
When a Flash interface is used to ask a question, the Corvid Servlet Runtime will send it XML data on the
variable(s) being asked. This includes prompt text, allowed values, and range limitations. This XML data can
also include the name of the SWF to use for the next question or step in the system. With a small amount of
Action Script (described below) this new SWF can be called and passed the XML data. The Exsys Corvid
development interfaces makes it easy to associate a Flash SWF file with an Exsys variable, and to specify
what XML data is passed to the SWF file. This allows the logic of a system to dynamically determine the
order of the questions to ask. The XML data for each question will indicate the SWF to use.
It is possible to simply hard code all the text in the Flash SWF question screen and ignore the XML data from
Corvid, but generally it is better to use the XML data as it opens up many capabilities and makes systems
easier to maintain and enhance. For example, the Corvid Servlet Runtime will send the prompt text for the
variable. If the SWF file uses the XML data to determine the prompt text for the Flash application, then editing
the text need only be done in the Corvid development environment and it will automatically be picked up and
used in the Flash interface.
If the system is to run in multiple languages, Corvid can use resource files to select the appropriate language
prompt text, send it to the SWF and have a single SWF run in multiple languages. The text for values in
Static Lists are also passed in the XML and can be used in the same way. When there are multiple question
screens with similar layout, it is possible to build a single Flash SWF file that reconfigures the text and number
of buttons for each question.
B. The FIRST post to the Corvid Servlet Runtime MUST include the KBNAME= value to specify the
system to run. This should only be included in the first POST to start the system.
C. All subsequent POSTs to the Corvid Servlet Runtime for that session must include a
~SCRNUM=scrnum value. This tells the runtime which session is being run. The value for scrnum
will be sent back from the Corvid Servlet Runtime in the XML data after the initial POST.
D. All Posts can also include the value(s) of any Corvid variables that have been asked with the SWF
screen. These are included a [Varname]=value.
E. The various data items should be separated by &.
The “RUNMODE=FLASH” tells the Corvid Servlet Runtime this is from a Flash SWF file, and that the
response should be in XML, rather than the normal HTML that is used in non-Flash systems.
The “KBNAME=ExsysKBLocation” indicates which Corvid CVR file to run. This is the same as when running
non-Flash systems. This MUST be the second pair for the first post to Corvid.
The “~SCRNUM=scrnum” tells the Corvid Servlet Runtime which session is being run, and where the system
is in the session. This is required for all posts except the first. The value of scrnum will be provided in the
XML data sent back from the previous call to the Corvid Servlet Runtime. (This is explained in more detail
when looking at the actual code and XML data.)
Once the string of data to send to Corvid is built, it is sent using POST.
Normally it is a good idea to specify the URL for the Corvid Servlet Runtime and Corvid CVR system file being
run as Action Script variables so they can be easily modified if the system is moved. (If it is impractical to
rebuild the SWF when files are moved, these can be put in a file that is read by Action Script commands in the
SWF file.)
var ExsysRuntimeLocation:String = "http://www.myServer.com/CORVID/corvidsr";
! var ExsysKBLocation:String = "../FlashSystems/mySystem.cvR";
! var header:URLRequestHeader = new URLRequestHeader("pragma", "no-cache");
Create a URLRequest to the Corvid Servlet Runtime using the ExsysRuntimeLocation variable.
var request:URLRequest = new URLRequest(ExsysRuntimeLocation);
Build the data to send in a string. For example:
dataToSend = "RUNMODE=FLASH&KBNAME=”+ ExsysKBLocation+”&[Color]="+numSel;
Remember, subsequent SWF files MUST include ~SCRNUM= followed by the screen number sent back from
Corvid in XML. This is not needed (or possible) for the first screen, but is required for all other screens.
! function configureListeners(dispatcher:IEventDispatcher):void {
! ! dispatcher.addEventListener(Event.COMPLETE, loadCompleteHandler);
! }
Try to load the request, which will pass the data to the Corvid Servlet Runtime, catching and displaying any
error that might occur.
! ! try {
! loader.load(request);
2. Using the XML Data Sent Back from the Corvid Servlet Runtime
The Corvid Servlet Runtime will process the data sent, using the logic and rules in the Corvid system. This
may lead to the Corvid Inference Engine determining that more data is needed, or it may be able to reach a
conclusion and display the results and advice. In either case, it will send back XML data.
The “loadCompleteHandler” specified in the Event Listeners will be called when the COMPLETE event for the
load occurs. This processes the data sent back from Corvid:
! function loadCompleteHandler(event:Event):void {
var exsysData:URLLoader = URLLoader(event.target);
The nextScreenXMLData will hold the XML data returned from Exsys. At this point the data will be used
mainly to determine the next SWF to load and action to take.
var nextScreenXMLData:XML;
If nextScreenXMLData.error is an empty string (“”), then there was no error and the returned data can be
used. The first thing to determine is the type of action to take next. This is also in
“nextScreenXMLData.action.type”. There are various possible values (explained below), but the most
common are “ASK” and “RESULTS”. The value “ASK” indicates that there is another question to ask, and
“RESULTS” indicates that the system is done and the XML included the results/advice to display.
! ! if (nextScreenXMLData.action.type == "RESULTS")
! ! ! // display the results / advice
If either the next question or results requires loading another SWF file, the name of that file will be in
“nextScreenXMLData.action.template”. In that case, a function to load the next screen is called, passing it the
name of the SWF file to use and the data returned from Corvid. This can be used to set the text and layout of
the next screen, along with setting the value for “~SCRNUM” that may need to be passed later.
! loadNextScreen(nextScreenXMLData.action.template, returnedData);
! ! !
The sendingLC is used to send data to the next SWF, and the receivingLC is used to get data from a previous
SWF. Since the starting SWF does not receive data, it only really needs the sendingLC, and since the last SWF
(typically for results display) does not send data to continue the session, it only really needs the receivingLC.
In Section #2, when the XML data returned from Corvid was read, loading the next SWF file was down using
loadNextScreen(). This is the function that loads the SWF and passes the Corvid data to it.
On the next SWFs INIT event establish the LocalConnection from this SWF for “CorvidData”. This MUST be
done on the INIT event for the data to be successfully passed. If you wait until the COMPLETE event the
connection cannot be setup because the previous SWF is gone.
! nextScreenLoader.contentLoaderInfo.addEventListener (Event.INIT ,
! ! function(evt:Event):void {
! ! sendingLC = new LocalConnection();
! ! sendingLC.client = this;! ! ! !
! ! ! try {
! ! ! ! sendingLC.connect("CorvidData");
! ! ! } catch (e:Error) {
! ! ! ! trace("Local Connection error : " + e);
! ! ! }
! ! }
! ! );
(For those that prefer to create a separate named function, that will also work. It is included internally here to
make it clearer that it is associated with the INIT event.)
This INIT function will fire as soon as the next SWF is loaded and initialized, but not displayed.
On the COMPLETE event for loading the next SWF, call addChild to display that SWF and send the data to
that screen. The INIT event will have already established the LocalConnection. The new SWF is responsible
for picking up the passed data and processing it.
nextScreenLoader.contentLoaderInfo.addEventListener (Event.COMPLETE,
! ! function(evt:Event):void {
! ! ! addChild(nextScreenLoader);
Send the data return from Corvid (dataToPass) labeled “CorvidData” to be processed by the function
“NextScrn” when it is read by the next SWF file.
! ! sendingLC.send("CorvidData", "NextScrn",
dataToPass)!
! ! }
! ! );
Once the event Listeners are added, go ahead and load the next screen.
! ! ! // load the screen
! ! nextScreenLoader.load(new URLRequest(fileToLoad));!
! ! }
This process of loading new SWF files and passing data can be repeated as many times as needed.
For the final screen, typically when action.type = “RESULTS”, the SWF to display the results screen should be
loaded. This will not need a sendingLC since it is the last screen. The result data will be passed in the XML,
and the screen will need to parse and display it.
For all SWF except the first, when the SWF loads it should create the recievingLC and look for data.
! receivingLC = new LocalConnection();
receivingLC.client = this;
! try{
!! receivingLC.connect("CorvidData");
! } catch (error:Error) {
! ! trace( "Receiving LocalConnection Error: Can't connect");
! ! }
Once the “CorvidData” is read, the function specified in the LocalConnection.send from in the previous SWF
file will be called. In the example, this is the function “NextScrn”. (The names “CorvidData” and “NextScrn”
can be anything you choose, as long as they are used consistently.)
The NextScrn function will automatically be passed the data sent as “CorvidData”. It converts into the global
Flash XML object, receivedXMLData, for use later and closes the local connection.
function NextScrn(passedData:String):void {
! ! ! // name specified in LocalConnection call
! receivedXMLData = new XML(passedData);
! receivingLC.close();
! buildUI(); // build the UI based on the passed data
! }
The function buildUI() uses the XML data to layout the controls, set text or do whatever is needed to present
the user interface based on the data from Corvid. For customized SWF files designed for specific questions,
this may not require any action. For “template” SWF files, it may require creating and laying out controls
based on the type of question(s) and number of possible values.
Once the user provides their input, the data is sent back to corvid using the same approach as in section #1
above. However, for each SWF except the first, the data POSTed to Corvid MUST include the ~SCRNUM
parameter. The value for this comes from receivedXMLData. The string value that must be passed as
~SCRNUM is:
receivedXMLData.scrnum
The post string will be similar to:
“RUNMODE=FLASH&~SCRNUM=” + receivedXMLData.scrnum + “&[var1]=” +...
Required import of the LocalConnection object to pass data between SWF files.
(If there is only a single SWF file for the entire system, this LocalConnection import and all the objects based
on LocalConnection are not needed.)
Define strings for the location of the Exsys Servlet Runtime and Exsys application CVR file. These can just be
coded into the system at the appropriate place, but putting them here makes it easy to find when the URL
changes or the system is moved to a new server. If you do not want to recompile the Flash code whenever the
system is moved, these locations can be put in a text file that would be read at the start of the run. In that case,
only the text in the file would need to be changed when systems are moved, without rebuilding the SWF file.
var ExsysRuntimeLocation:String = "http://www.myServer.com/CORVID/corvidsr";
! var ExsysKBLocation:String = "../FlashSystems/mySystem.cvR";
Define LocalConnection objects to send and receive data for multiple SWF systems. The first screen only needs a
sendingLC. The last screen needs only a receivingLC to get data from the previous screen. All other screens
need both. If a system has only a single SWF file, these LocalConnection objects are not needed.
! var sendingLC:LocalConnection;
! // First screen only needs to send. Others need to send and receive
! var receivingLC:LocalConnection;
! // Last screen only needs to receive. Others need to send and receive
Define a global variable receivedXMLData to hold the XML data returned from Exsys and passed to the
current SWF from the previous SWF file. This is not needed in the first SWF file, or for systems that only use
a single SWF file.
var receivedXMLData:XML; // The XML data passed in
Setup the receiving LocalConnection when this Action Script starts. This is not needed in the first SWF file, or
for systems that only use a single SWF file.
receivingLC = new LocalConnection();
! receivingLC.client = this;
Try to receive the data sent by the previous SWF file under the label “CorvidData”. If this fails, report an error.
This is not needed in first SWF or if there is only a single SWF.
Configure the listeners for the URLLoader. (Done below) The only required listener is for the COMPLETE
event, but others can be used as desired to show progress, check for errors, etc.
configureListeners(loader);
Set the header to not cache data. (This may not be required in all cases, but could prevent some problems.)
While waiting for Exsys to return data, remove or hide any controls used on the screen that are unique to the
specific question being asked. If the control is to be reused in a template, it can be hidden or otherwise
obscured. The control that sends the data to Corvid should be immediately removed or disabled to prevent
sending multiple sets of data.
The nextScreenXMLData will hold the XML data returned from Corvid. At this point the data will be used
mainly to determine the next SWF to load and action to take.
! var nextScreenXMLData:XML;
If the XML Action Type is “ERROR”, check the “error” value. It should be displayed and processing stopped.
This will be an Exsys error message.
! if (nextScreenXMLData.action.type == "ERROR") {
! ! // if an error was returned
! ! trace(nextScreenXMLData.error); // display the error
! ! return; // exit
! }
If the action.type from Corvid is ASK, then load the next screen, or reconfigure the controls on a template
screen. Send the returnedData string on to the next screen, which will build its own XML object and use it
as needed.
When there is an ASK command, the action.template value will be the SWF file to use. This can be specified
for the variable in the Corvid development environment.
! if (nextScreenXMLData.action.type == "ASK")
! ! loadNextScreen(nextScreenXMLData.action.template, returnedData);
! ! ! // load screen and send data
The action type can also be “RESULTS” in which case the XML data will contain the system
recommendations and advice. An Action Type of “Display_HTML” indicates a URL should be immediately
displayed.
! ! } catch (e:Error) {
! ! trace("XML error : " + e);
! ! }
! }
! }
Other optional loader events. The errors should be sent to trace() which will display them.
function openHandler(event:Event):void {
}
function progressHandler(event:ProgressEvent):void {
trace("progressHandler loaded:" + event.bytesLoaded + " total: "
! ! + event.bytesTotal);
}
function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
}
function httpStatusHandler(event:HTTPStatusEvent):void {
trace("httpStatusHandler: " + event);
}
Add an INIT event listener for the SWF file that is being loaded. This will fire as soon as the next SWF is
loaded and initialized, but not displayed. It is VERY IMPORTANT that this be done on the INIT event. There
is only a moment when both SWF files exist in a way that allows data to be sent and received.
Send the data labeled “CorvidData” to be processed by the function “NextScrn” when it is read by the next
SWF file. (These names can be anything you choose, as long as they are used consistently)
sendingLC.send("CorvidData", "NextScrn", dataToPass) !
! }
! );
Once the event Listeners are added, go ahead and load the next screen.
! // load the screen
! <exsysVar>
! ! Data on one or more Exsys Variables
! </exsysVar>
! <trace> trace data if that is turned on </trace>
</exsysdata>
<scrnum>
Inside the <exsysdata> tag, there will always be a <scrnum> tag:
<scrnum> Exsys Screen Identifier </scrnum>
This is added automatically by Exsys. Exsys uses the <scrnum> value to tell it what session it is in and where
it is in that session. All POSTs back to Exsys (except the first) MUST include:
~SCRNUM=value of <scrnum>
as the second item the POST. Exsys will automatically use this value to find the appropriate session and
update the <scrnum> value when it sends XML data back for the next SWF file. Each set of data returned
from Corvid will have a different scrnum value, so it must be obtained each time. The value of scrnum can be
obtained from the nextScreenXMLData object using E4X as:
receivedXMLData.scrnum
ASK Ask the user the the value of the Corvid variable named in <target>
using the SWF file specified in <template>
It is the responsibility of the developer to check the action type to determine what to do. Even in cases where it
is known what should follow the current question, there should always be a check for <type> being “ERROR”:
if (receivedXMLData.action.type == “ERROR”) {
! report and handle the error in receivedXMLData.error
! ! }
<error>
Inside the <exsysdata> tag, there will always be a <error> tag. This will normally be blank, but if an error
occurred in processing the data sent to the Corvid Servlet Runtime, it will be reported here. If the error tag is
not blank, the action type tag will be “ERROR”. All returned data should be checked to see if the error tag is
not blank, or the action type tag is “ERROR”. If there is an error, it should be reported or displayed in some
way so it can be corrected and that session terminated.
<trace>
A <trace> tag will be added to the <exsysdata> ONLY if the system has “Add Trace in Servlet” selected in the
Corvid development environment. This should be used ONLY for debugging during development since it will
add a large amount of text to the XML file and make the system run MUCH slower than normal. However, if a
system is not producing the correct results, this is an easy way to get the trace for the run. If the contents
of receivedXMLData.trace are put in an edit box, it can be easily copied and pasted into an editor to
examine it.
<exsysVar>
<name> Variable name </name>
<type> Variable type </type>
<varPrompt> Prompt </varPrompt>
<possibleValues>
<count> Number of possible values for List variables </count>
<valueText> text of value 1 </valueText>
<valueText> text of value 2 </valueText>
<valueText> text of value 3 </valueText>
...
</possibleValues>
<alsoAsk>
<count> Number of also ask variables </count>
<alsoAskVarName> Name of “Also Ask” variable 1 </alsoAskVarName>
<alsoAskVarName> Name of “Also Ask” variable 2 </alsoAskVarName>
<alsoAskVarName> Name of “Also Ask” variable 3 </alsoAskVarName>
...
</alsoAsk>
<limits>
If ”Numeric”:
<upper> Upper limit value or blank </upper>
<lower> Lower limit value or blank </lower>
<intOnly> Require integer value -TRUE or FALSE </intOnly>
If “StaticList” or “DynamicList”:
<maxNumValues> Number of allowed values </maxNumValues>
If ”String”:
<mask> mask string or blank </mask>
If ”Date”:
<maxDaysPast> Max days past value or blank </maxDaysPast>
<maxDaysFuture> Max days future value or blank </maxDaysFuture>
</limits>
<type>
Within an <exsysVar> item, there will always be a <type> tag with type of variable. The type is a string and
can be:
! StaticList
! DynamicList
! Numeric
! String
! Date
! Collection
! Confidence
Note that “StaticList” and “DynamicList” do NOT have spaces in them. The type can be used to determine
how to ask a question, the options on values and the tags that may be in the <limits> tag.
<varPrompt>
Within an <exsysVar> item, there will always be a <varPrompt> tag with the prompt to use when asking for
the variable. If a Corvid variable has multiple prompts or resource files are being used, the correct prompt will
have already been set by Corvid.
<possibleValues>
The <possibleValues> tag provides the information on the values that can be selected among for questions
that ask Static or Dynamic List variables. This tag is included only if the <type> tag is either “StaticList” or
“DynamicList” and the action type is “ASK”.
Within the <possibleValues> tag there is a <count> tag with the number of values that can be selected
among. There are then a series of <valueText> tags each with the text of one of the possible values.
Template SWF files can check the <count> tag and then read and display that many <valueText> values.
As with prompts, multiple value or resource file settings will have already been resolved by Corvid before
creating the XML. For Dynamic Lists, the value list will have been populated from the variable’s
associated source.
<defaultValue>
Within an <exsysVar> item, there will be a <defaultValue> tag when the action type is “ASK”. This is the
default value to use for the variable when asking the user for a value. The option to use a default value, and
the value itself, is set in the Corvid development environment.
For Static and Dynamic List variables, this will be the number of the value to use as the default. For String,
Numeric and Date variables, this will be the text of the value to use as the default. If there is no default value
specified for the variable, this will be blank.
<control>
Within an <exsysVar> item, there will be a <control> tag when the action type is “ASK”. This will contain the
“Control to Use” that was specified for the variable in Corvid. This can be used for more complex template SWF
files that can accommodate multiple types of controls. (A typical use would be to select between checkboxes
and radio buttons.) Flash SWF files that are designed for a single control type can ignore the value of this tag.
The values for <control> are a number indicating the control specified in Corvid:
1 Radio Button
2 Checkbox
3 List Box
4 Drop Down List
5 Edit Box
6 Button
7 Image Map
<alsoAsk>
Within an <exsysVar> item, there will be a <alsoAsk> tag when the action type is “ASK”.
This lists any variables specified in the main variable’s Also Ask list. The main variable is the one specified by
the Action Target tag. The <count> tag will have the number of variables in the list, followed by individual
<alsoAskVarName> tags with the names of the variables in the list. If there are no Also Ask variables for the
main variable, all will be blank.
<alsoAsk>
<count> number of also ask variables </count>
<alsoAskVarName> var 1 </alsoAskVarName>
<alsoAskVarName> var 2 </alsoAskVarName>
<alsoAskVarName> var 3 </alsoAskVarName>
...
</alsoAsk>
nextScreenXMLData.exsysVar.(name == currentAlsoAskVar).varPrompt
<limits>
Within an <exsysVar> item, there will be a <limits> tag when the action type is “ASK”. This provides
information on any limits to the input values that should be accepted. These limits come from Corvid and are
set in the Corvid development environment. The Corvid Servlet Runtime will reject any value not meeting the
limits, but this requires sending data to Corvid only to have the question reasked. It is generally better and
more efficient to validate the value in Flash with Action Script before sending it to Corvid. This makes for a
better user experience, and allows the SWF file to immediately display message about invalid input, or to only
activate a “Submit” button when input is within acceptable ranges.
The tags within the <limits> tag depend on the variable type. If there are no limits the values will be blank.
If the variable type is ”Numeric” there will be:
<limits>
<upper> Upper limit value or blank </upper>
<lower> Lower limit value or blank </lower>
<intOnly> Accept only integers - “TRUE” or “FALSE” </intOnly>
</limits>
If there is a <upper> value, the input value must be less than or equal to that value. If the <upper> value is
blank, there is no upper limit.
If there is a <lower> value, the input value must be greater than or equal to that value. If the <lower> value is
blank, there is no lower limit.
If the <intOnly> value is “TRUE”, then only a value that is an exact integer will be accepted. If the <intOnly>
value is “FALSE” there is not restriction on the value.
If the variable type is ”StaticList” or “DynamicList” there will be:
<limits>
<maxNumValues>value or blank </maxNumValues>
</limits>
If there is a <maxNumValues> value, that is the maximum number of values that can be simultaneously
selected. If the value is blank, any number of values can be selected.
If the variable type is ”String” there will be:
<limits>
<mask> mask string or blank </mask>
</limits>
If there is a <mask> value, the string must match the pattern set by the mask. The mask pattern syntax is
the same as when running without Flash and is explained in the Corvid manual. If the value is blank, any
string is accepted.
If the variable type is ”Date” there will be:
<limits>
<maxDaysPast> Max days past value or blank </maxDaysPast>
<maxDaysFuture> Max days future value or blank </maxDaysFuture>
</limits>
<currentValue>
Within an <exsysVar> item, there will be a <currentValue> tag. This contains the current value of the variable.
This is normally only used when action type is “RESULTS”, but can also be used for displaying intermediate
results or during debugging. The value used is the immediate value, and does not lead to additional rules
being fired to derive a value, or external sources for the value being used. If a final value is needed, use
other commands in the system to derive the final value before using the <currentValue> tag. If the variable
does not have a value set yet, this will be blank. This is the same value as [[*varname.VALUE]].
<other>
Within an <exsysVar> item, there will be an <other> tag. The value of this tag can be set by the system
developer in the Corvid development environment (details to follow). This tag can contain any string. It can
include double square bracket replacements of other values and even other data in your own XML tags.
(Remember if you use XML syntax to add your own tags, be sure that tags are nested correctly and closed
correctly - otherwise you will get very difficult to debug error messages when the Exsys data is converted to a
Flash XML object.)
</exsysdata>
When the next action is to ask a questions, the action type tag will be “ASK”.
if (receivedXMLData.action.type == “ASK”)
! ! // ask the next question
}
In this case, the action target tag will be the name of the main variable to ask:
! varname = receivedXMLData.action.target
<exsysVar>
Data on one or more Exsys Variables to use in the results
</exsysVar
<full> Full value of prompt and all values set. Same as [varname.FULL]
<short> Short text of values set. Same as [varname.SHORT]
<time> Time the variable was set. Same as [varname.TIME]
<age> Milliseconds since the value was set. Same as [varname.AGE]
<how> How the variable was set. Same as [varname.HOW] - this can be quite long
<age> Custom string the developer may add. Can include [[ ]] replacement
In this case the XML data is very simple since it only needs to include the URL to open.
<exsysdata>
<action>
<type> DISPLAY_HTML </type>
<target> The URL of the page to display </target>
<template> </template>
</action>
</exsysdata>
</exsysdata>
All XML data returned from Corvid should be immediately checked to see if the action type is “ERROR”. If it
is, it should be reported in some way and the session terminated.
<full> The full text of the prompt and any values set
<short> The short text of any values set for Static List variables
<time> The time the value was set
<age> The time in milliseconds since the value was set
<how> A detailed explanation of how the value was set (Requires HOW
be activated with the ALLOW_HOW special command)
<special> Any other string you would like to add - similar to <other>
Flash Editor
When using Flash for the user interface, it can be
convenient to have the “New/Edit” button next to the
edit box open the Flash or Flex IDE. To do this set
the “HTML Editor” in the Properties window to point
to the Flash or Flex development program. When
the “New/Edit” button is clicked, the specified
program will be called.
MetaBlock Parameters
If the node is being added to a Logic Block that is a MetaBlock, the active MetaBlock parameters
(spreadsheet column headings) can be used in formulas. For information on MetaBlocks, see Chapter 12.
Expression Syntax
In addition to Corvid variables, expressions may contain:
! Numbers in various formats:
- Integers (e.g. 5)
- Decimal numbers (e.g. 4.56)
- Exponential format - a number, “e” and a base 10 exponent to multiply the number by.
(e.g. 1.2e2 = 1.2 x 100 = 120 .12345e3 = .12345 x 1000 = 123.45)
! Functions (described below) Any function argument can be an expression itself, with any level of nesting.
! Parenthesis for function arguments and for grouping (to change the order of operations).
! Arithmetic operation signs +, -, *, /, the power sign ^ and modulo operator %
- The power sign ^ is used to raise a number to a power.
For example 3^2 is 3 squared or 9. 2^3 is two cubed or 8.
- The modulo operator: X % Y returns the remainder after X is divided by Y the maximum
integer number of times. 7 % 3 = 1
! Logical operation signs <, <=, >, >=, !=, ==, ~=, !, |, &
Blank spaces in the expression are ignored. Parentheses are supported.
Logical Operations
The supported logical operators are:
The operation signs may not follow each other unless they make up another operator. Do not write something
in the style 2--1. Use parenthesis here instead: 2-(-1).
A logical expression is evaluated as 1 if it is true and as 0 if it is false. The 1 / 0 value can be used in other
expressions as a numeric value.
It is a good idea to always use parenthesis to ensure desired precedence and priority with respect to
arithmetical operations. Generally arithmetical operations are assigned higher priority than the logical ones.
Examples:
2 + 1 < 2 is interpreted as (1 + 2) < 2 (= 0), and not as 2 + (1 < 2) (= 3).
1 < 2 < 3 is evaluated as (1 < 2) < 3 i.e. (1 < 2) < 3= 1 < 3 = 1.
At the same time 3 > 2 > 1 is evaluated as (3 > 2) > 1, i.e. (3 > 2) > 1= 1 > 1 = 0.
A.2 Constants
Corvid supports several constants that can be used in expressions. The constants should be used “as is” and
not in quotes - but must be used in the expression at a place where that “type” can be used.
PI 3.14159 Numeric
Example:
[A] = PI * [R] * [R]
[S] = “abc” + TAB + “def”
NOTE: The CR, LF and CRLF characters do NOT cause a line break when displayed on the screen. Use
<BR> to do that. These are used for precise control when writing to files or emails to add specific characters
to output.
Each function returns a value of a particular type and must be used in an expression where that type is
syntactically correct. For example, the sine function SIN(X) will return a numeric value and the argument “X”,
must also be a numeric value. SIN(.5) is legal, but SIN(“ABC”) is not since “ABC” is a string rather than a
numeric value. Likewise, [X]=1+SIN(.5) is legal, but [S]=”ABC” + SIN(.5) is not since the expression would
require a string value and SIN is numeric.
The argument of a function can be a complex expression involving other functions and Corvid variables,
provided the overall expression is the correct type. For example:
The argument to a function must be in parenthesis. Some functions take more than one argument and the
individual arguments must be separated by commas.
Most windows for entering expressions have a “Functions” button. Clicking the button displays a list of
functions supported in Corvid. Simply select the function needed and click OK, or double click on the
function. The function prototype will be added to the edit box at the current cursor and can then be edited.
COS(x)
Cosine of angle in radians
Returns: Numeric Argument: Numeric
Example: COS(.5) COS([X])
TAN(x)
Tangent of angle in radians
Returns: Numeric Argument: Numeric
Example: TAN(.5) TAN([X])
ATAN(x)
Arc tangent. Returns a value in radians
Returns: Numeric Argument: Numeric
Example: ATAN(.5) ATAN([X])
ACOS(x)
Arc cosine. Returns a value in radians
Returns: Numeric Argument: Numeric
Example: ACOS(.5) ACOS([X])
SQRT(x)
Square Root
Returns: Numeric Argument: Numeric
Example: SQRT(4) SQRT([X])
ABS(x)
Absolute Value For positive number, the value. For negative values, the value converted to a positive
Returns: Numeric Argument: Numeric
Example: ABS(4) = 4 ABS(-4) = 4
EXP(x)
e raised to the power x
Returns: Numeric Argument: Numeric
Example: EXP(4) EXP([X])
LN(x)
Natural Logarithm (log base e) (For log base 10, use LOG(x) )
Returns: Numeric Argument: Numeric
Example: LN(4) LN([X])
LOG(x)
Base 10 Logarithm (For log base e, use LN(x) )
Returns: Numeric Argument: Numeric
Example: LOG(4) LOG([X])
FLOOR(x)
Highest integer value less than x. (See comparison with INT(x) below)
Returns: Numeric Argument: Numeric
Example: FLOOR(4.3) FLOOR([X])
INT(x)
Integer part of x
Returns: Numeric Argument: Numeric
The INT() and FLOOR() functions are very similar and for positive numbers give the same value.
The difference is that for negative numbers, FLOOR() is the first integer value less than the argument,
while INT() is the integer part of the negative number. FLOOR(-2.5) = -3 while INT(-2.5) = -2.
Example: INT(4.3) INT([X])
FRAC(x)
Fractional part. Applies to positive or negative numbers.
Returns: Numeric Argument: Numeric
Example: FRAC(4.5) = .5 FRAC(-2.1) = .1
RANDOM()
Generates a random number between 0 and 1
Returns: Numeric Argument: None
Example: RANDOM()
MIN(x, y, z,...)
Minimum of list of values. Returns the lowest value from the list. There can be any number of numeric
arguments separated by commas
Returns: Numeric Argument: List of numeric values separated by commas
Example: MIN( 5, 3, 1, 7) = 1
MAX(x, y, z,...)
Maximum of list of values. Returns the largest value from the list. There can be any number of numeric
arguments separated by commas
Returns: Numeric Argument: List of numeric values separated by commas
Example: MAX( 5, 7, 1, 3) = 7
RAD(x)
Convert Degrees to Radians
Returns: Numeric Argument: Numeric
Example: RAD(234)
NUM(s)
Convert a string to a number. The string must be a string representation of a number in any of the
supported formats. This is can be used when a string (such as one obtained from a tokenize() call) needs
to be used as a numeric in a calculation.
Returns: Numeric Argument: String
Examples: NUM(“123”) = 123
NUM(“1.5e3”) = 1500
NUM(“abc”) = illegal
LEFT(s, n)
Left n characters of string s
Returns: String Arguments: s - String, n-numeric
Example: LEFT(“abcde”, 3) = “abc”
RIGHT(s, n)
Right n characters of string s
Returns: String Arguments: s - String, n-numeric
Example: RIGHT(“abcde”, 3) = “cde”
MID(s, x, n)
Middle n characters of string s starting at character number x
Returns: String Arguments: s - String, x,n-numeric
Example: MID(“abcdefg”, 3, 2) = “cd”
LEN(s)
Length of string s
Returns: Numeric Argument: String
Example: LEN(“abcde”) = 5
UCASE(s)
Convert string s to all upper case
Returns: String Argument: String
Example: UCASE(“abc”) = “ABC”
LCASE(s)
Convert string s to all lower case
Returns: String Argument: String
Example: UCASE(“ABC”) = “abc”
A in B
A <INSTR> B
Both “A in B” and “A <INSTR> B” return “True” if the string B contains the string A, and false otherwise.
Some find “A in B” is easier to read, but both are functionally identical.
TRIM(sourceStr, trimCharSet)
Remove Specified Characters from the start and end of a String
Returns: String Arguments: String
sourceStr The initial string to trim
trimCharSet A string containing the characters to remove
Returns the sourceStr, but with every character in trimCharSet deleted from the start and end of the
source string. Occurrences of trim characters in the middle of the string (between non-trimmed
characters) are not deleted. The match for the characters to trim is case sensitive.
Both sourceStr and trimCharSet are strings and should either be the value of a string variable, a string
expression or just a string in " ". This is most often used to trim unwanted spaces from the ends of a
string. To do this the trimCharSet should be “ “ (a space in quotes).
NOTE: This will remove all spaces in the string.
Example:
TRIM(" # hello ##;", " #;") returns "hello"
TRIM("abcdefghijk", "jbak") returns "cdefghi"
TRIM("abcdefghijk", "jbeak") returns "cdfghi"
FINDCHR(sourceStr, searchCharSet)
Returns the numeric index of the first character in the sourceStr string that is a character in the
searchCharSet string.
Returns: String Arguments: String
sourceStr The string to search
searchCharSet A string containing the characters to search for
Returns the numeric index of the first character in sourceStr that is in searchCharSet. If no character
from searchCharSet is found, 0 (False) is returned. The index of the first character in sourceStr is 1.
Both sourceStr and searchCharSet are strings and should either be the value of a string variable, a
string expression or a string in " ". The character match is case sensitive.
parse(sourceStr, patternStr)
Create a Tab-Delimited String Based on a Pattern String
Returns: String Arguments: String
sourceStr The source string
PARSETEST(sourceStr, patternStr)
PARSETEST() has the same syntax and parameters same as PARSE() but does NOT actually parse the
string, instead it returns True or False if the PARSE() function can be successfully performed. This is
used in cases where actually executing the PARSE() function could lead to a syntax error. Instead call
PARSETEST first, and only call PARSE() if PARSETEST returns TRUE.
Returns: Boolean (False=0) Arguments: String
sourceStr The source string
patternStr The pattern to parse with
Example:
PARSETEST("WARNING 99-bad widget:12345", "ERROR {0}-{1}:{2}") returns False (0)
REVERSE(sourceStr)
Reverse the order of the characters in a String
Returns: String Arguments: String
sourceStr The string to reverse. should be either the value of a string variable, a string
expression or just a string in " ".
Returns the sourceStr reversed. This makes it possible to perform actions on the right side of the source
string using a function that acts on the left side of the source.
For example to replace the last 3 occurrences of "dog" with "cat", do this:
reverse(replace(reverse([source]), "god", "tac", true, 3))
Notice you have to reverse all inputs and then reverse the output. This is not an easy function to build but
it makes it possible to work backwards on a source string.
For example:
REVERSE("abc") returns "cba"
FILL(patternStr, tabDelimStr)
Build a String by Replacing Parameters in a Pattern
Returns: String Arguments: String
patternStr The pattern string
tabDelimStr A tab-delimited string
Returns a string built by replacing parameters in a pattern with the values from the tab-delimited string.
The parameters to replace in the pattern are indicated by {#}, where # can be a value from 0 to 9. FILL()
takes the first value (everything up to the first tab) in tabDelimStr and puts it into the patternStr
everywhere it has "{0}", if any. A {1} in the pattern is replaced by the next value in tabDelimStr , etc.
NOTE: The index of the first value in the tab-delimited string is {0}.
It is not required to use all the values in the tab delimited string variable. If the tabDelimStr string has
fewer number of entries than the # specified in the {#}, it does not replace the {#}. It is not necessary to
use every entry of the collection variable and they do not have to be used in numeric order.
The tab-delimited string can be easily created from a Collection variable using the .TABDELIM method.
This method returns a tab-delimited string from a Collection variable, with the first value in the Collection,
a tab, the second value, a tab, the third value, etc.
Early version of Java only supported index number values from 0 to 9. In Java ver 1.4.0 or higher, the
index numbers can be greater than 9.
The collection_var_name can be just the name, or the name in square brackets. If it is a string constant, it
must be in quotes.
The tab-delimited string can be assigned to a Collection variable using the .ADD or .ADDFIRST methods.
Each item in the tab-delimited string will be added to the Collection variable in turn. If .ADDFIRST is used,
each item will become the new first item in the value list.
If the Collection variable [Collection_var] is empty, and [S] is a string variable:
[S] = TOKENIZE("one two three four", " ", " ")
[Collection_var.ADD] [[S]]
will result in [Collection_var] having 4 values, "one", "two", "three", "four"
[Collection_var.ADDFIRST] [[S]]
will result in [Collection_var] having 4 values, "four", "three", "two", "one"
NOTE: The variable [S] must first be assigned the values from TOKENIZE and then its value
added to the collection. Using: [Collection_var.ADD] tokenize("one two three four", " ", " ") will not
work because the .ADD method does not evaluate the string being added.
DATE( )
Returns the current date as a string - month, may, year. (The exact formatting is dependent on the
localizations settings of the computer.) This can be used as a string or assigned to a date variable. (See
other formats for the DATE(...) function below)
Returns: String Arguments: None
Example:
[S] = “Today is: “ + DATE()
NOW( )
Returns the current date and time as a string - month, day, year hours:minutes:seconds (The exact
formatting is dependent on the localizations settings of the computer.) This can be used as a string or
assigned to a date variable.
Returns: String Arguments: None
Example:
[S] = “Today is: “ + NOW()
NOWMSEC( )
Returns the current date and time as a numeric value of the milliseconds since Jan 1, 1970. This can be
used as a numeric or assigned to a date variable.
Returns: String Arguments: None
This can be used for timers, such as setting the NOWMSEC() when the system starts and subtracting it
from NOWMSEC() at the end to know how long the system took in milliseconds. A similar technique can
be used to see how long it takes a user to answer particular questions,
DAYSDIFF(date1, date2)
Returns the absolute integer number of calendar days between two dates. The order of the dates is not
important and the function will always return a positive number. The number of days is always rounded
up. If the date interval includes any portion of a day, that day is counted. Two dates on the same day will
return 0.
Returns: Numeric Arguments: Dates
Examples:
DAYSDIFF([today], [tomorrow]) = 1
DAYSDIFF([one_second_before_midnight], [one_second_after_the_same_midnight]) = 1
because the calendar day starts at midnight.
DAYSDIFF([now], [5_minutes_from_now]) = 0
until the time is within 5 minutes of midnight, at which time it will return 1 since the time period
would be over 2 different days.
Examples:
CREATEDATE([today], 0, 0, 1) will return tomorrow
CREATEDATE([today], 0, 0, 45) will return a date 45 days from now
CREATEDATE([today], 1, -1, 0) will return the date 11 calendar months from now
because 1 year - 1 month = 11 months
No Property
When used in a report with no property specified, the text output is the full text of the prompt followed by the full
text of any values set, connected with “AND”. This is the default text and is equivalent to using the .FULL property.
Example:
[PRICE]
would output:
The price of the item is about equal to the customer’s budget.
When used in an expression, Static List variables are a little different from other types. Normally, IF nodes
built with Static List variables will be built from the Static List tab and will be just “Variable name = value”
without square brackets. This is to make the Logic Blocks easier to read.
Price = at_budget
However, when combined with other variables in more complex expressions from the “Expressions” tab, the
syntax required is [variable name] = “value text” where value text is the text of the value or the short text
of the value if that is different.
[Price] = “at_budget”
This form is only needed when building more complex expressions:
( [Price] = “at_budget” ) & ([X] > 0)
When building complex expressions, it is often better to use one of the other properties such as .NUM to
simplify the expressions and make them clearer.
[PRICE.CHECK 2]
would return:
1
[PRICE.CHECK at_budget]
would return:
1
The return values of “1” and “0” are equivalent to TRUE and FALSE and can be used to build complex
Boolean test expressions, or can be used as a numeric value in expressions.
No Property
When used in a report with no property specified, the text output is the full text of the prompt followed by
the full text of any values set, connected with “AND”. This is the default text and is equivalent to using
the .FULL property.
Example:
[CARS_ON_THE_LOT]
would output:
The type of car desired is SUV
When used in an expression, the syntax required is [variable name] = “value text” where value text is the
text of the value or the short text of the value if that is different.
[CARS_ON_THE_LOT] = “SUV”
[CARS_ON_THE_LOT.CHECK SUV]
would output:
1
The return values of “1” and “0” are equivalent to TRUE and FALSE and can be used to build complex
Boolean test expressions, or can be used as a numeric value in expressions.
[CARS_ON_THE_LOT.INCLUDES Wagon ]
would output:
0
The return values of “1” and “0” are equivalent to TRUE and FALSE and can be used to build complex
Boolean test expressions, or can be used as a numeric value in expressions.
[CARS_ON_THE_LOT.INCLUDES Wagon ]
would output:
1
No Property
When used in a report with no property specified, the text output is the full text of the prompt followed by the
full text of the value. This is the default text and is equivalent to using the .FULL property.
Example:
[PRICE]
would output:
The price of the item is 123.45
When used in an expression, [variable name] is replaced by the value of the variable. If the variable is a
numeric, it will be a numeric value and should be used in a location where a numeric would be legal syntax.
If the variable is a string or date variable, the value will be a string and should be used in a location where a
string would be legal syntax. Date variables can also be used in a numeric context, in which case the value
will be the date converted to the number of milliseconds since Jan 1, 1970.
[PRICE] > 100
[NAME] = “Fred”
.VALUE - Value
The property .VALUE is the value, without the prompt.
If the variable is a numeric, it will be a numeric value and should be used in a location where a numeric would
be legal syntax. If the variable is a string, the value will be a string and should be used in a location where a
string would be legal syntax.
For Date variables, the value will be as string expression of the date as “month, day, year hour:minute:second”
If a date .VALUE property is used in a numeric expression, the date value will be expressed as the numeric
value of the number of milliseconds since Jan 1, 1970. This number of seconds can be used to perform
calculations to determine the number of days, years, etc between dates.
Example:
[PRICE.VALUE]
would output:
123.45
[NAME.VALUE]
would output:
Bob
Character Meaning
0 A digit
; Separates formats for positive and negative numbers (Positive numbers will
use the format left of the ; and negative numbers will use the format right of
the ;
- Negative prefix
For example:
[PRICE.FORMAT ###]
would output
123
[PRICE.FORMAT 0000.##]
would output
0123.45
[PRICE.FORMAT $###.##]
would output
$123.45
[PRICE.FORMAT $###.##;($###.##)]
would output
$123.45
but if the value were -555.23, it would output
($555.23)
DATE_FULL The longest form of the date (e.g. Thursday, April 5, 2001)
The fmtStr can combine any DATE_* with any TIME_* or just a DATE_* or just a TIME_*. If both DATE and
TIME are specified, they should be separated by a space in the fmtStr.
For example:
[D.FORMAT DATE_MEDIUM TIME_SHORT]
would output a medium format date string with a short format time string.
[D.PFORMAT fmtStr]
will output the date formatted by the format string, but preceded by the prompt of the variable.
.No Property
When used in a report with no property specified, the text output is the full text of the prompt followed by the
full text of the value. This is the default text and is equivalent to using the .FULL property.
Example:
[Good_Fit]
would output:
The likelihood that the item is appropriate for the intended use is 82.5
When used in an expression, [variable name] is replaced by the numeric value of the variable.
[Good_Fit] > 100
Example:
[Good_Fit.FULL]
would output:
The likelihood that the item is appropriate for the intended use is 82.
.VALUE - Value
The property .VALUE causes the value to be output, without the prompt.
Example:
[Good_Fit.VALUE]
would output:
82.5
[Good_Fit.FORMAT 0000.##]
would output
0082.5
[Good_Fit.FORMAT ***##]
would output
***82
[Good_Fit.FORMAT ###.##;(###.##)]
would output
82.5
but if the value were -82.5, it would output
(82.5)
No Property
If there is no property specified, the text output is the full text of the prompt followed by the values
concatenated together with a space between them. This is the default text and is equivalent to using
the .FULL property with no separator text.
Example:
[DOG]
would output:
The best breed of dog for you is Beagle Labrador Retriever Golden Retriever
.FULL Separator - Prompt and all values set with a separator string
The property .FULL is the prompt followed by the values. If the optional separator string is added, it will be
added between each value. The separator word will be padded on each side with a space. If the separator
word in not included, the values will be separated by a space.
Example:
[DOG.FULL OR]
would output:
The best breed of dog for you is Beagle OR Labrador Retriever OR Golden Retriever
[DOG.VALUE OR]
would output:
Beagle OR Labrador Retriever OR Golden Retriever
[DOG.INCLUDES Poodle ]
would output:
0
INCLUDES can accept an embedded variable as the value to test against.
For example:
[THINGS.INCLUDES [[test_str.value]] ]
where [THINGS] is a collection variable, and [test_str] is a string to test to see if it is one of the items in the
collection.
[DOG.NOTINCL Poodle ]
would output:
1
Properties that return True or False can be used in IF nodes or other Boolean tests. They can also be used
in numeric expressions.
When building IF nodes in a Logic Block, if a Collection
variable is selected, the “Collection” tab will be active. This
allows building the standard boolean properties of the
Collection variable. Select the type of test from the radio
buttons and then enter the test value. For example to build
a NOTINCL property, click the "Does NOT Contain" radio
button and enter the value to search for.
More complex expressions using Collection variables can be built from the “Expression” tab.
[SampleData.GETAFTER "Mike", 2]
[SampleData.GETAFTER "[[IDStr]]", 2]
[SampleData.GETAFTER "[[IDStr]]", [[x]] ]
To have either parameter set by an expression, set another Corvid variable first, and then use [[ ]] to embed
that variable. For example:
SET [X] ([z] + [N]/3)
[SampleData.GETAFTER "abc", [[X]] ]
If test1 is TRUE and test2 is TRUE, the lines included would be:
aaa
bbb
ccc
ddd
eee
[Col.REMOVE] #5
will remove the 5th item from the Collection variable’s value list.
If there is an item with text “#X” (where X is the number), then that item will be removed regardless of the
numeric position, and the numeric item will not be removed.
www.exsys.com
All rights reserved.