Sunteți pe pagina 1din 521

© Copyright Exsys Inc.

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.

Moving to Corvid v6 from Earlier Versions of Corvid


If you are moving to Corvid v6 from an earlier version of Corvid

1. If you installed Apache Tomcat locally:

• IMPORTANT: Make a backup copy of the current Tomcat folder


(This may have Corvid system files you need later)

• Uninstall your current Apache Tomcat

• Uninstall your current Exsys Corvid

2. Follow the Corvid v6 install instructions

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.

1: Installing Exsys Corvid 1


Installing Exsys Corvid

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.

To install Exsys Corvid, double click on the “Setup” program


icon.

This will start the install program.

This is a typical MS Windows install that will ask you to accept


the license, enter a name and organization.

It will by default install Corvid to:

Program Files\Exsys\Corvid

or (depending on your version on Windows)

Program Files (x86)\Exsys\Corvid

It is strongly recommended that you use this default location for


the install.

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.

2 1: Installing Exsys Corvid


First you will see the Exsys Corvid splash screen. This will go to
the next screen in a few seconds, or click on it to make it
change immediately.

The next screen is the License Activation screen. By


default, Corvid installs set to run for 30 days and
allow only building systems of up to 150 nodes.
These settings are changed by entering an Activation
Code.

If You Purchased Exsys Corvid:


(Only do this if you have already purchased a Corvid
license)

1. Click the “Send Info” button


2. Accept the License terms
3. Fill out the Registration form and send it to
info@exsys.com
4. Once Exsys verifies the purchase, an Activation
Code will be emailed to you. Activation Codes are
generated during normal business hours.
5. When you receive your activation code, copy it to
the Activation Code edit box and click the
“Register” button.
6. While you are waiting for your Activation Code to
be sent back to you, you can continue configuring
and using Corvid by clicking the “Continue without
Activation” button.

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.

Academic Use in a Class


If your professor has given you a “Pre-approved Activation Code”, make sure you are online, enter the code in
the Activation Code edit box and click the “Register” button. This will convert your copy of Corvid to run for
120 days and allow 250 node systems.

If you are just using the 30 day / 150 node “Demo” version for the class, just click the “Continue without
Activation” button.

1: Installing Exsys Corvid 3


Configuring Exsys Corvid
When Corvid first starts, it displays the Configuration screen for setting up Java and your CorvidProjects
folder. This is a simple process. Corvid helps you with each step and checks that it was successfully done.
The Configuration steps need to be done in order. The bar at the top of the window reminds you what step
you need to do.

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.

If it does not find Java, it will tell you. If the “Next


Action” is “Create CorvidProjects Folder”, Java was
found on the computer and it does not need to be
reinstalled.

If you need to install Java, click the “Install Java”


button. This will open a browser window for the
java.com site to download Java. You need to be online
for this step.

Click the “Free Java Download” button. (Note, this


screen changes occasionally, so it may not look exactly
like the illustration, but should have a “Free Java
Download” button somewhere)

Java determines your operating system and displays


the window to download the version of Java correct for your
PC.

Click the “Agree and Start Free Download” button.

4 1: Installing Exsys Corvid


Select that you want to RUN the install and follow the install
instructions.

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.

After a few install screens, you should get to the “Successfully


Installed” screen.

Java then opens a test URL to make sure Java is working in


your browser.

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)

Click the “Run” button.

1: Installing Exsys Corvid 5


You should see the “Congratulations” screen indicating that
Java was successfully installed.

Close the Browser window and return to the Exsys Corvid


Configuration window.

2. Create the CorvidProjects Folder


The next step is to create the CorvidProjects
folder. This is automatically created in your
“/Users/LoginName” folder. The actual folder
for your computer is displayed in the edit box
next to the “Create CorvidProjects” button.

Corvid automatically also installs:


• A copy of Apache Tomcat
• The Exsys Servlet programs
• Batch files to start and stop Tomcat

There is really nothing to select in this step of


the install. The CorvidProjects folder is always
created in “/Users/LoginName” (On Windows XP this is “/Documents and Settings/LoginName”

You will see various messages as the items are installed. Corvid will then start Apache Tomcat to deploy the
servlet files.

Tomcat Control Window


Corvid will automatically start Tomcat when needed. This is
done with a batch file that runs in a Windows command
window. Do Not close this window or Tomcat will stop.
The contents of this window generally can be ignored and
the window minimized once Tomcat starts. If for some
reason Tomcat has a problem starting, this window may
have error messages that will help to diagnose the problem

6 1: Installing Exsys Corvid


Configuration Done
That should have made all the Configuration steps
green.

You can click “Done” and start using Exsys Corvid.

You can optionally change the browser to use


when you run systems. By default this is set to
Internet Explorer since that is always on any
Windows machine.

If you want to change this to some other browser


such as Firefox, click the “Browse” button next to
the Browser edit box and select the browser you
wish to use.

The Tomcat install can be tested by clicking the


“Test Tomcat” button which should display the Tomcat “Welcome” screen in a browser window. The Corvid
Servlet Runtime install can be tested by clicking the “Test Servlet Runtime” button which will display a browser
window confirming the install.

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.

If You Need to Reinstall CorvidProjects


If you need to reinstall or rebuild the CorvidProjects folder for some reason:

1. Stop Corvid and Apache Tomcat


2. Rename the CorvidProjects folder in “/Users/LoginName”. The name can be changed to anything you like,
other than “CorvidProjects”. (Note: Do not delete it yet! It may have information you will need to copy to
the new CorvidProjects folder
3. Restart Corvid. It will detect that the expected CorvidProjects folder is missing and display the
Configuration window to allow you to rebuild it. Just click the “Create CorvidProjects Folder” button and a
new CorvidProjects folder will be created
4. Move any system Project folder from the old CorvidProjects folder to the new one. This can be done by just
dragging the system project folders to the new CorvidProject or using the Project Manager to move the
CVD file and create a new project.7

1: Installing Exsys Corvid 7


Chapter 2: Exsys Corvid Concepts

Important: Using this Manual


Exsys Corvid is relatively easy to learn, but does involve concepts not found in other programs (such
as Backward Chaining) and has a very rich range of features that can, at first, be intimidating. This
manual will get you started with Corvid as quickly as possible.
The chapters in this manual are designed to be read in order, and are organized as an instructional
class in learning to use Corvid. To build systems with Corvid there are key concepts that apply to all
systems and which must be learned. These are covered in chapters 2-8. Chapters 9 and higher
cover other important information, and should be read, but they may not be immediately relevant to
the specific system you are building.
The Appendices in the book are Reference material. They cover the details of many commands and
options needed to build systems. The chapters explain the concepts needed to build systems with
Corvid, and refer to the appendices. Later when building systems, you will probably only need to look
at the Appendices for the command specifics - though the Corvid development environment helps you
build most commands.
Many students have learned Corvid and we have found that presenting the same concept in different
ways is often the key to having it “click”. In addition to this manual, there are 2 other main resources
for learning Corvid.

Online Tutorials - A set of online tutorials can be run from:


http://www.exsys.com/CorvidTutorials.html
These are a set of automated tutorials that each take about 10-15 minutes. They are self-paced and
illustrate Corvid concepts. It is highly recommended that the tutorials relevant to a chapter be
run before reading the chapter. The combination is the best way to learn Corvid.

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.

2: Exsys Corvid Concepts 9


2.1 Decisions, Decisions
There are vast numbers of decisions everyone has to make every day. Some are easy, and can be made
without much thought. Some are matters of personal taste and totally subjective. But a large number of
decisions require analysis and consideration of various factors to reach a conclusion or choice of action.
Often these decisions require experience or specialized knowledge to do the analysis properly, especially
when there is a “correct” or “best” answer. For those, it is best to get the advice of an expert.
“Experts” are the people that have the background and knowledge to be able to correctly advise on a
particular type of decision. They have acquired the needed knowledge through education, training, and
experience. It may be a decision about why the car does not start, a legal question or a medical issue.
No one can be an expert in everything. The brain surgeon may not know how to fix their car, and the ace car
mechanic is not the one to go to for medical problems. Everyone needs the advice of an expert on some
decisions. Exsys Corvid expert systems make it possible to capture the decision-making logic and process of
an expert and deliver it in an online system that can interact with end users as if they were talking to the
human expert to produce user specific advice comparable to what they would get from the human expert.
Corvid makes it possible to automatically deliver expert advice to anyone that needs it - employees,
customers and the public. Human experts are not always available and are often expensive. Corvid expert
systems can deliver comparable advice for a wide range of situations.
Corporate web sites are the way companies reach the public and their employees. There is a huge benefit to
making those sites “smart” and able to provide precise, situation specific advice. Most organizations have
ways to disseminate data. Corvid expert systems provide a way to disseminate knowledge online. Once a
Corvid application is built and put on-line, the problem-solving skill it contains is available to everyone. Staff
with minimal training can immediately perform at a much higher level by using expert systems. On the Web,
anyone can access the systems. They can provide traffic-building capabilities on your site, assist potential
customers in selecting your products, and reduce the load on support staff.

2.2 Expert Systems


Expert systems are computer programs that emulate the interaction that a person would have working with a
human expert for advice or a recommendation. Corvid includes both a development environment for building
and testing expert systems and runtime programs for fielding them online.
Expert knowledge of how to solve a problem is often scarce and valuable - it can be a company's greatest
asset and key competitive differentiator. Expert systems capture this knowledge and allow its dissemination to
others. Most other approaches to knowledge distribution just provide people with information, and rely on
them to read, understand, and convert it to usable knowledge on their own - in effect, self-teaching
themselves to be an expert. The problem is that realistically, most people do not remember all that they are
shown. It is difficult to teach people how to solve problems of even average complexity. And, most importantly in
today’s rapidly changing world, people don’t have time to master all of the problem-solving skills they need.
Expert systems are different in that they directly deliver knowledge to people - "know-how", advice, and
recommendations - rather than just information. This enables people to solve complex decision-making
problems without training or having to learn the underlying logic. As an example, think of going to the doctor -
the doctor asks a few questions, does a few tests to get data, and prescribes a medicine or therapy. The
patient does not need to understand anatomy or the details of how the diagnosis was done - they have their
answer. This is the power that expert systems provide - direct delivery of knowledge to the people that need
it, when they need it.
Ideally, people would have immediate contact with human experts in every area of specialty that they might
need, 24 hours a day. But realistically this can’t happen. Experts are scarce, busy and often difficult to reach,
and many decisions can’t wait for access to an expert. Expert systems provide a very effective and efficient
way to provide people - prospects, customers, employees and even advisors themselves, with a way to have
access to top-level expert decision-making knowledge and advice for specific problems. This expert
knowledge can be delivered via the Web and made constantly and consistently available worldwide.

10 2: Exsys Corvid Concepts


2.3 Exsys Corvid
A human expert makes a complex decision by considering many things. Through experience and “know-how”
an expert learns which factors are potentially relevant, the implications of certain factors or circumstances,
and how they should be combined and weighted to reach a recommendation. The goal of an expert system
development project is to make the computer behave the same way - ask the same questions, analyze user
input and reach the same conclusions.
When a decision-making task is well understood the steps can be precisely stated. This may be in formal flow
charts, procedure manuals or training materials. Sometimes the steps are not documented, but the expert
can still explain precisely how and why each step was taken.
This type of logic could be “hard coded” and directly programmed in a computer language such as C++ or
Java. However, attempting to code the many interrelated rules that apply to complex decisions would be
VERY difficult - and certainly a maintenance nightmare. It is difficult to even flowchart a decision based on
many interrelated probabilistic factors that must be combined or where some intermediate steps are
themselves based on complex lower level factors. Attempting to program this type of problem using standard
programming techniques requires teams of developers and substantial time, generally resulting in code that is
difficult to debug, maintain and enhance. A change in one seemingly small factor can ripple through the code
producing serious unwanted side effects. Add in user interfaces, connections to databases and fielding a
system using traditional approaches can become a major project.
With Exsys Corvid, this type of system is MUCH easier to build. Corvid uses simple human readable rules
that describe individual steps in making the decision or solving the problem. The rules are “Heuristics”
- IF/THEN rules of thumb that are the individual steps or factors that makeup the overall decision. In Exsys
Corvid, rules are written in English (or whatever language is preferred) and algebra. They are easy to read
and very similar to what the expert would tell you if you asked, “How did you make that decision?” Exsys
Corvid is designed to allow non-programmer domain experts to build rules that are easy to read,
understand and maintain.

2.4 Capturing the Decision Making Logic


Expert system development with Corvid has 3 main parts:
! Fully capturing the decision-making logic and process of the domain expert.
! Wrapping the system in a user interface with the desired look-and-feel for online deployment.
! Integrating with other IT resources.
Fully capturing the domain expert’s decision making logic and process is essential to building a system that
can provide advice comparable to the expert. The rules in a system must be able to completely describe how
the expert makes the decision. Many problems can seem simple at first, but when examined in detail have
aspects that are subtle, complicated or probabilistic. Exsys Corvid is designed to handle even very complex
logic, and the many systems built with it illustrate its flexibility and power.
The key to fully capturing the expert’s decision-making logic is to describe it in the same way the expert thinks
about it. Rules that are written this way are far more likely to be accurate and complete compared to rules
that have been converted into a complex syntax or computer language. The approach used in Exsys Corvid
is to write rules that are easily read, and that closely match the way the domain expert would explain their
logic to another person. If there is existing documentation, the Corvid system can be built to follow it.
Keeping the rules easy to read enables the domain expert to build, or directly participate in building, the
system and makes it much easier to fully capture the expert’s logic. It also has major benefits in
maintenance. When the meaning of the rules is clear, changes can be quickly and reliably implemented.
The combination of all the rules in a system allows the overall decision-making problem to be solved. In our
brain, people combine these individual rules intuitively and systematically. You don’t have to stop and say,
“Now I need to know this to help make that decision…”, our brain just does it.

2: Exsys Corvid Concepts 11


With Exsys Corvid, building an expert system is primarily identifying the individual decision steps and
converting them into a form that a computer can use, but that is still easy for people to read and understand.
There are many ways of describing the rules for a decision-making process, but the one that has proven the
most effective and efficient is the IF/THEN rule. This is a rule where there is an IF part that can be tested to
be true or false based on the data for a specific case or situation. When the IF part is determined to be true,
the statements in the THEN part are also considered true and added to the data available to the system.
For example, a basic rule might be:
IF
It is raining
THEN
You should wear a raincoat
With Exsys Corvid, the rules are very similar to the form that you would use to explain the step to another
person. This rule includes a small amount of syntax, but it is still very easy to read and understand what it
means. If you built similar rules for each of the heuristics in the decision-making process, you would have the
logic for the expert system.
A rule may have one or more IF conditions, and one or more THEN conditions. The IF conditions are always
Boolean tests that will evaluate to TRUE or FALSE. This can be done with algebraic expressions, special
Corvid functions, or simple tests to see if a particular value was selected. When there are multiple IF
conditions, they are combined with AND and must all be true for the overall rule to be TRUE. (There are
also ways to build conditions with OR and other logical operators when needed).
The THEN statements assign a value to a variable. This may be simply setting a value, adding content to a
report, or adjusting a confidence (probability) value for a particular fact. When the IF conditions for a rule are
TRUE, the assignments in the THEN statements are made, adding to the information the system has, or
setting values that may be part of the results and system advice.
Each rule is a small part of the overall decision-making logic. The Corvid Inference Engine processes all the
rules in a system to use them in the most effective way to solve a particular problem. In general, Corvid
rules can be in any order and structured in any way - allowing the organization of the rules to match the way
the domain expert approaches a problem, or existing documentation of the process. This is quite different
and MUCH easier than in standard programming where the order of code is critical. It removes one of the
most difficult parts of programming.

2.5 If / Then Rules


If / Then logic is something everyone uses every day, usually without thinking about it. Virtually every
decision you make or action you take is due to some form of If/Then logic. You just do it without thinking, until
someone asks “Why did you do ...”. Then the explanation may not use “IF” and “THEN”, but it will be
equivalent to If/Then rules.

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

12 2: Exsys Corvid Concepts


IF
Rain is forecast
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.

2.6 The Corvid Inference Engine


Building a Corvid expert system is largely a matter of describing the logic, approach and knowledge that a
human expert would use to solve a problem in a way that the Corvid Inference Engine can use to emulate the
human expert. That sounds like it would involve a lot of complex programming, and to do it in standard
computer languages, it would. But the Corvid Inference Engine does much of the work for you.

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.

2: Exsys Corvid Concepts 13


It allows writing rules that each describe a small step in making the decision or solving the problem. The
inference engine processes and uses these rules, combining them into a logical flow that can solve the much
larger overall problem. Since the inference engine will automatically find, combine and use them as it needs
them, rule order is generally not important. Rules can be structured and organized in the way that makes
most sense to you.

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.

As it processes the rules, the inference engine determines:

! What rules should be used.


! What information it needs to process those rules.
! How needed information can be derived from other rules.
! What questions to ask the end user.
! How to format and present the User Interface.
! When there is enough information to reach a conclusion.
! How to format and present the results.
! When necessary, how to interact with other programs or resources.

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.

2.6.1 Backward Chaining


Backward chaining is one of the most powerful features of the Corvid Inference Engine and is the main
reason it is so much easier to solve complex problems with IF/THEN rules in Corvid than using IF/THEN
statements in a programming language.
Backward chaining is conceptually quite simple. If the Corvid Inference Engine needs a particular value for
what is is currently doing, it will check all the rules to see if there are any rules that could tell it that value. If it
finds a rule, it will suspend what it is currently doing and try to evaluate the new rule. Once it has gotten the
value it needs, it will return to what it was originally doing. This happens recursively, so if the new rule
required a value that could be obtained from other rules, those would be tested, etc.
People do it all the time when making decisions. If you are diagnosing a machine that is not working, you
might think: “Maybe it is the power supply”, but if you saw the lights were still on, you would know it was
getting power. You don’t consciously think, “If the lights are on, then the machine is getting power”, but if
asked “How do you know the machine is getting power?”, the answer would be the “lights”. In a Corvid
system there could be a rule:
IF
The machine’s lights are on
THEN
The machine is getting power
Backward chaining is often referred to as “Goal Driven” and it can be thought of as a “To Do” list. A system
will start with the top To Do list item being something like “Generate a report” or “Find the most likely
diagnosis”. The Corvid Inference Engine always tries to do whatever is at the top of the list. If the top item

14 2: Exsys Corvid Concepts


on the list requires some value that is not known, getting that value becomes the new top item on the list,
pushing down the previous goal. The Inference Engine now focuses on that item, but it too may require
other values that become the top values. As values are obtained from the rules, the items are removed from
the To Do list, and the item below again becomes the top item. This continues with items being added and
removed until all the items are removed and the system is done.
This may sound complicated, but it is all done automatically and invisibly by the Corvid Inference Engine. All
the developer has to do is provide the rules that will tell the system how to derive the values it needs. The
order of the rules is not particularly important, since the Inference Engine will find whatever rules are
appropriate when it needs them. This makes for the “free-form” approach to writing the rules, which is very
different from the highly order dependent way the logic has to be coded in a computer language.
Since rules will be used dynamically as needed, modules of rules can be created to solve parts of a problem
and they will be used when (and if) they are needed. Interdependencies between values or rules do not
have to be “hard coded” and happen automatically in Backward Chaining. This greatly simplifies
development of complex systems with many interrelated factors.

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.

2: Exsys Corvid Concepts 15


There could be other heuristic rules that also set the “risk tolerance” value. There also could be various other
rules that determine if “Meeting objectives requires rapid growth”. Those might be based on factors that
would be set by yet other 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.

2.6.2 NOT the Same as Programming


If you have worked with any computer language, you will have come across If/Then statements and logic.
Every computer language has them. They are a fundamental part of writing computer programs. It is easy to
think of Corvid’s If/Then rules as if they were lines of computer code, but they are quite different.

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.

16 2: Exsys Corvid Concepts


Also, Corvid does not have to test nested IF statements from the top-most in. If it already has data that allows
it to determine one of the lower IF statements is FALSE, it knows the overall group of IF statements must be
false, and there is not reason to test any of the statements. Again, this just does not happen in procedural
computer code.

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.

2: Exsys Corvid Concepts 17


Chapter 3: Creating and Running Systems

3.1 Corvid Files


A Corvid expert system is made up of multiple files for development, runtime, user interface, data, etc. Some
of these files will be found in all systems, others are optional and depend on the nature of the system. All the
files for a system should be kept in the same “project” folder. Understanding the various files makes it easier
to build and field systems.

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:

Files Needed for User Interface


The user interface is generally created using standard HTML and may call for images, CSS files,
JavaScript, linked HTML pages, etc. These are referenced from within a system via a URL. The
URL can be a full URL (http://www....) to reference a resource anywhere on the web. However, more
often they are resources specific to the system and are referenced locally, with the images, etc in the
same folder as the system CVD and CVR files.

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)

The CorvidProjects folder has a project folder for


each of your Corvid systems. This project folder
has the same name as the system .CVD file.
So, if you have a system named MySytem.CVD,
it will be in a project folder named MySystem.
When you create a new system Corvid will
automatically create the project folder in
CorvidProjects and build the system files in that
folder. All of the files related to the system
should be kept in that folder. This can include
other folders (e.g. an “images” folder) but all the
files should be in the overall project folder.
Corvid will automatically build the system .CVR
and .HTML files in the project folder and copy
ExsysCorvid.jar to the folder. Any system
templates, data files needed by the system, etc
should be placed in the folder. The one
exception is any database command file, which
you may have to put in Tomcat directly to have it
work.

3.2.1 What Happens When You Run a System


When Corvid was installed and configured, it installed a copy of Apache Tomcat in the CorvidProjects folder.
Unlike earlier versions of Corvid prior to v6, you will normally not need to modify the Tomcat files directly.
Under Corvid v6, when a Corvid system is run, Corvid automatically copies all the files in the project folder
(except the CVD file) to the appropriate place in Apache Tomcat and runs the system from there. If your
system needs a data, image or other files, put them in the project folder and they will be automatically copied
to Tomcat when needed.

When you select to run a system from the Corvid Development tool:

1. Corvid saves the system CVD file in the project folder.


2. Corvid rebuilds the system files that may have changed. A new .CVR (runtime) file is created in the project
folder based on the current CVD file. Other files such as the .HTML may also be recreated if they are
based on templates. All new files will be in the system project folder in CorvidProjects.

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.

6. Corvid creates the URL to run the system.


The exact URL depends on if you are
running with the applet or servlet runtime.
Corvid then opens a browser window with
URL and runs the system. This URL can
be saved and used to run the system
outside of Corvid as long as Tomcat is
running.

Because of this, you should not directly


make changes to the files in Tomcat.
Corvid will overwrite the files in the Tomcat
webapps folder for the system the next time it
runs. For example, suppose your system uses Metablocks and has a Products.dat file that is associated with
a Metablock Logic Block. The Products.dat file should be in the CorvidProjects folder for the system. When
the system is run, Corvid will copy the system files, including Products.dat, to the system folder in Tomcat’s
webapps folder and run the system. If you need to edit Products.dat and make a change to the copy of
Products.dat in Tomcat’s webapps folder, it will be overwritten the next time the system runs. The changes
MUST be made in the Products.dat file in the system project folder in CorvidProjects. This also applies to all
other system files.

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.

3.2.2 Creating New Corvid Systems


New systems are created by selecting “New” under the
“File” menu. Corvid will ask you for the system name.
This name is used to create both the project folder in
“CorvidProjects” and name the system .CVD file in that
folder.

It is recommended that system names be kept simple.


Spaces can be used but since the name will eventually be
part of a URL, spaces will be converted to “%20” in the
URL. This is legal, but makes the URL difficult to read and
remember. If you name your system “My System” (with a
space), you will end up with a URL that includes:
My%20System/My%20System.CVR

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

which is easier to read and remember.

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.

3.2.4 The Corvid Project Manager Window


Selecting “Project Manager” under the “File” menu opens
the Project Manager window. This displays the projects in
the CorvidProjects folder. It allows you to open, copy,
rename and delete projects without directly accessing the
CorvidProjects folder.

Open - Opens the selected project. This is the same as


selecting “Open” under the “File” menu

Copy - Makes a copy of an existing project with a new


name. For example, you may want to make a copy of an
existing system as the starting point for a new system, or
you may want to make a copy of a system as a backup
before you start to edit an existing system. Select a system
to copy, click the “Copy” button and enter the name for the
new project.

Rename - Changes the name of the selected system. The


name of the folder and system .CVD file are changed. This
will change the name of the system .CVR and .HTML files
when the system runs. Other files such as templates and
data files are not renamed.

Delete - Deletes the selected project. The project folder and all its contents are deleted.

3.2.5 Moving Older Systems into the CorvidProjects Folder


Corvid systems created with Corvid versions prior to version 6 and not in the CorvidProjects folder MUST be
moved into the CorvidProjects folder.

This can be done manually by:


1. Creating a folder in the CorvidProjects folder with exactly the SAME name as the system CVD file
2. Manually copying the system .CVD file, and any other files needed by the system, to the project folder.
However, Corvid simplifies this by using the “Project Manager”:

1. Select “Project Manager” under the “File” menu


2. Click the “Move System into CorvidProjects Folder” button in the lower left
3. Browse to the old Corvid system .CVD file and select it
4. Corvid will automatically build a folder in the CorvidProjects folder with the same name and copy the
system .CVD file.
5. Corvid will automatically build the system .CVR and .HTML files.
6. If the system requires other files for images, templates, data, etc, these must be moved into the new
project folder manually. Just copy them from the old folder into the new Project folder.

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.

Normal, this should happen automatically. IF Corvid


detects that Tomcat is needed but not running, it will
automatically start it. A message will be displayed,
and you will see a Command window that is
executing the batch file used to start Tomcat. This
window can be ignored but NOT CLOSED. Closing
the window will stop Tomcat. It is only needed if there
is a problem starting Tomcat since it may include
relevant error messages.

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.

In general, it is best to just let Corvid start Tomcat. However, if


you want to stop Tomcat for some reason, this is a convenient way
to do it.

Corvid provides another way to start and stop Tomcat


external to Corvid. When the CorvidProjects folder is
created, batch files “StartTomcat.bat” and
“StopTomcat.bat” are created. Double clicking on these
files will start/stop Tomcat without running Corvid. This
can be useful for testing or demoing system outside of
Corvid, but which that require Tomcat to be running.

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.

Systems can be run with either the Corvid Applet or


Servlet Runtime programs included with Corvid.
There are many differences in the end user interface options between the applet and servlet runtime, but the
system rules and logic are the same and can be run in either mode.

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

End User Interface Design

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

Support for CSS, Java Script, Spry, None Full


Ajax, HTML5

Support for Adobe Flash None Full

Support for Tables Very limited Full

Implement standard site look-and- Set style properties that HTML templates with replaceable parameters
feel apply to all questions

System user interface Applet window in HTML Full HTML page


page

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

Where system is run End user machine Server

System CVR (runtime) file sent to Yes No


end user machine

Other system files Must be available on Access to files can be blocked


server via a URL

Database

Database interface Requires server Internal - no potential external ability to run


program and file to limit commands. Higher security
commands that can be
run

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

Email

Automated support None Yes

Commercial Systems

Suitability Limited due to Highly Recommended - Also ideal for subscription


increasing browser and based systems
Java security issues

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.

To select which mode to run in, either:

1. Under the “Run” menu, click either “Run as Applet” or “Run


as Servlet”. When the blue run triangle is clicked, the system
will run in whichever mode is selected.

You can also select to run with the trace options turned on by
clicking the “Run with Trace” to select it.

2. In the menu bar, click on the “Properties” icon

In the window that opens, click the “Test Run” tab.


At the top there is a “Run As” section. Click “applet”
or “Servlet” to select the mode to use. (There is also
the option to run as an “Application” which is not
available under the “Run” menu)

Trace can be turned on by checking the “Run in


Trace Mode” or “Enable Trace” checkboxes.

3.4.2 Development Approach


Since it is easy to switch back and forth between applet and servlet runtime, they can each be used when
needed. The Trace feature of the Applet is very useful, especially when first starting with Corvid or when
building logic with complex backward chaining.

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:

Color Todays_Date Price Country Length_of_beam Report

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.2 The Corvid Variables Window


Variables are added and edited in the Variables window. This can be displayed by clicking on the
Variables icon in the main Exsys Corvid window.

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.)

If the system already has defined


variables, they will be displayed in the
variable list on the left of the window.
To see the properties for a variable,
click on it to select it. The top set of
tabs displays properties for all
variable types. The lower set of tabs
show the special properties for the
Type of variable selected.

Make sure the Show Advanced


Options checkbox at the bottom of
the window is UNSELECTED.

The Advance Options are


discussed later in this chapter.

4.3 Adding New Variables


To add a new variable, click the “New” button at the top left of the Variables window, above the variable list.
This will open the “New Variable” window. The new variable must be given a Name and a Type.

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.

Names can only contain letters, numbers, a few


special characters and most non-English
characters. Spaces and tabs are not allowed in
names. Square brackets are used to indicate a
variable in expressions, but should NOT be
part of the variable name. When naming a
variable, any illegal characters (including spaces,
tabs and brackets) will be automatically converted
to the underscore character _.

To name a variable, enter the name in the “Name” edit box on the “New Variable” window.

For systems built in English, variable names should only include:

A-Z a-z 0-9 _ # $ and %

Variable names built in non-English character sets can include any characters
EXCEPT:

[ ~ ! @ ^ & * ( ) + = " ' > < . / : ; { } ? | \ ` ] - , <space> <tab>

The following are examples of typical variable names:

Color Todays_Date Price Country Length_of_beam Report

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.4 Variable Types


All variables must have a “Type” that determines what kind of data it can hold and what type of expressions it
can be used in.

Exsys Corvid supports 7 variable Types:

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.)

4.4.1 Static List Variables


Static List variables are just multiple choice lists. The variable has a set list of possible values, and the actual
value for a particular situation will be one, or more, of the values from the list.
For example, a Static List variable [Day_of_the_week] could have a value list of:

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.

4.4.2 Numeric Variables


Numeric variables are variables whose value is a number. The value is a “floating point” number, (e.g
123.456). Numeric variables are very similar to numeric variables found in many computer languages. They
are used in algebraic expressions and assignments anywhere a number can be used. For example:

[Price] < 10

[Area] = [Length] * [Width]

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.

4.4.3 String Variables


String variables are variables whose value is a text string. The value can be a string of any length. The String
variable value can be used in string expressions to build, test or parse strings with various Corvid string
parsing functions. For example:

[Name] = “John” + “ “ + “Doe”

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.

4.4.4 Date Variables


Date variables are variables whose value is a date with an optional time. Dates/times can be input by the end
user, determined by system logic or obtained from system clocks. Date values can be tested against other
dates, or generated with Corvid’s date functions. Options allow controlling the range that a date may occur in.

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.

4.4.5 Collection Variables


Collection variables are variables whose value is a list of text strings. Collection variables are only assigned
values - never directly asked of an end user. Typically, each assignment adds to the list of strings. Corvid
provides various options to add content to the Collection value list either in a sorted or unsorted manner. The
overall value of a Collection variable can be many pages of text. The text can be used to build a report, and
may include HTML or RTF content.

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.

4.4.7 Dynamic List Variables


Dynamic List variables are a special type of variable. They are rarely used and are primarily for advanced
product selection systems. Dynamic List variables are similar in most ways to Static List variables. They also
have multiple choice lists of values, but the possible values in the list are set at runtime, rather than during
development. The values in the list might come from a database, a spreadsheet, XML data or be determined
by the rules and logic in the system. For example, a product selection system for cars might give the user the
option to select the color they would prefer, but should only offer the colors of cars in stock. This could be
done with a Dynamic List variable that got its value list from a database call that would return the list of colors
of cars in stock.
Dynamic Lists can be very powerful, but make the system logic more complicated to build since it must cover
all the possible values that could be set. Dynamic lists should only be used when the actual multiple choice
options that you want to present to the user cannot be specified during development, but will be known at
runtime. Use a Static List variable in place of a Dynamic List whenever possible.

4.4.8 Selecting the Type of Variable to Use


Often the meaning of a variable, and the data it will hold, makes it easy to select a variable’s type. However,
occasionally multiple types would work and it can be confusing, especially when starting with Corvid. The
following are some pointers to use when having difficulty selecting a type:
! If the possible values are a specific list, use a Static List variable. This should always be the first choice
if possible. An exception would be if the variable will be asked of the end user and the list is so long that
it would be impractical to have them read all the possibilities. If the list of values changes frequently and
can only be known at runtime, use a Dynamic List - but this will make the system more complex to build.

! 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.

4.5 Setting Other Variable Properties


Once the new variable has been given a name and Type, click the
OK button on the New Variables window. The variable will be
added to the list in the variables window and automatically
selected. The two sets of tabs on the right side of the Variables
window allow setting other properties for the new variable.

Depending on the variable’s type and how it will be used, it may


require that various properties be set, or the defaults may be
adequate. The properties can always be changed later as needed.
Many of the properties are related to the end user interface and
how the variable will be asked of the end user. Others control how
the variable’s value(s) are set or limited. The top set of tabs are
properties for all variables. The lower set are properties specific to
the variable’s Type.

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.

4.6 Variable Properties by Type


When a new variable is added, the lower tabs will have the tab for the variable’s Type selected. Each type of
variable has specific options and limits that can be specified.
If the incorrect Type was chosen for a new variable, it can be immediately changed by clicking on the
correct tab. This will change the Type. This can only be done before the variable is used in the system logic.
Once the variable has been used, its Type cannot be changed.

4.6.1 Static List Tab


If the variable is a Static List variable, the Static List tab will be
selected in the lower tab group.
Static List variables have a specified list of possible values.
These are entered on this tab.
There can be any number of values. Some Static List
variables have only 2 value (e.g. “Yes” “No”). Others may
have many. There is no limit on the number of values. The
text for a value can be any length and use any characters.
To add values:

1. Enter a value in the Value edit box. The value


can be any text, but should combine with the
Prompt to make a question or a statement.
2. Press the “Return” key or click the “Add to List”
button.

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”.

Once values have been added to the list, they can be


reordered and changed using the buttons on the right
side of the tab.

Change a value: Click the value to select it. Enter the


new text in the Value edit box. Click “Replace”.

To Reorder the list: Click a value to move. Click the “Up” / “Down” button to move it in the list.

To Delete a value: Click it to select it. Click “Delete” to remove it.

To see where in the rules a value is used: Click it to select it. Click “Where”.

Optional Short Text


In addition to the full value text, there can be an optional short text for each value. This is only useful when the
value text is quite long, and using it in the rules would be cumbersome. In most cases, short text is not needed.
When building rules, Static List expressions look like:
VarName = Value
where the “VarName” is the name of the variable and “Value” is the value text. If the value text is very long, it
is convenient to have a short version that can be used in the rules:

VarName = Value Short Text

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:

[ ~ ! @ ^ & * ( ) + = " ' > < . / : ; { } ? | \ ` ] - , <space> <tab>

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.

There is a radio button for each of the 3


Types. (If the incorrect Type was selected
when the variable was added, it can be
changed before the variable is used by
clicking the desired radio button.)

Each type has options to limit the values that


will be accepted as user input. Limiting the
acceptable values simplifies the logic since
out of range or invalid values will be rejected at input and do not have to be caught in the system logic.
Invalid input is immediately rejected and the user will be re-asked to provide a value. (When limits are used, it
is important to indicate this in the user interface so that the end user knows what value range is expected and
understands if their input is rejected.)

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

? 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 { }

{V-Z} Matches any single character between V and Z

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:

! To match a Social Security number, use ###-##-####.


! To match a product ID number that must start with an X or Y, followed by a number between 1 and 5
and then any other numbers, use {XY}{1-5}*.
! To match a 4 character string starting with Z, use Z???.
(NOTE: This same mask syntax is used in various places in Corvid to indicate or select a group of
variables or blocks.)

Date Limits
Date variables can have limits set that the input is not more than X days in the past or future.

4.6.3 Collection Tab


If the variable is a Collection variable, the
“Collection” tab will be selected in the lower tab
group.
The value for a Collection variable is a list of
text strings. Collection variables are never
directly asked of the end user, so there are no
input limit criteria. Instead values are added to
the collection in the rules and commands. The
individual values added may be obtained from
the end user, external sources, system logic,
etc.
In some cases, it can be useful to preload the
Collection’s value list at the start of a session.
This can be done either by specifying the
values to use to initialize the value list, or
specifying an external source to get values from.
To enter initial values:
! Enter the value in the lower edit box in the “Initialize List of Values” section.
! Click the “Add” button.
! Repeat as many times as needed to build the list.
To delete a value in the list:
.
! Click on it to select it.
! Click the “Delete” button.

Preload from an External Source


Obtaining the value list from an external source is covered in the External Interfaces chapter 13.

Maximum Number of Items in Collection


Normally a collection’s value list can have any number of items (text strings) in it. However, if it is necessary
to limit this:
! Go to the “Allow Only a maximum Number of Items in Collection” section.
! Enter the maximum number of items to allow.
! Select what should be done if the maximum is reached - drop from top/bottom or report error.
NOTE: Setting the “External Source” and “Maximum” options require that the “Show Advanced Options”
check box on the Variables window be selected.

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.

A Confidence variable is intended to


calculate an overall confidence value for
the variable. Usually, this is used when the
variable represents a possible
recommendation or solution to the problem
that the expert system solves, and the
Prompt will be displayed as a
recommendation if the variable’s
confidence value is high.

Confidence variables can also be used in


other ways, but in all cases, the variable
will be given one or more numeric values
which will be combined via a formula to
produce the overall confidence value.

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.

4.6.5 Dynamic List Tab


If the variable is a Dynamic List
variable, the “Dynamic List” tab will
be selected in the lower tab group.

Dynamic List variables are similar to


Static List variables, but their value
list is set at runtime. They must be
given a source to get their value list
that can be used at runtime. The
source must be available when the
system is run either online or as a file
distributed with the system.

There are 3 options for setting the


value list.

Tab Delimited Spreadsheet


The value can come from a column in
a tab delimited spreadsheet. This is
often done when building Corvid MetaBlock product selection systems to limit the end users options to ones
that appear in the product data spreadsheet.

To do this:

! Select the spreadsheet file.


! Select the column heading of the column to use. The column heading is selected from the drop down
list which will be loaded with the column heading labels as soon as the spreadsheet file is selected.

Chapter 12 provides instructions and details on Corvid MetaBlock systems.

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.7.2 Deleting Variables


To delete a variable, select it in the list and click the “Delete”
button. Corvid will check to see if the variable is used in the
system. If the variable is not used, it will be immediately
deleted.
A variable being used cannot be deleted, the places it appears
must edited so that it is no longer used in the system. If the
variable is in use, a window will appear showing the places it
is used.
This list can be printed. Some uses of the variable can be
directly edited from this window by double clicking on the items in the list.
Uses of the variable in blocks cannot be directly edited this way, but can
by going to the “Where” option under the “Window” menu. Then select
the variable to delete.
This will bring up a similar list of where the variable is used, but in that
window double clicking will display the uses in blocks. Edit all the places
the variable is used. Then return to the variable window and the variable
will be able to be deleted.

4.7.3 Question Defaults


The “Question Defaults” and “Preview All” buttons allow setting, editing and testing default formatting options
to use when the variable is asked of the end user. These are covered in chapter 11 on User Interface.

4.7.4 Show Advanced Options


The upper tabs on the Variables window depend on the status of the “Show Advance Options” checkbox at
the bottom of the window. For most systems, the “Advanced Options” are not needed, and some options may
make Corvid more difficult to use.

The “Show Advance Options” checkbox should be UNSELECTED, unless


the system:
! Needs to call external programs or databases.
! Will be run with the Corvid Servlet Runtime rather than the standard Applet Runtime.
! Needs to run in multiple languages.

4: Variables 43
With the “Show Advance Options” unselected the following controls are still available.

4.8 “Options” Tab


The Options tab controls how the value for the
variable will be obtained, default values and
how backward chaining will be used.

4.8.1 Maximum Number of Values


that can be Assigned
If the variable is a Static List or Dynamic List
variable, the options for the number of values
that can simultaneously be set will be enabled.

The options are:

! Allow only a single value.


! Allow any number of values.
! Allow no more than X values.
If a single value or X values is selected and the system attempts to assign more than that number, it will be
reported as an error.
By default, Static and Dynamic List variables can have any number of values set, and for most systems this is
the best option. If only a single value should be allowed, and the variable will get its value by asking the user
for input, the controls used to ask can limit the input to a single value. (e.g. use radio buttons rather than
checkboxes to ask since only one radio button can be chosen.)

4.8.2 Variable Default Value


Variables can have a default value. When the end user is asked to provide a value for the variable, the
default value will be pre-selected (or pre-entered) so the user only needs to press the return key to accept the
default value. However, the default value can be changed by the end user if they choose to do so.
For Static List variables, the default is a single value and can be selected from the drop down list. For
Numeric, String and Date variable, the default value is a text string and it can be entered in the edit box.
When the “Never ASK - Use Default Value” checkbox is selected, the variable will NOT be asked of the end
user, and instead the default value will be used automatically. In this case, the end user will not have the
option to change the value.
The Default value is very similar to the “Initialize” value below it, but in that case the value is assigned to the
variable at the start of a run and the system rules may modify it. The default value is assigned when the
variable would be asked of the end user and is considered to be a “final” value that the rules would not usually
modify. (The Initialize option requires the “Show Advanced Options” be selected)

4.9 “Ask With” Tab


The Ask With tab allows setting the controls and
designing the screen that will be used to ask for
user input when running with the Corvid Applet
Runtime.

The Ask With tab is covered in the User Interface


Chapter, section 11.4.4.

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.

4.11 Advanced Options


If the “Show Advanced Options” check box is selected, many other
options become available.

These are primarily for:


! Calling external programs or databases.
! Running with the Corvid Servlet Runtime rather than the standard Applet Runtime.
! Running in multiple languages.

Prompt Tab
With Advanced Options on, the Prompt tab has
options for:

! Calling an external program or database


that will return the text to use for the
prompt. This is covered in chapter 13
on External Interfaces.

! Alternate Prompts 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 text.

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.

If an existing system uses “To Be” commands, this


tab will be active and can be used. For new systems
or systems not already using “To Be” commands, the
tab will be inactive.

Options Tab
With Advanced Options on, the Options
tab has additional controls for setting a
variable’s value and controlling backward
chaining.

Backward Chaining Controls


The options in the “Backward Chaining”
group provide ways to control how
backward chaining is used for this
variable.

Backward chaining can be controlled in 3


ways, which can be specified individually
for each variable. A variable can be set to:
! Stop backward chaining as soon as any value is assigned to it - even if there are other rules that could
be tested.

! 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.

Final Results Display Flag


The Final Results Display Flag was originally used to select specific variables to be displayed in a systems
results screen. It can still be used this way (see User Interface section), but can also be used as a way to
select a group of variables for other actions such as in the DERIVE command to start backward chaining.

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.

After Ask Commands


After Ask commands are external interface commands that are automatically executed after the value of the
variable is asked of the end user. Normally these are database commands that write the user input to a
database so a session can be broken off and restarted later. Using the After Ask command is covered in the
external Interfaces section 13.2 and the “How To” on Save and Restore User Input.

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.

[Area] = [Length] * [Width]

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:

Name Prompt Values

Color The color of the light is red


yellow
green

Rain It is raining: Yes


No

Day_of_the_week Today is Monday


Tuesday
.....
Sunday

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.

Static List statements will be either:

variable_name = value

variable_name = value1, value2, value3 ....

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.

5.3.1 Static List IF Statements


When the statement appears in the IF part of a rule it is a boolean test. The statement will be true if the
variable has the specified value set. When there are multiple values in the statement, it will be TRUE if ANY
of the values is set. (The values are combined using logical OR)

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.

5.3.2 Static List THEN Statements


When the statement appears in the THEN part of a rule it is an assignment of one or more values to the
variable. When there are multiple values being assigned, they are ALL assigned (The values are combined
with AND). When Static List statements are viewed in the Rule View, the prompt text and all assigned values
will be displayed, with the values separated by “AND”.

For example, in the THEN part of a rule:

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.)

5.4 Continuous Variables - Numeric, String, Date


The “Continuous” variables in Corvid are Numeric, String and Date variables. In the Variables window, these
are all found on the “Continuous” tab. The syntax for building IF and THEN statements with these are all
basically the same, and very similar to other programming languages and algebra.

5.4.1 Continuous Variable IF Statements


IF statements built with numeric, string and date variables are just Boolean tests using algebraic expressions
that can include Corvid variables. There is a left side value, a comparison test and a right side value. The
expression will evaluate to TRUE or FALSE. For example:

[X] < 5 The value of variable X is less than 5.

[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:

Comparison Test Meaning

= 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.

Greater Than or Equal


Numeric: Left side is greater than or equal to right side.
>= String: Left side is alphabetically greater than or equal to right side*.
Date: Left date is chronologically greater (later) than or equal to 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 Occurs in Another String


IN String Type ONLY.
Left String occurs in the right string - Case Sensitive.

* 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:

[X] = ( [Y] + [Z] ) / 2

54 5: Expressions
5.4.5 Numbers
Numbers in expressions can be:

! Decimal numbers (typical numbers with a decimal point).


! Integers.
! Exponential numbers base 10 (1.2e3 evaluates to 1200) Useful for very large or very small values.

5.4.6 Constants
The following constants can be used in expressions:

Constant Value

PI 3.14159...

TRUE Logical TRUE

FALSE Logical FALSE

TAB The tab character

CR The Carriage Return character

LF The Line Feed character

CRLF The Carriage Return and Line Feed


characters

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.

5.4.7 Logical Operators


More complex boolean tests can be built up by using logical operators to combine other individual boolean
tests. The logical operators and parenthesis behave the same as in many other computer languages. The
logic operators are:

Operator Meaning

& Logical AND

| (vertical pipe) Logical OR

! Logical NOT

For example:

( [X] > 0) | ([Y] > 0) TRUE if either X or Y is greater than 0.

( [X] > 0) & ([Y] > 0) TRUE only if both X and Y are greater than 0.

! ( [S] IN “abcd”) TRUE if S is not a substring of “abcd”.

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

^ Exponentiation (3^2 is 3 squared)

% Modulo - Remainder after integer division (7 % 3 = 1)

5.4.9 Continuous Variable THEN Statements


Continuous variable assignments in the THEN part of rules are quite simple. Any expression can be assigned
to any continuous variable provided the type matches. The syntax is:

[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

[NOTE] = [NOTE] + “ One more thing”

5.4.10 Date Variable Assignments


Date variables can be assigned either:

! A date type value. (e.g. another date variable)


! A function that returns a date. (e.g. NOW() )
! A string that is in a date format.
! A number that will be taken as the milliseconds past Jan 1, 1970.

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)

5.5 Confidence Variables


Confidence variables are used to calculate an overall confidence or probability value for whatever the variable
represents. This is typically the likelihood that a particular diagnosis or action is correct, or an item should be
recommended. Confidence variables are used to build systems that can consider many options and rank
them based on potentially competing factors.

5.5.1 Confidence Variable IF Statements


The value of a Confidence variable is a number and can be used any place that a Numeric variable could be
used. The same options for expression syntax and functions that apply to numeric variables apply to
Confidence variables.
For example, if there are Confidence variables [CONF1] and [CONF2] and numeric variables [X] and [Y], the
following could be used as IF statements:

[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.5.2 Confidence Variable THEN Statements


Unlike numeric variables, where an assigned value overwrites previous values, Confidence variables combine
ALL the values they are assigned to produce an overall value. The way multiple assigned values are
combined is controlled by the variable’s Confidence Mode. The various confidence modes and how values
are combined is covered in the Variables chapter section 4.6.4.
Each Confidence variable has an associated Confidence mode that controls what range of values can be
assigned to the variable and how they will be combined. Some modes (e.g. Independent and Dependent
Probability) expect values between 0 and 1. Other can accept any value. Assigning a value that is out of
range will result in a Runtime Error.
The statements to assign a value to a Confidence variable are just the same as assigning a value to a Numeric
variable. Any expression that evaluates to a number (in the correct range) can be used. For example:

[CONF1] = 5 (Combine the value 5 with other values assigned to CONF1)


[CONF1] = [X] (Combine the value of X with other values assigned to CONF1)
[CONF1] = [CONF2] (Combine the value of CONF2 with other values assigned to CONF1)

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 an IF statement, it is


usually to test if a particular string is in the list. This is done
when building Logic Blocks, and Corvid will help you build
syntactically correct commands. For a collection variables
the window looks like:
Just select the type of test and enter the value to use in the
test. For example, if you want to know if “abc” is in the list,
select “Contains” and enter “abc” in the edit box. Corvid will
build the command for you. If the Collection variable was
named “COL”, the actual command built would be:
[COL.includes abc]
The “.includes” following the variable name is a “Property” for Collection variables that tests if an item is
already in the list. Collection variables have many methods and properties for working with the value list.
The property “.includes” and the value being tested are all in the square brackets, and will evaluate to TRUE
or FALSE. (These boolean tests can be used in larger, more complex expressions.)
If the test was to check the top item in the list, click “Top item is” and enter the “abc” value to check. This time
the command built will be:
[COL.first] = abc
This time the ‘first” Property of the Collection is used. Properties are a way to get additional information about the
variable. The “.first” property returns the first item in the value list. Here, we check that against the test string “abc”.
The other types of Corvid variables also have Properties that allow you to get additional information about the
variable or give you additional ways to use the variable. These are discussed in detail in Appendix B.

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.

The details of Collection variable Methods are covered in Appendix A.

5.7 Dynamic List Variables


A Dynamic List variable is very similar to a Static List variable, but the list of possible values is not set until
Runtime. Because of this, during development, the value list is not known and can not be used to build IF
and THEN statements. This limits the types of statements that can be built.
Dynamic List variable statements must be written as expressions. The name of the dynamic list variable in
square brackets will be evaluated to the text of the value, so expressions can be written that test the value
against specific text. For example, a dynamic list variable “DL” could have an IF statement:
[DL] = “abc”

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:

[S2] = LEFT( [S1], 5)

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.

5.9 Double Square Bracket Embedding - [[Name]]


Corvid supports a simple, but extremely useful technique called double square bracket embedding.
Any string, command or expression in a Corvid system can have the value of a
variable (or Property) embedded into it, by simply putting the name of variable in
double square brackets.
That sounds minor, but it is the key to many advanced techniques in Corvid, and can greatly simplify building
some Corvid expressions.
For example, suppose a system has asked the end user’s name and have it in a variable [NAME], and we
now want to ask their favorite color. We could just have a variable with the prompt text:
“What is your favorite color?”
But if we could make the prompt:
“[[NAME]], what is your favorite color?”
Now when this question is asked, their name will automatically be added to the prompt text.
This technique can also be used when adding content to a report. If there are variables [Day_of_week] with the
day of the week and [Temp] with the temperature, a report in a Collection variable could have the string added:
Today is [[Day_of_week]] and the temperature is [[Temp]].
By using embedded variables a single string can be added to the report that includes both text and variable
values. Systems can build blocks of content that are then embedded into templates to build reports.

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]

will not work since assignments must be of the same type.

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.

Double Square Brackets and Backward Chaining


When Corvid encounters an embedded double square bracket value in text it is trying to display, or in
expressions it is evaluating, it IMMEDIATELY needs to determine the value of the embedded variable.
Backward chaining is used to derive the value. This may cause other rules to be used that will require asking
other variable values, etc. Unless this is planned for, it may not be apparent why these other variables are
being asked. However, this can be very useful and template files with embedded variables can be used to
actually drive the system to set the values.
For example, if the prompt of a [Color] variable is:

“[[NAME]], what is your favorite color?”

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.

5.10 Variable Properties - [Name.value]


All Corvid variables have a value, and usually that is what is needed when building expressions. The
assignment:

[X] = [Y] + 1

means assign the value of [Y] plus 1 to the variable [X].

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]

Some properties have additional arguments and the form is:

[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”:

[Temp] will be replaced by “75.3”.


[Temp.Full] will be replaced by “The temperature is 75.3”.
[Temp.Format ##] will limit the value to 2 digits and be “75”.
[Temp.Pformat ##] will include the prompt with 2 digits - “The temperature is 75”.

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:

[S] = “ [[Temp.Pformat ##]] “”

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.

5.11 Expression Syntax Checking

When an expression is added, Corvid checks the


syntax to make sure it is correct.

If an error is detected in the expression syntax, a


warning widow will be displayed showing the error
detected.

The expression can be modified in the edit box and


then rechecked by clicking the “Recheck” button. If the
expression is then syntactically correct, it will be
accepted and used.

The edit window has “Variable” and “Function” buttons


to display the lists of variables and function, and help
build the command.

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.

If the expression includes double square bracket


embedding of variable, or embedded XML, the
expression checker does not know what the replaced
value will be and cannot parse it. Any expression
with [[..]] must be used “As Is”, but should be
carefully checked to prevent runtime errors.

Among other things, the Syntax Checker detects


undefined variables. It is best to define all variables before they are used in expressions. An expression with
undefined variables can be accepted by clicking the “Use As Is” button, but be sure to add the variable before
the system is run.

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:

# a sub-expression that evaluated to a numeric type.


$ a sub-expression that evaluated to a string type.
@ a sub-expression that evaluated to a date type.

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.

6.2 Forward Chaining


Part of the problem in understanding backward or forward chaining, is the terminology. There is nothing really
“backward” about backward chaining or “forward” about forward chaining. The terms have a long history
going back to the early days of expert systems in the 1980s. Unfortunately, despite being somewhat
confusing, the terms have stuck and are the ones commonly used.
Rather than thinking of “Backward” or “Forward”, it is better to think of how each approach uses the rules in a
system. Forward chaining is based on the sequential order of rules. The first rule is tested, and potentially
used, first. Then the next rule, then the next, etc. The rules used this way may be limited to those that come
from a particular Logic or Action Block, or may be all the rules in the system.
As rules are used in forward chaining, they may require asking the user for variable values to determine if the
IF tests are true, and rules that “fire” may set the values for other variables. The forward chaining, “Order
based” approach is much more like traditional programming since the inference engine just steps through the
If/Then rules in order and uses them as appropriate. It is quite easy to know what rule will be used next and
when particular variables will be needed. This generally makes the forward chaining “Order based” approach
easy to understand and visualize. This is particularly true of developers with a programming background who
expect their “code” to be executed in order. Many systems can be built this way, but it does not make use of
the real power of the Inference Engine.

6.3 Forward Chaining Limitations


Forward chaining is a very procedural and order dependent way to approach problems in steps. It is an
approach that can be implemented without any “inference engine”. When someone follows instructions to do
something, they are done in steps - first step first, second step next, etc. At step 3 the instructions do not
suddenly assume that you have done something from step 10 and then returned to step 3. There are vast
numbers of procedural operations that can be converted to forward chaining systems in Corvid - from baking
cookies to fixing jet engines. Forward chaining works well for converting these procedural operations to rules.
However, Corvid systems that capture decision-making knowledge of how an expert solves a complex
problem sometimes cannot be described the same way using sequential steps.
Corvid is based on If/Then rules that describe aspects of making a decision. These are built, arranged and
structured in Logic and Action blocks, but here we will just look at the rules themselves regardless of how they
are built.

6: Forward and Backward Chaining 65


In Corvid:

! 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).

Suppose there are just 2 rules:

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.

One solution is to change the first rule to:

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.

66 6: Forward and Backward Chaining


No matter how they are arranged, they may not work ideally as a forward chaining system - and that is just
with 2 rules. A real system may have hundreds of rules with many internal interrelationships. Creating a rule
order that can be run sequentially may be impossible. Also, forcing an order for procedural reasons and
adding extra conditions may make the rules difficult to understand and maintain, or repetitive.
When handling the actual process of how a decision is made by an expert, this type of logic is quite common.
A typical rule is:
IF
The customer has high risk tolerance
AND: Meeting objectives requires rapid growth
THEN
Mutual Fund X is a good choice
This is high level logic, but the system should not directly ask the user about their “risk tolerance” or
“objectives” since the end user may not be able to reliably answer those questions. Instead these should be
derived from other rules, but now there are the same internal interrelationship issues as with the 2 rule
sample above. What questions should be asked to derive values, when are they needed or not appropriate,
how should the rules be arranged. It can get very complicated very quickly. Fortunately backward chaining
solves this problem and makes it very easy to handle.

6.4 Backward Chaining


Backward Chaining is “Goal Driven”. This means that rather than running the rules in sequential order, the
Corvid Inference Engine is given a “Goal” to achieve. In Corvid, a “Goal” is always determining the value
for a variable. The Inference Engine examines the full set of rules to determine which ones can assist it in
achieving the current goal by assigning a value to the goal variable. The only rules that matter at the moment
are those that can potentially set a value for the goal variable by assigning a value to the variable in their
THEN part.
These are the only rules relevant to the immediate “Goal” and all other rules are, for the moment,
irrelevant to the “Goal” and are ignored. The Inference Engine will only test the relevant rules, even
though this may mean skipping over many “irrelevant” rules. The Inference Engine will test and use rules
based on its need to achieve “Goals” rather than the order that the rules were written in.
Programmers that are used to procedural approaches to writing systems may at first find this confusing and
unexpected. This is because with backward chaining, the Inference Engine does much of the work rather
than depending on sequential rule order.
Looking at the example from above:

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.

6: Forward and Backward Chaining 67


This happens to be the first rule, but the same rule could be anywhere in a system and work the same way.
To determine if this rule is true, the inference engine tests the first IF condition and needs the value of [X].

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.

68 6: Forward and Backward Chaining


Forward Chaining Order Rules used in sequential order
Driven

Backward Chaining Goal Driven Rules used based on relevance to


“Goals”, which change dynamically

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.

6.5 The Big “To Do” List


Backward Chaining is all based on a dynamic Goal List. One way to think of this list is as a “To Do” list made
up of a stack of sticky notes. Items can be added to the top of the stack, and when they are “done” they get
peeled off so that the next item in the list becomes the focus of attention.
In Corvid, the “Goals” in the “To Do” stack are always Corvid variables.
The Inference Engine is completely focused on assigning the value to the variable that is on the top of the
goal list “To Do” stack.
Whenever the goal (Variable) on the top of the “To Do” stack changes due to adding or removing a goal, the
Inference Engine immediately switches whatever it was doing to trying to assign the value to the new top variable.
To assign the value to the goal variable, the Inference Engine looks through all the rules in the system to find
any that would assign a value to the variable in the THEN part of the rule. Those rules become the “relevant”
rules and are the only ones tested for that goal variable.
If testing a relevant rule requires the value of any other variable either to test an IF condition or, when a rule
fires, to make an assignment, and that variable does not already have its final value assigned, that other
variable is put on the goal list as the top item in the “To Do” stack. Determining value to that new goal
variable, immediately becomes the focus of the Inference Engine. Processing of all other rules is temporarily
suspended, and only the rules “Relevant” to the new variable are tested.
If a “Relevant” rule for the top goal variable is found to be TRUE, the value will be assigned to the goal
variable, and any other THEN assignments in the rule will also be made, even though they do not involve
the goal variable. If any of the assignments require the value of other variables that do not have a value
assigned, those will be put on the top of the Goal list and become the focus of the Inference Engine.
If all the “Relevant” rules for the top goal variable are found to be FALSE, and a value cannot be assigned, the
Inference Engine will first check to see if there are any external data sources associated with the variable. If
there are, those will be used. If there are none, the variable will be asked of the end user via the user interface.
When a goal variable is assigned a value, either by its “relevant” rules, external data or asking the user, it will
be removed from the goal list “To Do” stack and the next variable down in the stack will become the top goal.
Since the top goal will have changed, the Inference Engine will immediately focus completely on assigning a
value to that variable. Since the other variables that were above it in the goal list were added previously in
the process of trying to assign a value to this variable, it will automatically return to the same point in the rules
but with additional variable values to use. This may now lead to being able to assign a value to the variable,
or may lead to other variables being added as the top level goals.
The Goal List “To Do” stack is constantly changing. Since variables are added based on the immediate need
for the variable’s value to achieve the lower level goals, the rules are used in a very focused way, with all
questions asked of the end user based on the need to get values to meet top level goals. Irrelevant variables
are automatically blocked and not asked or derived.

6: Forward and Backward Chaining 69


6.6 Another Example
To see how backward and forward chaining differ in how they use rules, lets look at another very simple 2 rule
system. The rules are:

Rule 1:
IF
Weather is COLD
THEN
Wear a Coat

Rule 2:
IF
[Temperature] < 32
THEN
Weather is COLD

These rules use:

! 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.

70 6: Forward and Backward Chaining


5. Now the Inference Engine has a new Goal, [Weather], so it suspends what it was doing to try to
immediately meet this new goal. It checks all the rules to see which are now relevant to this goal -
meaning it is assigned a value in the THEN part of the rule. The only one it finds is rule 2.
6. The Inference Engine tests the IF conditions of the “relevant” rule. To do this, it needs the value of
[Temperature], so [Temperature] becomes the new top level goal, pushing the others down in the list.
The goal list at this point is:
[Temperature]
[Weather]
[What_to_wear]
7. Since it has a new goal, it again looks for the rules relevant to this goal. There are no rules that assign
a value to [Temperature]. In Backward Chaining, when a variable is needed, but has no relevant rules
(or all relevant rules have been tested and found to be FALSE), the Inference Engine will:

! 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.

6: Forward and Backward Chaining 71


6.7 Rules and Logic Blocks
All Corvid systems, whether using backward or forward chaining, use the same rules that are built in Logic
and Action blocks. Each rule provides an individual “heuristic” - a single step or factor to use in making an
overall decision.

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.

72 6: Forward and Backward Chaining


Chapter 7: Logic Blocks - Controls
7.1 Rules and Logic Blocks
Corvid systems are defined by If/Then rules that describe the logic and process of a decision-making task.
The Corvid rules are similar to the way the steps would be explained to another person, but must be written
using the Corvid variables and expression syntax covered in Chapters 4 and 5.

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.

The rules should cover all the decision-making


factors in a system. They should explain how to Logic Block rules tell the system HOW to do things.
resolve each potential decision point in a Command Blocks tell the system WHAT to do.
system. However, they are NOT the procedural
steps to execute the system. Rules determine how to make decisions and derive facts in a system.
Command Blocks control how the rules will be used to perform a task. Command Blocks are covered in
Chapter 9.

7.2 Rules as Trees


Normally related rules are all in the same Logic Block. If rules share same high level IF tests, they can be
combined in a tree structure that will organize and structure the logic.

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

7: Logic Blocks - Controls 73


This is a valid rule, but what if “Test 1 = False”? The expert may say that then, Test 2 has to be examined,
and if that is True, the Result would be “B”.

IF
Test 1 = False
AND Test 2 = True
THEN
Result = B

And what if “Test 2 = false”, the expert may say:

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.

The first 2 lines are equivalent to the rule:

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.

74 7: Logic Blocks - Controls


At the same time, Corvid will display a Rule View window showing
the full text of the selected rule.

The Logic Block representation of the 3 rules is much more


compact and shows the structure of the rules. The rules cover all
possible combinations of values for Test 1 and Test 2. If any had
been left out, it would be easy to see in the tree structure (and
Corvid would highlight it).

7.3 Multiple Logic Blocks


If you have a programming background, at this point you may be thinking, “For any complex problem the
tree will get enormous and totally unmanageable.”. That would be true if the tree was procedural code with
deeply nested IF statements. However, Corvid Logic Blocks are just a way to organize individual, related
rules - not the logic for the total problem. A real system will have many Logic Blocks, each of which will
describe the rules for a portion of the problem. The Logic Block can be a fairly small, complete, consistent
set of logic that does one specific task. The Inference Engine will use the rules from the Logic Blocks as
needed, to solve the overall problem.

In Chapter 2, we had a high level heuristic 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.

7: Logic Blocks - Controls 75


7.4 Creating a Logic Block
Logic Block windows are used to create and edit Logic Blocks.
To open a new Logic Block window, click the “L” icon in the main
Exsys Corvid control bar.

The new Logic Block window will be displayed.

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.

Whenever an IF or THEN statement in the Logic Block is selected,


the corresponding rule (or portion of a rule) will be displayed in the
Rule View. (If the Rule View window is closed, it can be reopened by
selecting “Rule View” from the Corvid “Display” menu).

7.4.1 Logic Block Name


Each Logic Block has a name. When they are created, it will be “Logic Block #”, where # depends on the number
of Logic Blocks in the system. The first one will be “Logic Block 1”, the second “Logic Block 2”, etc. While this is a
valid name, it is generally better to give the block a name more representative of what the rules in it do. If this was
a Logic Block for the rules that would determine “Risk Tolerance”, it could be named that. To change the name,
click on the “Edit Name” button next to the name and enter the new name in the window displayed.

Logic lock names can be any text, but must be unique. They should be fairly short and easy to recognize.

7.4.2 Editing Existing Logic Blocks


If there are already other Logic Blocks in the
system, they can be displayed for editing by
clicking the name drop down control and
selecting the block to edit.

76 7: Logic Blocks - Controls


There can be multiple Logic Block windows open
at the same time, but a specific Logic Block can
only be open in one window at a time. To open a
new Logic Block window, just click the “L” icon in
the control bar.

The new window can either be a new Logic Block,


or an existing one can be selected from the name
drop down list. (When selecting an existing block,
if that block is already in an open window, that
window will be moved to the front, rather than
opening a second window for it.)

7.5 Building Rules in the Logic Block


Typically, a Logic Block will have a group of related rules that perform a portion of the overall decision-making
task. While these could be structured as individual rules, the real benefit of a Logic Block comes from
structuring the rules in tree diagrams. This is faster, more maintainable and makes the overall logical
structure easier to visualize.

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

7: Logic Blocks - Controls 77


When there are many nodes and many levels of indentation, it can be a little
difficult to see which nodes are associated, but clicking on any node in the
tree will highlight the parent nodes. All of the highlighted IF nodes will be
combined with AND to build the associated rule.

Building a Logic Block is a matter of taking the decision-making rules of a


problem and putting them in tree form that represents the logic in an
organized and complete way.

7.5.1 Adding the First Node


Nodes are added to the tree using the controls in the lower left of the
Logic Block window. When a new, empty Logic Block is created, the
only button active is the “Add” button, since the only option is to add the
first node.

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.

7.5.2 Adding Subsequent Nodes


Once the first node(s) in a Logic Block are added, the other controls for adding nodes become active.
Logic Blocks have a tree structure based on “parent” nodes. A node, plus
its parent nodes builds a rule.
The controls allow adding Parent or Child nodes to build the needed rule
structure. Sometimes it is desired to add a node at the same level in the
tree to build an independent block of rules that are based on the same
parent nodes.
The “AND” group has “Below” and “Above” buttons which add nodes that
are ANDed with the currently selected node.

78 7: Logic Blocks - Controls


IF - AND - Below
“Below” will add a child node(s) indented in from the currently selected node to produce nodes that
are ANDed together. If there are already child nodes of the currently selected node, they will become
to be child nodes of the first node added.

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.

7: Logic Blocks - Controls 79


2. Going back to the original “Today” nodes. This time click IF-AND-Above
and add the same group of 2 “Weather” nodes.

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.

7.5.3 Multiple Trees


Notice that when the “Same Level” buttons were used, the structure of the Logic Block is no longer a
traditional tree, but now 2 separate trees - one based on [Weather] and once based on [Today]. At the
moment these are just 2 pairs of nodes, but each of these could be built out to its own tree.
A good way to structure a system is
for each Logic Block to have all the
A Logic Block can contain multiple trees, or trees and
logic (rules) related to some aspect of
individual rules. All of the rules relevant to a portion of a
the overall problem. This may be a decision can be in the same Logic Block.
single simple tree, or may require
multiple trees. Some developers
prefer to have a single tree in each Logic Block and have more logic Blocks, others prefer to put multiple
trees in a Logic Block. Either way will work and is correct. It is all a matter of how the developer prefers to
build the system.

7.5.4 Adding THEN Nodes


Adding THEN nodes is actually much easier than adding IF nodes. Just click the IF node that is the last IF
node in the rule to build, and click the THEN-Variable button. Add one or more THEN assignments and they
will be added to the Logic Block indicated by an arrow icon.

80 7: Logic Blocks - Controls


If we take the Logic Block above and click on the ”Today = Weekend”
node. This highlights the “Weather = Sunny” node to indicate it is an IF
statement in the same rule, and the 2 nodes are ANDed together to build
the full IF part of the rule.

Clicking the THEN-Variable button and adding a THEN assignment for a


Confidence variable “Go to the beach” would add a THEN node to the tree.

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:

Dark Blue Static List

Light Blue Numeric, String, Date

Yellow Confidence

Green Dynamic List

Magenta Collection

7.5.5 Using a Right Click


Doing a Right Click on a node will select that node
and display a menu of options for that node.

Just select the action to take from the drop down


menu. This is a convenient and fast way to add
nodes. The menu actions are exactly the same as
clicking on the corresponding buttons in the left side
of the Logic Block window.

7: Logic Blocks - Controls 81


7.6 Adding Nodes
When the buttons for adding nodes to the Logic Block are clicked, the “Add to Block” dialog window is
displayed. This window is used to build both IF and THEN nodes. It can build groups of nodes to add,
making it easy to simultaneously add sets of nodes that cover all possible values.

The window has 3 main parts:

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.

7.6.1 Selecting the Variable


The first step in building a node is to select the variable to use by clicking on it in the top left list. This is
particularly important for Static List and Collection variables since they will set the correct tab on the right. All
other variables are built using the “Expression” tab, but clicking on the main variable to be used will copy it
into the Expression edit box.
When a variable is selected, the Prompt for that variable will be displayed in the text box below the list. This
allows checking that it is the correct variable if there should be any doubt.
The lower left section of the window has controls to limit the list. By default the list should show all variables.
If the desired variable is not displayed, turn off the limitations to see more of the full variable list.

82 7: Logic Blocks - Controls


7.6.2 Static List Variable IF Nodes
Static List variables are the easiest to use when building groups of IF nodes because they have a fixed set of
possible values. Normally, the group of IF nodes will have a node that covers each of the possible values -
though this is not required and sometimes only a single (or smaller group) of values needs to be built. If a
value will not have any logical meaning, it does not need to be added.
Static list nodes in the Logic Block are made up of the name of the variable, an equal sign “=” and one or
more of the possible values.
Today = Fri
In the IF part, nodes are tests that evaluate to TRUE or FALSE. The node will be TRUE if the specific value in
the node has been set. It may have been set by user input, other rules in the system, external interfaces, etc.
When the rule is tested, the Corvid Inference Engine will attempt to obtain or derive the value for the variable,
or will ask the end user for the value.
If there are multiple values in the IF node (e.g. Today = Sat OR Sun) The values are combined with OR.
The node will be true if ANY of the values has been set.
Adding Static List nodes is easiest to see with an example. Suppose
there is a Static List variable named “Today”. The prompt is “Today is”.
The values are:

Clicking on the variable “Today” in the


variable list on the left will bring the “Static
List” tab to the front and load the variable’s
values.
If the variable has both Short and Full text for
the values, the value list will display the short
text. In that case, to see the full text, click the
“Show Full Value Text” checkbox.

With a Static List variable, usually a group of


nodes will be built that cover all of the
possible values. The individual nodes can
contain one or more of the values, but the full
group will include all the values.

7: Logic Blocks - Controls 83


Adding One Node for Each Value
The easiest way to do this is when there will be a node added for
each individual value. This is used when there are different rules
that apply to each value, and each must be handled individually.

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.

Grouping Values in Nodes


The logic of the system dictates how the values should be grouped into nodes. Values that are logically
equivalent, and will have the same rules, should be combined in the same node. Otherwise, the Logic Block
will need to have duplicate logic under each of the equivalent nodes. (This is not illegal, but it is poor design
and makes maintenance more difficult.)

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.)

2. Click “Add to List”.

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.

84 7: Logic Blocks - Controls


The node will appear in the “Nodes to Add” list and the values used
will be removed from the upper value list. This helps make sure all
values are covered. When there is nothing left in the upper value list,
the nodes cover all the possibilities.

NOTE: A shortcut to select values and add them to the “Nodes to


Add” list is to:

! Double click on a single value to add it as a node.

! Select a value and Shift-Double Click on a second value to add


that block of values as a node.

! Select multiple values with Ctrl-Click, then Ctrl-Double Click the


last value to add the values as a node.

To add Mon, Tues and Wed as another single node, select the 3 values.

Click “Add to List” to add that node.

No there are only 2 values left in the value list.

These could be used to build nodes the same way, but it is


quicker to use the other buttons.

Clicking the “Add All in One Item” will add all the remaining
values into one node.

7: Logic Blocks - Controls 85


This would create a third node with Thurs and Fri in it.

If instead the “Add Each Individually” button had been clicked.

It would add an individual node for each of the remaining values.

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.

86 7: Logic Blocks - Controls


Removing Nodes from the “Nodes to Add”
To remove a node from the Nodes to Add list, select the node and click the
“Remove” button. This will remove the node from the list and add any values
used in that node to the list of values at the top of the window.

(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.)

7.6.3 Static List Variable THEN Nodes


Static List variable nodes for the THEN part of rules are built
almost exactly the same as IF nodes. The difference is that the
node will be an assignment of value, rather than a test of a
value. This means that typically only a single node will be
created and it will assign a single value. However, multiple
values can be assigned and when this happens the values are
combined with AND - meaning that all the values will be set.
Only the “Add to List” button is active, since typically there will
only be a single node for the variable and a single value
selected.
Multiple nodes can be added simultaneously to the same
THEN part of a rule, but they will normally be based on
different variables.

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.)

7.6.4 Expression IF Nodes


Expression IF nodes are any boolean expression. They can use any type of
variable, functions, operators, properties and double square bracket
embedding covered in the chapter on Expressions. This provides a great
deal of power and flexibility, especially when working with numeric, string,
date and confidence variables.

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

7: Logic Blocks - Controls 87


can be repeated building as many expressions as needed in the “Nodes to Add” list. Normally, multiple
expressions will be built that cover the range of possible variable values. These will then be added to the
Logic Block as a group by clicking the “Done” button.
Expressions are usually just standard algebra. They are very similar to writing boolean expressions in many
computer languages. The syntax for Corvid expressions was covered in Chapter 5 on expressions.
Variables in expressions are indicated by the name of the variable in square brackets [name] or
[name.property] if a property of the variable is being used. (The complete list of variable Properties is in
Appendix B.) When just the variable name in square brackets is used, it means the value of the variable.
For example: if there is a numeric variable named WEIGHT, there could be an expression:

[WEIGHT] < 100

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:

sin( [X] ) <= cos( [Z] / ( [A] + [B]) )

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.

A few properties require a numeric parameter.


These have a # in the property. If one of
these is selected, fill in the value of # in the
edit box below the properties.
The variable will be added to the expression
editing box at the current cursor point, in [ ].

The list of variables can also be displayed by pressing Ctrl-Alt-V.

88 7: Logic Blocks - Controls


Functions Button
Clicking the “Functions” button brings up a
list of all the Corvid functions. The function
list includes numeric, string and date
functions. The arguments to the function
are included along with a brief description of
the function.
Select the function needed and click OK, or
double click on the function. The function
will be added to the edit box at the cursor
point and can then be edited.
Functions that have arguments will have
placeholder arguments added. These can
be replaced by the actual values, which can
be fixed values, variables or other
expressions - provided they are the correct
type (numeric, string, date)

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.

7: Logic Blocks - Controls 89


Now add the last node for [Temp] <= 50 and click “Add to List”.

This puts all the nodes in the “Nodes to Add” list.


Click “Done” to add the group to the Logic Block.

7.6.5 Expression THEN Nodes


Expression THEN nodes assign a value to a numeric, string, date or confidence variable. The syntax is just:

[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

[X] = 123 Assign [X] the numeric value 123

[X] = sin( [Y] ) Assign [X] the value of the sin([Y])

Assign [S] the string “abc” (sting value must


[S] = “abc” be in quotes)

90 7: Logic Blocks - Controls


Node Meaning

Assigns [S] the string value of [S2]


[S] = [S2] + “abc” concatenated with “abc”

Assign [S] the value of numeric [X] converted


to a string (Double square brackets will
[S] = “ [[X]] “ embed the value of [X] within the quotes -
making it a valid string

[D] = now( ) Assign [D] the current date and time

[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)

The following are NOT legal assignments:

Node Problem

Assigning a string value to a numeric variable. Use double


[X] = [S] square brackets: [X] = [[S]] (but the string value of [S] must
be a valid number)

Assigning a string value to a numeric variable. Remove


[X] = “123” quotes.

[S] = abc abc is not a string - add quotes “abc”

[S] = [S2] + 1 Combines string and numeric values

[S] = [X] Assigning a numeric value to a string variable

[D] = now( ) + 3 Attempt to combine a date (now()) with a numeric

[D] = Jan 5, 2010 Assigned value must be in quotes

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.

7.6.6 Collection Variable IF Nodes


Collection variables have a value that is a list of text strings. The list can be a single item or can include many
items. Collection variables are very useful for building reports and other free-form dynamically created text.
Collection variables are not often used in IF nodes, but it is legal to do so. The IF node boolean expression
must test the value list in some way, testing either the content of the list or the number of elements in the list.

7: Logic Blocks - Controls 91


When a Collection variable is selected in the “Add to Block” variable
list for an IF node, the “Collection” tab is selected. There is an edit box
to enter a text string and 4 boolean test options are available:
! The value list contains the string.
! The value list does not contain the string.
! The string matches the first item in the value list.
! The string matches the last item in the value list.
These tests will evaluate to TRUE or FALSE. The nodes created by
the Collection variable IF node builder are actually expressions using
Collection variables properties.

The properties are:

Properties Meaning

TRUE if the collection [COL] value list includes string “str”,


[COL.INCLUDES str] otherwise FALSE

TRUE if the collection [COL] value list does NOT include


[COL.NOTINCL str] string “str”, otherwise FALSE

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.

7.6.7 Collection Variable THEN Nodes


Collection variables have a value that is a list of text strings. When used
in the THEN part of a rule, the nodes add or modify the values in the list.
There are a variety of Methods to do this. When a Collection variable is
selected in the variable list for a THEN node, a drop down list displays all the
Methods available. Some of these are quite special purpose, and not often
used.
The two most commonly used methods are to add a text item to the
collection and to add the content of a file to the collection. Other less
commonly used methods are covered in Appendix B. The “Add item with
Sort” is important when building MetaBlock systems and is covered in
chapter 12.

92 7: Logic Blocks - Controls


Adding an Item to the Collection
To add a new text item to the collection variable’s value list, select
“Add and item to the start/end of list” from the drop down list.

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”.

Click “Add to 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.

Adding Text from a File


To add a new text item to the collection variable’s value list, select
“Add items from a file”.

Enter, or browse to, the file to add.

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.

Other Collection Variable Methods


There are other methods for adding and removing values from the list. These include:

! Add the value of a variable.


! Add items with a Sort value to order the list.
! Conditionally add part of a file.
! Copy values from another collection.
! Assign an ordered group of values.
! Replace a value in the list.
! Remove a specified item from the list.
! Remove the first item in the list.
! Remove the last item in the list.
! Remove all items from the list.

These methods are explained in detail in Appendix B.

7: Logic Blocks - Controls 93


7.6.8 Limiting the Variable List
A particular Logic Block may only require a small
subset of the total variables in the system. The
specific variables displayed can be controlled
with the “Limit List” button. Clicking this button
will display a window for selecting variables to
display:
The variables listed on the right will be
displayed. All other variables in the system are
in the list on the left.
A variable can be moved from the Available to
Selected list by:
1. Select variable(s) in the Available list
2. Click the “>” button
A variable can be moved from the Selected to
Available list by:
1. Select variable(s) in the Selected list
2. Click the “<” button
All variables in the Available list can be moved to
the Selected list by clicking on the “>>” button
All variables in the Selected list can be moved to
the Available list by clicking on the “<<” button.

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.

Block Var Button


If a Logic Block has already been created and it is being edited, a quick way to limit the variable list to those
variables already used in the block is to click the “Block Var” button in the Logic Block window. This will bring
up the “Limit List” window with only the variables already in the block in the Selected list. This list can either
be immediately accepted by clicking “Done” or edited to add or remove variables.

94 7: Logic Blocks - Controls


7.7 Selecting and Editing Nodes
Nodes within a Logic Block can be selected for deletion, copying or moving. Nodes can also be copied and
pasted into other Logic Blocks.

7.7.1 Selecting Nodes


One or more nodes can be selected. The Control and Shift keys are used to select groups of nodes.

Left Click Selects the node and deselects all other nodes.

Shift – Left Click Selects the node and all its sub-nodes.

Selects the node without deselecting other nodes. If the


Ctrl – Left Click
node is already selected, it is deselected.

Shift – Ctrl – Left Click Selects the node and all its sub-nodes without
deselecting other selected nodes.

Selects the node and deselects all other nodes.


Right Click Displays a popup menu allowing easy access to the
editing options available.

Selects the node and all its parent nodes. This is


primarily used to see the rule structure. At the same
Shift – Right Click
time, displays the node and its parent nodes in the Rule
View window.

7.7.2 Logic Block Controls - Editing Controls


The nodes in a Logic Block can be edited and moved with the buttons on the control bar:

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.

Copy Saves a copy of the selected nodes 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.

7: Logic Blocks - Controls 95


Undo Moves back one step in the tree editing.

Redoes the last step that was removed via undo. This can only be done
Redo
to one level of undo.

Expands all compressed nodes, or if already expanded, compresses all


Expand /
nodes. Individual nodes can be expanded or compressed by clicking on
Compress
the small + or -boxes at the left of the node.

Undo and Redo can also be accessed from the Logic Block menu.

7.7.3 Controlling Tree Display


The display of a Logic Block tree is controlled by the menu items under “Display”.

Makes the font size used to display the nodes two


Font Larger
points larger.

Makes the font size used to display the nodes two


Font Smaller
points smaller.

Increases the amount that sub-nodes are indented from


their parent node. Increasing the indent level can make
Indent larger
the tree easier to read, but allows fewer levels to be
displayed without scrolling.

Decreases the amount that sub-nodes are indented


Indent Smaller
from their parent node.

Sets the tree to a mode where only one item in a group


will be expanded at a time. In this mode, if there are 3
branches, each with sub-nodes, and the first branch is
expanded to be worked on - expanding the second
Single Selection branch would automatically compress the first branch.
This can be useful for large trees since it automatically
closes the sections not being worked on. Some users
find this very convenient, others find it quite distracting.
It can be turned on or off by selecting the menu item.
A related function to “Single Selection” is to use the “Compress” option at the bottom of the Logic Block and
Rule View windows. The Compress check box displays the Logic Block trees in such a way as to display the

96 7: Logic Blocks - Controls


maximum number of nodes from the selected rule. Any branches that are not part of the selected rule will be
compressed. This does not change the display in the Rule View window, but can make it much easier to see
the rule structure in the Logic Block window for deeply nested trees.

7.7.4 Rule View Window and Block Navigation


The Rule View makes it easier to see and understand the
individual rule structure in the Logic Blocks. A Rule View
window displays the full text version of the node selected in the
Logic Block.
The Rule View is always displayed whenever a Logic Block is
being edited. A click on any node in the Logic Block will display
the full text of the associated rule in the Rule View Window and
will highlight the associated nodes in the Logic Block.
Buttons allow moving to the next (or previous) rule in the block.
Other buttons allow stepping through the block one
node at a time. These buttons are in both the Logic
Block and the Rule View Window so the logic can be
examined either with full text or within the block
structure.
Clicking the Next Rule button (> under Rule), will
display the full text of the next rule in the Rule View
window. A rule is defined as the next IF node that
could have a THEN node added below it. If any
THEN nodes have been added at that point, they will
be included. The Block will show the same nodes
highlighted.
The same buttons are at the bottom of the Logic
Block and Rule View windows. Either set will select
rules/nodes in both windows. To view the full text,
work from the buttons in the Rule View window. If
changes need to be made, just switch to the Logic
Block to make the changes.
The Compress check box displays the Logic Block trees in
such a way as to display the maximum number of nodes from
the selected rule. Any branches that are not part of the
selected rule will be compressed. This does not change the display in the Rule View window, but can make it
much easier to see the rule structure in the Logic Block window for deeply nested trees.

7.7.5 Grouping Nodes


Sometimes after editing and moving nodes, the bracket structure that
displays related nodes may not show all the nodes in the same bracket
groups. This can happen when a new value is added to a Static List
variable and inserted into the tree. This problem is only cosmetic, and
does not change the way the rules are built or executed. However, for
documentation or future system maintenance, it can be desired to reset
the brackets to correctly represent the developer’s intentions. To do this,
select a group or related nodes at the same level of indentation, and click
the “Group Together” button. This will make put brackets around this
group of nodes.

7: Logic Blocks - Controls 97


7.8 Changing Block Order
The order of the Logic Blocks in the system determines which Blocks will be used first. In a Forward Chaining
system, the blocks are fired in the order they were added to the system. In Backward Chaining, the Blocks
used to derive a value are tested in the order that they were added to the system.
In many cases, the Block order is not important, but some systems
require that the Blocks be fired in a particular order. To change the
order of the Logic Blocks, select “Reorder Logic Block” under the
“Run” Menu option. This will display a window that shows the
current Logic Block order. The same block order applies to all
operations (Forward and Backward chaining) that use the block
order.
To change the order of the Blocks:
! Click on the name of a Block to select it.
! Either click “Move Up” to move the Block towards the top of
the list, OR click “Move Down” to move the Block towards the
bottom of the list.
Once the Blocks are in the desired order, click the Done button.
NOTE: Block order applies to the entire system. If a system needs
to run blocks in a different order for one case, set the Block order for Backward Chaining and then use the
Command Language commands to force blocks to be run in a specific order for the special case.

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.

98 7: Logic Blocks - Controls


7.10 Adding Commands in a Logic Block
In addition to THEN nodes that assign a value to a variable, any command
that could be added to a Command Block can be added to the THEN portion
of a rule. If the rule fires, the command(s) will be executed. This allows rules
to perform a wide range of actions.
Click the “Command” button to add a THEN command. This will open the
window used to build commands for Command Blocks. Any individual
command can be added, but not IF, WHILE or FOR loops.
Some commands to run other Command Blocks or start backward chaining
for other variables, while legal, can make the flow of logic of the system
complex and difficult to follow. Generally, it is better not to use these commands in the THEN part of rule
unless the operation of the Inference Engine is well understood, since otherwise they may lead to
unexpected side effects.
Commands are very useful to clear and reset variables in some cases, cause external interfaces based on
rule logic and allow rules to implement more complex procedural logic than would be easy to do in
Command Blocks.
When commands are used in the THEN part, they require that there be some reason for the rule to fire.
Simply having a command in a rule is not enough, even with backward chaining. Either the rules must be run
in forward chaining, in which case all rules will be tested and fired when appropriate, or the THEN part with
the commands must also have a variable that is directly assigned a value (not in the command) and backward
chaining is used to trigger all rules associated with that variable.
The details of the available commands are covered in Chapter 9 on Command Blocks.

7.11 Merge Function


It is possible to merge separate Corvid systems into a single system. This is particularly useful if there are
multiple developers working on a single application. Each developer can build their section, and then the
sections can be merged together.
To use the “Merge” function:
1. Load the main system as usual.
2. From the File menu, select Merge and load the second system.
Merge will combine the Variable, Logic Blocks and Command Blocks from the second system to the system
already loaded.
If a second system has an item (Variable, Logic Block or Command Block) with a different name from the
already loaded system, it will simply be added to the system. If there is already a variable with the same
name, the existing variable and its various properties and settings will be used, and the new variable will not
be added.
If there are any potential conflicts, an error and warning screen will be displayed. Some conflicts are fatal
errors, and the systems cannot be merged until they are corrected. An Error dialog window will be displayed
explaining the error.
Usually in this case, it is best to make a copy of the system to be merged, make the required changes, and
then merge the systems.
In other cases the problems may be more minor and can be accommodated in the merge, but require
changes. In these cases, they will appear in the Warnings text box explaining the changes. If the changes
are acceptable, click the "Merge Systems" button. If the changes are unexpected and unwanted, click the
"Cancel Merge" button, make any needed changes and then merge the systems.

7: Logic Blocks - Controls 99


Merge is most useful when having multiple developers building a single system. Typically, there will be
variables (and sometimes Logic Blocks) that are shared by all the developers. To make this easier to
implement:
! Start by building a small system that has all the variables that should be shared among the
developers. These should have their parameters set to be appropriate for all developers. If there are
some underlying Logic Blocks that will also be shared, these should be added.

! 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.

100 7: Logic Blocks - Controls


Logic Blocks
To print the Logic Blocks in a system either click the “All Logic Blocks” radio button or the “Specific Logic
Blocks” radio button, and select the Logic Block(s) to print in the list on the right.
The printout is best printed to a color printer, since some information is highlighted with color, but a black and
white printer will also work.

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.

7: Logic Blocks - Controls 101


Rules
Often it is desirable to examine the actual rules produced by the Logic Blocks. For domain experts not
familiar with Corvid’s block structure, it is much easier to understand and review rules, which are just English
and algebra. When the rules are printed, the full text of the prompts and values is used, rather than the
variable names and short value text as is used in the Logic Blocks.
To print the rules, click the “Print Rules in IF / THEN Form” checkbox. This will print the rules in the order that
they occur in the Logic Blocks. To print one rule per page, check the “One Rule Per Page” checkbox.
Each rule is given a label “Block:xxx Row:###”. The block is the name of the block that the rule came from.
The row number is the number of the first THEN condition in the rule. This number corresponds to the
numbering on the Logic Block printout.
Rules can also be printed to a file by clicking the “Print Rules to File” checkbox and selecting a file name.

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.

102 7: Logic Blocks - Controls


Chapter 8: Logic Blocks - Building Rules from
Tree Diagrams
8.1 Rules and Logic Blocks
The last chapter covered the mechanics of building Logic Blocks and structuring rules. Here we will look at a
small example of how an actual systems are built.
There are 2 main approaches to building a Logic Block. The first is where there is a written representation of
the logic, such as a flow chart, SOP, regulations, manuals, etc. In this case, the best approach is usually to
try to make the Logic Block structure match the structure of the source material. Though in some cases, the
logic must be broken into pieces in multiple Logic Blocks.
The other approach is when the source knowledge is not documented and the process of building the Logic
Block is used to obtain the logic from an expert, using Corvid to capture and structure the knowledge. This
can be more complicated to do, but can be very effective.

8.2 Building a Simple Tree


Logic Blocks are a natural fit for tree diagrams since the Logic Block can be easily built with a tree structure. The
first example is the common problem of taking an existing tree diagram and converting it into a Corvid Logic Block.
There are many types of diagrams made of decision-making tasks. Various diagramming tools such as
PowerPoint and Visio allow creating diagrams that while sometimes are not actual trees, may be “flow charts”
of the decision-making process. Since these tools are more drawing tools than logic tools, the diagrams they
create may not convert directly to a single Corvid tree. Here we will concentrate on true tree diagrams.
These are diagrams where:

! The logic progresses out a branch to the end.


! The logic does not loop back.
! Any node only has one input path.
This is certainly not the only type of diagram Corvid can build and we will later see how to build systems for logic
that breaks all these criteria, but is the easiest and is actually the basis for all the more complex diagrams. “True
Trees” include many logic diagrams and all the “Dichotomous Keys” used in biology and other scientific fields.
This example will convert a simple tree
to identify a few common farm animals
into a Logic Block.
The tree is:
This simplistic tree is not supposed to
be the definitive ID knowledge since
there are many animals it does not
cover. It is just something for the
example. Once you know the
technique to convert a tree to a Logic
Block, it really does not matter what the
details of the content are or how big
the tree is.

8: Logic Blocks - Building Rules from Tree Diagrams 103


Building the System
Start a new Corvid system. First create the variables needed to build the system.
When converting a written tree into a Logic Block, the various possible answers (animals) and factors to
consider (branch points) are known at the start. The tree can be built two ways - either add all the variables
that will be needed before starting the Logic Block, or add the variables as needed while building the Logic
Block. Both approaches can be used and are a matter of personal preference of the developer. Here we will
add all the variables first. This is often a little easier since you do not have to jump back and forth between
windows, and it can be easier to create a consistent phrasing of the questions since they are all built at the
same time. However, it is perfectly legal to add variables at any time and some developers prefer to only add
them at the point where they are needed.
This tree has 5 possible identifications: Horse, Pig, Cattle,
Chicken and Goose. For this simple tree, these could be
represented by several types of variables, but here
Confidence variables will be used. Confidence variables
would allow the system to easily expand to include other
factors in in the identification with the confidence values
automatically combined.
First create a new Confidence variable named “Horse”.
Open the Variables window and click “New Variable”.
Enter the name “Horse” and select “Confidence”. (For
details on creating variables see Chapter 4.)
The Prompt text can remain the same as the variable
name.

Repeat this creating confidence variables “Cattle”, “Pig”,


“Chicken” and “Goose”
When these are added the Variable window should show
the 5 variables.

The top decision branch point in the tree diagram is based


on the number of legs the animal has: 2 or 4.

Since there are a fixed number of possible values, this will


work well as a Static List variable, even though the value is
numeric. This will make the logic easier to build and make
a better user interface,.

Add a new variable. Name it “Number of Legs” and select


Static List.

104 8: Logic Blocks - Building Rules from Tree Diagrams


Change the Prompt to the question that should be
asked of the end user: “How many legs does the
animal have?”
Enter values of “Two” and “Four”.
It is better to use the words “Two” and “Four” rather
than “2” and “4”. However, if “2” and “4” are
preferred, Corvid will automatically change the
“Short Text” for the values to “_2” and “_4”. This is
because a value can be referred to by either the
“Short text” (normally the same as the value text) or
by its number. Having a short text of “2” would be
ambiguous since it could refer to either the value
with text “2” or the second value. By making the
short text “_2” this is avoided. Corvid handles this
automatically if there is any ambiguity.

Another decision point in the tree is “Does the


animal have horns?”
Add a Static List variable named “Horns” with a
Prompt to “Does the animal have horns?” and
values of “Yes” and “No”.

Now add Static List variables for the branch points


for “udder” and length of legs”.

Name the first “Udder” with a prompt of “Does the


animal have an udder?” and values of “Yes” and
“No”.

8: Logic Blocks - Building Rules from Tree Diagrams 105


Name the next variable “Length of Legs” with Prompt
“The animal’s legs are” and values of “Long” and
“Short”.

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”.

Change the Prompt to “The height of the animal (in


inches)”. This will be the prompt when the question
is asked of the end user. When asking for a
numeric value, it is always a good idea to include
any relevant units or other information the user may
need to answer the question precisely.

106 8: Logic Blocks - Building Rules from Tree Diagrams


That is all the variables that will be needed to build the system. To see the
variables arranged by Type, in the “Sort” radio buttons, click “By Variable
Type” button. Using the “Sort” buttons makes it easier to find and work with
the variables in the system:
! Order Created puts the most recently created variables at the bottom
of the list.
! “Type” sorts by variable type, and within each type by the order
created.
! “Type + Alpha” sorts by type and within each type the variables are
arranged alphabetically.

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”)

Now that the variables are defined, it is easy to


create a Logic Block that matches the tree
diagram.

Start a new Logic Block by clicking on the “L”


icon.

Click the “Edit Name” button and change the


name to “Animal ID”.

To add the first node to the block click the “Add”


button under “IF - AND”. (This is always the first
step in building a new block.)

8: Logic Blocks - Building Rules from Tree Diagrams 107


The top decision branch point in the tree diagram is the
one on “number of legs”. It is easiest to have the
structure of the Logic Block match the tree diagram, so
the top node here will be the top node in the tree. In the
“Add to Block” window, select the corresponding variable
“Number_of_legs”.

The tree diagram has separate logic for each of the 2


possible values, so click “Add Each Individually” to add a
node in the Logic Block for each.

This will add 2 nodes in the “Nodes to Add” box.

Click “Done” to add them to the Logic Block.

The 2 nodes will be added to the block.


Now each of the branches have to be built out to match the decision
tree. In the decision tree, the decision branch point under “Number of
legs = Four” is the question on “Horns?”.
If it is not already selected, click on the block node “Number_of_legs
= Four” to select it. This makes it the point that the next node will be
added relative to.

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.

108 8: Logic Blocks - Building Rules from Tree Diagrams


This time select the “Horns” variable and again add each
value as a separate node and click “Done” to add them
to the block.

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.)

This time the decision tree is at an ending node indicating a conclusion,


rather than at a decision branch point. In the Logic Block, the
corresponding node will be a THEN node since it is assigning a value to
the “Cattle” confidence variable. To add a THEN node, click the “Variable”
button under “THEN”.

8: Logic Blocks - Building Rules from Tree Diagrams 109


This time select the “Cattle” Confidence Variable.
Confidence variables are assigned a numeric value that
indicates the level of “Confidence” or likelihood that
whatever the variable represents is “correct”. The
values can be relative to each other, or more of a “flag”
value to differentiate confidence variables that had a
value set from others.
The “Value to Assign” edit box will display “[Cattle] =”.
This node is assigning a value to the variable [Cattle].
For this simple system, any positive numeric value could
be used since there are not multiple rules combining
confidence values.

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.

110 8: Logic Blocks - Building Rules from Tree Diagrams


The Rule View window also shows the full text of the rule
associated with the selected node. This uses the text of the
prompt and values structured as an IF/Then rule.
(If the Rule View window is not displayed, select “Rule View”
under the “Display” menu when a Logic Block is active.)

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.

8: Logic Blocks - Building Rules from Tree Diagrams 111


Click on the variable “Height” to select it. Since it is a
Numeric variable, nodes are built using Boolean
expressions rather than just by selecting values as was
done with Static List variables.
The edit box will display “[Height]”.

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.

Since this is an IF node group, there should be nodes to cover all


possible values. Here that can be done by adding another node
“[Height] > 12”. To do this, click the “Height” variable again and build
the expression “Height] > 12”.
Click the “Add to List” button to add the second node to the list. The
“Add to List” edit box should show BOTH nodes before you click
“Done”.
Click “Done” to add the nodes to the block.

112 8: Logic Blocks - Building Rules from Tree Diagrams


Now that the IF nodes have been added, just add the THEN assignment nodes
for “Chicken” and “Goose” at the appropriate places.

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.

As THEN nodes are selected, their


associated IF nodes are highlighted
making it easy to check the logic.

The Rule View window displays the rules


associated with the selected nodes

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.

8: Logic Blocks - Building Rules from Tree Diagrams 113


To run the system, click the blue Run triangle in the command bar.

Since there is no Command Block, an error


message will be displayed.
For this system, select the “Forward Chain” option
and click “Build Command Block”. Corvid will build
a simple Command Block adequate to run these
rules.
NOTE: Corvid’s default Command Blocks are
very simple and Command Blocks built
specifically for the system should normally be
used.
They are only being used here because a full
discussion of Command Blocks will be done later.

Corvid will build the runtime files and open them


using the Corvid Applet Runtime. The system will
start asking questions based on the logic.
Only the minimum number of questions will be
asked to reach a conclusion.

When enough information has been obtained


to make an ID, the system will display the
results.
These are the Confidence variables selected
with its value and the input that lead to the
conclusion. These are not formatted and
presented in the simplest way. There are
many way to change the look and feel of how
questions are asked and results presented.
These are covered in Chapter 11 on User Interfaces.

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.

114 8: Logic Blocks - Building Rules from Tree Diagrams


8.3 Breaking a Tree into Pieces
It is relatively easy to convert a small tree into a Logic Block. The same technique can be used when the tree
gets larger, but at some point the levels of indentation and nesting will become difficult to manage. At this
point the tree needs to be broken up into smaller pieces. (This is also the same technique used to handle
most other types of logic diagrams that are not really tree structured, such as when some nodes have multiple
entry points. Break them into parts that are trees and use backward chaining to combine them.)
Due to the limitations of building and printing large trees in “drawing” oriented tools, often even the
documentation for a large tree will be broken into pieces. Often a large tree diagram will have a branch that
ends with “Go to page x” rather than putting the additional logic on the actual branch itself. This is easy to
handle in Corvid and allows building Logic Blocks that match the “Pages” in the decision-tree. Here we will
take the logic diagram for the farm animal system and break it up into 3 sections.
This is the same logic, but it has added breaks to put sections on “Page 2” and “Page 3”:

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”.

First start with the same variables that were used to


build the first system. These are the variables for the
goals (animals) and the decision branch points in the
3 trees.

8: Logic Blocks - Building Rules from Tree Diagrams 115


Now add the “Flow” variables. These will be used to determine
when the 2nd and 3rd tree should be used. Create a new
variable. Name it “Go to page 2” and make it a Static List
variable.

Give the variable 2 values “Yes” and “No”. The prompt


can remain “Go to page 2”.

This variable should never be asked directly of the end


user - that would only confuse them. To make sure
this never happens, go to the “Options” tab, set the
“Default” value to “No” and select the “Never ask”
check box. With these options set, if Corvid needs the
value for the variable, it will automatically be set to
“No” without asking the user. However, we can set it
to “Yes” in the rules - which is what we will do to trigger
the Page 2 part of the tree to fire.

Now do the same thing to create a “Go to page 3” variable, with


the same values and same options set.
Be sure to set its default to “No” and select the “Never Ask”
option.

116 8: Logic Blocks - Building Rules from Tree Diagrams


These variables will be all that is needed to
convert the original tree into the one with three
pieces.

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.)

8: Logic Blocks - Building Rules from Tree Diagrams 117


Select the “Go_to_page_2” variable and set the value
to “Yes”.

then “Add to List” button and then “Done”.

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.

118 8: Logic Blocks - Building Rules from Tree Diagrams


Now to add the other trees. First add a new Logic Block by
clicking on the “L” icon and change the name to “Page 2”. This
will have the rules that match the “Page 2” tree.

The first node in this tree is the key to getting the


multiple trees to work as one.
Select the “Add” button and add a SINGLE node as
the first node in the tree.
Select the “Go to page 2” variable and the value
“Yes”.
Before, IF nodes were always added in groups to
cover the possible values, but here ONLY the “Yes”
value has any significance, so the “No” value does
not have to be added.

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.

8: Logic Blocks - Building Rules from Tree Diagrams 119


The “Page 2” tree identifies chickens and
geese based on height.
Add the “Height” nodes.

Now add the THEN nodes for “Chicken” and


“Goose”.

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.

The first question is the same as before on “Legs”.


Select “Two”. We know from the tree that this will lead to the “Page
2” section of the tree.
Here that happens automatically and the next question is about
“Height” and asked from the “Page 2” Logic Block rules.
Enter a value of “14” and the results are displayed.

120 8: Logic Blocks - Building Rules from Tree Diagrams


These have the correct answer (Geese). The only difference
with the first system is that this one also displays the “flow”
variables. That is only because we are using a default Results
screen that shows all the variables set in the system. In a real
system, the results screen would be defined so that it did not
include these variables that have no meaning to the end user.

This technique of breaking up a larger tree into parts and setting


“Flow” variables to connect them is a very effective way to
handle many tree structured systems. The breaks in the main
tree can come from the documentation and just be implemented in the Logic Blocks to better match the
source documentation, or they can be added by the system developer to break a tree into parts that are more
easily handled, or which require a some special functions.

8.4 Running with Backward Chaining


The first system where all the logic is in one Logic Block works well as a forward chaining system. This is
because the original tree diagram is based on just going out a branch to the end, which has the ID. When the
Corvid version was run, the default “Forward chaining” option was used and worked well.
The version of the system that was broken into 3 Logic Blocks is a little more complicated. The default
forward chaining option is to run all the Logic Blocks with forward chaining. By default, this runs the Logic
Blocks in the order that they were created. Here that is:
Animal ID
Page 2
Page 3
The “Animal ID” tree sets the variables which determine if the “Page 2” or “Page 3” Logic Blocks should fire.
Remember the “Go_to_page_x” variables are set to automatically be “No” unless the rules have set them to
“Yes”. If the first tree sets “Go_to_page_2” to “Yes”, the “Page 2” rules will be used. However, the “Page 3”
rules will NOT be used since all the rules from that Logic Block start with “Go_to_page_3 = Yes”, and the
“Go_to_page_3” variable will have automatically been set to its default value of “No”.
Since the first Logic Block (Animal ID) does not require values set in the later Logic Blocks (Page 2 and Page
3), the system can be run in forward chaining. However, if the order was:
Page 2
Page 3
Animal ID
Then the “flow” variables that are needed in “Page 2” and “Page 3” would default to their “No” value (blocking
the rules in those 2 Logic Blocks) and “Animal ID” would not have any rules to identify any animal except
“Cattle”. With this Logic Block order the system would not work correctly in forward chaining.
However, with backward chaining the system can be run correctly with ANY Logic Block order. To do this,
change the Command Block command “FORWARD
ALL” (which runs the rules in forward chaining) to “DERIVE
CONF” which uses backward chaining to derive the value of
all the Confidence variables.
1. Open the Command Block by clicking on the “C” icon on
the command bar and selecting “Default Command
Block” (or “Command Block 1” if it was not renamed) from
the name drop down.
2. Click on the “Forward All” command to select it and click
the “Edit” button.

8: Logic Blocks - Building Rules from Tree Diagrams 121


3. In the “Commands” window, click on the “Variables” tab and
select “All Confidence Variables” in the “Derive the Value of
the Variable Using Backward Chaining”.

4. The Command Block should now have a “DERIVE CONF”


command. Click “Done”.
In this system the Confidence variables are the various
animals that the system can select among. With backward
chaining the inference engine will start by making the
confidence variables the initial goals. This will start with a
Goal List that has all the Confidence variables (in the order
they were added to the system).
[Horse]
[Cattle]
[Pig]
[Chicken]
[Goose]
Since [Horse] is the top goal variable, the rules that could set a value for it are the ones the inference engine
will test first. The only rule it finds is from the “Page 3” rules:
IF
Go_to_page_3 = Yes
AND Length_of_legs = Long
THEN
[Horse] = 1
To test this rule, the inference engine needs to know if “Go_to_page_3 = Yes”. This makes [Go_to_page_3]
the new top level goal in the goal list:
[Go_to_page_3]
[Horse]
[Cattle]
[Pig]
[Chicken]
[Goose]
The inference engine now searches for rules that could set the value for [Go_to_page_3]. The only rule it
finds is from the “Animal ID” Logic Block.
IF
Number_of_legs = four
AND Horns = No
AND Udder = No
THEN
Go_to_Page_3 = Yes

122 8: Logic Blocks - Building Rules from Tree Diagrams


To test this rule [Number_of_legs] becomes the new top level goal.
[Number_of_legs]
[Go_to_page_3]
[Horse]
[Cattle]
[Pig]
[Chicken]
[Goose]
Since there are no rules that can set a value for [Number_of_legs] it will be asked of the end user and dropped
from the goal list. If the number of legs entered is “2”, then the rule will be false, and [Go_to_page_3] will not be
assigned a value. However, this variable is set to automatically use a default value of “No”. Rather than asking
the user for the value, “No” will be assigned and it will be dropped off the goal list.
Since [Go_to_page_3] is “No”, the one rule that could assign a value to [Horse] is false. Since there are no
other rules that can assign a value to [Horse], it has no value and is dropped off the goal list. Unlike some of
the other types of variable, Confidence variable are NEVER directly asked of the end user. If nothing assigns
a value to them, they just have no value.
With [Horse] dropped off the goal list, it is now:

[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

To test this rule, [Go_to_page_2] becomes the new top goal:

[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

8: Logic Blocks - Building Rules from Tree Diagrams 123


Since the system already knows “Number_of_legs = 2”, this rule is true, and [Go_to_Page_2] is assigned the
value of “Yes” and dropped from the goal list. The goal list is now back to:
[Chicken]
[Goose]
but the system now has the additional data that “Go_to_page_2 = Yes”, so the rules from that tree can be used.
Now the rule that can set the value for [Chicken] needs to know the [Height] so that becomes the top goal.
[Height]
[Chicken]
[Goose]
While the [Height] variable is also needed to make a determination about the next goal [Goose], the inference
engine does not know or care about that at this point. [Height] is only needed because it can help to set a
value for the top goal [Chicken]. Since there are no rules to set [Height] it is asked of the end user. If
[Height] is less than or equal to 12, the [Chicken] rule will fire, setting a value for [Chicken] and dropping it off
the goal list. If the value for [Height] is greater than 12, the [Chicken] rule will be false and [Chicken] dropped
from the goal list since all its relevant rules will have been tested.
Either way, [Goose] will become the new top goal, and since [Height] is now known, the rule for [Goose] will
be tested and found to be true or false (based on the [Height] value), and [Goose] will be dropped from the
goal list.
The goal list is now empty and the DERIVE command is done. With backward chaining, the rules were
used in a VERY different order from the way they appear in the Logic Blocks - however, they were used in a
much more logical way to make the ID. The backward chaining approach would work regardless of how
the blocks were ordered, or how the rules were arranged in the blocks. The backward chaining approach
may seem complicated at first, but all the complexity happens invisible to the developer or end user. Once
the backward chaining approach is understood, it is actually much easier to build the system for backward
chaining since rule order does not have an effect on interrelationships between rules. If the system was
probabilistic and made more complex use of the confidence variables, the benefits of backward chaining
would be even greater.

8.4.1 Trees with Nodes that have Multiple Entry Paths


The same approach of breaking a tree into multiple sections and using “Go_to_page_X” can be used to build
systems that have been diagrammed with nodes that have multiple entry paths. A “true” tree will have only
one path into each node, but often for
convenience and to avoid redundancy,
diagrams may have multiple paths into
a node.
This tree has nodes A, B, C..., each of
which can be True or False. The
paths:
! A=True and D=True
! A=False and B=True
! A=False and B=False and
C=True
all go to the E node. Building this type
of structure as a single “true” tree can
only be done by repeating the logic in
the box starting with node E.
A much easier approach is to separate the logic in the box into a separate Logic Block and us
“Go_to_Page_X” variables. Add a [Go_to_tree_2] variable with values of “Yes” and “No”. Give this a default
value of “No” and set it to “Never Ask”. That will set it to “No” unless some other rule sets it to “Yes”.

124 8: Logic Blocks - Building Rules from Tree Diagrams


In the main Logic Block add rules for:
! IF: A=True and D=True THEN: [Go to tree 2] =Yes
! IF: A=False and B=True THEN: [Go to tree 2] =Yes
! IF: A=False and B=False and C=True THEN: [Go to tree 2] =Yes
Then start a new Logic Block with the top single IF node “[Go to tree 2] =Yes” and build out the logic for nodes
in the box. e.g.:
IF:
[Go to tree 2] =Yes
AND: E= True
THEN:
...
Run the system with backward chaining and the multiple entry points in the E node will be handled correctly
and without having to duplicate any rules.

8: Logic Blocks - Building Rules from Tree Diagrams 125


Chapter 9: Command Blocks
9.1 What is a Command Block
Command Blocks control how a system
operates, what actions to take and in what
order to perform actions. The Logic Blocks in Logic Block rules tell the system HOW to do things.
a system contain the detailed logic of how to Command Blocks tell the system WHAT to do.
do something, but these must be invoked from
a Command Block. Every Corvid system
MUST have a Command Block.
Command Blocks separate the procedural flow of execution from the rules that describe the decision-
making logic. Without Command Blocks, artificial and “kludgy” rules would have to be built to force
procedural action using the rule logic. This would result in overly complicated, convoluted rules that would
be difficult to read or maintain. The more complex the procedural operation of a system, the greater the
problem. Command Blocks solve this by providing a script-like approach to describing the procedural
steps, independent from the system logic.

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.

9: Command Blocks 127


Logic Commands - These are the commands that tell the Inference Engine what to do with the rules.
These may be one or more FORWARD commands to run the rules in a forward chaining mode or
DERIVE commands to run the rules in a backward chaining mode. These commands will usually
result in the system asking the user questions, but the question order is based on when (and if) the
variables are needed in the rules. These commands should completely run the system logic.
Result Commands - These are commands to display the results to the end user. This may be simply
displaying advice, creating and displaying a report, writing information into a database, etc. Like the
starting commands, these are to implement a user interface rather than 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.

9.2 Default Command Block


In the sample systems that were run in the
preceding chapters, some were run without
building a Command Block. This leads to a
warning window and an option to create a
“default” Command Block for either backward or
forward chaining.

While this can work for very simple systems, the


default Command Block should ALWAYS be
replaced by a custom built Command Block for
the system.

The warning window for not having a


Command Block should be treated as an error
and a reminder to build a Command Block.
Simple Command Blocks only takes a few
minutes to build, and provide precise control on how
a system will run. If a system requires a more complex Command Block, it will not run correctly with the
“default” commands that are automatically built.

9.3 Adding a Command Block


Command Blocks are added by clicking on the Command Block button:
or by selecting “Command Block” under the “Window” menu.

128 9: Command Blocks


This displays a new empty Command Block editing
window. When a new Command Block is added, it
will be named “Command Block #”, where # will be
the number of the Command Block in the system.
This name can be kept or changed to another name
by editing the name text by clicking the “Edit Name”
button.
Other Command Blocks already in the system can
be selected from the pull down list.
NOTE: If a system has only one Command Block
(the case in most systems), keeping the name
“Command Block” is useful to separate it from the
Logic Blocks.
If the Ctrl key is held down when you click the
Command button, the most recently closed
Command block will be displayed. If no blocks have been previously closed, a Ctrl click on the Command
Block button will display the “Starting Command Block”. Most systems only have a single Command Block
and can be displayed by holding the “ctrl” key and clicking the “C” icon.

Starting Command Block


When a system is run, there is always a “Starting Command Block” that
will be used first. Any other Command Blocks will only be used if they
are explicitly called from the starting Command Block or from the
THEN part of rules that fire. If there is only one Command Block (the
typical situation) this will be used as the Starting Command Block. If
there are multiple Command Blocks, any one of them can be made the
Starting block. This is done by selecting “Set Starting Command
Block” under the Corvid “Run” menu.
In the “Starting Command Block” window, select the Command Block
to use as the “Starting” block. Any other Command Blocks may be
called by that block or from the rules. There can be extra Command
Blocks in a system that are not used. These may be for special tests
or for possible use in development. Normally, these should be deleted
before the system is fielded, but that is not required..
Systems can be designed to do different things simply by changing the
Command Block. For example, one Command Block might write a
detailed trace of a run to a file, but another “production” Command
Block might skip this. The trace could be turned on and off simply by
setting the Command Block.

9.4 Command Nodes


There are two main types of command nodes:
! Executable commands.
! Looping/branching commands.
Executable commands are ones that can be directly executed. These are the most commonly used and involve:
! Assigning or deriving a value for a variable.
! Executing a Logic, Action or Command Block.
! Clearing or resetting a variable or blocks.
! Building and displaying reports.
! Controlling external interfaces.

9: Command Blocks 129


Most Command Blocks are simply a list of a few executable commands that are
executed in order. In this case, the Command Block instructs the system to:
1. Ask for the value of the variable [Name].
2. Ask for the value of the variable [Date].
3. Use the system rules (Logic and Action Blocks) to derive the value of all Confidence variables.
4. Display the results.
Looping and Branching commands allow creating:
! WHILE and FOR loops for systems that run multiple times.
! IF branches to control when certain commands are used.
Most systems will not need looping commands, and IF commands should only be used for conditional
procedural control and not to describe complex logic. However, for certain types of system logic, the looping
commands make it easy to describe complex procedural operations.
In this case, there is a FOR loop assigning the variable [X]
values from 1 to 20 with a step of 4. The value of the
variable [Y] is set to the value of [X] plus the value of
variable [Z] (which would be derived or asked of the user.).
The “DERIV CONF” command causes all confidence
variables to have their values derived from the Logic Blocks.
This may involve asking for data, testing rules, setting values
and any other operation performed by the Logic Blocks.
If the value for Confidence variable [ConfVar] is greater than
75, the results screen will be displayed, and if not, all the
Confidence variables will have their values reset to
“unknown” and Logic Blocks reset. Since this is the end of
the FOR group, [X] will be increased by the step amount and
the process will repeat until [X] has a value greater than 20, at which time a results screen based on the file
“All_OK” will be displayed. Attempting to implement this type of procedural control in the rules would be
almost impossible, but In a Command Block it is just a few lines.

9.4.1 Working with Nodes


The nodes in a Command Block can be selected individually or in groups. Groups of nodes are selected by
clicking on them in combination with the Shift and Control keys. (These are the same selection options as
Logic Blocks.)

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.

130 9: Command Blocks


Command Block Controls
The nodes in a Command Block can be edited and moved with the buttons on the control bar:

Deletes all selected nodes. This operation deletes all


Delete selected nodes and their subnodes. Deleted nodes are
not saved.

Deletes all selected nodes and subnodes. The deleted


Cut nodes are saved for pasting.

Copy Saves a copy of the selected nodes for pasting.

Pastes any saved nodes under the selected node, at


Paste Below the same level in the tree.
Pastes any saved nodes above the selected node, at
Paste Above the same level in the tree.

Pastes any saved nodes indented below the selected


Paste Indented node. This can only be used to paste nodes under a
loop control (IF, While, FOR).

Undo Moves back one step in the editing.

Redo the last step that was removed via Undo. This
Redo can only be done once to reset one level of Undo.

Expands all compressed nodes, or if already expanded,


compresses all nodes. Individual nodes can be
Expand/Compress expanded or compressed by clicking on the small + or -
boxes at the left of the node.

9.4.2 Executable Commands


Executable commands are added to the Command Block using the Command Builder window. This makes it
easy to build commands without memorizing command syntax. Just select the command, enter the
parameters and Corvid will build the command for you. Executable commands are added by:

! Clicking “Add” to add the first command in a block.


! Clicking on an existing command to select it and clicking “Add Below”
or “Add Above” to add a new command relative to the selected
command.

! 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”.

Each command can also have an associated comment. This is entered in


the “Comment” edit field. The comment text has no effect on execution,
but can make the Command Block much easier to read. To add a
comment, click on a command to select it and enter the comment. The
comment will automatically be added to the command in the block.

9: Command Blocks 131


9.5 Command Builder Window
Individual commands are built in the Command
Builder window. It has tabs for various types of
commands.

Using the “Commands” window makes it easy to


build commands without having to memorize syntax.
Just select the options and the command will be built
automatically.

It is also possible to just type the command in the


edit box at the bottom of the window, but this is
much more prone to typos and syntax errors. Since
most Command Blocks are only a few commands, it
is better to build the commands individually using
the controls.

The Command Builder window provides many


options for building commands, but only a small
subset are used frequently and many are only for very special purposes. The window has 9 tabs grouping
related commands.

This table summarizes the commands on each tab and how often they are used.

Tab Use

Variables Frequently Used


Commands related to assigning, asking or deriving the value of variables.
• Assign a value to a variable outside of the rules for procedural reasons
• Use the rules in the system to derive the value of any variable or group of
variables via backward chaining
• Force a variable to be asked of the end user at a particular point rather than
when needed in the logic

Blocks Frequently Used


Commands related to running specific Blocks.
• Run a Logic or Action Block in Forward Chaining
• Run the commands in a specific Command Block

Reset Rarely Used


Commands to reset variables or blocks to unused. ONLY needed for systems with
WHILE or FOR loops that reuse variables or blocks

External Special Use


Commands to read and write external files or call external data sources such as
databases.

Control Rarely Used


Commands to limit the scope of backward chaining and special options.
• Exit the Command Block that is being run
• Limit the scope of backward chaining to specific blocks
• Have a system sleep (used with systems that periodically monitor a process)
• Special commands

132 9: Command Blocks


Tab Use

Results Frequently Used


Commands to display the system results and other screens.
• Display the default result screen
• Display other screens from the Applet Runtime
• Display an HTML page in a browser window

Title Rarely Used


Command to display a title screen at the start of a session. (This was the only way to
build title screens in early versions of Corvid. This is now usually done using the more
general commands on the Results tab which can display any screen.)

Reports Special Use


Commands to save and display HTML, RTF and PDF reports. These reports require
that files be written on a server via a special servlet program and then displayed.

Email Special Use


Commands to send emails. These only apply to the Corvid Servlet Runtime.

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.

9.6 Variables Tab


The Variables tab is used to build commands that set
or derive the value for a variable, or force the
variable to be asked of the end user. This is a
frequently used tab.
The SET commands are used to set the value of a
variable in the Command Block, outside of the THEN
part of a Logic or Action Block.
The DERIVE commands are used to start backward
chaining to derive the value for a variable or group of
variables.
The ASK commands can be used to control the
specific order that certain variables should be asked
at the start of a session, rather than using the order
dictated by the Inference Engine’s use of the rules.

9: Command Blocks 133


9.6.1 SET Command - Assign a Value
Many systems need to set a variable’s value as part of the procedural execution of the system. This may be
to set initial value (such as for a counter), or to set a string value that will be used in other commands.
To set the value of a variable in the command file:
1. Click the “Assign a
Value to a Variable”
radio button.
2. Select the variable to
assign a value to in the
drop down list. (The variable must have already been added to the system.)
3. Enter the expression to assign in the edit box. The expression can include variables (including the
variable being assigned to) and any operators or functions.
4. If setting a Collection variable, select the Method from the “Method” drop down list. This will display
the various Collection methods. Then enter the value to add in the “Expression” edit box.
The expression to assign must be of the correct “type” for the variable.
While building the expression, pressing Ctrl-Alt-V will display a list of the variables in the system and their
properties. If a variable is selected from the list, it will be added to the expression at the cursor point.
Pressing Ctrl-Alt-E will display a list of the Corvid functions that can be used to build expressions.

Numeric and Confidence Variables


Numeric and Confidence variables must be assigned a numeric value or an expression that evaluates to a
numeric value.
For example:
SET [X] 0
SET [X] ([Y] / [Z]) + 1
SET [CONF] [X]/2
For Confidence variables, make sure the value assigned is consistent with range of allowed values for the
confidence mode set for that variable.

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.

134 9: Command Blocks


Date Variables
Date variables must be assigned a date value. This can be:
! Text in quotes that is a date in one of the valid date formats.
! Another Date variable.
! An expression or function that evaluates to a Date.
For example:
SET [D] “Jan 1, 2011”
SET [D] “1/1/11”
SET [S] [AnotherDateVariable]
SET [S] now()

Static List Variables


When a Static List variable is selected, the “Expression” edit
box becomes a drop down list with the variable’s values. To
select a single value to assign, just select it from the list.
To assign more than one value, a list of values can be typed
into the edit box instead of selecting values from the drop
down list. Enter either the numbers of the values to assign
separated by a space or comma or the short text of the
values to assign separated by a space or comma. For
example:
SET [SL] 1 2
SET [SL] 1, 2
SET [SL] red green
SET [SL] red, green
When assigning a value to a Static List variable, the values will be added to any other values already set by
initialization, rule firing or user input. The new values will not overwrite or replace the previous values. To
remove any existing values and replace them with new values, use a RESET command for the variable to first
delete the old values and then a SET command to add the new ones.

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.

9: Command Blocks 135


For example:
SET [COL.ADD] “Text to add”
SET [COL.ADD] “The value of X is [[X.value]]”
SET [COL.ADDSORTED] “Item to add”, 10
SET [COL.CLEAR]

Dynamic List Variables


The SET command for Dynamic List variables is similar to Static List variables, but since the values are set at
runtime, only the value numbers can be used. The expression should one or more value numbers separated
by a space or comma.
For example:
SET [DL] 1
SET [DL] 1 2
SET [DL] 1, 2

9.6.2 DERIVE Command - Determine a value via Backward Chaining


The DERIVE command is used to start backward chaining. It establishes the variable(s) as the top level
goal(s) for backward chaining and then instructs the Corvid Inference Engine to determine the value using the
rules in the system and backward chaining. This is a very commonly used command and the primary way to
start systems that use backward chaining. This can also be used if a variable has an associated external
interface command, and the intent is to immediately use that interface to set the variable’s value. Backward
Chaining concepts are covered in detail in Chapter 4.
To use backward chaining to derive the value of a variable:
1. Click on the “Derive the Value of a
Variable Using Backward Chaining” radio
button.
2. Select the variable(s) to derive. This can
be a single variable or a group of
variables.

The variable(s) to derive can be selected individually or as a group in various ways.

Single Variable
Click on the drop down list next the “Variable” radio button. Select the variable to derive.

All Confidence Variables


Click the “All Confidence variables” radio button. Many systems use a set of confidence variables as the
possible results or advice options that can be presented to the user at the end of the session. This single
command will tell the Inference Engine to use backward chaining to derive the value for all the
Confidence variables in the system. The Confidence variables will be derived in the order that they were
added to the system.

Final Result Flag Variables


Click the “All variables with the Final Results flag set” radio button. In some cases, the possible final results
of a system can include a mixed group of variables that are not “All Confidence” or “All Collection”. In this
case, they can either be derived one at a time, or the Final Result flag can be used to designate the group.

136 9: Command Blocks


The “Final Result” flag can be set for individual variables
from the “Options” tab on the “Variables” window.

1. Open the Variables window and select a variable


to include in the group to derive.
2. Make sure the “Advance Options” check box is
selected at the bottom of the window.
3. Go to the “Options” tab.
4. Click the “Final Results Display Flag” check box.
5. Repeat for each of the variables to add to the
Derive group.

All Collection Variables


Click the “All Collection variables” radio button. Many
systems use one or more Collection variables to dynamically build content or a report that is displayed at the
end of the session. This single command will tell the Inference Engine to use backward chaining to derive the
value for all the Collection variables in the system. The Collection variables will be derived in the order that
they were added to the system.
Variables whose Name Fits a Mask Pattern
Click the “Variables Fitting the Mask” radio button and enter a Mask Pattern. The syntax for the mask is:

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_”.

9.6.3 ASK Command - Force a Variable to be Asked of the End User


The ASK command is used to force a variable to be asked of the end user, regardless of its use in the rules, it
ability to be derived through backward chaining or external interfaces associate with the variable.

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.

9: Command Blocks 137


Each ASK command will only ask a single variable, but if that variable has an associated list of “Also Ask”
variables, those will be asked at the same time on the same screen.
The ASK command will cause the variable to be asked of the user even if it can be derived from rules or has
an associated external source for the value. (To have the external interface for a variable to be used, rather
than asking the variable, use the DERIVE command.)
If the variable has a default value and the “Never Ask” option is selected, the default value will be assigned to
the variable and it will not be asked.

9.7 Blocks Tab


The Blocks tab is used to run a Logic or Action Block in
Forward Chaining or to execute the commands in another
Command Block.
The commands to run Logic Blocks in forward chaining is
commonly used and is the standard way to run forward
chaining systems.
The commands to have one Command Block run other
Command Blocks is rarely used unless there is a need for a
very complex Command Block structure.

9.7.1 FORWARD Command - Running Blocks with Forward Chaining


The FORWARD commands allow running one or more
Logic or Action Blocks in forward chaining.
Forward chaining tests the rules in the block in order
from top to bottom. If the IF part of a rule is true, the
THEN part assignments are made. If the IF part is
false, the THEN part is not used. The first rule in the
block is tested first, then the next, etc., to the bottom. The command continues executing until all the rules in
the block have been tested and either fired or discarded. Once rules are tested, they will not be tested again
unless the block is reset with a RESET command.
The rules are evaluated based on the value of variables at that moment - other rules are NOT automatically
called to derive variable values as is done in backward chaining. When a variable value is needed to
evaluate the IF part of a rule or make a THEN assignment:
! If the variable has a value (the value was already been set by another rule, user input or an external
interface) the value will be used immediately.
! If the variable does not have a value, any external interface associated with the variable will be tried
first. If after that, the variable still does not have a value, it will be asked of the end user.

Using Backward Chaining to Derive Values


Backward chaining can be turned on to derive the value of
variables by selecting the “Allow backward chaining to derive the
value of variables used in the blocks” check box. With this
selected, the rules in the block will still be tested in order, from the
top - but backward chaining will be used to derive the value of the
any variables used in the IF tests or THEN assignments.

138 9: Command Blocks


This is a good option to select, unless the rules are organized to make sure that all needed values will have
been assigned before they are used. When allowing backward chaining, the “ALLOW_DERIVE” option will be
added to the command.
For example:
There are 2 Logic Blocks:
Logic Block 1:
IF
[X] > 0
THEN
Advice 1 is YES
IF
[X] <= 0
THEN
Advice 1 is NO

Logic Block 2:
IF
[Y] > 0
THEN
[X] = [Y] + 1

A command to run Logic Block 1 in Forward chaining will:


! Ask for the value of [X] because it is needed in the IF part of the rules.
! Based on the value of [X] or of the Logic Block 1 rules will fire.
! The rules in Logic Block 2 will NOT be used and [Y] will not be asked.

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).

9: Command Blocks 139


While this approach would work here, sometimes there are many interrelationships between Logic Blocks
where some rules set values needed by others. The FORWARD command works with entire Logic Blocks,
while the backward chaining “ALLOW_DERIVE” option works with the individual variables in a Logic Block.
This can be a much more effective way to handle complex systems.

All Logic and Action Blocks


To run all the Logic and Action Blocks in a system click on
the “All Logic and Action Block” radio button. All blocks
will be run in order. If the “Allow backward chaining”
check box is selected, backward chaining will be used to
derive variable values needed in all the blocks.

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.

Block Whose Name Matches a Mask Pattern


To run only selected blocks where the name matches a
mask pattern, click the “Blocks Fitting a Mask” radio
button and enter the mask pattern. The mask options
are the same as those for variables (See Section 9.6.2
above). If the “Allow backward chaining” check box is
selected, backward chaining will be used to derive variable
values needed in the block(s).

140 9: Command Blocks


While more complex masks can be created, if masks are going to be used to select specific blocks to run, it is
best to simply start the name of those blocks with a letter such as “F_” to indicate they are to be run in
forward chaining and then just use the mask F_*
When a group of blocks is selected using a mask, the block order will be the same as when “All Blocks” is
selected, but only the ones matching the mask will be used.

9.7.2 EXEC Command - Running a Different Command Block


The EXEC commands allow running another Command Block. The commands in the called block will be
run and then control will return to this block. It is just like the commands in the called block were inserted in
the calling block.
The EXEC command is rarely needed. It is generally
only needed:
! If there are a group of commands that need to be
call from different places in the system. Those
commands can be put in a separate Command
Block and then called when needed.
! If there is a Command Block with IF, WHILE or FOR that needs to be called from the THEN part of a
rule. (While multiple command can be in the THEN part, looping is only possible in a Command Block)
! If there is a very complex command structure and segmenting it into multiple blocks makes it easier to
manage or better matches existing procedure documentation.

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)

All Command Blocks


To run all blocks (other than the calling block), click the “All Command Blocks” radio button. The blocks will
be run in the order they were added to the system. To run blocks in a specific order, use multiple EXEC
commands to run specific blocks. (This is very rarely needed)

Run a Specific Command Block


To run only a specific block, click the “Command Block” radio button and select the block from the drop
down list.

Block Whose Name Matches a Mask Pattern


To run only selected Command blocks where the name matches a mask pattern, click the “Command Blocks
Fitting the Mask” and enter a mask pattern. The mask patterns are the same as for variables.

9: Command Blocks 141


9.8 Reset Tab
The Reset tab is used to reset the value of variables to
“unknown” and allow Logic or Action Blocks to be
reused in systems that loop.
The commands on the Reset tab are specialized and
needed only for systems that:
• Do some type of looping.
• Contain logic that requires clearing and resetting
the value of variables such as internal data
consistency checking systems.
(NOTE: MetaBlock systems that loop and reuse
variables do NOT need the commands on the Reset
tab since variable clearing and reuse is handled as
part of the MetaBlock parameters.)

9.8.1 RESET Command for Variables


The RESET command allows resetting the value of a variable. This is rarely needed, and only for special
types of systems with fairly complex logic. Normally, once the value for a variable is established, that value
will be used for the rest of the session. If a variable is “RESET”, its value is changed to the initial state of
“unknown” This means that if the system logic needs that variable’s value after the RESET, the Inference
Engine will use the rules and external interfaces to get a new value. Remember, the rules used to originally
set the value will also have been used and will NOT be reused unless they too are RESET.
RESET can be required for systems that monitor a process by getting a snap shot of process data, analyze
the data and then loop to repeat the analysis with a new set of data. Using the RESET command clears the
old variable(s) value and the Inference Engine will get new values from external interfaces. (This type of
system also requires resetting the Logic Blocks so that they will fire multiple times.)
RESET commands can also be useful for changing the value of Static List variables, where an earlier value
needs to be overwritten with a new value. Unlike some other types of Corvid variables, Static List variables
“remember” earlier values and setting a new value (either in Logic or Command Blocks) adds that value to
any values that may already be set. The new value does not automatically overwrite the old value the way a
numeric, string or date variable would. In many systems this is a very useful behavior, but sometimes a
system’s logic calls for overwriting a previous value for a Static List variable. To do this use a RESET
command followed by an assignment of the new value. This can be done in a Command Block, or by putting
a RESET command in the THEN part of a Logic or Action Block just before the new value is assigned.
RESET commands can specify one or more variables. The options for selecting the variable(s) are very
similar to other commands that allow multiple variables to be selected.
Radio buttons allow selecting:
! All Variables.
! All Static List Variables.
! All Dynamic List Variables.
! All Collection Variables.
! All Continuous (Numeric, String and
Date) Variables.
! All Confidence Variables.
In addition, individual variables can be selected from the “Variable” drop down list.
Variables whose name matches a mask pattern can be selected by specifying the mask string.

142 9: Command Blocks


Two check boxes are available to implement special options.
The first allows limiting the RESET command to only variables whose value is older than a specified number
of seconds. This can be used in monitoring systems. For example, a system could include a group of
numeric variables that contain information on a process. Based on the rate of change of the process, If the
data is older than X seconds it should be updated. Resetting all continuous variables where the value is older
than X seconds leads to the inference engine to calling the external interface to get new values for those
variables.
The second option is for systems that get their value from an end user, but loop to handle multiple situations.
It allows resetting the variable, but retaining the old value as the default value. This means that when the
variable is re-asked of the end user, the old value that they had previously supplied will be pre-selected as the
default and all they need to do is press the Enter (Return) key to accept the value.

9.8.2 RESET Command for Blocks


When used with blocks, the RESET command allows resetting a blocks “flag” that indicates it has already
been used. Normally, a Logic, Action or Command Block is only used once in a session and then a flag is set
to prevent the Inference Engine from reusing it, which could potentially result in values being set multiple
times. The RESET command can clear this “flag” allowing the Inference Engine to use a block again. This is
rarely needed except in systems that need to repeatedly reuse the same rules to analyze new sets of data.
The Blocks to RESET can be selected either as
a group by selecting the radio button for:
! All Blocks.
! All Logic and Action Blocks.
! All Command Blocks.
Individual blocks can be selected from the drop down list next to “Block”.
Groups of blocks can be selected by using a “mask” for the name, in the same way masks could be used for
variables.

9.9 External Tab


The External tab is used to build various commands
that interface to external programs and files to read
and write data.
There are other ways on the Variables window to
associate external interface commands with a specific
a variable or operation. The external interface
commands used in a Command Block are usually to
either get data for multiple Corvid variables at the
same time, or perform some external interface
operation as part of the procedural flow of execution,
such as writing final session data to a database.
Some of the commands built from the External tab
only apply to certain modes that Corvid can be run in
such as running in a standalone mode.
Some external interfaces can be called using multiple
commands. Some interfaces were originally implemented one way, then as other more general interface
techniques became more powerful in later versions of Corvid, they overlapped some of the other techniques.
For compatibility with earlier systems, both approaches are still supported.

9: Command Blocks 143


9.9.1 Calling External Databases and Other Sources
Clicking the “Edit” button next to the
“Call Databases or Other External
Source for Data” will display the
window for building external interface
commands.
This window allows building a variety of external
interface commands. The details of building
commands from this window are covered in chapter 13.
When used in a Command Block, only commands that
either can write data out, or which can assign values to
multiple variables are enabled. The XML and Param
tabs are disabled since those build commands are
associated with specific variables.
Some of the commands that can be built from this
window are functionally the same as commands that
can be directly built from the “External”, such as
reading data from a URL, and either command can be
used. Normally, this External Interface approach would
only be used for database commands that write data
out to the database. However, other external interface
commands can be useful in special situations.

9.9.2 READ - Reading Data from a Local File or URL


The READ command allows Corvid to read data from an external file either on the local computer or specified
by a URL. This can be done in stand-alone mode or online. The file of data may contain values for multiple
variables and may contain multiple batches of data that can be run sequentially.
To read a file of data, use the command builder from a Command or Logic Block.
Select the “External” tab:

! Click the “Read a set of


variable values from the
file:” radio button.
! Enter the name of the
file (or a URL), or click
the browse button and select the file.

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.

144 9: Command Blocks


Some variables allow the value to be specified in multiple ways:
Static List
#
# (TAB) # …
short_name
short_name (TAB) short_name (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; (TAB) is the
tab character; and short_name is the short name for the value. (If the values do not have separate short
names, the short name is the same as the full name.)

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

9: Command Blocks 145


Date
String
Corvid expression that evaluates to a date string
For example:
[D] “Jan 1, 2011” would set date Jan 1, 2011
[D] NOW() would set the current date and time

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

Multiple Batches of Data


The data file can contain multiple batches of data. These batches must be separated by a line with “END” on
it. When a READ command is executed, all lines in the file will be read until the end of the file, or an END
command is reached. When an END command is encountered, the READ will return “TRUE” and the lines
following the READ will be executed. The next READ command will start at the first line after the END
command. When a READ command tries to read from a file that has reached the end of the file, it will return
“False”. This allows the READ to be used in a WHILE loop that will read through a file of data with any
number of records.

146 9: Command Blocks


For example, if the file to read data from was:
[A] 1
[B] 5
END
[A] 7
[B] 22
END
The first READ command would set [A] to 1 and [B] to 5. The commands after the READ command would
then be executed. The next READ command would set [A] to 7 and [B] to 22.
There are several ways to work with files that have multiple batches of data. If there is always a fixed number
of records, there can be a matching number of READ commands or a FOR loop can be used. If the number
of batches of data in the file may vary, the best approach is to use a WHILE command.
The WHILE test expression can be a READ command. If the READ command successfully reads data
from the file, it will return TRUE. If the READ command is unable to read additional data, due to reaching
the end of the file, it will return FALSE.
This enables the WHILE command to be a “While there is more data to read…”. For example, if you have a
data file, input_data.dat, that may have multiple batches of data you can process the file with:

WHILE (READ “input_data.dat”)


Commands to analyze the data
Usually, commands to clear some variables
// While End
Commands to execute after the full file is read
NOTE: Generally systems will set the values of various other variables during the processing of each
set of data. Be sure to clear those variables before the next set of data is read.
Usually a READ is used in a WHILE or FOR loop to process the entire file with no additional user interaction.
However, if a system may require user input when certain values are read from the READ file, the "Back"
button should NOT be used. Any questions that could be asked in this way should have the "back" button
disabled with the "No Back" option.
NOTE: In a WHILE (READ “filename”) command, the filename MUST be in quotes.
For example:
Using a data file, values.txt :
[A] 1
[B] 5
END
[A] 7
[B] 22
END
with numeric variables [A], [B] and [X] and a Collection variable [Col]. the Command Block:
WHILE (READ “values.txt”)
SET [X] [A]+[B]
SET [Col.add] A plus B equals [[X]]
// WHILE end

9: Command Blocks 147


The WHILE will loop through the data using the READ command. The READ will read each block of data
down to an END. The first SET command sets the value of [X] to [A] + [B]. The second SET command adds
the string “A plus B equals [[X]]” to the collection variable [Col], where [[X]] double square bracket embeds the
value of [X] in the string. The WHILE loop will run twice, once for each block of data, and each loop will add a
line to the collection variable [Col]. After the second block of data, the end of the data file will have been
reached. The next loop will again call READ, but this time it will not set any data and will return FALSE. This
will break out of the WHILE loop.

The final value of [Col] will be:


A plus B equals 6
A plus B equals 29

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:

It is necessary to restart reading from the top of the file


or
The remaining batches of data in the file should be skipped and not read.

9.9.3 EXTERN - Calling External Programs


The EXTERN command allows calling an
external executable program. This is a
program on the local machine which will
be run as if it was directly executed - not
an applet, Servlet, JSP or other resource
accessed via Web techniques and
referenced as a URL (Those are run using other commands below.)
Due to Java security restrictions, this can only be done when either running the Corvid
Runtime as a Standalone Java application or when using the Servlet Runtime calling a
program on the same server.
Click the “Call and External Program” radio button and enter the name of the executable program. Usually
this must include the full path to the program, and using the “Browse” button will simplify getting the complete
path correct.
The “Parameters” edit box can be used to enter parameters to pass to the called program. This data will
come into the called program as if it was part of the command line.
For example, to have the program Notepad open a specific file for editing:
! The program name would be “path/Notepad”, where “path” is the full path to the Notepad executable.
! The Parameter would be the name of the file to open with Notepad.

148 9: Command Blocks


The Parameter data can include Corvid variables by embedding them using double square brackets. For
example, if the name of the file to have Notepad open was in the Corvid variable [myFile], putting “[[myFile]]”
as the Parameter would pass that variable’s value.

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.

9.9.4 WRITE - Writing Data to a Local File


The WRITE command allows writing data to a
local file.

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.

9: Command Blocks 149


NOTE: The WRITE command only works when running standalone, or when using the Servlet
Runtime. When running using the Applet Runtime, use the SaveReport and DisplayReport
commands to build reports. In most case it is also better to use the SaveReport / Display Report
commands when building reports from the Servlet Runtime since those provide more security options.
These are discussed in Chapter 14 on reports.

9.10 Control Tab


The Control tab is used to build various
commands that modify the default behavior of the
Corvid Inference Engine to either exit from a
Command Block or to limit the scope of blocks
used during Backward Chaining.
The sleep command pauses the system. This is
used in monitoring systems that read data
automatically and loop. Adding a sleep command
slows the repetition rate to whatever is appropriate
for the process and reduces resource use.
The special commands set very specialized
options on how systems work. These are very
rarely needed.
These are all rarely used commands to handle
very special situations.

9.10.1 Return and Exit


One Command Block can call another with the
EXEC command. Normally, when this is done,
the called Command Block executes all its
commands and control returns to the calling
Command Block, which will then do the command following the EXEC command. However, sometimes a
system requires that the called Command Block return before it has finished. To do this. add a RETURN
command in the called Command Block by clicking the “Return to calling Command Block”.
For example, if there are 2 Command Blocks “Main” and “OtherCommands” and the system starts with “Main:

Command Block: Main


ASK [X]
EXEC OtherCommands
RESULTS

Command Block: OtherCommands


ASK [Y]
IF (Y] < 0)
RETURN
ENDIF
ASK [Z]

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

150 9: Command Blocks


“RETURN” command would end running commands in “OtherCommands” block and RESULTS would be
displayed. If [y] was not less than 0, the RETURN would be skipped and [Z] would be asked.
The EXIT command is similar to RETURN, but terminates all commands in the system. This leads a system
being run as an applet to display the default “System Done” message, or a system run as a standalone Java
application to terminate the application and close the Java window running it. EXIT is not generally used with
the Corvid Servlet Runtime since there is no default ending window, but execution will be stopped. In the
above example, if the RETURN was changed to an EXIT command, if [Y] was less than 0, the system would
terminate and display the “System Done” window, without displaying the RESULTS.
To add an EXIT command click the “Terminate Run” radio button.

9.10.2 Allow and Exclude


Normally, backward chaining will check all Logic
Blocks to try to find any rule that can derive the
value for the current “goal” variable. The ALLOW
and EXCLUDE commands provide a way to limit
the scope of the backward chaining search by
forcing the Inference Engine to skip some blocks.

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.)

ALLOW specificBlock Allow a specific block that had been excluded.

EXCLUDE ALL Exclude all blocks. This effectively disables


backward chaining and should only be used in
combination with one or more ALLOW commands
when this is the most efficient way to specify the
blocks to allow.

EXCLUDE specificBlock Exclude a specific block

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.

9: Command Blocks 151


A better solution is to put those conditions as the top level node(s) in the block, and if those tests are not true,
the entire block will be skipped. Instead make the first (top level) node in the “California_Rules” Logic Block:
State = California
Since this is the top node, and all other IF nodes are indented under it, all rules in the block have this as their
first IF condition. If the state is not California, none of the rules can be true, and consequently will not be used.
This approach is easier to expand to other blocks as needed and puts all the logic related to the rules in the same
Logic Block, rather than splitting it between the logic and Command Block. This is generally the better approach.
One place where ALLOW and EXCLUDE commands are very useful is during development to test alternate
versions of a Logic Block. Suppose that a Logic Block is to be modified. It can be copied into another Logic
Block, which can be edited. Then by using an EXCLUDE command at the start of the Command Block, the
system can be run with either the old or new version (but not both). Once the changes have been validated,
the old Logic Block can just be deleted along with the EXCLUDE command.

9.10.3 SLEEP Command


The SLEEP command is used in
systems that loop to monitor a process.
Monitoring systems often are designed to run periodically (e.g. every 10 minutes) to automatically get data
from an external source (e.g. sensors, databases) and check for certain conditions. If the system detects a
problem, it performs some action, but normally the system determines there is no problem, waits a length of
time and runs again.
To simplify this type of system, the SLEEP command has been added. The command is added by selecting
the "Sleep" radio button and entering the number of milliseconds to sleep. The milliseconds can be a
formula using Corvid variables. This allows the system to automatically change the sleep period based on
Corvid variables and system logic. For example, if the process is getting up to a higher temperature, the
system might check it more frequently than if it were cold.
A formula is also convenient when specifying a longer time period by explicitly specifying hours, minutes,
seconds and milliseconds. For example, to sleep for 2 hours, enter:
2*60*60*1000
When the system is "sleeping" it uses no processor resources. When the SLEEP command is executed, the
system processing will stop for the specified time. At the end of the time, the commands following the
SLEEP command will be executed.
The SLEEP command is a special purpose command that should rarely be needed except in process
monitoring situations.

9.10.4 SPECIAL Commands


There are a variety of “Special Commands” that
can be used to perform actions or set options
needed in some systems. These are very rarely
needed. Many of the special commands
change the default way that the Exsys Corvid
Runtimes work, so they should be used with care and only when required by a particular system.
Special Commands are by selecting the command from the drop down list of “Special Commands”. Each
command in the list has the command and a brief description of what the command does. Selecting a
command and clicking the “?” button will display more information on that command. Some commands
require additional parameters. If the selected command requires a parameter, a prompt for the parameter will
be displayed, and the parameter can be added in the edit box.

152 9: Command Blocks


Special Commands

Command Use

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
Parameter: TRUE or FALSE item is added separately. A value of TRUE will retain the tabs.
If the system later needs to have tabs handled in the standard
way (breaking on the tabs and adding multiple items), use the
command again with FALSE.

COMMENT: The COMMENT: command allows comments to be added to a


Command Block. Comments are ignored when the system
Parameter: Comment Text runs. (Comments can also be associated with individual
commands. This is provided for compatibility with earlier
versions of Corvid.)

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.

DONE_SCR= This command specifies a file of screen commands to display


in place of the default “System Done” message.
Parameter: Screen Command File

EMPTY_CELL= This command specifies what value should be used for an


empty cell in the data for a MetaBlock. Normally, the value of
Parameter: String to use for empty an empty cell is an empty string which will be added wherever
cells the MetaBlock parameter is embedded. The EMPTY_CELL
command is useful in cases where the MetaBlock file is also
used for other purposes, or comes from a database and is
likely to have blank fields. The command allows setting a
value for use as a MetaBlock that will make sense in the
context of the expert system.

HYPERTEXT_BG_COLOR= This command specifies what background color to use when


displaying a HTML link from a <A HREF=...> command.
Parameter: RGB color value

HYPERTEXT_COLOR= This command specifies what color to use when displaying a


HTML link from a <A HREF=...> command.
Parameter: RGB color value

9: Command Blocks 153


Command Use

NO_PARSE_ERRORS A variable name in [[ ]] can be used to embed the value of


variable in other strings. Normally, if Corvid finds a [[ ]]
Parameter: None expression that does not match a variable, it will report an
error. Some files, such as PDF templates, may use [[ in other
ways, and lead to invalid error messages. This command
turns off all such messages.

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

SPECIAL_BUTTON Adds a custom button on Question screens linked to a


Command Block. Clicking the button will run the Command
Parameter: Button Label, Command Block.
Block

SPECIAL_BUTTON_OFF Stop adding a custom button on Question screens. Use after


SPECIAL_BUTTON command.
Parameter: None

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.

USE_EXT_BROWSER= Allows URLs from DISPLAY_HTML and HREF links to be


displayed in a browser window when running as an Application.
Parameter: Path/name for Browser This has no effect when running as an Applet.

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

154 9: Command Blocks


Once this command is executed, whenever a string is added to a collection variable, it will retain the tabs. If
the system later needs to have tabs handled in the standard way (breaking on the tabs and adding multiple
items), use the special command:
ALLOW_TABS_IN_COLLECTIONS=FALSE
This will return Corvid to the default way of handling of tabs.

Special Command: COMMENT:


The COMMENT: command allows comments to be added to a Command Block. Select the command from
the drop down list and enter the comment to add. Comments are ignored when the system runs. Adding
comments with this command is for compatibility with older Corvid systems. Any line in a Command Block
can now have an associate comment, and adding comments this way is no longer needed.

Special Command: DO_NOT_ALLOW_HOW


The .HOW property for a variable displays the full history of how the variable’s value was set during the
session. This can be very useful for debugging, or for systems that need to store the basis for each decision
in a database. However, this is rarely the case and keeping track of the information for .HOW does use
resources, especially for MetaBlock systems that set and clear variables many times. Adding:
DO_NOT_ALLOW_HOW
in the Command Block will prevent the use of the .HOW property and will tell the inference engine to not keep
track of the information needed for .HOW. This can slightly improve performance for systems that do very
large numbers of assignments, especially MetaBlock systems.

Special Command: DO_NOT_LOOK_AHEAD


In certain special cases when backward chaining Corvid v3.2 (and earlier), could ask a question that was not
actually required. This could happen if a Static List Variable had its value set either by being asked or
derived, and it was also used in other than the top node of a rule that was also used in backward chaining. If
the value set for the variable made the node False, the nodes above the Static List node would still be tested,
even though they were actually not needed.
For example, consider the two rules:
IF:
The color is Blue
THEN:
ConfVar = 5
IF:
The temperature is Hot
AND: The color is Red
THEN:
ConfVar = 8
If the system backward chains to set the value of Confidence variable ConfVar, the first rule will be tested.
This will lead to asking the value of [Color]. If the user inputs “Blue”, the first rule will fire. The If nodes in the
second rule will then be tested in order. This will lead to asking [Temperature]. However, since there is
already enough information to know that the 2nd node is false, this question is not needed. The 2nd rule
would not fire, and it would not change the results, but it would lead to an unnecessary question.
Corvid checks for this type of situation and will not ask the unnecessary question. In rare cases, this may

9: Command Blocks 155


change the way existing systems run, but the difference is to not ask an unnecessary questions. For virtually
all systems this is the better option, but if a system relied on the earlier behavior to force questions to be
asked in a particular order, and that behavior is preferred, the special command:
DO_NOT_LOOK_AHEAD
can be added to the command file to preserve earlier behavior.

Special Command: DONE_SCR=…


When Corvid reaches the end of the starting Command Block, it displays a “System Done” message. This is
not the desired user interface for some systems. In most cases, it can be prevented by adding the
“LastScreen” option to a Results screen, but this is not practical for some systems. The DONE_SCR option
allows specifying a set of Corvid screen commands that will be displayed in place of the “System Done”
screen. The file of commands is built as if it was part of a DISPLAY command, but instead of adding the
DISPLAY command, add a:

DONE_SCR=filename
and the screen commands will build a screen that will be used in place of the “System Done” screen.

Special Command: EMPTY_CELL=…


This command specifies what value should be used for an empty cell in the data for a MetaBlock. Normally,
the value of an empty cell is an empty string, " ", and the " " will be added wherever the MetaBlock parameter
is embedded.
The EMPTY_CELL command is particularly useful in cases where the MetaBlock file is also used for other
purposes, or comes from a database and is likely to have blank fields. The command allows setting a value
for use as a MetaBlock that will make sense in the context of the expert system.
For example: If there are 3 columns in the MetaBlock (A, B and C) and the system should concatenate
the 3 values together in a string variable [S]:
[S] = "{A}{B}{C}"
If the value of column A is 1 and C is 2, but B was blank, the value that would be assigned to [S] would be 1"
"2 (which is illegal and would result in an error message)
If the intention was to have a blank cell taken as 0, then adding the special command at the start of the
Command Block:

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=" "

Special Command: HYPERTEXT_BG_COLOR, HYPERTEXT_COLOR


When a section of text is marked as an HTML link using <A href=..”>, the default way that Corvid displays it is
to make the text blue with a white background. For some color schemes and designs, it is better to change
this to another combination of colors. To do this the commands:
Hypertext_color= RBG_color
Hypertext_bg_color= RBG_color

156 9: Command Blocks


allow the foreground text and background colors to be changed. These should be added to the Command
block somewhere before the screens using the links 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.

Special Command: NO_PARSE_ERRORS


A variable name in double square brackets [[ ]] can be used to embed the value of the variable in other
strings. Normally, if Corvid finds a [[ ]] expression that does not match a system variable or one of the special
“variables” such as [[~input]], it will report an error.
Any occurrence of "[[ ]]" will cause Corvid to handle it as an embedded variable. In some cases, it is
necessary to use files that have "[[ ]]" in them that are not associated with Corvid variables. This can happen
when using a PDF document as a template to build a form.
Adding the command:
NO_PARSE_ERRORS
at the start of the Command Block, will cause Corvid to NOT report embedded [[ ]] that do not match variables
as errors. Any embedded [[var]] that matches a variable will be replaced by the value of that variable. Any
other [[ ]] that is found will not be modified.
This command should be used with caution since it turns off error reporting and any typo in a variable name
that was intended to be embedded will also not be reported.

Special Command: NO_RESOURCE_CHECK


Resource files use [< … >] to mark the text that is replaced by the resource file. All external files are checked
for such links when they are read. If the “[<” is in the file for other syntactical reasons, such as data in a PDF
or other file, the “[<” will be misinterpreted and will lead to an error.
Adding the command:
NO_RESOURCE_CHECK
at the start of the Command Block, will cause Corvid to NOT check for “[<” in the system.
NOTE: This command will disable using any resource file with the system.

Special Command: QUIT_MB


When a Logic Block uses a MetaBlock, it runs the rules against each row of the MetaBlock. Normally after all
MetaBlock rows have been processed, the “best” options are selected based on their score. However, to
terminate a MetaBlock without running every row, the command:
QUIT_MB
can be used. Unlike the other special commands, this would be a command used within the Logic Block as a
command in the THEN part of a rule, rather than in the Command Block. It could be used if one of the items
in the MetaBlock received such a high score that there was no point in looking at the other options.
It can also be used when the MetaBlock is actually being used as a look-up table and it only needs to find the
first match.

9: Command Blocks 157


For example:
IF
{PartNum} = [Part_Number]
THEN
[Part_Name] = "{PartName}"
QUIT_MB
This would ask the user for a part number that would be stored in the variable [Part_Number]. This would
be compared to the rows in the spreadsheet to find a matching value in the PartNum column. When the
match is found, the string variable [Part_Name] is assigned the corresponding value from the PartName
column. At this point the lookup has done all it needs to, so the QUIT_MB can be used to stop processing
of subsequent rows.

Special Command: RESOURCE=


Resource files are used to build systems that run in multiple languages. (See section 11.6 on Resource files.)
The default resource file for a system is KBName.res, where “KBName” is the name of the system. If another
resource file is preferred, the command:
RESOURCE=filename
can be used in a Command Block or Logic Block, however this should be done before text from the resource
file is needed. If a system uses resource files to run in multiple languages, it can select the appropriate
resource file with rules such as:
IF:
Language = English
THEN
RESOURCE=MySystem_English.res

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

Special Command: SPECIAL_BUTTON=, SPECIAL_BUTTON_OFF


A button can be added to each question screen to perform some special action. The button is associated with
a Command block in the system. If the button is clicked, that Command block will be executed. This is done
by adding the command:

158 9: Command Blocks


SPECIAL_BUTTON "button_label" "command_block_name"
to the Command block. The button will appear on the lower right side of the applet window. The button can be
turned off when not needed by using the command:
SPECIAL_BUTTON_OFF
later in the Command block, for example, the command:
SPECIAL_BUTTON "Save data and exit", "SaveDataCmds"
would add a button labeled “Save data and exit” to all question screens.
Clicking the button would run the Command block “SaveDataCmds” which could have the database
commands to save all the session data to a database.
The called Command block can have any functions needed to perform a the special action. It should NOT
modify the values of variables currently in use, especially in a backward chaining system. Normally the called
Command block should end or terminate the system.

Special Command: 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 (Tomcat, Websphere, etc.) will terminate the session and free the session resources.
Unfortunately, the servlet engine does not know when the user has finished, so the session can stay active for
some time after the user is actually done.
The default time is set by the servlet engine, but is often 30 minutes. This means that the session resources
will not be released for that length of time. For most systems this is not a problem, but if there are expected to
be many simultaneous users, it is an unnecessary use of resources.
The time can be reduced by using the special command:
TERMINATE_IF_INACTIVE: #min
This can be set to a lower value (shorter length of time) to free up resources sooner for other system users. The
value should be set to be more than long enough for a typical user to respond to any screen that requires a
response. The goal is to free resources when the user is done, not to terminate a session they are running.
Another use is for a final screen that presents results and does not require a response. The screen can
remain displayed indefinitely, but does not require additional server-side session resources.
The TERMINATE_IF_INACTIVE command can be used to immediately free resources before the display of
the final results. This can be done by adding:
TERMINATE_IF_INACTIVE: 1
just before the final RESULTS command. Doing this will release the resources in 1 minute. After that, the user
will not be able to go back into the session using the Back button on their browser.
(NOTE: Some servlet engines may support using TERMINATE_IF_INACTIVE: 0, before the final RESULTS
commands, but behavior can be unpredictable and a value of 1 is recommended rather than 0.)

Special Command: USE_EXT_BROWSER


When running the Corvid Runtime as a Java Application (not as an Applet), trying to display an HTML page
using DISPLAY_HTML or links in text. requires having a specified browser program to call.
The command:
USE_EXT_BROWSER= file
specifies the browser program to be used to display pages when running as an application. Any URL from a

9: Command Blocks 159


DISPLAY_HTML or HREF link associated with text or an image will cause the URL to be displayed using the
specified browser program. This is ONLY needed when running as a Java Application and will have no
effect on systems run as applets or with the Corvid Servlet Runtime.
The browser program name should be a full path either from the root, or relative to the local directory of the
system CVR file. The command should be added to the Command block somewhere prior to the
DISPLAY_HTML command or any text with a link in it.

9.10.5 The TRACE Command


The Trace Applet allows examining the value of variables and the state of the rules and Logic Blocks in a
system at a particular point during a run. However, the Trace Applet is constantly interacting with the Corvid
Runtime Applet during a session receiving updates on the status. Because of this, the Trace Applet can only
be used when the system pauses to either ask a question or display a results screen. Normally this is not a
problem, since it is at these points that the developer most needs to check on the value of variables and rules.
However, for some systems it is desirable to be able to pause the session so that the Trace Applet can be
used to examine the current state.

This can be done with the TRACE command.


The TRACE command is a standard Corvid
command that can be added in the THEN part
of rules or in a Command Block. It is built from
the “Control” tab on the Corvid Command
Builder. It allows a string to be added which
will be displayed when the TRACE command
is executed. This can be used to identify the
specific TRACE command and indicate where
in the system session is.

The TRACE command can be added in the THEN part of


rules (Logic Blocks), or in Command Blocks.

160 9: 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 use 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.

9.11 Results Tab


The Results tab is used to build the “Results” screen
typically displayed at the end of a session containing
the systems conclusions, advice or answer. It can
also be used to build similar screens displayed at
other points in a system.
The screen commands associated with the display
commands only apply when running with the Corvid
Applet Runtime (either online or as a standalone
application). However, the HTML template files used
by the Corvid Servlet Runtime and Adobe Flash
interface files can also be specified.
Most systems will end with a RESULTS command.

9.11.1 RESULTS Command


Most interactive Corvid systems will display some
sort of results or conclusions at the end of a session.
This can be done in various ways, but the RESULTS
command is an easy way to display a formatted
results screen.
The RESULTS command displays the “Default”
results screen. There is only a single “Default”
results screen and the commands for this screen are
stored in the CVR runtime file. Other equivalent screens can also be created and incorporated into the
system with the DISPLAY command (explained below), but those store the screen commands in a separate
file. The RESULTS and DISPLAY screens have identical options and commands. The only difference is where
the commands are stored - internal to the CVR or in a separate file.
To add a RESULTS command, click on the “Display Default Results Screen” radio button. The commands for
the default results screen will be displayed in the box under the radio button.

9: Command Blocks 161


When a new system is started, there are no commands for the “Default Results”. Corvid automatically
considers this equivalent to the “Variables” command which will display all the variables that were assigned a
value during the session. If the box under the “Display Default Results” is empty, Corvid will display all
variables that were assigned a value.
The “default” commands can be edited by clicking on the “Edit” button under the command list. They can also
be edited by selecting the “Set RESULTS Default” item under the Corvid “Windows” menu.
The details of the Corvid Screen Commands are covered in Chapter 11 on the User Interface.

Systems using the Corvid Servlet Runtime and Flash


The default screen commands ONLY apply to systems that are run with the Corvid Applet Runtime, either
online or running as a standalone system with Java. Systems that run with the Corvid Servlet Runtime use
HTML templates to define the results (and all other) screens. In that case, design a HTML template file for
the results, click the “Browse” button and select that file to associate it with the RESULTS command. (Details
of Corvid Servlet Runtime templates are in Chapter 17 on the Corvid Servlet Runtime).
A RESULTS command can have both Applet Screen Commands and an associated HTML template. If the
system is run with the Applet Runtime, the screen commands will be used. If the system is run with the
Servlet Runtime, the template file will be used.

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).

“System Done” Message


At the end of a run, if the starting Command Block ends with a results screen that does not include a
“LastScreen” option, the screen will have an “OK” button. Clicking the button will take the system past the last
command in the Command Block and the system will automatically display a simple “System Done” message
and a restart button. This prevents systems that simply end with a blank screen in the applet window.
To have the Results be the last screen displayed, with no option to continue on to the “System Done” screen,
add a “LastScreen” option to the Results screen. (See chapter 11 on Corvid Screen Commands for details of
the “LastScreen” option.) The LastScreen option will change the “OK” button to a “Restart” button so there is
no way to move past the end of the Command Block.
It is also possible to change the screen that is displayed for the “System Done” message. Design a screen
and store it in a file. Add the command “DONE_SCR=filename” anywhere in the Command Block. This
command can be built as a “Special Command” on the “Control” tab. (See section 9.10.4 for information on
“Special Commands’).

9.11.2 DISPLAY Command


Corvid systems can only have a single
“default” Results screen stored in the CVR file,
but can have any number of similar screens
that store the screen commands in other files.
These are just text files containing the
associated screen commands.
Functionally the screens using DISPLAY are exactly the same at those using RESULTS, the only difference is
that DISPLAY must specify the file where the commands are.
To add a DISPLAY command, click the “Display File of Corvid Screen Commands” and either browse to and
existing file of command, or click “New” to create a new one. Once the file is specific, the “Edit” button will

162 9: Command Blocks


allow editing the commands. The commands are built and edited in the same way as the default RESULTS
command. (The details of the Corvid Screen Commands are covered in Chapter 11 on the User Interface.)
Like a RESULTS command, the DISPLAY command can have an associated HTML template to use when
running with the Corvid Servlet Runtime and XML specification to use when running with Flash.

9.11.3 DISPLAY_HTML Command


Corvid systems running with the Applet
Runtime can use the DISPLAY_HTML
command to open a HTML page in a separate
browser window. Normally this is done either
as the result of the link being clicked on, or using the Corvid Screen Command, but sometimes it is needed to
procedurally force a page to be displayed from the command file or logic.
To do this click the “Display HTML Page” radio button and enter the URL of the page to display.
The URL can be either a full URL or one local to where the system is run. So, if a HTML page MyPage.html
has been created, and put in the same folder as the Corvid CVR file, it can be referenced as just
“MyPage.html”. The page can also be anywhere else on the web and referenced by a full URL
(e.g. http://www.exsys.com/.../MyPage.html)
The DISPLAY_HTML command ONLY works with the Corvid Applet Runtime and has no meaning in the
Corvid Servlet Runtime (which has many other ways to display HTML pages).

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.12 Title Tab


A system can have a default “Title” screen defined with
Custom Screen commands and stored in the CVR file.
This is very similar to the default “Results” screen, but
is normally displayed as a title screen at the start of a
session.
Any screen can be defined with Custom Screen
Commands, stored in a separate file and displayed
with the DISPLAY command, so the TITLE screen is
redundant and not needed. Very early versions of
Exsys Corvid did not have the DISPLAY command and
used only the TITLE and RESULTS commands. The
TITLE command is retained for backward compatibility,
but no longer required.

The “title” commands can be edited by clicking on the


“Edit” button under the command list. They are edited
in the Corvid Screen Command builder window covered
in the chapter on the User Interface.

9: Command Blocks 163


The TITLE screen commands apply ONLY to the Corvid Applet Runtime running online or standalone. For
compatibility with the Corvid Servlet Runtime, a HTML template file can be associated with the TITLE
command. This template will be used when running with the Corvid Servlet Runtime.

9.13 Reports Tab


The Reports tab is used to build the commands to
build and save reports.
Many systems simply display a “report” of the
conclusions of the session using the RESULTS
command and Corvid Custom screen commands.
However some systems need to build and display
HTML, RTF or PDF reports. This is more complex
and requires server-side programs to meet Java
security requirements and provide special
functionality. The “Reports” tab is used to build these
commands.
See chapter 14 on Advanced Reports for the details of
building advanced reports and using the commands
on this tab.

9.14 Email Tab


The Email tab is used to build the commands to
automatically send emails. This can ONLY be
done when running with the Corvid Servlet
Runtime.
The details of generating and sending emails is
covered in section 17.10 on email.

164 9: Command Blocks


9.15 IF, WHILE and FOR Nodes
In addition to the normal command nodes in the Command Block, special nodes can be
added for IF, WHILE and FOR. These allow a section of commands to be executed only
if certain conditions are met, and allow a block of commands to be run multiple times.
These commands allow building complex Command Blocks for systems that require
more advanced procedural control.
The IF, WHILE and FOR sections can be nested to whatever level is required. However,
it is bad system design to put logic in a Command Block that should be put in a Logic or
Action Block. The logic in the Command Block should be limited to procedural
logic to control the flow of execution of the system, not core heuristic logic of the
decision-making task which should be in a Logic or Action Block. This is
sometimes a gray area, and a properly constructed system can work
correctly either way.
The commands associated with (and controlled by) an IF, WHILE or
FOR control are indented under that control and highlighted by a
colored bar. In this case, the group of 3 commands with the orange
bar will only be used if the IF test ([X] > 0) is true.
Each of the 3 controls has a different color, and when nested, the level
of the indent shows the controls associated with each control.
Each control ends with and “End” marker. This is actually only a comment and has no function except to mark
the end, however, the “End” marker is a convenient way to add nodes under the control. It is possible to
inadvertently delete the “End” marker. This will not change how the control works, but will make it difficult to add
new commands under the IF/WHILE/FOR group. This can be corrected by selecting the IF, WHILE or FOR
control that has lost the “End” marker, and clicking the “End Control Group” button. This will add a new “END”
marker.

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.)

9: Command Blocks 165


2. Click the IF control button.

3. This will open the same widow as is used for building


boolean expressions in the IF part of Logic Blocks.
Any boolean test that could be part of the Logic Block
can be used in the IF control Build any SINGLE
boolean test. This is usually done with the
“Expressions” tab, but can also be built with the “Static
List” or “Collection” tab.

Once the expression is built, click the “Add to List”


button.

4. This will add the boolean test to the “Nodes to


Add” list. There should only be a single item in the
list.

Click the “Done” button.

5. This will add the IF control to the Command Block.


It will be below the node that had been selected
and be just an IF control with the boolean
expression and a closing “IF End” node, which is just a comment.

166 9: Command Blocks


6. To add the command nodes in the IF group, click on
the IF control to select it. Then click the “Add
Below” button.

7. Add commands the same as adding any other


commands to a Command Block. They will be
added in IF control group. Additional commands
can be added by selecting a command in the IF
control group and clicking the “Add Below” and
“Add Above” buttons. The will be added in the IF
group relative to the selected node.

8. To add commands below the end of the IF control


group. Click on the “IF END” node to select it and
click the “Add Below” button.

9. The command added will be below the “IF End” and


not indented.

9.15.2 WHILE Controls


A WHILE control marks a group of nodes that will be executed based on whether a
boolean test is true or false. This is very similar to an IF control, but a WHILE control will
repeatedly execute the commands in the group UNTIL the boolean test is false.
! If the boolean test is true, the commands in the group will be executed in order
and then the boolean test will again be reevaluated. If it remains true, the
commands will be executed again. This will continue until the boolean test
evaluates to false. Once the boolean test is false, the first command after the
“WHILE End” will be executed.
! If the boolean test is false, the commands in the WHILE control
group will be skipped, and the first command after the “WHILE
End” will be executed.

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

9: Command Blocks 167


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 WHILE control marks one or more nodes with a light blue bar and ends with an “WHILE End”. Any
Command Block command or control (IF, WHILE, FOR) can be in the group of nodes associated with the
WHILE control.
WHILE control groups are added exactly the same way as IF control groups described above:
! Select the node above where the WHILE group will be added.
! Click the “While” button and build the boolean expression.
! Click the WHILE node, and click “Add Below” to add the first node in the group.
! Click any node in the group and click “Add Above” or “Add Below” to add nodes in the group, relative
to the selected node.
! When done, click the “WHILE end” node and click “Add Below” to add a node below and outside of the
the WHILE loop.

Reusing Rules and Variables in WHILE Groups


There are special considerations when using WHILE controls:
! Corvid will only use a rule ONCE and will not reuse it
unless it is reset with a RESET command. If a Logic or
Action Block needs to be used each time the WHILE loop
is executed, there MUST be a RESET command(s) in the
command group. If this is not done, the rules from the
Logic/Action block will fire the first time, but will not change
(or even be used) in the later loops.
! Likewise, once a variable has a value, Corvid will not derive a new the value for a variable unless it is
RESET. If the WHILE commands require getting new values for variables, either through derivation or
from external sources, there must be a RESET command for each of the variables. If the values are
being derived by rules, be sure to RESET the appropriate Logic/Action blocks that set the values.
! If many variables need to be reset, it is easiest to use a naming convention for those variables so their
names all start the same. For example, if all the variables that need to be reset start with “R_”, the
simple command “RESET R_*” will reset all of them.
! Be careful when reseting the variables used in the boolean test. If the boolean test is “[X] > 0”, ending
the WHILE command group with “RESET [X]” will cause the value of [X] to be derived or obtained from
external sources before the boolean test can be evaluated. This may be a good approach if the value
comes from external sources, but if it is derived, be sure to also RESET the rules that are needed to
derive it.
! If an external source sets the value for variables, that
can be used to overwrite the current values with new
values. This is often done in a system that gets data
from sensors or monitors a process. In this case, it is
not necessary to reset the numeric, string or date
variables that have their value set, but it may still
necessary to RESET any variables derived or
calculated from these variables. Since Static List,
Confidence and Collection variables can have multiple values, it will still be necessary to RESET them.
Infinite Loops
Infinite loops are legal, and sometimes used for monitoring systems. To make a WHILE control run
continuously, the boolean test “TRUE” can be used.
Unless the group of commands in the WHILE control is intended to loop continuously, there must be

168 9: Command Blocks


something within the command group that will eventually make the boolean test false. This may be the value
of a variable(s) that is derived or obtained from an external source, a READ command, etc.
To limit the rate at which the system will loop, use the SLEEP command in the command group. Select a
value that matches the rate at which the process being monitored changes. This will allow the system to
monitor effectively, but not unnecessarily use system resources.

9.15.3 FOR Controls


A FOR control marks a group of nodes that will be executed multiple times based on
various values for a variable. There are two types of FOR loops - one using a numeric
variable and one using a string variable and an associated collection variable.
! The most common FOR control uses a numeric variable. The FOR control has a
starting value, ending value and optional increment. The variable is set to the
starting value and the commands in the FOR group are executed. The variable is
then incremented and the associated commands executed again. This continues
until the variable reaches its ending value. The increment value by default is 1, but can be set to any
other value. The starting, ending and increment values can be static numbers, or expressions using
Corvid variables.
! A second type of FOR control is the FOR EACH. This uses a string variable and a collection variable.
The string variable is sequentially set to each value in the collection variable’s value list and the
commands in the FOR group are executed.

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.

Numeric FOR Controls


1. Select the upper “FOR” radio button.
2. Select the numeric variable to assign values to
to from the “Variable” drop down list. The list will
display all the Numeric variables in the system.
This is the variable whose value will change
each time the group of commands is executed.
3. Enter the “From” and “To” values. “From” is the
starting value. “To” is the ending value.
4. For a “Step” (Increment) value other than 1,
enter the “Step” value.
The variable selected will be assigned the “From” value and the commands in the group executed. The
variable’s value will then be increased by 1 (default) or the “Step” value if one is defined. The commands in
the group will be executed again. This will repeat until the value assigned to the variable is greater than the

9: Command Blocks 169


“To” value. If the value assigned to the variable is less than or equal to the “To” value, the command group
will be executed. If it is greater than the “To” value, the commands will NOT be executed.
The values entered for “From”, “To” and “Step” can be simple numbers or expressions that evaluate to
numeric values. The expressions can use Corvid variables or double square bracket embedded variables.

String FOR EACH Controls


1. Select the lower “FOR EACH” radio button.
2. Select the String variable to assign values to
from the “Assign to” drop down list. The list
will display all the String variables in the
system. This is the variable whose value will
change each time the group of commands is
executed.
3. Select the Collection variable whose values
will be used from the “Collection Variable”
drop down list. The list will display all the
Collection variables in the system.
The String variable selected will be assigned the first value from the Collection variable’s value list and the
commands in the group executed. The String variable’s value will then be assigned the next value in the
Collection variable’s value list and the commands executed again. This will be repeated until all of the values
in the Collection variable’s value list have been used.
Like a WHILE control, the FOR and FOR EACH controls generally reuse Corvid rules and
variables. The same issues for reusing rules and variables must be considered (see the
WHILE section above). The main variable associated with the FOR or FOR EACH will
automatically have its value set by the control, but any other variables may have to have their
value reset to have new values calculated. Likewise, rules may need to be RESET to have
them fire each time the FOR control loops.

9.16 Typical Command Blocks


Most Command Blocks have 3 main parts:
• Starting Commands - These are commands that display a title or explanatory screen on what the
system will do, what is expected of the user.
• Logic Commands - These are the commands that tell the Inference Engine what to do with the
rules.
• Result Commands - These are commands to display the results to the end user. This may be
simply displaying advice, creating and displaying a report, writing information into a database, etc.
Each of these sections has typical commands, and they can be combined in various ways depending on the
system requirements.

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.)

170 9: Command Blocks


The explanation of what the system is can be displayed with a TITLE or DISPLAY command to present a
screen built using Corvid screen commands for the Applet Runtime or HTML for the servlet runtime. This is
optional and some systems don’t need it. Sometimes the context of the system, the HTML page that linked
into the system or, for the applet runtime, other content on the page running the system makes this
unnecessary. However it is presented, it is always a good idea to tell the user what the system will do for
them and what they will get for answering the systems questions.
Once the system starts running the rules, it will typically ask the user questions. Depending on the nature of
the system the question order may be dynamic and change based on input, or be fixed. Sometimes the
desired user interface specifies that particular specific questions should always be asked at the start in a
particular order. If this is not the order that is automatically asked by the Inference Engine, it is generally
better to procedurally force those questions to be asked at the start, rather than modifying the rules to ask the
questions in a desired order.
The starting question order is a procedural, rather than logical, so it belongs in the Command Block. This can
be implemented in the starting commands by using ASK commands to force specific variables to be asked in
order. These individual variables may have “ALSO ASK” options set to ask other questions on the same
screen. When the logic needs the values, they will already be in the system and can be used. Questions
asked this way should be ones that will always be asked of everyone. If the need to ask a question is
dependent on the value of another variable, it is logic, and should handled in the rules.
Normally, the starting questions will just be a list of ASK commands. One exception is systems that run in
multiple languages. One way to handle these is through Corvid resource files for the various languages.
Selecting the language is procedural, and fits well in the
Command Block with an IF command. The Command Block IF
command can be used to select which resource file to use based
on the language. Even though this uses an If/Then syntax, the
selection of the language is procedural and does not change the
system logic. (However, if there were many languages, it might
be easier to build this type of logic in a Logic Block and simply call
it with at FORWARD command.)

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.

9: Command Blocks 171


If the decision-making logic requires WHILE or FOR loops, those have to be implemented in the Command
Block. That will require a more complex set of commands, breaking the rules into blocks that can be called
with either backward or forward chaining within the WHILE or FOR loops. This type of logic will also generally
require using RESET commands for the blocks and variables to allow each loop to run with new data.
The logic commands should completely run the rules and come to whatever conclusions the system will reach.

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.

172 9: Command Blocks


Chapter 10: Action Blocks and Smart
Questionnaires
10.1 Overview
Action Blocks provide another way to describe decision-making logic. They are an alternative to Logic Blocks
for certain types of systems, and can be used in conjunction with Logic Blocks.
Action Blocks use a “spreadsheet” approach to representing a series of questions or steps. This is quite
different from Logic Blocks which typically use a tree structured approach to the logic of a system. This was
originally created for “Smart Questionnaires” which ask a series of questions, but certain answers lead to
skipping over some unnecessary questions.
Action Blocks are ideal for:
! Smart questionnaires.
! Surveys.
! Implementing procedural instructions.
! Dichotomous keys.
Many procedures and operations are already in a written form that can be very easily converted to an Action
Block and implemented online with Corvid. Anything from tax forms to instructions on how to assemble a
bicycle can directly converted to Action Blocks and fielded online.
Actions blocks can:
! Ask questions in order to collect data or indicate a step has been done.
! Use all the Corvid options for online user interface design.
! Analyze the user input to perform calculations or apply Corvid rules, including using other Corvid Logic
Blocks when needed.
! Skip questions or sections when they are not needed.
! Dynamically build reports.
! Present the conclusions, reports and advice to the end user.
! Save the end user’s input in databases or interface with other external programs.

10.2 Action Block Structure


This section explains the controls on the Action Block window. The next section “Action Block Tutorial” shows
actually building a small system as an Action Block and illustrates using the controls.
Action Blocks use an easy to understand spreadsheet style interface. The rows in the block contain the
various questions or boolean expression the system will use. Each related answer, or expression, is on a
separate row. Each of the answers can have one or more actions
associated with it. The actions can perform calculations, skip down to a
lower row (skipping some questions), add content to a report or various
other actions. This is a very simple way to describe logic that can be
rapidly learned, and it is applicable to a wide range of problems –
especially when combined with capabilities of Logic Blocks where
needed.
To add an Action Block to a system, click the “A” icon.

10: Action Blocks and Smart Questionnaires 173


This will open a new Action Block window. The window
is a spreadsheet with rows and columns.
Content is added to the Action Block in the same way
as other spreadsheets.
The Action Block rows will be the various questions or
expressions need for a specific system. The columns
are always the same 6 columns.

Action Block Columns:


A unique label for the question. This is used to identify rows FOR “GoTo” actions that
Label
skip over some questions.

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.

174 10: Action Blocks and Smart Questionnaires


The rows in the Action Block will be in the same order as
the questions/steps in the form or questionnaire being
converted to the Action Block.

When a new Action Block is created it will not have any


rows.

To add the first question to the Action Block, click the “Add
Question” button.

The “questions” in an Action Block are the same as the


IF nodes in a Logic Block, built using a Corvid variable.
They are added the same way, with the same options.
They can use either variables already in the system or
new variables added as needed.

The same window used for adding Logic Block IF


nodes is displayed, and it works exactly the same way.
For example, if the “Add Each Individually” button is
clicked for a Static List variable, each value will be
added individually. For Static List variables, the
possible values can be added individually or as groups
that all have the same logical meaning. For other
types of variables, groups of related boolean
expressions can be added using one or more
variables.

Here there is a variable [Color] with values of “red”,


“blue” and “green” and each value will be added as a
separate node.

Click the “Done” button to add the selections to the


Action Block.

When added to the Action Block, the “Label” value is

10: Action Blocks and Smart Questionnaires 175


set to the variable name and the
“Question” is set to the variable
prompt. There will be a row for
each value. The “Label” and
“Question” apply to all the value
rows.

Instead of adding nodes to a Logic Block tree, there are rows in a


spreadsheet.

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.

Add a string to a Collection variable. This is a convenient way to dynamically build


reports based on the user’s input. This text can be simple statements for a report,
Add to
or complex HTML commands to dynamically build a custom web page for the user.
Collection
The Collection variable to use is entered in the “To” column and the text to add is
entered in the “Content” column.

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.

176 10: Action Blocks and Smart Questionnaires


Ask the end user for the value of a variable. This can be used to obtain additional
information that is not explicitly needed as part of the system logic, but which may
Ask
be included in reports etc. The variable to ask is entered in the “To” column.
Nothing is needed in the Content column.

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.

Replace Add a new question replacing the currently selected question.


Delete Delete the currently selected question.
Open the Variable window to edit the Prompt and other properties of the variable
Edit associated with the selected question. Remember changing the properties of a
variable change it everywhere the variable is used.

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.)

10: Action Blocks and Smart Questionnaires 177


Move Up Move the question and all its values up in the list.
Move Down Move the question and all its values down in the list.
Edit the selected label. This is active only if the click to select the question was on the
Edit Label
Label column.

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.

Copy Copy the current Action to be pasted.

Cut Delete the current Actions, but keep a copy that can be pasted.

Paste Paste the Action from the last cut or copy.

Delete Delete the selected Action.

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

178 10: Action Blocks and Smart Questionnaires


Add Heading Buttons
The Add Heading button will add a heading line. Heading lines have no
effect on the logic, but make it easier to segment the questions.
Clicking the button will display the heading window.
Enter the heading to add, and select to add it to the end or to insert it at
the currently selected question.

Undo Button
The Undo button allows you to undo your last actions. You can undo up to 5 steps back.

Convert to Logic Block Button


The Convert to Logic Block button will permanently convert the Action Block to an equivalent Logic Block.
This will allow you to edit and enhance it as a Logic Block. Once converted the Logic Block cannot be
converted back to an Action Block. The Undo command cannot be used to step back to the Action Block
once it is converted. The new Logic Block will have the same name as the Action Block. The Action Block
will be deleted once it is converted. Delete Block Button

Delete Block Button


The Delete Block button will delete the current Action Block.

10: Action Blocks and Smart Questionnaires 179


10.3 Action Block Tutorial
Action Blocks are quite easy to use. The best way to learn them is to follow along building an actual system.

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.

Variables can be used to directly ask the user for


information that will be used in the system, for internal use
to do calculations, hold values or build reports. The
questions you want the system to ask the user are:

! Do you have credit cards?


! How many cards do they have?
! What is the total balance on the cards?
! What is your annual income?

In addition, checking account questions will be used to


start the next section.

The system also needs a variable to hold the ratio of debt


to annual income, and a variable to build a report on
status.
Each variable has:

! 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.

180 10: Action Blocks and Smart Questionnaires


The variables in the system will be:

Name Prompt Type


Credit_Card Do you have any credit cards? Static List
Values: Yes / No
Number_of_Cards How many credit cards do you have? Numeric

Card_Balance What is the total balance on all credit Numeric


cards?
Annual_Income What is your annual income? Numeric
Has_A_Checking_Acct Do you have a checking account? Static List
Values: Yes / No
Debt_ratio Ratio of credit card debt to annual Numeric
income.
Report Report Collection

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.

Variable names must be unique and cannot include spaces,


or the characters:

[!~!@^&*()-+="?><.,/:;{}|\`]

If spaces or any illegal character is included in the name,


Corvid will automatically convert it to an underscore
character.
Enter “Credit card” as the name, and Corvid will convert it to
“Credit_card”. This is a Static List variable with 2 values, so
make sure “Static List” is selected and click the OK button.

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?”

For Static List variables, the list of possible values must be


defined. This question will have only “Yes” and “No” as values.
Enter “Yes” in the green value edit box and click the “Add to
List” button. This will add “Yes” in the list box below.

10: Action Blocks and Smart Questionnaires 181


Now enter “No” in the value edit box and click the “Add to List”
button again, to add that value to the list.

That is all that is needed to define the first variable.

The next variable is a Numeric variable.

Click the “New” button in the Variables window to bring up the


windows for entering the name and type of the new variable.

Enter a name of “Number of cards” and set the type to “Numeric”.

Click the OK button.

Change the Prompt to “How many credit cards do you have?”


Since this is a Numeric variable, it does not have a specific value list,
and it is fully defined.

Follow the same steps to add the other 4 variables:

Name Prompt Type


Card_Balance What is the total balance on all credit Numeric
cards?
Annual_Income What is your annual income? Numeric
Has_A_Checking_Acct Do you have a checking account? Static List
Values: Yes / No
Debt_ratio Ratio of credit card debt to annual Numeric
income.

Once they are added the variable window should look like:

The last variable to add is a


Collection variable that will be
used to build a report. It’s name
is “Report”. It is added just like the other variables, but the Type
is “Collection / Report”.
In this case the Prompt can be left as “Report”.
That is all the variables needed for this tutorial. Here all the
variables were added at the start, but that is not required.
Additional variables can be added at any time. Also, all
properties of the variable can be changed at any time – except
the Type. The Type can be changed until the variable has been
used in one of the Action Blocks.
Close the Variables window by clicking the “Done” button.

182 10: Action Blocks and Smart Questionnaires


Building Rules in an Action Block
Now that the variables are entered, the next step is to build the rules in the Action Block.

Open a new Action Block by clicking on the Action Block icon on the command bar.

Click on the “Add Question” button to add the first question in


the block.

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.

Click on the “Credit_card” variable in the list to select it.


The “Yes” and “No” values for the variable are displayed in the
right list box.

You want a separate rule for each value.

10: Action Blocks and Smart Questionnaires 183


Click the “Add Each Individually” button.

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.

Click on the Action drop down list next to the


“No” in the values column. (Be sure you are
on the second row next to the “No”.)

Select “Goto Label”.


The cell in the “To” column will turn red to
remind you that a value needs to be entered
there. However, the other questions have not
been entered yet, so just leave this as a
reminder to select a label later.

Now for the “Yes” value. There are various


ways this can be approached. One option
would be to not have any action associated
with this value. If the user says “Yes”, it
would not do anything, but would just move
on to the next question that you will add. If
they said “No”, the Goto Label action would skip over the credit card questions.

Here you will use a more advanced approach


using the Set action to calculate a value that
can be used later. In the Action column next
to the “Yes” value, click the drop down list and
select “Set”.
The “To” column turned red to remind you that
the variable to be “Set” needs to be selected.
The “To” cell also became a drop down list of
all the variables in the system. Pull down the
drop down list and select “Debt_ratio”.

184 10: Action Blocks and Smart Questionnaires


If you need to make the “To” column wider, click on the vertical divider just right of the “To” in the
header, and drag it to the right.

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]

will calculate the value of the variable Debt_ratio.

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.

The content text can be entered either directly in the


spreadsheet, or in the Content edit box. In most cases, it
is easier to add and build expressions in the edit box
because a special window to add variable names can be
called. This makes it easier to build expressions and
reduced the chance of a typographical error.

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.

Click on “Card_balance”. The properties for the variable will


be displayed on the right, but you do not need those at the
moment. Click OK. You can also just double click on
“Card_balance”, which is quicker in cases where a property
is not needed.

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.

The cursor should now be just right of the closing ].

10: Action Blocks and Smart Questionnaires 185


Type in the division sign /
Now hit Ctrl-Alt-v again to bring up the variable window and double click
on “Annual_income”. This will add that variable to the content field.

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.

Using Variables that Already Have a Value


Now add some rules that make use of the debt_ratio that
was calculated in the first rule. If the user answers “No” to
the first question, the Goto Label will skip over this question.

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.

Click on the variable Debt_ratio in the left list to select it.


Since it is a numeric variable, the “Expression” tab is
automatically selected and the variable name in [ ] is copied
over there so it can be used to build a Boolean expression.

Since the expressions you are building will become the IF


parts of rules, they must be tested to evaluate to true or
false. The first test if the ratio is less than 20% (.2).

186 10: Action Blocks and Smart Questionnaires


To do this enter < .2 after the variable name. Then click the “Add to List”
button. The test will appear in the “Nodes to Add” list.

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.

Whenever an expression is entered, Corvid checks the syntax to


make sure it is correct. If there are no errors, it will be added. If
any errors are found, Corvid will display a window indicating the
error so you can make corrections. If the expression was correct,
you should not see this window. If it is displayed, correct the text
and click the “Recheck”. (In this sample one of the parenthesis
was left off.)

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 “Add to Report/Collection” action requires


that the “To” column be a “Collection variable”.

10: Action Blocks and Smart Questionnaires 187


Since there is only one Collection variable
defined, it is automatically selected. The Content
column is the text that will be added to the report.
It is automatically set to the value that was used.
In this case, what you want to add to the report is
the note: “The amount on the credit cards is
reasonable considering the income.”

Change the text in the Content edit box to:

! The amount on the credit cards is reasonable considering the income.

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.

Value Text to Add to Report

([debt_ratio] >= .2) & ([debt_ratio] < .3) The amount of credit card debt is a little high, and
should be reduced.

[debt_ratio] >= .3 The amount of credit card debt is quite high.


Reducing this should be a priority.

When done the spreadsheet will look like:

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.

188 10: Action Blocks and Smart Questionnaires


Adding Another Question
Now add one more question on the number of cards the user has. You will use the Number_of_cards variable
that was added at the start of the system.

Click the “Add to End” button and in the window for building test conditions, add 3 tests:

[Number_of_cards] <= 6

([Number_of_cards] > 6) & ([Number_of_cards] <= 10)

[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:

Value Text to Add

[Number_of_cards] <= 6 The number of credit cards is reasonable.

([Number_of_cards] > 6) & The number of credit cards is a little high.


([Number_of_cards] <= 10)

[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.

The spreadsheet should now look like:

10: Action Blocks and Smart Questionnaires 189


Adding Headings
That is all you will do with credit cards in this demo. If the system was to examine many aspects of the user’s
finances, it could cover credit cards, checking accounts, loans, investments, IRAs, etc. For this demo, we will
just show how to start the next section, but you will not fully build it.

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.

To add a heading, click the “Add Heading” button at the


bottom left corner of the Action Block window.

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.

190 10: Action Blocks and Smart Questionnaires


Using the Goto Label Action
There is only one step left in the Action Block (at least for this tutorial). The spreadsheet still has the red cell
on row 2. Red cells indicate a cell that requires some input. Here you are not able to select the label to go to,
since you do not have the other questions in place.

Now add a question under the “Checking Account”


heading.

Click the “Add to End” button. Select the variable


Checking_account, and click the “Add Each
Individually” to add a row for each value, and click the
“Done” button.

The spreadsheet should now look like:

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.

To do this, click the “To” column in row 2 and select the


label for row 10 “Checking_Account” from the drop-
down list. This list will have the names of the “Labels”
that occur in the Action Block below the line selected.

That completes building the Action Block.

10: Action Blocks and Smart Questionnaires 191


Running the System
Now you can run the system. To run a system, click the blue triangle icon in the
command bar.

At this point you will get a warning that


there is no Command Block.

All systems MUST have a Command


Block to run. For systems that require
particular ways to run the rules, the
Command Block must be built in the
Command Block building window.
However, here all you want to do is run the
Action Block in forward chaining and
display the results. Corvid can
automatically build a simple Command
Block to do this.

Click the “Forward Chaining” radio button


and then the “Build Command Block”
button.

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.

192 10: Action Blocks and Smart Questionnaires


The blue portion of the window is just a standard
HTML template that can be easily modified with any
HTML editor. The white rectangle is the Corvid
Applet Runtime that is running the system.

As expected the first question asks if you have a


credit card. Click the “Yes” radio button and then
the OK button.

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.

The system now displays a default “Results”


screen. This screen shows the values of all
the variables used in the system. The first 5
are the variables that were asked directly of
the user. The next line is the Debt_ratio that
the system calculated. The last 2 lines are the
report that the system generated.

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.

10: Action Blocks and Smart Questionnaires 193


Chapter 11: Controlling the User Interface
11.1 End User Interface
Most expert systems built with Exsys Corvid are interactive, asking the end user questions and, based on
their input and system logic, reaching conclusions or advice that is presented to the end user. Systems can
be run using the default look-and-feel, but most system developers will want to change the user interface to
match a web site, incorporate more advanced graphical features or just for stylistic reasons.
There are 4 main types of screens are used when running an expert system:
! Static content screens such as Title screens.
! Question Screens that ask the user for input.
! Conclusion screens that display system results.
! Ancillary screens that provide additional information, often linked to content on one of the other
screens.
Screens such as title and conclusion screens are displayed procedurally from the Command Block using
special Command Block commands. Screens to ask questions are associated with specific variables and
when the variable is needed, and asked, the associated screen will be displayed.

11.1.1 Applet vs Servlet User Interface


The end user interface can be designed in two main ways. The first is with Corvid Screen Commands. These
are simple commands that allow text, images, variable values, etc to be added to a screen with formatting and
relatively simple arrangements. These commands are easy to use and will work with either the Applet
Runtime or the Servlet Runtime with the default templates. While they do not provide the design options of
the more advance customized templates, they are generally adequate for most system design and are
certainly the best to use when developing the system logic.

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.

11: Controlling the User Interface 195


11.2 Setting the Runtime Applet Window Properties
When a system runs using the Corvid Applet
Runtime, the system screens will be displayed in
an HTML page with an applet window.
(Systems running standalone as Java applications
will be the same as the applet window portion of
the screen.)
The user interface created with the Corvid Screen
Commands will appear in the 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.

The Controls on the ”Applet” tab set


how the system will be displayed in the
HTML page.
! Width / Height: The width and
height of the applet window for
the system. These are
measured in pixels.
! Align: Sets how the applet is
aligned in the HTML page.
Default is “Middle” (Centered).
! Background Color: The
background color for all applet
windows.
! Button Labels: Sets the labels
for the buttons that Corvid adds
automatically. These can be
changed to other languages when needed.
! KB Default Font: Default font used for all text in the system. This can be overridden for individual
items of text in the system.
! Vspace / Hspace: The separation values between the Corvid applet and the Trace Applet. (This
should normally stay at the default value.)

196 11: Controlling the User Interface


The Applet Runtime HTML Page
Corvid automatically generates a HTML page to run a system with the applet runtime. This uses the default
Corvid template and the values set on the “Applet” tab. The default page template is
“Corvid_Run_Template.HTML” Generally this is all that is need for development, but when the system is
fielded the overall page can be modified to whatever look-and-feel is desired.
The HTML page that runs the system will contain an applet tag. This will looks something like:

<applet code="Corvid.Runtime.class" name="CorvidRuntime"


archive="ExsysCorvid.jar" width=700 height=400 hspace=0 vspace=0 align=middle>
<param name="KBBASE" value="">
<param name="KBNAME" value="MySystem.CVR">
<param name="KBWIDTH" value="700">
</applet>
The contents of the applet tag generated by Corvid should not be modified, but the rest of the HTML on the
page can be changed in any way to make it match the look of a site, fit the design of the system, provide
other information, etc. Just open the page in an HTML editor and make any changes that are desired.
If there is already a HTML page with the look that you would like for your systems, this can be used in place of
the Corvid default page. Design the page with a standard HTML editor and simply insert the text
“CORVID_RUNTIME_APPLET” where the applet tag should be included. This should be simple unformatted
text on the page. Corvid will automatically convert “CORVID_RUNTIME_APPLET” to the actual applet tag
using the values set on the “Properties” window “Applet tab”.
Then set this as the HTML page to use to run the system. In the “Properties” window, “Applet” tag, on the
“Applet Runtime HTML Template” area, click “Use Custom” and enter or browse to the HTML page.
When Corvid runs it will use the template to build the HTML page named KB_name.html (Where “KB_name”
is the name of your system.) The same template can be used for many systems that should have the same
look-and-feel. The KB_name.html page that Corvid generates is used to field your system - the template file
does not need to be distributed or used outside of the development environment.

11.3 Corvid Screen Commands


The screens displayed by the Corvid Applet Runtime in the Applet window and displayed by the Servlet
Runtime default templates are defined by Corvid Screen Commands. There are commands to display text,
variables, controls, images and buttons to create the screen design. Most screens, or sections of a screen,
will have a list of commands to add various items.

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.

11: Controlling the User Interface 197


If you want to experiment with screen commands, select “Set RESULT Default”
under the Corvid “Windows” menu. This will display the screen command builder
and allow you to add commands. These commands would be displayed with the
RESULTS command.

NOTE: The Corvid Screen Commands provide a great deal of design


flexibility, especially when combined with HTML designs for the rest of the
page that contains the applet tag. However, they are not as flexible or
powerful as customized HTML templates for the Corvid Servlet Runtime or
interfaces using Adobe Flash. For most complex systems, those may be
better options.

Screen Commands are built with the Screen Commands


window. This window is displayed whenever Screen
Commands need to be added or edited.
The top of the window is a list of the commands for the
screen or section of a screen. These can be added,
deleted, edited and reordered with the buttons below the
list.
Various types of items can be added to the screen using
the controls on the lower left. Properties for many of the
items can be set using the controls on the lower right under
the various tabs.

11.3.1 Adding / Editing Screen Commands


Screen commands should be built using the controls in the lower part of the window. This way, commands will
automatically be built with the correct syntax. When a command is built, it will appear in the edit box below the
list of commands. It can be directly edited in this box, but editing with the controls below is recommended.
Items display on the final screen in the order of the commands in the command list. If the command list had 2
“TEXT” commands:
TEXT “First Line”
TEXT “Second Line”
it would display as:
First Line
Second Line
Some commands such as the “Buttons” commands set button properties for the displayed screen and can be
anywhere in the command list.
To add a screen command: Build the command with
the controls in the lower part of the window. The
command will appear in the “Command Edit Box”.
If this is the first command, the only active button
will be an “Add” button. Click the “Add” button or
the return key to add the command as the first
command in the list.

198 11: Controlling the User Interface


Once there are commands in the list, new commands can be added to the end of the list by clicking “Add
Last”. If a command in the Command List is selected, the new command can be inserted before the selected
command by clicking “Insert” or the new command can replace the selected command by clicking “Replace”
To editing an existing command, click on the command in the list to select it and click the “Edit/Build” button.
The command will appear in the Command Edit Box and the controls below will be set to the values from the
command. Make any changes with the controls and click the “Replace” button to replace the selected
command in the list with the edited one. If the command should be replaced by a different command, just
build that command with the control and click “Replace” to replace the existing command.
A command can be deleted by clicking the command to select it and clicking “Delete”.
The order of commands in the list can be changed by clicking on a command to select it, and clicking the “Up”
and “Down” buttons to move that command up/down in the command list.
To add/edit the format associated with the selected line, click the “Format” button. (Formatting is explained below.)

11.3.2 Text Screen Commands


The most common operation in designing screens is to display a text
string. The Corvid Screen Commands have several related
commands to display text on the screen:
! Display a specific text string.
! Display text from a file.
! Display the value of one or more Corvid variables.
All of these commands are built from the Screen Commands window.

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.

Text from a File


Enter the name of the file of text in the edit box below “Text File”, or click the “Browse” button and select the
file. The file should be a text file - just text with no formatting. The text can include embedded variables or
other embedded data which will be replaced when it is displayed. Using text from a file can be convenient if
the text is long, or to edit/generate the text outside of Corvid.

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.

11: Controlling the User Interface 199


To include the Properties for a variable, click the “Prop” button. This will display a window with all the
variables and their associated properties. Select the variable/property.
There are many other options available when displaying the text of variables. See section 11.5.2 on using
variables in Results screens.

11.3.3 Setting the Screen Background Color


The default background color for all screens in a system is set from the
“Options” window, “Applet” tab as described in Sect 11.2 above. To set
the background color for a specific screen to a different color, add a
“Background color” command at the top of the screen commands.
Click “Choose” and select the color from the color picker.
This color will apply only to the specific screen. Other screens will use the default color.

11.3.4 Formatting Text


All of the text commands are formatted the same way using the
Format window. There are 2 ways to get to the Format window.
! Click the “Format” button in the controls at the top of the
window. This will apply the format to the currently
selected command in the command list, not the
command being built.
! Click the “Edit” button on the “Format” tab. This will apply
the format to the command currently being built.
Either option will open the Format window. This
has many controls to format different types of
screen objects and not all apply to text.
The ones that apply to text are very similar to the
sort of options that are set for word processing text:
! Font size, style and color
! Position
! Indent
! Text box

Font Size and Style


In the “Font” control group select the font, size and
style. The fonts are limited to “generic” Java fonts that
are found on all systems, rather than more specific
font types. The font, size and style apply to all the text
in the single command. (However, the font properties on a line can be changed with the SAMELINE command, and
inline <Format..> command covered below.)
Foreground / Background Color
Enter the RGB values separated by commas, or click the “Choose” button and select the color from the color
picker.

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.

200 11: Controlling the User Interface


Text Width
Normally text that is more than one line will wrap to fit in the applet window (Corvid Runtime Window). To
force the text to wrap sooner, enter the number of pixels in the “Text Width” edit box. This should be a value
less than the width of the applet window. Text will wrap at that width or less so that no words are broken.

Indent
To have the text indented from the margin, enter the number of pixels to indent from the left.

Text Box Area


Text boxes are a way to put a large amount of text in a small area. The box has a fixed maximum number of
characters per line, and number of lines displayed. These set the size of the box (NOTE: The width is in
number of characters, not pixels, and the actual size will depend on the font and character size chosen) The
number of actual lines of text can be any amount. Normally, the text box should have the “Vertical Scroll Bar”
checked. This puts a scroll bar and thumb on the box so that the text can be scrolled. If the box does not
have a vertical scroll bar, it can still contain more text than can be displayed at one time. If horizontal
scrollbar is selected, the text will be a single line, but can be scrolled. The text in the box should be simple
text with no formatting. The font style, size and color properties applies to the text in the box. The text cannot
contain links or images. It can contain embedded variables or other embedded data.
Examples:

11: Controlling the User Interface 201


11.3.5 HTML Links in Text
Text displayed on any Corvid screen can include HTML links. The linked text will be highlighted when it is
displayed, and clicking on the link will display the linked URL in a new browser page (or browser tab -
depending on the end user’s browser settings). The link is added using standard HTML code:
A HREF=”link”>text</A>
For example, if the text is:
The recommended product is the <A HREF= “http://www.mysite.com/products/X123.html"> X123 </A>. It
would meet your requirements very well.
This would be displayed as:
The recommended product is the X123. It would meet your requirements very well.
A click on “X123” would bring up a new browser window displaying the associated URL.
The “A HREF” is not case sensitive, and <a href=”..”>...</a> is an alternative
Because of the way Java displays the links, it may put an extra space around it. If this is a problem, it can be
compensated for by not adding spaces in the text around the linked word or phrase.
Since this uses standard HTML, the link in the text will work with both the Applet and Servlet Runtime
programs. However, the applet only supports the simple “A” tags. The Corvid Servlet Runtime supports more
complex tags with “Class” and other properties.

Changing Hypertext Link Color


When a section of text is marked as an HTML link, the default way that Corvid displays it is to make the text
blue with a white background. For some color schemes and designs, it is better to change this to another
combination of colors. To do this the commands:

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.

202 11: Controlling the User Interface


11.3.6 Image Screen Commands
There are 2 ways to add images to screens. Images that should appear on
their own line can be added with the “Image” command from the screen
command builder.
This allows including JPG or GIF images, including animated GIFs. Enter the
name of the image file or click “Browse” and select the file. The image will be
displayed at its actual pixel size. If the image is too large for the window, it
should be resized in an image editing tool.
The options for “Indent” and “Position” (Left, Center, Right) apply to images
added with the IMAGE command.

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)

Positioning an IMG SRC Command at the Start of a String


If a text string starts with an IMG SRC command, Corvid will display the image to
the left of the text. The "ImagePos=" format command allows the image to be
placed in other locations. The default is to have the image to the left of the text.
This is ImagePos=W (Image is west of the text). Options are ImagePos=N
(Image is north, above, text) and ImagePos=E (Image is east, left, of text).
These option only apply when the text string starts with the IMG SRC command,
or an IMG SRC command that has been made a link.
The format options do not apply to this command.

11: Controlling the User Interface 203


11.3.7 Putting Multiple Items on the Same Line
By default, the Corvid Screen Commands, put each item on a new line. An option allows multiple items to be
placed on the same line. For example the commands:
Text "AAA"
Text "BBB"
Text "CCC"
would display as
AAA
BBB
CCC

The option "SAMELINE" can be added into a list of applet


screen commands. All items following the SAMELINE
command will be placed on the same line until a
SAMELINE_END command or another SAMELINE
command is encountered.
Click the "Same Line" button at the bottom of the
command builder window, and then the "Add" or "Insert"
button to add the command to the command list. The
"End Same Line" button will likewise add the
SAMELINE_END command.
The commands:
SAMELINE
Text "AAA"
Text "BBB"
ext "CCC"
SAMELINE_END
would display as:
AAA BBB CCC
This is particularly useful for adding text on the same line as images.
When using the SAMELINE command, remember that the line height will be the height of the tallest item on
the line. Also, adding many items on the line may cause the applet display width to be larger than the width
allowed for the applet window. This will cause a horizontal scroll bar to be displayed at the bottom of the
applet window and will require scrolling to see the entire image. In some cases this may be desirable, but it is
generally better to only have the vertical scroll on the right side of the applet window.
Often it is better to create a single longer string, double square bracket embed multiple variable values in a
string or use an “img src=”..”> to put multiple items on the same line.

204 11: Controlling the User Interface


11.3.8 FORMAT Commands in Text String
Any screen command that displays text can have an associated format to set its font, size, color, etc. This is
built with the format options and applies to the entire text string and Corvid will display the entire string on
one line (though it may need to wrap the line.)
There are special format commands that can be put in a line of text to allow formats to apply to only sections
of the string, and commands to force Corvid to add a line break within the string. This allows more control on
the display and formatting of the text.

<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

11: Controlling the User Interface 205


BCOLOR=#,#,#
The background color for the text. As with FCOLOR, the color is started as the RGB value. To have
a white background use BCOLOR=255,255,255
An example:
To make the text 14 point, bold and blue, use:
<FORMAT SIZE=14 STYLE=BOLD FCOLOR=0,0,255 >
To return to the default format, use the command </FORMAT>.
The screen command:
Text "AAA BBB"
would display as:
AAA BBB
However, the command:
Text "AAA <FORMAT SIZE=16 STYLE=Bold>BBB"
Would display as:
AAA
BBB
NOTE: the <FORMAT> command always puts the following text on a new line.
When adding individual items of text to an applet screen, the format options provide great flexibility. The
<FORMAT..> command is most useful when formatting text in a report that is dynamically built in a Collection
Variable and later displayed in an applet window. For example, if [RPT] is a Collection Variable being used to
build a report, the commands:
[RPT.ADD] <FORMAT: SIZE=18 STYLE=BOLD FCOLOR=0,0,255>
[RPT.ADD] [[Rpt_title]]
[RPT.ADD] </FORMAT>
[RPT.ADD] [[Author]]

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.

11.4 Question Screens - Asking the End User for Input


The core part of most Corvid systems is the dynamic interaction they have with the end user. A well designed
system will ask questions similar to talking to a human expert. The system only asks relevant questions,
skipping over irrelevant ones and digging in for more details when the decision-making logic calls for it.

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.

206 11: Controlling the User Interface


Corvid Question screens are structured in layers.
Each of the layers is built using the Screen Command
builder and a list of screen commands. Except for the
prompt and input controls, the other layers are optional.
Generally the question header/footer will apply to all
question screens and help define the overall look and
feel. The question “Other Graphic” will come from each
question individually and usually be defined individually.
The question prompt / values will be set by each
question, but using a “template” style that allows Corvid
to dynamically build these automatically based on the
question prompt, type and value list.

11.4.1 Question Screen Header and Footer


The overall header and footer are a set of screen
commands that will be displayed in every question
screen. Typically this can be a logo, system title or some
design element that is wanted on each screen. The
header and footer should not have anything in them that
applies to only individual questions.
The overall header, footer and defaults that apply to all
question screens are set by opening the Variables
window and clicking on the “Question Defaults” button.
This will open the dialog box for setting the header, footer
and default formats. These will apply to ALL question
screens.
To add content for the Header:
! Click the Header radio button. If there are any
Header commands they will be displayed in the
box.
! Click the “Edit” button to the right of the box.
! This will open the standard Screen Command
builder window. Add whatever commands are
desire for the header section. (Blank lines to
space down can be added by just clicking a space
in the “Text” command and adding a space in it.)
To add content for the Footer, click the “Footer” radio
button and add commands just like for the header.

11.4.2 Default Prompt Format


Corvid will automatically add the Prompt text for each variable on a questions screen. To set the format for
the Prompt, click the “Edit” button right of the “Prompt Format” edit box. This will display the standard Format
dialog. Set the font, size, color, indent, etc for the Prompt text. This format will apply to the Prompt displayed
in all question screens.

11: Controlling the User Interface 207


11.4.3 Default Value Format
Corvid will automatically add the controls for the end
user to input a value on a questions screen. To set the
format for the value, click the “Edit” button right of the
“Value Format” edit box.

This will display the standard Format dialog. Static and


Dynamic List variables will have text associated with
each value. Set the font, size, color, indent, etc for the
value text. Other variables may have edit boxes or
drop-down lists as controls and the “Control Width”
setting determines how wide the control will be. The
“Control Rows” setting is how many rows will be
displayed for list boxes and drop-down lists.
“Indent” will indent control or group of controls being
used to ask the question.
If the system is in a language that reads right to left, click the “Radio button or Checkbox to right of text” to
have the controls also go right to left.

11.4.4 Individual Question Graphics and Formats


The next layer in the question screen is text/graphics associated with individual questions. The Prompt for
the variable being asked is always added to the screen by Corvid, but sometimes additional explanatory text
should be included. Instead of adding this to the Prompt, it can be added only to the question screens.
This is done from the “Variables” window. Click on a specific variable to select it and go to the “Ask With” tab.
The lower part of the “Ask With” tab is
used to set the “Other Graphics”
commands. These are just Corvid screen
commands. They are added exactly the
same as the Header and Footer
commands, but apply only to this
individual variable / question. The text/
graphics added as “Other Graphics” will be
displayed after the Header graphics, but
before the Prompt. The “After” graphics
will be displayed after the controls, but
before the Footer graphics.
The “Ask With” tab also allows setting a “Prompt Format” and “Value Format” for the specific variable. These
specific commands supersede the overall Prompt and Value formats for this individual variable. If an overall
format property is not changed by the individual format, that overall property will remain. For example, if the
overall format set the prompt text to 14 pt Red, and the individual format set this to 16 pt, but did not set
another color, the prompt would be displayed in 16 pt Red.

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.

208 11: Controlling the User Interface


11.4.6 Controls
Corvid will automatically add a control or group of
controls consistent with type of variables. By default,
Static and Dynamic List variables are asked using radio
buttons and Numeric, String and Date variables are
asked using edit boxes.
Usually, those are good choices, but they can be
changed for individual variables using the options on the
“Ask With” tab.
Open the Variables window, and select a specific variable. Go to the “Ask With” tab and the control options
that apply to that variables type can be selected in the “Use” control group.

11.4.7 Static and Dynamic List Variables


Static and Dynamic List variables have the most options since there are many ways to present controls that
let the end user select one or more items from a list. For Static and Dynamic Lists the control options are:

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.

Giving the Last Value in a Check Boxes Special Meaning


Sometimes a question may involve selection of several items from a list, or a final value of
"None of the above". In some cases, selecting a value(s) in addition to the "None of the
above" can confuse the logic. It is possible to write logic to detect the input error and deal with it
(re-ask the question, report an error, etc.), but that can be unnecessarily complicated. The alternative is to
use radio buttons, but then only a single value could be selected. For some situations, multiple values are
required.
The question can be presented so that either a selection can be made from the list, or the last value can be
selected - but not both. This guarantees no conflicting answers at the question level and can greatly simplify
the logic of the system.
To do this, select “Checkboxes” and select the “Last value clears all others” options on the right.
When the system is run, the checkboxes will be displayed as usual. The user can select any value(s) except
the last value. If the last value is selected, the preceding checkboxes for that variable will be un-checked and
disabled. The other checkboxes will not be able to be selected unless the final value checkbox is un-
selected, at which time the other checkboxes will again be enabled.
The final value can be anything that should not be selected in addition to any of the other values. This is
typically "None of the above" or "Does not apply", but this option can be used in any case where the final
value has special significance. Only the final value in the list can be selected to override the others.

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.

11: Controlling the User Interface 209


Drop-Down List
The drop-down control is similar to a list, but only a single value is displayed. Clicking
on the control drops down the full list and allows the user to select a value. As with the
list control, the width is set to match the longest value text and should not be used when
this text is quite long. Drop-down lists only allow the end user to select a single 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.

11.4.8 Numeric, String and Date Variables


When Asking for the value of a Numeric, String or Date variable, the only real option is some form of edit box.

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.

Edit Fields for Passwords


Edit fields that are used to ask for passwords can be set to
echo back only asterisks rather than the actual password.
To do this, create a screen to ask for the value of a string
variable that will hold the password. Go to the "Ask With"
tab for that variable and in the "Value Format" edit box
enter PASSWORD.
If there are other value format commands replace them
with "PASSWORD".
When the variable is asked, the edit box will echo ****** as
the user types their input.

210 11: Controlling the User Interface


11.4.9 Control Arrangement
There are several options on how the controls for value input should be arranged relative to the prompt. In
addition to the arrangement control, indenting, font, style, color, etc. are controlled by the Value Format
command string.

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.

One Per Line


The values will be displayed one item per line under the prompt for as many lines as required.
This is particularly useful for radio buttons and check boxes with long value text. This is the
default arrangement.

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.

All on One Line


All of the values will be put on a single line under the prompt. This
should be used only when there are a fairly small number of values and
the text of each is short.

Placing the radio button or checkbox to right of text


In languages that read right to left, it is often better to
place the radio button or check box to the right of the
associated text, rather than to the left as in English. Many
aspects of screen design are handled automatically by
Java, which uses the localization of the computer to
determine how to place items. However, Corvid directly
controls the placement of the radio button and checkbox.
In the "Edit Format" window, select the “Radio button or
Checkbox to right of text”.

11: Controlling the User Interface 211


11.4.10 Image Maps
Image maps provide a more advanced way to field more complex end user interfaces. An image map is a
JPG or GIF image file that has “hot spot” regions associated with it. This image map can be used to ask the
end user for data. A click on a hot spot assigns a value to a variable, or links to a HTML page.
Image maps provide a very flexible and powerful way to control the user interface. Since the developer has
control over every pixel and hot spot region, highly customized screens can be created that would not be
possible by other techniques. This is especially effective where graphics are required or a very specific look-
and-feel is needed. Hot spots can be used to set values for Static or Dynamic Lists, Numeric and String
variables, as well as link to HTML pages. Numeric variables can use formulas to have the hot spot region
function similar to a slide bar with the value assigned to the variable determined by where in the hot spot
region the user clicks both horizontally and vertically. An image map can have overlapping hot spots setting
values for multiple variables simultaneously.
Image maps apply ONLY to the Applet Runtime and are not automatically converted to HTML for the
Servlet Runtime.

11.4.11 Adding an Image Map


An image map can be associated with a variable using the Variable dialog window. Select a variable and click
the “Ask With" tab.
If the variable has an associated image map, the “Image Map”
radio button will be selected. To add an image map, click the
“Edit Map” button. This will both select the “Image Map” radio
button, and give you the opportunity to select and edit the
image map.
The Image Map editing window will be displayed.
If there is already is an associated image file
it will be displayed in the edit region on the
right. Any currently defined hot spots will be
displayed on it.
To select the image file to use either:
! Enter the name of the file in the
“Image File” edit box and click the
“Load” button.
! Click the “Browse” button and select
a file.
The image file must be either a JPG or GIF
image. This file can be created in any image
editing software. Corvid will display the
image in the applet window, so it should be
sized to fit in the window. Only the single
image will be displayed to ask the question,
so the image should contain all the information needed to present and explain the question to the end user -
text, images, etc. However the “Other Graphics” Before and After commands can be used to put other text or
image content above or below the image, but that content cannot have hot spots.
The image can contain HTML links to web pages for additional details when needed.
If the image is too large for the edit region on the Hot Spot Editor, resize the window by pulling down on the
lower right corner of the window.

212 11: Controlling the User Interface


11.4.12 Adding Hot Spots
Once an image file is added, the next step is to add hot spots and define the action to take when the end user
clicks on them.
Select a rectangular region on the image where you want to have a hot spot.
If the end user clicks in the rectangle, it will set a variable value or activate a
link. If the area you want to cover is not rectangular, multiple overlapping
rectangular hot spots can be added to cover any shape.
Adding hot spots is a simple click and drag operation. Just position the
mouse cursor on the image at one corner of where you would like a hot spot.
Press the left mouse button down, drag to form a rectangle, and release the
mouse button. This will create a rectangle on the image.
When a new hot spot rectangle is added, it will automatically be selected.
This is indicated by a different color (which varies with the background color)
and small square “handles” in the corner of the hot spot region. To select a
region, just click in it.
To move a selected region, just move the cursor into the region, press the left
mouse button down and drag the region to a new location. Only a single region can be moved at a time. To
resize a selected region, move the mouse cursor over one of the corner “handles” and drag the corner to a
new size. A hot spot can also be resized in a more precise way by selecting it and then modifying the X and
Y coordinates for the box in the “Coordinates” section. Just enter a new value and press return.
Once the hot spot is added and selected, the next step is to select the variable
and value to assign if the hot spot is clicked on. Most hot spots are assigned to
Static List variables. (Numerics can also be assigned values as explained
below). In the “On Click” control section, select the variable from the drop-
down list.
For Static List variables, this will have the “Value” drop-down” list be the values
for that variable. Select the value to assign.
Once the variable and value is selected, that value will be assigned to the
selected hot spot. The variable/value associated with a hot spot can be
changed simply by clicking the hot spot to select it (which will display the
current variable/value associated with that hot spot). Then just select a different
variable/value for the hot spot.
A single variable / value can have multiple hot spots associated with it. If the
value requires another hot spot, just leave the variable and value settings the
same and click/drag to add another hot spot. It will be associated with the
currently set variable/value settings.
Hot spots can overlap. Normally this should only be done when they have the
same variable/value settings since a click in the overlap region will trigger both hot
spots. Sometime it is useful to nest or overlap hot spots for different variables to
have a single click set both, but this should only be done if it is apparent from the
image that the overlap region has some special significance.
It is easy to add unintended extra hot spots by accidentally clicking on the image. To
remove these, click in the hot spot to select it and click the “Delete Selected” button.

11: Controlling the User Interface 213


11.4.13 Associating a Link with a Hot Spot
In addition to having hot spots set variable values, they can link to external
URLs. This is done by creating a hot spot as above, but in the “On Click”
group, select the “Link To” radio button, and either enter a URL of the page
in the edit region or, browse to a local HTML page.
The image should have some content to indicate that a click on this area will
trigger the link, such as “More Info”. The section of the image can even be
made to look like a button.
If a local HTML page is selected, that file must be distributed with the
system. If the page to link to is somewhere else on the web, the full URL
can be entered (e.g. http://www....)
A click on the link will display the associated page/URL in a new browser
window. To display the page in a named frame, add a comma and the
frame name after the URL. For example, the link "my_page.html" would
display my_page in a new browser window. "my_page.html, frm2" would
display the page in a frame named "frm2" on the same page as the applet.
(See section 11.7 for more information on running Corvid system with frames.)

11.4.14 Hot Spots for Numeric Variables


In addition to Static List values, hot spots can assign a value to a Numeric variable. To do this, select the
variable in the variable drop-down and enter a formula in the “Value” box. The formula can be any legal
Corvid expression that returns a numeric value, and can be designed to indicate where in the hot spot the
user clicked. This enables a hot spot to function similar to a slider, where the user can select a value in a
continuum between ranges.
The formula in the “Value” box can optionally include "X" and "Y". These indicate where in the hot spot the
user clicked. X will be a value between 0 and 1 indicating the horizontal percent of hot spot width where the
user clicked. Y is a value between 0 and 1 indicating the vertical percent of the hot spot height where the
user clicked. The values will always be between 0 and 1 regardless of the size or location of the hot spot.
If the formula used was 10*X, and the user clicked exactly in the middle of the hot spot, the value would be 10
* (.5) = 5. If the image uses both vertical and horizontal information, the formula can include both X and Y.
This value can then be used in the rules to process the user input.
For example, an image might be used to
ask the user for their budget. For the
system, this could be a value from $5 to
$50. An image could be created to allow
the user to select the value by clicking on
the appropriate point on the image.
Create numeric variable “Budget” and
set it to be asked with the image map.
Add a hot spot on the entire green
part of the image so that the left edge
corresponds to the $5 and the right
edge corresponds to the $50. For the
value enter “(45 * X) +5”. This will set
a value that corresponds to the scale
on the image. On the left edge, X will be 0 and the formula will return 5 and on the right edge, X will be 1 and
the formula will return 50. The values in between will be set correspondingly.
When a system needs to get both the X and Y value, use 2 hot spots of the same size and position. Use one
to set the X value and the other to set the Y value. Since they overlap, a click will trigger both.

214 11: Controlling the User Interface


11.4.15 Hot Spot Accuracy and Precision
Using a hot spot for a numeric variable can be very accurate, but several factors can degrade accuracy.

! 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.

11.4.16 Displaying and Finding Hot Spot Regions


The controls in the “Find” group provide ways to find, select and examine hot spots and their associated
variable/value or link. If a variable is selected from the drop down list in the “Find” group and then a value is
selected from the list (for static list variables) or entered (for string or numeric variables), all regions that are
associated with that value will be highlighted and selected. This can be a quick way to check the regions for
each value of a variable.
If a variable is selected and the “Select All Values” button is clicked, all regions that will assign any value to
that variable will be selected.
Clicking the “Select All” button will select all regions in the image map.
The “<” and “>” buttons sequentially select the previous or next region. Clicking these buttons allows stepping
through the hot spot regions.

Check Your Image Map


When building image maps, it is easy to either accidentally click and add an unintended hot spot, or to get
the variable/value for a hot spot set incorrectly.
When you are done with the image map, click the “Select All” button to display and select all hot spots on
the image.
If there are any unintended hot spots, click the “<“ and “>” buttons until that hot spot is the only one
selected. Then click “Delete Selected”.
Use the “<“ and “>” buttons to go through each of the hot spots. As they are selected, the variable/value
or link for that hot spot will be displayed on the left. Make sure they are all set correctly.

11.4.17 Using an Image Map to Ask for Multiple Variables


An image map can contain hot spots that are associated with multiple variables. The hot spot regions can
overlap. A click in overlapping regions will set BOTH values. This opens up a wide range of more complex uses.
There are several things to consider when building multi-variable image maps:
! Determine what variable is the primary variable that causes the image map to be displayed. This is also
the variable that must eventually be given a value by the image map. (If the user clicks on the image
map in an area that does not set a value for the primary variable, even if it sets values for other
variables, the image map will be redisplayed to again ask for a value for the primary variable.

11: Controlling the User Interface 215


! Do you want a single click to set multiple variables?
! If the variables on the map are independent (not overlapping), consider if the system should echo back
the values set as the user clicks on the map.
The simplest type of multi-variable image map is one that always sets the primary variable and may also set
other variables. For example, the system might be asking what state the user's location is in, using a map
with the company's various facilities across several states. The [STATE] variable would be the primary
variable and would be set by a click anywhere on the map. In addition, you might have several specific major
facilities on the map. These would have small hot spots associated with the variable [FACILITY] so that a
click directly on a facility hot spot would set both [STATE] and [FACILITY] variables. If click was not on one of
the specific facilities, only the [STATE] variable would be set and the system would later ask for the value for
[FACILITY] in another question.
A more complex image map may use non-overlapping hot spots. A click on some areas will set a value for
some variable(s), but not the primary variable. In this case, the system still needs the value for the primary
variable and will redisplay that image map. The data that was assigned to the other variable can be echoed
back by using the "Other Graphics" commands on the "Ask With" tab to display the values of the other
variables on the same screen that asks for data.
While normally used to display graphics or text, any Screen Commands can be entered to be displayed
before or after the image map - including commands to display the value of variables. Just select the variables
to be displayed in the command builder. If these variables have no value, they will not be displayed. However,
once given a value, they will be echoed back. This allows the user to select multiple values from the image and
have immediate display of the values selected. When a hot spot is selected that sets a value for the primary
variable, all the values will be taken and used. If an image map is used in this way to display the values, clicking
the "Back" button will step back one "click" at a time.

11.4.18 Use Images for Prompts and Values


In addition to Image Maps, where an image is used to ask an entire question graphically, images can be used
in place of the Prompt and Value text for a question. Normally the prompt and values will be displayed as text
using a font, color, style, etc. specified by the Prompt or Value Format command string. However, in some
cases, it is preferable to present them as an image file to show graphical information or have more control on
the user interface.
To do this:
1. On the Variables window, select the variable
that will use images.
2. On the “Ask With” tab, check the “Use Image
Files” checkbox.
3. Select JPG or GIF format for the files.
4. Create an image file for the prompt named
VARNAME.JPG or VARNAME.GIF, where
VARNAME is the name of the variable.
5. For each value, create an image file for the value named VARNAME_VALUENAME.JPG or
VARNAME_VALUENAME.GIF.
6. Store the various image files in the same directory as the Corvid knowledge base file.
For example, if you have a Static List variable named [TEMP] and it has two values named COLD and HOT,
you would create a JPG file named TEMP.JPG to use for the prompt and files TEMP_COLD.JPG and
TEMP_HOT.JPG for the values. When the variable needed to be asked, these images would be
automatically used rather than the text.
When using images for the values only the Radio Button or Checkbox options can be used. If there is only an
image for the prompt, any of the controls can be used. Since the images can be created in an image editing

216 11: Controlling the User Interface


program, they can use any fonts, colors, designs, etc.

11.4.19 Previewing Question Screens


The screens used to ask the user for input can be previewed without running the full system. Either a single
screen, or all question screens can be displayed. Any formatting, headers, footers, and Also Ask options will
be displayed.
Previewing is done by Corvid automatically building a temporary Command Block that asks the specific
variable(s) and then running the system using that Command Block. The system will
run with whatever options are chosen for how to run the system. This includes
running as an application/applet, using a specific browser, and the applet size. To be
able to preview a system, the system must be able to be run.
Both types of previews are done from the “Variables” window.
To see a single screen, select the variable and click the Ask With tab. Click the
Preview button on that tab.
To preview all screens, click on the Preview button under the variable
list, just above the Done button.
This will show all screens that could be used to ask the end user for
data. Only Static List and Continuous (numeric, string and date)
variables will be asked. (Collection and Confidence variables are
never asked of a user and Dynamic List variables are not defined until
runtime.) If a variable has associated Also Ask variables, these will be displayed. If a variable has a default
initial value, it will be displayed. Variables that have default values to use instead of asking, or initial values,
would never be asked of the user and will not be displayed.
To go to the next variable, just provide any answer. However, input must be within any range limits that are set
for the variable or the question will be reasked. For example, if a numeric variable is set to only accept values
between 0 and 10, and you input 12, the variable will be reasked.
If there are Also Ask variables on a screen, they do not need to be answered during the preview - only the
main controlling variable. The Also Ask variables will be asked again later individually to preview their
individual screen. If input was provided for them earlier, they will still be asked, but will show the earlier input
as a default value.
The “preview all variables” option is a very convenient way to check the look of the entire system without
having to go through all possible paths to display all variables. It is a good idea to always check the look of all
questions on at least the common browsers.

11.4.20 Add a Custom Button To Run a Command Block


A button can be added to each question screen to perform some special action. The button is associated with
a Command block in the system. If the button is clicked, that Command block will be executed. This is done
by adding the command:
SPECIAL_BUTTON "button_label" "command_block_name"
to the Command block. The button will appear on the lower right side of the applet window. The button can
be turned off when not needed by using the command:
SPECIAL_BUTTON_OFF
Later in the Command block, for example, the command:
SPECIAL_BUTTON "Save data and exit" "SaveDataCmds"

11: Controlling the User Interface 217


would add a button:
Clicking the button would run the Command block “SaveDataCmds”.

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.

Select “SPECIAL_BUTTON” and enter the button


label and Command Block to execute if the
button is clicked. Both the button label and
Command Block name must be in quotes and
separated by a comma.

The SPECIAL_BUTTON_OFF command is built


from the same “Special Commands” drop-down
list.

11.5 Information Screens - Title, Results


Generally all the screens in a system, excluding Questions screens, are information screens that display text,
images and variable values using the text and image commands covered in section 11.3.
There are 3 main types of informational screen commands:
! Title
! Results
! Other screens not used to ask questions

11.5.1 Title Screens


Title screens are completely optional, and many systems
do not use them, especially when either the HTML
surrounding the applet tag contains all the relevant
information, or when the HTML pages that link into the
system serve as the title.
Title screens are added to a system in the Command
Block using the “Title” command. This is built from the
“Title” tab on the command builder window.
Normally the TITLE command will be the first command in
the Command Block that displays something.

218 11: Controlling the User Interface


The “Title” tab on the command builder window will display the commands for the screen. To add or edit the
commands, click the “Edit” button at the lower right. This will display the standard Screen Command builder
window.
The screen will display whatever text and images are included with the screen commands and will
automatically add an “OK” button at the bottom of the page. The page will be displayed until the end user
clicks the “OK” button, at which point the next command in the Command Block will be executed.

Title pages often contain:


! Logos or images.
! System tile / developer.
! An explanation of what the system will do or what is expected of the end user.
! Links to other related resources.
! Copyright notices.

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.

11.5.2 Results Screens


Most systems end with a Results screen which displays the system conclusions, advice or recommendations.
This involves the display of one or more Corvid variables whose value was set during the session, plus
additional text and images. The content in the results will often be longer than what can be displayed in the
Corvid applet window, and Corvid will automatically add a scroll bar on the right side of the applet window so
that all the content can be displayed.
A Corvid system can have multiple results screens that are either displayed at different parts of the system, or
for different reasons. These are all designed the same basic way, but ONE screen is the default results
screen and its screen commands are stored internally in the system CVD and CVR files. Other results
screens are built with the same screen commands, but the commands are stored in a file external to the
system, and this file must be fielded with the system.
The default results screen is created/edited from the
Results tab on the command builder. The screen
commands for the default screen are displayed in the
box at the top of the window and are edited by clicking
the “Edit” button at the lower right of that box.
Other results screens are built from the same tab, but
using the controls in the “Display File of Corvid Screen
Commands” section. Click the “New” button to start a
new file of commands. You will be prompted to name the
file. This file must be distributed with the system when it
is fielded. To edit an existing file of screen commands,
enter the name of the file and click “Edit” or “Browse” to
the file. If a Command Block command to display a file of
screen commands is being edited, the file name will have
automatically been added to the edit box, and all that is
needed to edit it is to click the “Edit” button.
The results screen can include text and image commands needed for system design but will almost always
include the value of one or more Corvid variables set during the session. Some system will put all of the

11: Controlling the User Interface 219


advice/results in a single Collection variable that can be displayed. Others will use a set of Confidence
variables, and the ones with the highest confidence values will be displayed. Others may have a specific set
of variables or properties of variables that should be included. Corvid has many options for including
variables in the results screens.

11.5.3 Including Variable Values


Variables are added to the Results screens, or any other screen that needs to
include the value of variables (including question screens), using the
“Variables” controls and options on the Screen Command builder window.
This will display all of the specified variables that had a value set. If the
variable does not have a value when the RESULTS or DISPLAY command is
executed, it will not be included in the display. Variables in the command list
without a value will NOT be derived via backward chaining or asked. They will
simply be skipped. (Variables included in text with double square brackets,
WILL be derived via backward chaining if they do not already have a value.
Click the drop-down list under “Variables”. This has various options to select
one or more variables to include in a single command. Other controls will allow
you to limit the variables included, even when a group of variables is selected.
The first items in the drop-down list are to select groups of variables by their “Type”. Selecting “Collection”,
“Confidence”, “Date”, “Dynamic List”, “Numeric”, “Static List” or “String” will add all variables in the system of
the corresponding type to the screen command.
There are also two special selections:
! “Variables” will add ALL the variables in the system of all types.
! “Continuous” will add all “Numeric”, “String” and “Date” variables.
Following these options to select groups of variables, the drop-down alphabetically lists all the variables in the
system and these can be selected individually. When these are selected, the screen command will be the
name of the variable in square brackets.
Properties
Individual variable properties can also be added. By default, when a variable is displayed it will display the
variable’s prompt followed by the value. This is equivalent to the .FULL property. To instead display other
properties, click the “Prop” button right of “Variables” and select the variable / property to include. For
example, to just include the value, without the prompt, use [varname.VALUE]

9.5.4 Limiting and Controlling Variable Display


There are various ways to provide more control on when variables are displayed and how they are displayed
with the tabbed group on the right side of the window.

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,

220 11: Controlling the User Interface


the variable will be displayed. If it is false, the variable will not be displayed. Generally, the “#” will be in
square brackets and can include properties. The “#” will be replaced by the variable’s name, NOT the name in
brackets.
For example: If only confidence variables that received a value greater than 50 should be displayed:
1. Select the group “Confidence” for the variable.
2. Enter “[#] > 50” for the test.
The test expression can include properties. Just use the [#.property] in the expression. For example, to select
only Static List variables that have 2 or more values selected, select “Static List” and use [#.COUNT] >= 2.

Final Results Flag


A quick way of grouping variables to display
is to use the “Display with Final Results”
flag. This is set in the variable editing
window under the “Options” tab. (Be sure
to select “Show Advanced Options” at the
bottom of the Variables window to enable
the “Final Results” control.)
Select a group of variables (either all variables with “Variables” or one of the variable type options
(Confidence, Static List, etc), and then limit the display to only those that have the flag set. Then go into the
Variables window, and set the “Final Results” flag for the variables to display. (NOTE: While the Results
screen is the original use for the Final Results flag, it can also be used for other places in a system that need
to select a group of variables.)

User Provided the Answer


Sometimes it is desirable to display all of the input that was provided by the user. This can be done by
selecting the “Variables” group to start by including all variables. Then check the “User provided the value”
box. This will limit the display to only those variables that were directly asked of the user. Variables that had
values derived from the logic will not be included.
Sort Confidence Values
This option only applies when the “Confidence” group of variables is selected. It allows the confidence
variables to be sorted by value.
Many systems use Confidence variables as the possible options that the system will select among. The logic
assigns each variable a value. To view the Confidence variables arranged in order:
1. Select the group “Confidence” in the variable list.
2. Click on the “Sort Confidence Variables” checkbox.
3. Select how to sort: Ascending (Lowest value first), or Descending (highest value first).
Property
An individual variable can be selected to display with an associated property. To display a Property for each
of a group of variables has been selected, there is no direct way to add the property in the variable edit box.
Instead, select a group of variables (“Collection”, “Confidence”, etc.), and add the property to apply to each of
the variables in the “Property” edit box.
For example, to display all Collection variables as concatenated strings, rather than lists:
1. Select “Collection” as the variable.
2. Check the Property checkbox.
3. Enter a Property (e.g “VALUE”) to apply to each variable.
The property should be just the Property name without the period. If a property has additional parameters,
they can be entered. For example, to format the a numeric variable to an integer, enter “FORMAT #”.
“FORMAT” is the property , and # is the format string for a single digit.

11: Controlling the User Interface 221


Instead Tab
The Instead tab provides a way to use variables in the system to
control the display of other items of text or graphics. For example a
Confidence variable might be used to diagnose the cause of a
machine stopping, but it might be better to display the repair
procedures in the results than just the cause. The rules can use the
shorter, more manageable, cause description, while still displaying
the longer repair procedures in the results.
If the variable selected would be displayed, instead the alternate
text, image or file is displayed.
1. The variable is selected in the standard way (Click the
“Variable” radio button on the Display Command builder
dialog and select a variable.)
2. Determine under what conditions the variable will be
displayed. This may be due to the logic of the system or
display limits added under the “Display” tab.
3. Select what alternate content should be displayed if the variable passed the test(s). This can be a
text string, and image or the text content of a file.
If text is used, just enter the text in the edit box.
If an image is used, enter the address of the image. Remember that when the system runs, this address will be
a URL relative to the base address of the system on the server and the image must be fielded with the system.
If displaying a file, the file should be a simple ASCII text file. Enter the location of the file. Remember that
when the system runs, this location will be a URL relative to the base address of the system on the server,
and the file must be fielded with the system.

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”.

222 11: Controlling the User Interface


The prompt can also be limited to only the short text (Variable name). For static lists, the value text can be
limited to only the alternate short text for the values. This is done by selecting the “Use short text for prompt”
and “Use short text for value” check boxes.

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.

11.5.5 Buttons on the Results Screen


Most Corvid screens automatically have 3 control buttons - “OK”,
“Back” and “Restart” . The “Back” button allows the user to go back to
a previous question. “Restart” takes the user back to the beginning of a
run. By default, the “Back” and “Restart” buttons appear on all screens
except the first screen.
The buttons on a screen can be controlled by adding one or more
“Button” commands. Click the drop-down list next to “Buttons” and select the options. For multiple options on
the same screen, add multiple commands. The commands can be anywhere in the screen command list.
To NOT have a “Back” button on a screen select the “No BACK Button” check box for any text on the screen.
This is rarely needed and mainly for MetaBlock system that ask questions asked during the running of a
MetaBlock after some of the spreadsheet rows have been processed.
To not have a “Restart” button on a screen select the “No RESTART Button” check box for any text on the screen.
The results screen is normally the last screen in a system and the last command in the Command Block.
Because of this, it should not have an “OK” button since that would go past the end of the Command Block
and Corvid will display a default “System Done” screen. In a fielded system, it is best to prevent the “System
Done” screen from being displayed since it will not mean anything to the end user.
To remove the “OK” button and display a “Restart” button instead, use the “Last Screen (No OK)” checkbox.
This will convert the “OK” button into the “Restart” button and give the user the opportunity to rerun the system.
The “Single Line” option will display the “OK”, “Back” and “Restart” button in a single line rather than the
default arrangement.
The “Align Left” option will display the buttons on the left side of the screen rather than the default arrangement.
The labels on the buttons can be changed from the “Properties” window, “Applet” tab.

11: Controlling the User Interface 223


11.5.6 Typical Results Screens
Results screens are typically fairly simple, and rely on system logic to select the content to display. Often This
is assigning the values for a set of confidence variables, with the ones that have the highest values being the
answers or advice to display to the end user. Another approach is to have the rules dynamically add content
to a Collection variable to build the content to display. Some systems use the logic to set the value of a single
Static List variable, or set the value of a numeric variable.
Most results screens will have:
! Graphics or text at the top clearly indicating this is the conclusion of the system.
! Either:
- One or more Confidence variables that received the highest values by the system logic.
- A Collection variable with content built by the system rules.
- One or more other variables whose value was set by the logic.
! These items may have HTML links to other URLs for additional details.
! Buttons limited to “Restart” by the “Last Screen” option.

11.6 Resource Files and Multiple Language Support


When building systems that are to run in multiple languages, “Resource Files” can be used to store text used
in the system in a separate file. As the system runs, the resource file can be used to provide any text needed
by the system.
The text in the resource file can be edited with a standard text editor without going through the Corvid
development environment. This allows the text in a system to be translated to various languages, with the
end user interface controlled by the resource file used. It also allows editing the text in a system without
having to work through Corvid, and with no chance that system logic might be modified.
Text that comes from the resource file is indicated in the system in a way very similar to embedded variables.
Resource file markers are indicated by:
[<marker>]// comment
where the marker is listed in the resource file by:
[<xxx>] = text to use
The optional “//comment” is used to remind the developer of the text being included, or if resources are used
for multiple languages, the comment can be the text in the developer’s preferred language. If “[<marker>]//
comment” is used in Corvid, the “//” and all text following will be ignored, and will not appear when the system
is run.

224 11: Controlling the User Interface


11.6.1 Selecting the Resource File
The default resource file for a system is
KBName.res, where “KBName” is the name
of the system. If another resource file is
preferred, the command:
RESOURCE=filename
can be used in a Command Block or Logic
Block, however this should be done before
text from the resource file is needed.
The command is added from the Corvid
Command Builder window, on the “Control”
tab. In the “Special Commands” drop-down,
select “Resource =”.

Enter the name of the resource file to use in


the edit box and add the command to the
system.
If a system uses resource files to run in multiple
languages, it can select the appropriate
resource file with rules such as:

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

11: Controlling the User Interface 225


11.6.2 Resource File Markers
Any text in a system in [<…>] is used as a marker for text to obtain from the resource file. When the
marker [<xxx>] is found, the resource file will be searched for a line that starts with:
[<xxx>] =
The text following the “=”, and all following lines will be used, up to the end of the file, or the next line that
starts with “[<”. If there are multiple lines, they will be concatenated with a space.
The marker in the system can have an optional comment indicated by:
[<marker>]// comment

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.

11.6.3 Building a Resource File


Corvid provides an easy way to automatically build resource files, and also to
import text from a resource file into a system so that it will no longer need the external
resource file.
Under the “File” menu, the command “Build Resource File” will use system text to
build a resource file.
Normally, the logic in a system should be finished before creating the resource
file. Additional resource strings can be added later, but it is easier if everything is
already built and Corvid does the work for you.
Selecting to build a resource file will display a warning that building the resource
will permanently change system text.

Always make a backup copy of your system before


building a resource file.
If you select to proceed, Corvid will ask for a
filename for the resource file. Unless a
system will have multiple resource files in
different languages, it is best to select the
default name. If a resource file already exists,
markers matching the existing markers will be
replaced. Other markers in the resource file will
be kept, and new markers will be added.

226 11: Controlling the User Interface


There are options for which text to export:

! Variable prompts and value.


! All string assignments.
Checking “Variable Prompts” will export all
variable prompts; and for static lists, the text
of the values to the resource file. “All Strings”
will also export the strings used in THEN
assignments. (This is very useful if the system
builds a report by adding content to a
Collection variable.)

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.

After building a resource file, the prompt will be:

[<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

The resource file will contain:


[<color>] = The color is
[<color_red>] = red
[<color_blue>] = blue
[<color_green>] = green
[<color_yellow>] = yellow
[<color_white>] = white

11: Controlling the User Interface 227


Whatever text is right of the “=” in the resource file for a specific resource marker will be used in place of that
marker when the system is run. To make the system run in a different language, just make a copy of the
resource file, translate it and have Corvid use that file. For example, Spanish would be:

[<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.)

11.6.4 Importing a Resource File


The “Import Resource” option under the Corvid “File” menu will take a Corvid system using a resource file,
and replace all the resource references in the system with the actual text from the resource file. Any
resources not found in the resource file will be reported as errors. All variable strings and nodes are checked.
External resources (other files read in, etc.) are not checked.
To import a resource file, under the File menu select “Import Resource File”. The system will ask for the name
of the resource file to import and will then replace the resource markers with the actual text from that file.
Any place that [<marker>] is found it will be replaced with text from the resource file. If used, the optional “//
comment” will be stripped off. All text following the // will be deleted.

11.6.5 Fielding a System with Resource Files


When a system using a Resource File is fielded, the resource file must be placed on the server in the same
folder as the system .CVR file.

11.6.6 Non-Standard Uses for Resource Files


Resource files are primarily for systems that run in multiple languages, however they can be used in other
ways. When Corvid runs a system, it checks all strings for resource file markers, [<marker>].
If a marker is found it is replaced by that marker’s text from the resource file. This will be the default
KBName.res (where KBName is the name of the system) unless a RESOURCE= command has set a
different resource file.
This allows any string in a Corvid system to embed text that is stored, and editable, in the resource file. If a
system needs to have a threshold value that may change or needs to be configured outside of the Corvid
editor, use an expression such as:
IF
[X] > [<threshold>]
...

228 11: Controlling the User Interface


Not the threshold value will be read from the resource file, which should have a line:
[<threshold>] = 5
The threshold can now be changed external to Corvid just by changing the value in the resource file. This
can be done with something a simple as Notepad, or generated by another program.
Resource can be used this way to embed anything from a simple value to entire expressions in a system. More
complex embedding of values can be done using XML, but most systems that require this functionality can use
the simple “flat file” approach of resources. (For information on XML data embedding, see section 13.5.7)

11.6.7 Alternate Prompts to Handle Multiple Languages


Resource files are the recommended way to handle systems that run in multiple languages, however Corvid
has another way to assign multiple text strings to variable prompts and values. This is another way to handle
multiple languages or any situation where the variable
prompt / value text needs to change for different users
or at different points in a system.
To use “Alternate Prompts”, open the Variables window
and turn on “Advance Options” at the bottom of the
window. Open the “Prompt” tab.

External Sources for the Prompt


There are 2 ways to set the Prompt text. The first is to
use the “External Source For Prompt Text”. This gets
the prompt text from a database, XML file or other
external program. Click the “Edit” button and build an external interface command that will return a string that
can be used for the Prompt. See chapter 13 on building External interface commands.

Alternate Text Strings


In addition to the main prompt, there can be alternate prompts in other languages or alternate ways to ask the
user for the value of the variable. For example, the system could have two modes - expert and novice. In
expert mode, it would ask shorter and more technical questions that an expert could answer while in novice
mode it would ask simpler more explanatory questions.
To add alternate prompts:
1. Select a key variable that indicates what prompt to use.
2. Enter the alternate prompt(s).

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.

11: Controlling the User Interface 229


Alternate Prompts
The alternate prompts are entered in the edit
region at the bottom of the Prompt page. The
number above the edit region indicates which
prompt is being entered. (Remember #1 is the
Main Prompt, so the numbers start at 2). Like the
Main Prompt, the alternate prompts can be any
length and any text.
If a single key variable is used for all prompts,
make sure that the alternate prompts are
consistent. For example, alternate prompt 2 is
always Spanish and alternate prompt 3 is always
French, etc.
Only 5 alternate prompts can be added. After that,
resource files must be used.

External Sources for the Value


For Static List variables, there are also comparable options for alternate value text. These must be set for
EACH VALUE. There are 2 ways to set the value text. The first is to use the “External Source For Value
Text”. This gets the value text from a database, XML file or other external program. Click the “Edit” button
and build an external interface command the will return a string that can be used for the specific value
selected. See chapter 13 on building External interface commands.
Alternate Value Test
In addition to the main value text, there can be alternate values. These are built the same as the alternate
prompts, but there must be a set of alternate value texts entered for each of the possible values. The key
variable selected for the variable’s alternate prompt is also automatically used for that variable’s alternate
values.
To add alternate values:
1. Select a value from the value list.
2. Enter the alternate prompt(s).
Remember, the original text is “alternate 1” and the first true alternate is #2. Enter the alternate value text,
clicking the “<“ and “>” to enter all the alternates for that value. Then select the next value and repeat the
process, being careful to keep the languages in sync with the prompt and other variables.
When the system is run, when the first variable with alternate prompts needs to be asked or displayed, the
Key Variable will first be asked or derived and the appropriate prompt / value text strings will be used.

11.7 Running Systems with Frames


HTML frames provide a way to divide a web page in to several regions that can display different content but
still communicate. Corvid can utilize this running the Corvid system in one frame and having that system
push content into other frames either automatically or when links are clicked.

230 11: Controlling the User Interface


This can be used in various way. The most common ones are:
! When a question is asked in the Corvid system, Corvid system running in this frame
explanatory material or images can automatically be ____________________________
displayed in other frames on the page. Since navigation
in those frames remains in that frame, the displayed
HTML content in this frame
material can have other links to get more information
without changing the Corvid question, which always (Pushed in by Corvid)
remains visible and active. This allows the 2nd frame to
use designs that would not be possible with the Corvid
Applet Runtime, using the full capability of HTML, HTML5, Flash, etc. Anything that the browser can
display can be used.
! When a HTML link in a Corvid system is clicked, the linked page can be displayed in a frame rather
than a new browser window or tab.

11.7.1 Creating a the Frames


The frame set can be any layout and use any of the HTML frame command options. Typically it is either two
frames dividing the window horizontally or vertically, but more than 2 frames can be used for more complex
designs. Building the frame set is just standard HTML and the many options for frames are covered in HTML
design manuals.
The minimum requirements are:
! The must be at least 2 frames.
! One of the frames must have the SRC set to a HTML page that runs the Corvid system.
! The other frame(s) must have a name set with “name=”.
! The other frame should have the SRC set to some content to display when the system first starts.

This can be as simple as:


<HTML>
<FRAMESET rows="50%,50%">
<FRAME SRC="kb_name.html">
<FRAME SRC="StartingComments.html" name="Comments">
</FRAMESET>
</HTML>
In this example, the page has a frame on the top of the page running the Corvid system using a HTML page
“kb_name.html”, which will have the APPLET tag that runs the system (where “kb_name” is the name of your
system). The bottom of the page will display the the HTML page “StartingComments.html”. That frame is
named “Comments”.

11: Controlling the User Interface 231


11.7.2 Instructing Corvid to use the Frames
Save the frame HTML page as a name DIFFERENT from the name of your system HTML page, which will be
“kb_name.html”. For example the frame set page could be “kb_name_FRAME.html”.
To have Corvid use the frame page when it runs.
! Open the “Properties” window.
! On the “Test Run” tab, set “Specific URL”
to the name of the frame page.
Now when the system is run, Corvid will still
automatically build the page that contains the
system in “kb_name.html”, but will call
“kb_name_FRAME.html” to run it. That frame
will load “kb_name.html” along with whatever
other frames were added.

11.7.3 Pushing Content into the Other Frames


Any of the commands in Corvid that display HTML content in a new browser window can be set to display that
content in one of the other named frames on the frame layout page.

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.

Writing to Frames when a Question is Asked


One of the most effective uses of frames is to have extra explanatory content displayed in them automatically
when Corvid asks a question. When the question is displayed in the frame running the Corvid system, the
other frames automatically display the additional details or pictures that might be needed to explain the
question. This is a convenient way to display information that some users may need without requiring that the
user click a link to ask for "More information". It also allows using the full design capability of HTML to display
the explanatory information which can include graphics, animation, Flash, video, etc.

232 11: Controlling the User Interface


Open the Variables window and select the
variable that should display content in the
frame when it is asked.
Go to the “Ask With” tab.
In the “Other Graphics” box, select either
“Before” or “After” and click the “Edit” button to
add a command. If there are already other
commands in this section, that is OK and the
new command will be added to them.

This will open the standard Corvid Command


Builder. (If there were other commands already
entered, they will be displayed at the top. A
DISPLAY_HTML command will be added to the
list, but it can be added anywhere in the
command list since it will only act on the content
in the other frame and not change how any other
commands display.
Click the “Display_HTML” button.

Add the name of the HTML page to display.


Normally this will just be the page name, and the page
should be kept and fielded in the same folder as the system
CVR file. However, the link can be any link, anywhere on the
web. In that case, start the link with “http://www...”
For the “Frame” enter the name of the frame that the content
should be displayed in.
Add the DISPLAY_HTML command to the
command list. If there are other commands in
the list, it can be added anywhere in the list.

Click “OK” to add the command as the “Other Graphics” for the variable.

11: Controlling the User Interface 233


Now when the question is asked, the
“Other Graphics” commands will be
added. The DISPLAY_HTML will
automatically push the specified page
content into the other frame. If the
page has more than one additional frame for explanatory content, use another DISPLAY_HTML command to
push other content into that frame.
NOTE: Once one question pushes content into the other frames, that content will remain there until it
is replaced. If later questions should not have the same content in the frames, be sure to add other
DISPLAY_HTML commands to those variables to replace the content for the one question with
something more “generic” and appropriate for the later questions.

Writing to Frames when a Question is Asked


In addition to automatically pushing content into a frame when a question is asked, the same technique can
be used for any Corvid Applet Runtime screen designed with Corvid Screen Commands. This includes Title,
Results and other “information” screens.
This is done the same way as with the Questions screens. Just add a DISPLAY_HTML command anywhere
in the command list. Include the HTML page to display and the name of the frame to display it in. When the
content is displayed, the HTML page will be pushed into the frame.

11.8 Making the Applet Fill the Window


Normally the applet box used to run a Corvid system is a fixed size region in a browser window, with other
HTML content around it. For most systems this is preferred since the areas outside of the applet box can
contain company logos, titles, instructions and any other information that is static, but which should be
displayed with the application.
However, for some systems, it may be better to use a design where the applet box occupies the entire visible
portion of the web page in the browser. This allows the applet box to fill the entire window and it is resized
when the browser window is resized. This makes the border of the applet box no longer noticeable, and in
many ways the systems looks more like it is running with the Corvid Servlet Runtime.

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).

234 11: Controlling the User Interface


! Delete all the BODY content EXCEPT for content between the opening “<APPLET” and closing “</
APPLET>” tags.
! In the applet tag, change the WIDTH and HEIGHT values to “100%”.
! Delete the line with the KBWIDTH parameter.
! In the HEAD section add a style to remove the margin around the applet:
<HEAD>
<style type="text/css"><!--
body {
margin: 0;
}
--></style>
</HEAD>
! Save the page with a name DIFFERENT from kb_name.html. (Corvid rebuilds that page every time it
runs and would erase your changes)
! Open the “Properties” window, goto the “Test Run” tab and change the “Specific URL” to the edited
page just created. Now when Corvid runs, it will use the edited page.
The HTML page should look similar to:
<HTML>
<HEAD>

<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>

11: Controlling the User Interface 235


11.9 Using Double Square Bracket Embedding
The usefulness of double square bracket embedding of Corvid variables cannot be over emphasized. It is the
key to many of the advanced features in Corvid and can greatly simplify other tasks.

Any Corvid variable value or other property can be embedded in any


string in any expression or command.
If a TEXT command needs to include the value of 2 Corvid variables, [X] and [Y], Instead of trying to combine
strings and variable values, just use the command:
TEXT “The value of X is [[X]] and the value of Y is [[Y]]”
Corvid will embed the value of X and Y in place of the double square brackets before the string is displayed.
Corvid parses all strings for double square bracket embedded values (along with resource file markers and
embedded XML). If any are found, they are replaced by their associated value before the string or command
is used. This may require backward chaining to derive the value, or calling external program commands to
obtain a value. This allows dynamically building the content that is displayed in question or results screens.
In addition to the simple variable name in square brackets, there are also other special embeddable
“variables” described below.
For example, the special variable [[~input]] can be used to embed all the variables that the user has provided
input data for.
The format:
[[var]BEFORE:str AFTER:str2]
allows adding additional content before and after the variable value. This can be used to add extra text when
there are multiple values, such as [[~input]] or a Collection variable’s value list.

11.9.1 Embedding Corvid Variables


Any text string can have the text of a Corvid variable embedded in it by placing the name of the embedded
variable in double square brackets [[ ]]. The [[var]] expression will be immediately replaced by the value of the
variable before the string is used.
Since the value must be determine to embed it, the Corvid Inference Engine will try to determine the value
and will, in order:
! If the variable has been had its value fully derived or asked of the end user, that value will be
immediately used in the string.
! If the value of the embed variables is not known, the Corvid inference Engine will use backward
chaining to derive the value from other rules. The backward chaining may cause the system to need
to ask other questions before the embedded variable value can be obtained, and the initial string used.
! If the values cannot be derived, and it has an associated external interface command, that command
will be executed to set the value.
! If none of the above set the value, the end user will be asked to provide the value.
It is generally best to embed variables whose value is known, but this is not required and the embedded
variables can be used as a way to force backward chaining on specific variables outside of the Command
Block. This can be an effective way to build some systems, but if it is used, remember that since the flow of
backward chaining is coming from the embedded variables, rather than the Command Block, it may be more
difficult to follow the flow of execution.
For clarity, it is sometimes better to add ASK or DERIVE commands at the start of the Command Block to

236 11: Controlling the User Interface


establish the value for embedded variables. These may not be necessary, but will make the procedural flow
clearer and easier to maintain.
For example, one way embedded variables are often used is to add the users name. The prompt of a
variable can be:
[[NAME]], what is…..
When the system runs, the [[NAME]] will be replaced by the actual name. If the value of [NAME] is known , it
will be used. If it is not known it will be derived or asked.

11.9.2 Embedding Variable Properties


In addition to embedding the value of a variable, any of the variable properties can also be embedded by
using:
[[var.property]]
In this case, the value of the variable will first be determined and then the specified property will be evaluated
and inserted as a string. (If the property evaluates to a numeric value, it will be converted to a string.).
The full list of variable properties is in Appendix B.
For example, if there is a variable [TEMP] with a prompt “The temperature is” and a value of “75.33”
Embedding [[TEMP]] would embed just the value: “75.33”.
Embedding [[TEMP.Full]] would embed the prompt plus value: “The temperature is 75.33”.
Embedding [[TEMP.Format ##]] would embed the value with as a 2 digit integer: “75”.
Embedding [[TEMP.Pformat ##]] would embed the prompt plus formatted value: “The temperature is 75”.

11.9.3 Embedding Variable WITHOUT Forcing Derivation


If a variable is embedded in text that is being displayed and the value of the variable is not known, Corvid will
automatically attempt to derive a value from the Logic Blocks or, if that is not possible, ask the user for the
value. In most cases this is the correct and desired action, but sometimes the value of the variable at that
moment should be embedded, without deriving a value or asking the end user. In this case, if the variable
does not have any value assigned, the embedded variable will be replaced by a blank. If it has a value, that
current value will be embedded.
This is done by embedding:
[[*var_name]]
If the variable name is preceded by an *, the current value will be used and there will be no attempt to derive
or ask a value. This applies to both simple embedded variables and ones using any of the properties.
For example, there is a Collection variable [ADVICE], and that variable will have various strings added by
various rules in the system as it runs. A question screen could have text displayed that said:
“So far the advice is [[*ADVICE]]”
This would embed the value of [ADVICE] with whatever strings had been added so far. If the asterisk was not
there, Corvid would try to use backward chaining to test ALL the rules that could set a value for [ADVICE]
before it was embedded. That would not be the flow desired since the intent is to embed the partial value at
that point of the run.
If [ADVICE] was going to be embedded in a final report, it would probably use [[ADVICE]] since deriving the
final value would be appropriate for the overall results.
Using the [[*...]] form is rarely needed unless the intent is to display intermediate values. It can also be used
to correct a confusing flow of execution due to backward chaining on the embedded variable, but this usually
indicates other procedural problems that should be corrected in the Command Block.

11: Controlling the User Interface 237


11.9.4 Special Embedded Identifiers
There are several special embeddable identifiers that will embed groups of variables These behave very
similar to [[ ]] replacement of any Corvid variable, but embed multiple variables at one time. Any text in the
system can include these identifiers. They are most often used with database commands to store input data,
but can be used in result screens to display user input or values set.

[[~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.

[[~SORTED_INPUT] AFTER: <BR>]


This is replaced by the same list of variables and values as the [[~SORTED_INPUT]] but puts a “<BR>”
between each value. This puts each variable on a separate line. (Both the Java applet and Servlet
runtimes will display this as a line break.) When the “AFTER:” or “BEFORE:” options are used, they are
applied to each variable in the list.

[[~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.

238 11: Controlling the User Interface


11.9.5 Additional Text in [[...]]
When building complex reports, it is sometimes necessary to have additional text added when a variable is
embedded to control lines, format etc. If the report uses HTML, it is sometimes necessary to wrap tags
around individual values. However, when the variable was not set by the system and has no value, the
additional text should not be added.
For example, suppose that there are 3 variables that each might have been set by a system [X], [Y] and [Z],
and the ones that have a value are to be displayed in an HTML page with one item per line.
If the report contained:
[[*X]]<BR>[[*Y]]<BR>[[*Z]]<BR>
this would work as long as all 3 variables have a value. If one did NOT have a value, that variable would not
be used but the <BR> would still be included. This would result in extra blank lines.
To handle this situation, Corvid supports several options for [[ ]].
[[var]str]
[[var]str] will be replaced by the value of variable var followed by the text of string str. If var has no
value, str will not be added. To handle the case above, use:

[[*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:

[[X.VALUE] BEFORE: <BR>]

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>]

to wrap the <LI> tag around each value.

11: Controlling the User Interface 239


Adding < and > in BEFORE: and AFTER:
Embedded variables using the BEFORE: and AFTER: options to add text to the variable, can use &lt; and
&gt; for the < and > symbols. For example:
[[~SORTED_INPUT] AFTER: &ltBR&gt]
is equivalent to:

[[~SORTED_INPUT] AFTER: <BR>]

The < and > characters can still be used in most cases. Using “&lt” and “&gt” 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.

11.9.7 Embedding Information on Java System Properties


Java has many “system properties” that provide information on the user’s configuration, OS, language etc. A
special embeddable command allows you to automatically obtain this information when needed.
[[~SYSPROP java_system_property_name]]
java_system_property_name = The name of a java property

[[~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

240 11: Controlling the User Interface


Some of the more common useful system properties are:

Key Meaning

file.separator File separator (for example, "/")


java.class.version Java class version number
java.home Java installation directory
java.vendor Java vendor-specific string
java.vendor.url Java vendor URL
java.version Java version number
line.separator Line separator
os.arch Operating system architecture
os.name Operating system name
os.version Operating system version
path.separator Path separator (for example, ":")
user.dir User's current working directory
user.home User’s home directory
user.language User’s language setting

11: Controlling the User Interface 241


Chapter 12: MetaBlocks - Probabilistic
Product Selection
12.1 Overview
MetaBlocks provide a way to build expert systems that have generalized decision-making rules in a Logic
Block that interacts with a separate data file containing detailed information on multiple items. This approach
makes it easy to update and maintain a system by adding, editing or deleting items in the external data file
without changing the internal rules. MetaBlocks are aimed primarily at problems that involve comparing,
ranking and selecting the various items from the data file based on user requirements or other parameters.
This type of Corvid system is ideal for product selection and recommendation system that provides
probabilistic “best fit” recommendations of products to meet a user’s requirements. The results are quite
different from a database approach, which requires a match on every feature. When the user’s desired
features conflict, such as a high-end feature with a low price, the system does not just report “No match
found”. Instead it can present an explanation that the feature requires going to higher priced products, and
present those products with a note that they cost more than the users desired price point, but would be a
better fit to their needs. This approach is MUCH more like the interaction with a human salesperson and
much more informative, interactive and motivating.
MetaBlocks are most often used for selection problems that involve choosing among many items based on
properties or features, where either the data changes frequently or building the logic in a standard Logic Block
would be very repetitive. MetaBlocks can also be used for many other types of probabilistic systems where the
“best” item(s) are selected from a list. This includes probabilistic diagnostics and equipment recommendations.
There are several steps in setting up a MetaBlock system, but they are not complicated once MetaBlocks are
understood. MetaBlocks work with a file of data. The file is generally structured as a tab delimited text
spreadsheet file, although XML data and database commands can also be used to generate the data file.
The rules in a MetaBlock are always run in forward chaining and the entire MetaBlock is run once for each
row of data in the file. In the rules, special markers indicate columns in the data file. These markers are
replaced by the value for the specified column in the row currently being run. The rest of the rule structure is
the same as any other Logic Block. After the rules are run on each row of data, typically some conclusions
about the row (item) will be saved and some variables will be cleared before processing the next row.

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.

12: MetaBlocks 243


MetaBlocks are a combination of logic and
data. The logic is contained in the Logic Block,
the data can come from several sources. The
easiest to understand and work with is a tab
delimited text “spreadsheet” file. However, the
data can also come from an XML file or
external source that can return data in a form
equivalent to the spreadsheet file. This
chapter will first work with the spreadsheet
approach to explain the concepts. Alternate
data sources are covered in chapter 13 on
external interfaces.
When using MetaBlocks, the rules in the Logic
Block are always run in forward chaining.
However, backward chaining can be used to
derive the values of any Corvid variables, which may involve running other Logic Blocks to derive needed values.
The rules in the Logic Block are processed sequentially from top to bottom. However, this is repeated once
for each data row in the spreadsheet. All the rules in the block will be applied to the data in each row of the
spreadsheet. Corvid does an automatic “RESET” to allow the rules in the block to be run multiple times, and
clears certain variables as needed. Because of this, the rules in the MetaBlock are a combination of standard
Corvid rules and variables, and special “markers” which be replaced by the values in the current spreadsheet
row. These “markers” are indicated by the column name in { } and are updated with the corresponding values
as each row in the spreadsheet is processed. The Corvid variables in the MetaBlock are typically set only
once and apply to all rows, except for those that are cleared.

12.3 MetaBlock Spreadsheet


Most MetaBlocks use a simple spreadsheet for the data. This is the easiest to start with. The spreadsheet
should be structured to provide properties, specifications or other data that describe a product or item. This
is easiest to think of as “products” with various specs or features, though it can be applied to many other
types of problems.
Normally the left column will be the identifier for the “product”. The other columns will be for various features,
capabilities or properties of the product. In this example, the products are “A123” and “B999” and the
properties that describe them are their “Price” and “Weight”.

Product Price Weight


A123 12.35 1.5
B999 15.97 3.2

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.

244 12: MetaBlocks


The spreadsheet should contain ALL the data that will needed in the logic to decide among the various
products. The logic in a MetaBlock should be generalized and not have any product specific rules.

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.

12: MetaBlocks 245


If the string value were being tested against the value of a Corvid string variable [PreferredManufacturer], the
expressing would be:
“{Manufacturer}” = [PreferredManufacturer]
since the value of the string variable [PreferredManufacturer] is automatically a string, it does not require
quotes, but the value used to replace {Manufacturer} still needs to be in quotes.
When the data in the spreadsheet is a number, then the quotes are not needed and an expression such as:
{Price} > 14
can be used.

12.4 Selecting and Creating a Spreadsheet


The spreadsheet file to use is selected from the MetaBlock
window.
The controls in the upper left corner allow selecting and editing
the spreadsheet file, and selecting other types of data sources.
To select an existing spreadsheet, enter the name of the file in the
edit box under “Source” and click “Load”, or click the “Browse”
button and select the file. Normally the spreadsheet file should
be in the same folder as the system CVD and CVR files, but it can
be anywhere. The “Source” can be a URL to a file anywhere on
the Web, but Corvid can only load and edit the file in the
development environment if it is on the local PC.
When the file is selected and loaded, the “Column Headings” box will display
the heading from the spreadsheet. This can be used to check that the file is
the correct one for the system being built.
To create a New spreadsheet file, click the “New” button. This will ask you to
provide a name for the new file and will open the Corvid spreadsheet editor to
add content.

12.5 Editing a Spreadsheet


An existing spreadsheet file that has been loaded can be edited by clicking the
“Edit” button. This will display the Corvid spreadsheet editor, loaded with the
current content of the file.
MetaBlock data spreadsheet files can be created
and edited with many programs from Notepad to
Excel, but the Corvid Spreadsheet Editor is
designed to make it easy to build and edit
MetaBlock data files without the extra unnecessary
features of a full spreadsheet program, or the
problems of keeping the tab delimited structure
that text editors present.
The Corvid spreadsheet editor is designed for
adding and editing the content of MetaBlock data
files. It can read tab delimited text files, and will
save any changes as a tab delimited text file.

246 12: MetaBlocks


The controls on the lower left allow adding, deleting and moving rows and columns
of data.
To add a row: Click the “Add” button under “Row” this will add a new blank row to
the spreadsheet.
To delete a row: Click any cell in the row to select it and click the “Delete” button
under “Rows”. This will delete the entire row of data.
To add a new column: Click the “Add” button under “Columns”. Corvid will ask for the new column header.
The header must be unique. Corvid will add a new blank column at the currently selected column, shifting
other columns to the right.
To delete a column: Click anywhere in the column to select a cell. Click the “Delete” button under “Columns”.
To move rows or columns: Click on a cell to select the row/column. Click the “Move Up/Down” and “Move
Left/Right” buttons to move the entire row or column in the specified direction. Corvid does not care about the
order of the rows or columns. Rows are processed in order from the top, but unless a system is designed to
exit the MetaBlock under certain conditions, all rows will be processed. The order of columns also does not
matter to Corvid, which just identifies the column by its header, regardless of order. However, reordering the
rows/columns can make the spreadsheet easier for the developers to read and maintain.

Editing Cell Content


When a cell is selected by clicking, all of the
unique values in the column will be displayed
in the “Values Used” box and the cell text will
be copied to the edit box on the lower right.
The text in the cell can be edited 3 ways:
! The text can be edited directly in the cell.
! The text can be edited in the lower right edit box.
! Clicking on a value in the “Values Used” will copy the value to the cell. This is very useful if the
content of all the cells in the column are one of a few specific values, and the rules are designed to
expect one of the specific values. Once each of the values have been added to any cell in the
columns, additional cells can be quickly given one of the allowed values by simply clicking on the
value in the “Values Used” list.
The “Values Used” list is also a quick way to make sure all the values in the column are correct when the
rules expect specific values. Since all the unique values for the column will be displayed in the box when a
cell is selected, typos are much easier to find since they will stand out in the list more readily than in the
overall spreadsheet.

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.

12.6 MetaBlock Logic


The logic in the MetaBlock is built like any other Corvid Logic Block. All of the same types of variables, rule
structures and functions are available in a MetaBlock. What makes a MetaBlock different is:
! The rules are written using the {columnName} markers that will be replaced by values from the
spreadsheet.
! The rules in the MetaBlock will be run in forward chaining, and the entire block will be run for each row
in the spreadsheet.
! The goal of most MetaBlocks is to compare and sort the “products” represented by the rows in the
spreadsheet to find the one that is “best” - based on the logic of the system.

12: MetaBlocks 247


12.6.1 Expressions
Most MetaBlocks have rules that compare some end user preferences that are the same for all rows with the
values that come from each individual row. For example, one item in a product selection system would be to
compare the customer’s budget with the price of each item in the spreadsheet. If the price is over the budget,
that product is a less good choice than a product that is under budget. In the MetaBlock there could be a
numeric variable [BUDGET] that is used to ask the customer their budget amount. The value of this variable
will be the same for all rows. The spreadsheet of data on the products could have a “Price” column with the
price for each product.
The MetaBlock rules there could be a rule:

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.

Keeping the Questions Easy to Answer


When adding logic to the MetaBlock, the questions that will be asked of the end user should be kept as easily
answered as possible. Here there is another product attribute in the spreadsheet of “Weight”. This is a
numeric value, but unlike “Price”, it is not a good idea to ask the end user what is the maximum weight they
want the product to be. This is not a criteria most people think of and there are many ways that weight is
represented. It is better to ask the user if they prefer a product that is “light” compared to the typical weight
for similar products, or if “weight is not important”. These can be worked into the logic and converted to what
constitutes a “Light” product based on current product specs.

248 12: MetaBlocks


This would be rules similar to:
IF
Product should be Light
AND: {Weight} > 2
THEN
Decrease the score for this product

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.

Building MetaBlock Expressions


Building expressions in a MetaBlock is done in the same window as
building other expressions in a Logic Block, but if the block is set to be a
MetaBlock and has a spreadsheet file assigned, the “MetaBlock” button
will be enabled. Clicking this button will display a list of all the spreadsheet
column headers that can be used in the system.

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.

12: MetaBlocks 249


12.6.2 Numeric Expressions
Numeric expressions are the easiest to use in MetaBlocks. If the spreadsheet column has numeric data, just
use the {columnName} in the expression where the number would appear. For example, if the column is
“Price” with numeric values, an expression could be:
{Price} <= [Budget]
The expression can be any Corvid expression. The {columnHeader} values will be replaced in the expression
before the expression is evaluated.
Numeric values can also be used in the THEN part of rules to add data to reports of do other calculations.
The {..} values will be replaced in strings before the rest of the command is processed. For example, the
report might add a string to a report:
[Report.add] The price of this product is ${Price}
Here {Price} will be replaced by the value in the string, which will then be added to the report.

12.6.3 String Expressions


String expressions are similar to numeric expressions, but often require that the {columnHeader} be enclosed
in quotes to make a legal Corvid expression. For example:
“{Manufacturer}” = [PreferredManufacture]
Remember when using expressions like this that the value of [PreferredManufacture] must EXACTLY match
the value in {Manufacturer} or the expression will be false. Normally, this type of expression is only used
when the value of [PreferredManufacture] is set by the rules, rather than directly entered by the end user. If
the end user is entering a value, it may not match in case, be misspelled, or not match exactly such as “Ford
Motors”. In most cases, it is better to use a static list variable than a string for this type of match since the end
user will then select a specific value from the Static List’s value list.
String expressions are most often used in the THEN part of rules. They can be easily incorporated into the
text added to reports or other text items. For example, if the spreadsheet had columns for {Product} with the
product name, and {Link} with the URL of a web page with details on the product, a HTML report might
include the product name linked to the page:
[Report.add] <a href=”{link}”>{Product}</a>

12.6.4 Static List Variable Expressions


Static List variables work very well with MetaBlocks since both can be designed to have exactly the same list
of values. However, the test expressions in the MetaBlock must be designed to work with the value from the
Static List as a string.
If there is a Static List variable [Color], with values “red”, “blue” and “green”, and a column in the MetaBlock
data file with a header of {productColor}. If an IF condition is added to the block using the variable [Color], it
will automatically select the “Static List” tab. MetaBlock tests cannot be built from this tab - they must be built
as expressions. Click the “Expressions” tab to select it. Static List IF conditions are built very similarly to
string tests and are based on matching the selected value of [Color] as a string with the value from the
MetaBlock column.
If [Color] will only have a single value selected use either:

[Color] = "{productColor}"
or
[Color.value] = "{productColor}"

250 12: MetaBlocks


If [Color] can have multiple values, the expression must be written to test if the color from the MetaBlock is
one of the possibly several colors selected for [Color]. This can be done with:

"{productColor}" <INSTR> [Color.VALUE]


This tests if the {productColor} is one of the values in the value list for [Color]. If using the multiple value
version, make sure that none of the value strings are substrings of other values. For example, if there were 2
values “red” and “reddish-brown”, the <INSTR> operator would find and match “red” in “reddish-brown”.
When using Static List variables in MetaBlock expressions, make sure the values for the variable and MetaBlock
column match EXACTLY in both wording and capitalization. If for some reason due to data sources, the case of
the values cannot be made to match, use the UCASE() function to force both the upper case:

UCASE([Color.value]) = UCASE("{productColor}")

12.6.5 Dynamic Lists to Customize Questions


Some systems have the data in the spreadsheet change frequently, and some columns may not always have
all the possible values of the corresponding static list variable. One option is to use a Dynamic List variable
and have its value list be the unique values in a specific column in the MetaBlock data. This means that the
user will only be presented with a list of values to select among that actually exist in the data, and the list of
values will change as the data changes.
For example, a used car selection system might have data in the spreadsheet of the used cars currently in
inventory. The end user might be asked what manufacturer they prefer. If this was done with a static list, it
would have to present all the possible manufactures - regardless of whether or not they were in stock. With a
Dynamic List, the value list can be set to the unique values of the “Manufacture” column of the current
spreadsheet. All the manufactures available will be displayed, and whatever the user selects will match
something in the data.
! Corvid makes this type of interface easy to
build.
! Create a new Dynamic List variable in the
Variable window. This will open the
“Dynamic List” tab.
! Select the “Use Tab Delimited Spreadsheet
column unique values”.
! Enter or browse to the MetaBlock data file.
! Once the file is selected, the “Column” drop down list will contain the column names from that
spreadsheet.
! Select the column to use for the Dynamic List value list.
When the system runs, the value list will be set from the spreadsheet.
Build the expressions in the MetaBlock rules exactly like Static List expressions, using a text comparison with
the value of the Dynamic List.

12: MetaBlocks 251


12.6.6 Ranking the Products
The goal of most MetaBlock systems is to rank the
various “products” or items described by each row of
data. There are many ways to do this, but one of the
easiest is to use a Confidence variable to calculate a
score or ranking for each item.
Create a new Confidence variable named [Score] and
set it to the “Sum” mode. This mode allows multiple
rules in the MetaBlock to add or subtract “points” from
the variable and it will automatically sum them to a final
overall value. (Any of the other confidence modes can
also be used if appropriate, but the Increment/
Decrement mode works well for most systems.)
Each of the rules in the MetaBlock can add or subtract
points from [Score]. If a product is a very good match
with an end user preference, [Score] can be given
many points. If it is a very poor match it can be given
more negative points (subtracting from [Score]). Preferences that match (or don’t match) can be given lesser
amounts of points. The number of points added or subtracted can be designed to match the importance of the
criteria and how good/bad the fit is. If a product is a very poor match for a highly important criteria, it can have
a very large number of points subtracted, effectively eliminating the product regardless of other rules. This
allows the expert knowledge of a salesperson to be incorporated into the system, so it will find the best overall
match, even when all preferences cannot be match for any one product.
Looking at the example on if the product fits in the customer’s budget:
IF
{Price} <= [BUDGET]
THEN
[Score] = 10

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.

252 12: MetaBlocks


12.6.7 Building a Report on the Product
In addition to creating s [Score] for each product, it is also very easy to generate a report on each individual
product. This can tell the end user how well the product meets their preferences. With a MetaBlock, an
individual product may get the highest score, even though it may not match all of the preferences. The
MetaBlock combines all the factors to find the “best” overall, and it may not match some preferences, but be
particularly good in others. The report on the product can explain which preferences were met and which
were not. This way, the customer is given a full explanation and can make a more informed decision.
Building a report on each product is very easy. First create a Collection variable to hold the report on each
product, [productReport]. Then have each rule that sets a value for [Score] also write something into the
report explaining how well the product matches or does not match that preference. Remember, adding
content for the preferences that do not match is just as important as adding content for the ones that do.
Even though some negative rules may fire, the product may still be the “best” overall and the report should
cover all the factors that went into the decision. The content added to the report should always be written
assuming the product will be selected as one of the “Best”. Each item added is independent of any
other content that was added.
Looking at the example again, the variable [productReport] will have content added for each rule:
IF
{Price} <= [BUDGET]
THEN
[Score] = 10
AND: [productReport.ADD] The product is within the budget.
IF
{Price} > [BUDGET]
THEN
[Score] = -10
AND: [productReport.ADD] The product is a little over the budget at ${Price}

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.

12: MetaBlocks 253


If the system has information for a URL link about the product, this can be expanded to include the product
identifier as a HTML link:
IF
{Price} <= [BUDGET]
THEN
[Score] = 10
AND: [productReport.ADD] <a href=”{link}”>{Product}:</a> The product is within the
budget.

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.

12.6.8 Saving the Results of Running a Row of Data


Most of the MetaBlock will be made up of rules that analyze the various factors and determine the value of
[Score] and the individual product report. The last rule in the MetaBlock determines how this information will
be saved before the MetaBlock is run again with the new row of data. (Remember the full set of MetaBlock
rules will be run in forward chaining for EACH row of data.). Each row is processed individually and has
no information on the values in the other rows.
To save the data, there needs to be an overall report that will be displayed as the recommendations. This can
be easily done with a Collection variable [Recommendations]. This will be the “best” products.
The last rule in the MetaBlock should be one that adds the information on the individual product
[productReport] to the overall report [Recommendations], and adds it using a sort value of [Score]. Since the
[Recommendations] collection is sorted, the products with the highest scores will automatically “float” to the
top and be the ones that will be displayed to the end user. Each row can be handled individually since the
“sort” will automatically select the ones with the highest score.
The simplest approach is just to add all the individual products to [Recommendations] with a sort.
IF
TRUE
THEN
[Recommendations.ADDSORTED] [productReprot.CONCAT], [Score]
This rule first concatenates all the individual strings added to [productReport] to make a single string
describing that product. That string is then added to the Collection variable [Recommendations] using the
value of [Score] as the sort value. The sort value will automatically insert the string into the collection based
on the sort value. The strings (products) with the highest [Score] will be at the top of the collection’s value list
and the ones with the lowest values will be at the bottom - all automatically arranged by sort value. The final
RESULTS command can then just display [Recommendations] to show the sorted list of “Best” products.
Some systems are designed to only include products that reach some specific threshold, and this can be
easily incorporated. Perhaps the nature of the system is that products that get an overall [Score] of less than
20 are such poor matches that they should never be recommended. Just change the last rule to:

IF
[Score] >= 20
THEN
[Recommendations.ADDSORTED] [productReprot.CONCAT], [Score]

254 12: MetaBlocks


If [Score] is less than 20, the data on that product will not be saved and will just be discarded when the next
row of data is run. (Systems that do this should generally check that when the MetaBlock is done some
products have been added to the collection. If [Recommendations] has not content, this should be explained
to the end user.)

12.6.9 Clearing Data


The MetaBlock will run the rules once for each
row of data. However, at least the variables
[Score] and [productReport] need to be reset
after each row or they will retain data on the
previous product. MetaBlocks make this very
easy to do.
In the MetaBlock window, the right side has a
list of variables to clear. Any variable added to
the list will be cleared after each row is
processed by the MetaBlock. This allows
each row to be processed individually, and the
variables needed to analyze that row’s data
do not carry over data from a previous
product.
To add a variable to the “Clear” list, select it
from the drop down list in the upper right and click “Add”. Items can be remove from the list by selecting them
and clicking “Remove from List”
Variables that do calculations or get values associated with a individual “product” (row) should be cleared.
This includes the [Score] for that product and any report built up on that specific product, [productReport].
The following should NOT be cleared:
! Variables whose value is the same processing all rows. (e.g. User preferences and variables set
outside of the MetaBlock).
! Variables that are used to collect and save the overall results of other rows, such as
[Recommendations].
! Any variable asked of the end user. (Clearing a variable that is needed in the MetaBlock, but asked of
the end user, will result in the variable being re-asked for each row).
! Any variable that does not appear in the MetaBlock.
It is important to set the “Clear” list correctly or the MetaBlock will either not retain data correctly or will
incorrectly consider data from a previous product. Each row should be analyzed independently, and data
specific to a previous block should be cleared.

12: MetaBlocks 255


12.6.10 Running a MetaBlock
MetaBlock are run from the Command Block
with the FORWARD command. Just add the
command to run a Logic Block that has been
defined to be a MetaBlock and Corvid will
automatically process it as a MetaBlock using
the associated data file.
Typically, after the MetaBlock has run, the
recommendations will be displayed. This is
generally a Collection variable that had data
on the products added with a sort value.
Displaying this collection variable will display
the products sorted in order.
Many systems only show the top few products.
this can be done by limiting the display of the
collection variable to the top N items. This can
be easily done using the TOP # property.

[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.

12.7 MetaBlock Sample System


The best way to understand MetaBlocks is to see one built. This example system is a simple restaurant selector.

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.

12.7.1 User Requirements


The first part of building a product selection system is to define what user requirements the system is going to
consider and support. Also, consider which requirements can be directly asked of the user and which should
be derived from other logic in the system, asking the user simpler questions.
In this case, the system will consider:
! Price.
! Type of food.
! Restaurant Atmosphere.
! Open or closed that night.
Desired price range and type of food can be directly asked of the user. For this system, it will derive what
type of atmosphere is desired by asking about what type of occasion it is to determine if the restaurant should
be quiet and intimate or a loud party atmosphere. (Obviously, just this part of the system could get quite
large, and it is simplified considerably.)
First add a Corvid Numeric variable for the price the end user is willing to pay:
! [Budget]
! Prompt: The maximum price I want to pay for an individual dinner.

256 12: MetaBlocks


This will be directly asked of the user.
There are 2 ways to handle the type of food, either:
! Add a single Static List variable with values that list the types of foods the system is going to support,
OR
! Add multiple variables, a Static List variable for each type of food with values of:
- Must have
- Would like to have
- Don’t care for
The latter approach allows better matching with the restaurant since weighting can be given to the strong
preferences and is the approach used here.
The system will offer: Steak, Seafood, Vegetarian, Asian (Japanese, Chinese and Vietnamese) and Mexican.
All of the “types of food” questions are put on a single screen with radio buttons to select the answers.
The data in a restaurant spreadsheet will rank each restaurant on its offering of these types of food on a scale
of 0 - 5. A value of 0 indicates that type of food is not available, a value of 5 indicates that this is the
restaurant’s main (or only) type of food.
For atmosphere, there are 3 numeric variables that will reflect end user preferences, but will be set by rules in
the system and based on the reason for going to the restaurant.
! [NOISE]
! [PRIVACY]
! [FORMAL]
[NOISE] is a measure of how noisy or quiet the restaurant should be, with 0=very quiet and 5=very noisy.
[PRIVACY] is a measure of how private the restaurant should be, with 0=very private and 5=not at all private.
[FORMAL] is a measure of how formal the dress should be, with 0 = Shoes and Shirt, 5 = Jacket and Tie.
The spreadsheet will contain data on how each restaurant is ranked in these factors.
Criteria like noise, privacy, and formal could be asked of the end user, but that would be quite subjective on
their part. It is better to ask about the occasion and have the system set the optimum values for noise,
privacy, and formal in a more consistent way.
This is done using a variable [Occasion] with values “Business Meeting”, “Date”, “Relaxing after work”, “No
occasion - just want dinner”. Some of the values such as “Business Meeting” can then lead to other more
detailed questions on the type of meeting: “Casual”, “Trying to close sale”, “Confidential Discussions”, etc.
These (and other similar) variables are used to fill out a Logic Block that sets the values for [NOISE],
[PRIVACY], and [FORMAL] in a very consistent way, and the user is asked simple questions that they should
be able to answer.

12: MetaBlocks 257


Since this Logic Block sets the values for [NOISE],
[PRIVACY], and [FORMAL], it will be called automatically to
derive the values and then use them in the MetaBlock.
Remember, MetaBlocks themselves always run in FORWARD
chaining, but they can use Backward Chaining to derive
values that are needed.
There is one more major requirement to add - is the restaurant
open. Most of the restaurants in the system are open
everyday, but some are closed Sunday and some close
Monday. This will be included in the system with a large
number of negative points if the restaurant is closed on that
day. It does not matter how great the restaurant is, if it is not
open, it is eliminated.
In the data spreadsheet, this will be given a value of 0 - 5,
where 0 is a very quiet restaurant ideal for talking to fellow
diners without interruption or competing sounds and 5 is a
very noisy party atmosphere.
This will also be given a value of 0 - 5, where 0 is a crowded
restaurant where conversations can be easily overheard and 5
is very private, suitable for discussions that should not be
overheard.
This will be give a value of 0 - 5 where 0 is very informal and 5
is a formal restaurant, jacket and tie required

12.7.2 Data Spreadsheet


The spreadsheet will need to contain data on each of the restaurants in the system. To store this create a
spreadsheet with column headings:
Name - The name of the restaurant
Address - The address and phone number
Cost - The typical price of a dinner
Noise - A ranking of how noisy the restaurant is: 0 - 5
Privacy - A ranking of how private the restaurant is: 0 - 5
Formal - A ranking of how formal dress is at the restaurant: 0 - 5
Steak - A ranking of the availability of steak: 0 - 5
Seafood - A ranking of the availability of seafood: 0 - 5
Vegetarian - a ranking of the availability of vegetarian meals: 0 - 5
Asian - A ranking of the availability of Asian cuisine: 0 - 5
Mexican - A ranking of the availability of Mexican cuisine: 0 - 5
Closed Sunday - A “1” if closed on Sunday, otherwise a “0”
Closed Monday - A “1” if closed on Monday, otherwise a “0”
Image - The filename of a JPG image for the restaurant
Notes - Other comments on the restaurant
This spreadsheet will hold all of the details on the restaurants. This makes it easy to update the information
and add restaurants.

258 12: MetaBlocks


12.7.3 Defining the MetaBlock
The next step is to build rules in a new Logic Block that will be the selection MetaBlock.
This will need 3 new variables:
! The first is a Confidence variable that will be used to calculate how likely the restaurant is to meet the
users requirements. This confidence variable will be named [Ranking] and will use the “Sum”
method of combining confidence values.
! A Collection variable named [Comments] will hold comments on the individual restaurant being analyzed.
! Another Collection variable named [Best_Choices] will be used to store the best selections.
When the system runs, it will clear [Ranking] and [Comments] after each row since their value is recalculated
for each row. These are the only variables need to be cleared since all others stay the same for the entire
system, or, for [Best_Choices], are built during the processing of many rows in the system.
To build the MetaBlock:
1. Start a new Logic Block named “Restaurant MB”.
2. Make the block a MetaBlock by clicking on the “MetaBlock” button.
3. In the MetaBlock dialog:
! Select the restaurant spreadsheet.
! In the “Variables to clear” drop down list on the right, select Ranking.
! Click the “Add” button.
! In the same drop down, select Comments.
! Click the “Add” button.
NOTE: A Logic Block that is made a MetaBlock can be named anything, but using the name of the
spreadsheet followed by “MB” makes it easy to recognize that this is a MetaBlock and what it does.

12.7.4 Adding the First Rule


Now add the actual logic. Most MetaBlock systems have multiple trees in the block. - remember all of the
logic that is applied to the spreadsheet data must be in the same block. Other logic that derives values can
be in other blocks.
The first factor to consider is price. There is a Numeric variable in the system [Budget]. This will be used to
ask the user what is the maximum they want to pay. There is also a column in the spreadsheet labeled “Cost”
which is the typical cost of a meal in the specific restaurant. If the cost is within the budget, add points to the
[Ranking] variable. If the cost is higher than the budget subtract points from [Ranking]. The number
subtracted should increase as the cost gets higher above the [Budget].
The number of points to add or subtract and the formula you use to increase this amount as the cost gets
higher are some of the ways that various factors can be weighted in the system. For example, a simple
approach is to say if the typical cost is less than the budget, give the restaurant 50 points and if it is over
budget, deduct 50 points. This is simple, but if the cost is one cent over budget it deducts as many points as
if it were $100 over budget -not a very reasonable approach.
A better approach would be to always start with 100 points. If the cost is over budget, deduct 5 points for
every dollar over budget. In rules this would be:
IF
[BUDGET] >= {Cost}
THEN
[Ranking] = 100

12: MetaBlocks 259


IF
[BUDGET] < {Cost}
THEN
[Ranking] = 100 - (5 * ({Cost} - [Budget]))

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.

12.7.5 Adding Comments


The rules will start the variable [Ranking] off with 100 points for restaurants under budget, going to 0 points for
restaurants that are $20 over budget, and negative points for even more expensive restaurants. But
remember, there are other factors that still have to be considered, and the system will be showing the user the
“Best” selections based on the overall consideration of all factors.
The other factors could add enough points that even a restaurant well over budget may be the best. (Perhaps
the budget is unrealistic - a quiet romantic evening for $5). It is a good idea to ALWAYS assume that a
product (restaurant in this case) MAY turn out to be a “best choice”, even if it is ranked low in one area.
If other factors push an over budget restaurant into the “Best” category, the system should warn the user that
dinner would be more expensive than they were planning. To do this, build a set of comments in the
Collection variable [Comments] while going through the rules. These comments apply only to the individual
restaurant and are cleared after each row of the spreadsheet. (This variable was already defined and added
to the MetaBlock parameters to be cleared.)
To add a note to the Collection variable, you use the .ADD method to add a string. The string added can
contain information from the spreadsheet by simply using the {…} notation.
If the price of dinner is $10 - $20 more than requested, add a note that dinner will be “more expensive than
requested”, and if more than $20 over, add a note that it will be “Considerably more than requested.” In both
cases you will include the typical cost of the dinner from the spreadsheet.
NOTE: These new nodes were
added at the same level as the
first. These are a separate tree,
though in the same Logic Block.
They were added by clicking on the
top node to selected it and then
clicking the “Same Level-Below”
button in the IF button group.
As the spreadsheet data is analyzed, many notes can be added to the [Comments] variable. This is a very
useful and easy way to provide the user with personalized information very specific to their requests.

260 12: MetaBlocks


12.7.6 Expanding the Logic
The next step is to add rules for the other factors in the decision. First the [Noise], [Privacy] and [Formal]
factors. Each of these is ranked on a 0-5 scale for what would be most appropriate based on the occasion.
The spreadsheet also has columns with the same names, which indicate the restaurant’s score in each of
these areas on the same 0-5 scale.
The system adds 35 points if the restaurant’s “noise”
ranking and the user’s desired ranking exactly match. For
ones that don’t match, it starts with 30 points and takes
15 points off for each point that they are different. (For
example, if you want a restaurant with a ranking of 2 and
the actual ranking is 2, you give 35 points. If the actual
ranking is 1 or 3, give 15 points. If 0 or 4 give 0 points. If
5, give -15 points.)
NOTE: There are many ways these factors can be
worked into the system. The way to do it and number of points added control how heavily
weighted these factors are in the overall recommendation.
In addition, since a little too quiet is usually OK, but too
noisy can be a real problem, add a warning to the user if
the restaurant is likely to be too noisy when there is more
than 2 ranking steps difference. This is also done for
privacy and formality.
Add the [Noise] factor to the “Restaurant MB” Logic Block.
The [Privacy] ranking is handled the same as [Noise]. For
[Formal], the weighting this less heavy with fewer points
added or subtracted. A warning is added if the restaurant
may be significantly more formal than they may be
expecting.

12.7.7 Controlling Weighting Factors


Now add the factors on what type of food is desired. The weighting put on the food selection varies with the
occasion. When just going out for no occasion, finding the type of food you most want is important. If it is a
business meeting, the atmosphere is more important than the specific type of food.
This could results in a fairly large tree, but instead set a [Food_Points] variable based on the occasion. This
only needs to be done once, since it is defined by the occasion and will be the same for all restaurants. This
will be added to the “Atmosphere” tree, rather than the MetaBlock.
These rules set [Food_points] to a low value of 10 for business meetings, dates and meeting people. For
occasions where the type of food is more important (relaxation after work, pre-theater or no occasion) assign
a higher value of 25. Now use the [Food_points] variable in the “Restaurant MB” rules to assign points for
each type of food. Since this is already weighted by the occasion, these rules will be much simpler.
For each of the food types you used a static list variable with 3 values:
! Must have.
! Would like to have.
! Don’t care for.

12: MetaBlocks 261


Now the system needs to consider each of these values in setting points. The restaurants are ranked 0-5 on
each food type. The values mean:
0 - That type of food is unavailable.
1 - Occasionally on the menu, but don’t count on it.
2 - Should be one item on the menu, but no selection.
3 - A few items on the menu.
4 - A good selection, plenty to choose form.
5 - The restaurant’s specialty.

For each food type:


If the user selects “Must have”: subtract points equal to [Food_points] for
restaurant rankings of 0-2, add [Food_points]/2 for a ranking of 3, add
[Food_points] for a ranking of 4 and add 2*[Food_points] for a ranking of 5.
If the user selects “Don’t care for”: subtract 2* [Food_points] for rankings
of 5.
Adding the rules for “Steak” to the “Restaurant MB”:
Now the equivalent rules have to be added for each of the other food
types in the system.

12.7.8 Factors that Eliminate Products


The last factor that has to be added is a check to see if the restaurant is
open. If it is not, it should be eliminated regardless of how good a fit it is.
Add a variable [Day_of_week] that asks what day of the week the user
plans to go to the restaurant. If the day selected is a day the restaurant is
closed, it will deduct 1000 points, which will effectively eliminate it from
consideration. To get data for this, use the “Closed Monday” and “Closed
Sunday” columns in the spreadsheet.

12.7.9 Saving the Data


Now the system has all the rules needed to rank each restaurant, and set the value of the variable [Ranking]
to measure how good a fit the restaurant is to the user’s requirements. There is also a Collection variable
[Comments] with specific comments on the restaurant.
This data needs to be saved in the overall Collection variable [Best_Choices] before the next row in the
spreadsheet is analyzed. To eliminate potential bad fits, the system only includes restaurants that received a
[Ranking] value of greater than 0. Selecting this cutoff point depends on how many restaurants there are in
the system and the likelihood that some will have received a fairly high [Ranking] value. If it is very likely that
at least a few would get rankings of over 50, cutoff could be set higher. Another option is to just include all
restaurants in the list thereby guaranteeing that there will always have a “best” selection. For this system use
the cutoff of a ranking of 0.
There are several items of information on the restaurant in the spreadsheet that were not used in the analysis
- name, address, notes and image. The image is a JPG image for the restaurant. This could be a photo of
the restaurant, a sign or some other image to use. This image can be simply displayed or could be made into
a link to the restaurant’s home page. The “Notes” column in the spreadsheet is a place where a short
description of the restaurant or special comments can be added.
Since this was not already added to [Comments] in this system, first add the image to the start of the
comments as an IMG SRC command. (To make this a link, you would use an HREF command.) Then add

262 12: MetaBlocks


the “Notes” to the end of the comment and then add the name and address.
The ADDFIRST method puts the IMG SRC command
as the first item in the list. The following ADD methods
put the other information at the end. The last line is
VERY important. It is the one that saves the data. It
concatenates all of the comments on the individual
restaurant together and adds it as a single item in the
collection variable [Best_Choices] with sorting based on
the [Ranking] variable.
As each row is analyzed, all of the information is added to [Best_Choices]. This list of restaurants is sorted by
the ranking the restaurant received. After each row [Ranking] and [Comments] are cleared automatically
since by the MetaBlock.

12.7.10 Adding a Command Block


The command file for this MetaBlock based system is simple.
Create a new Command Block and add:
The FORWARD command is set from the BLOCK tab. Just
select the MetaBlock to run. When the block needs other information, it will derive it from the other block(s) in
the system.

12.7.11 Adding a Spreadsheet


The spreadsheet used for the data now needs to be populated. Setup the spreadsheet restaurant.xls as a
Microsoft Excel spreadsheet and then save it as a tab delimited file in restaurant.txt.

12.7.12 Displaying the Results


After the system runs, the system needs to display the results. Setting the correct RESULTS commands
does this.
The variable [Best_Choices] may have a few or many
items depending on how many were found that met the
selection criteria. The system could display all of them,
but instead it only shows the top 5 recommendations by
using the [Best_Choice.TOP 5] property.
Each restaurant selected will have a JPG image and a
block of text that includes the comments, the
spreadsheet note about the restaurant and the address.
This text can vary in length. One very effective way to
format this is to use TEXTBOX format option. The
TEXTBOX format allows specifying a part of the results
window that can display any amount of text. The
number of rows in the TEXTBOX can be set. If there is
more text than fits in the window, a small scroll bar is
displayed for the box.
The TEXTBOX is defined from the format window for the
results command.
Textboxes are a built in Java control and must follow the constraints that the control has. All text must be a
single size, font and color. IMG SRC and HREF commands cannot be put in the textbox.

12: MetaBlocks 263


Since the comments start with an IMG SRC command, and this cannot go in the text box, Corvid
automatically displays the image and then puts the rest of the text in the TEXTBOX.
Each restaurant has an associated JPG image. This could be a picture of the restaurant, the typical food, etc.
For this system, the JPGs are just the name of the restaurant. These are all the same size (in this case
175x175 pixels).
The default formats were set to make the prompt text blue and slightly larger font. The [Occasion], [Budget],
and [Day_of_week] questions have been put on a single screen, as have all of the “type of food” questions.

When you run the system, the first question is:


Answer that you are looking for a restaurant for a
business meeting on a Wednesday in the $35 or less
range. Since “Business Meeting” was selected, the
system needs to know the type of business meeting to
set the value for [NOISE], [Privacy] and [Formal].

The next question is:

Click on the “Casual” radio button and “OK”.

The system will display its recommendations, a


list of the top 5 restaurants based on the criteria
you set. This system can be run with other input
from the Samples/Restaurant directory.

12.7.13 System Maintenance


Once a system is finished, there are always maintenance issues. The first step is to have users test the
system and see if they agree with the results. If they don’t, it is likely to indicate that the weighting given to
various factors (price, food type, etc) need to be reconsidered. It may also be that the rankings given for the
individual restaurants in the spreadsheet need to be looked at.
Once the system is running as desired, it is very easy to maintain. All that is required to add a new restaurant
is to add it to the spreadsheet. The system will then automatically consider it. If something changes at a
restaurant (such as menu or pricing), just update its rankings on the spreadsheet.
Even adding a whole new cuisine is just a matter of adding a new variable in the system, adding a few rules
to work that factor into the rankings and adding a new column in the spreadsheet - less than an hours work.
Product selection systems in Corvid are very easy to maintain and allow even complex logic to be
incorporated into the decision process.

264 12: MetaBlocks


12.8 Other MetaBlock Data Sources
Most MetaBlocks work with standard tab-delimited spreadsheet files. These files can be created in Corvid or
a spreadsheet program such as Microsoft Excel.
However, any program or data source that can return data in a form that is comparable to a tab-delimited
spreadsheet can also be used. This allows using databases, servlets or other programs that can be called as
a URL.
When a datasource like this is used, it is a good idea to build a standard static tab-delimited file with the same
structure to use to build and test the system. Once the system is working, switch to the external source.
MetaBlock data can also come from XML files. See section 13.5.8 on the details of using XML data as the
data source for a MetaBlock.

12: MetaBlocks 265


Chapter 13: Interfacing to External Programs
13.1 Overview
Corvid systems can interface to resources and programs external to the Corvid Runtime program to obtain
data, perform special actions and integrate into an overall IT environment.
There are a variety of places that a Corvid system can call external resources. Usually this is done to obtain
data, such as reading from a database, but can involve many other actions and types of programs. External
interface commands can be added to:
! Get the value for a variable(s) at Runtime.
! Get the value list for a Dynamic List variable.
! Get initialization values for a Collection Variable.
! Set the Prompt text for a variable.
! Set the text for a Static List variable value(s).
! Execute a command after the end user provides input.
! Execute an External Interface command in a Logic or Command Block.
! Obtaining a MetaBlock data file.
All of these have a similar interface to build the associated command. The types of commands that can be
used are:
! URL: Calling a URL or local file to perform actions and return data. (Section 13.4)
! XML: XPath commands to read data. (Section 13.5)
! Database: SQL Commands to read or write data. (Section 13.6)
! PARAM: Reading data from the Applet tag. (Section 13.7)
! Applet: Calling a Java Applet to perform actions and return data. (Section 13.8)

13.2 Where to Use External Interface Commands


There are various places in the Corvid Development environment where external interface commands can be
added. In general, any type of external interface command that
returns the correct type of data can be used.

Whenever an external interface command can be used, there is


an associated “Edit” button, which will display a window to build
the command with tabs for XML, Database, Applet, Parameter
and URL external interface options. The external interface
commands are displayed in text boxes next to the “Edit” button.
It is possible to directly edit the command in the edit box, but
since most commands have fairly complicated syntax, it is
much easier to build/edit the command by clicking the “Edit”
button.
NOTE: Most external interface commands are found
on the Variables window and are
considered “Advanced Options”.
To enable these command options, make sure the “Advanced
Options” checkbox is selected at the bottom of the variables window.

13: Interfacing to External Programs 267


Setting the Value for a Variable
This is the most common use of external data sources. In
the Variables window, go to the Options tab. Click the
“Edit” button next to “External Source for Value” and build a
command.
When the value of the variable is needed, rather than
asking the end user, the external source for the data will be
used. This allows systems to automatically obtain some, or
all, of their values from external sources. The external
source/program called must return a value for at least the
variable associated with the command, and can return data for other additional variables. The returned value
must be consistent with the variable type (e.g. a numeric variable needs to have a numeric value returned, a
static list needs to have a value number or short text returned)

Setting the Value List for a Dynamic List


Variable
In the Variables window, select a Dynamic List variable. In
the “Dynamic List” tab, one of the options for the value list
is an external source. Click the “Edit” button next to the
“Use External Source for Value List” and build a command.
When the Dynamic List variable is asked or included in a
report, the associated value list will be obtained from the
external source.

Initializing a Collection Variable


In the Variables window, select a Collection variable. In the
“Collection” tab, one of the options is to initialize the value
list from an external source. Click the “Edit” button in the
“Preload from an External Source at Runtime” and build
the command.
Collection variables preloaded with values from an external
source will call the external source to initialize the
collection before the variable is used in the system. This
can be convenient to provide starting content for a report,
or to load the collection with items that will be analyzed by
the Corvid system. The value returned from the external
program can be a single string, or multiple strings
separated by a tab or line feed character. When there are
multiple strings, they will be assigned in order as multiple items in the collection value list. A single string will
be assigned as a single value in the collection value list.

Prompt Text for a Variable:


In the Variable Window, select the Variable that will get its
Prompt from the external source. Go to the Prompt tab.
Click “Edit” in the “External Source for Prompt Text” and
build a command.
When the prompt text for the variable is needed to ask the user
a question or to include the variable in a report, the text will be
obtained from the external source. The external source should
return a single string for the associated variable.
Systems that run in multiple languages, or need to have

268 13: Interfacing to External Programs


prompts that change dynamically, can use an external source for the Prompt text. XML can be a convenient
way to handle systems with multiple prompts. Corvid also provides internal support for up to 5 prompts based
on a key variable, and resource files are often a more convenient way to handle systems that run in multiple
languages.

Static List Variable Value Text


In the Variable Window, select a Static List Variable. On the
Static List tab, select a value. An external source can be
specified for each value individually. Click “Edit” in the
“External Source for Value Text” section and build the
command.
When the variable value text is needed to ask the user a
question or to include the variable in a report, the value text
will be obtained from the external source. The external
source should return a single string for the associated
value.
Systems that run in multiple languages, or need to have
value text that change dynamically, can use an external
source for the text of the values. XML can be a convenient
way to handle systems with multiple value texts. Corvid also provides internal support for up to 5 value
strings based on a key variable, and resource files are often a more convenient way to handle systems that
run in multiple languages.

After Ask Calls


In the Variables window, go to the Options tab. Click the
“Edit” button next to “After ASK call” and build a command.
The “After Ask” command is executed after the end user is
asked to provide the value for the variable. Normally this is
used to write out user’s input to a database either to log the
users interaction, or to save the “state” of a session so that
the user can exit and return to the system later. After Ask
commands are limited to commands that can write data
either to a database or other external program.

External Interfaces in Commands


In addition to the options for using external
interface commands with variables, they can also
be used as commands, either in a Command
Block or Logic Block. When building a command
in the Command Builder window, the “External”
tab provides various options for external
commands.

13: Interfacing to External Programs 269


External Sources for MetaBlock Data
When building MetaBlock systems, the MetaBlock
data file is normally a static tab delimited
spreadsheet file, however, such systems can
incorporate dynamic data by using an external
source for the MetaBlock data. This is done from
the MetaBlock window, which allows adding
database and XML sources for the data.

13.3 Types of External Data Commands


Exsys Corvid supports 5 types of external interface commands. All of the external data commands are built
from the External Data Sources window. This is displayed by clicking the “Edit” button next to any of the
options that can use external data sources.

! 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.

270 13: Interfacing to External Programs


For most options using external data, any of the command types can be used. However, system architecture
and delivery mode will determine what is best for a particular application. The commands “Param” and
“Applet” can only be used with the Corvid Applet Runtime. Some command types require additional server
programs or resources.

13.3.1 URL / External Program


URL commands can be used to read data from
any source that can be referenced by a URL, and
can also be used to call local programs.
The source of the data can be a simple text file
stored locally, or the URL of a server program
(Java Servlet, CGI program or any other dynamic
resource that can be accessed by a URL) that will
return data. The URL can include embedded
Corvid variables (using double square brackets)
allowing the URL to be set dynamically, and
allowing Corvid data to be passed to the
program. By default, the URL approach uses
GET to send small amounts of data, but POST
can also be used when larger amounts of data
need to be sent.
The URL approach is often a very quick, easy and
reliable way to get external data into a Corvid
session. External server programs can be created
to add special functionality to Corvid as needed.
For command details see Section 13.4.

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.

13: Interfacing to External Programs 271


13.3.3 Database
Database commands are some of the most flexible and
commonly used external data commands. Corvid can
interface with any JDBC compliant database to read
and write data.
Standard SQL commands can be used to select and
read data. The values of Corvid variables can be sent
to the database to be stored, or used in commands that
select items of data to return to Corvid.
Database commands can be used with both the Corvid
Servlet Runtime and the Corvid Applet Runtime,
however the Applet Runtime requires server support for
database commands in the form of a Java Servlet
provided with Corvid.
The Corvid database interface provides a convenient
way to integrate Corvid expert systems into corporate
databases and IT infrastructure.
For command details see section 13.6.

13.3.4 PARAM Data


The Corvid Applet Runtime provides a way to run Corvid
expert systems in a browser window. An HTML “Applet”
tag defines where and how the Corvid Runtime will be
displayed in the HTML page. This applet tag can also
contain “PARAM” data to set the value for Corvid variables.
The PARAM external interface makes it easy to access this
PARAM data from within the system.
PARAM data is most useful for systems that dynamically
build the HTML pages that contain the Corvid Runtime,
such as with Cold Fusion, but can be used anytime there is
data that should be sent to specific Corvid sessions or
which should be used to configure the sessions to reflect
changing situations.
The PARAM approach can only be used with the Corvid Applet Runtime.
For command details see section 13.7.

13.3.5 APPLET Data


A Corvid session running the Corvid Applet Runtime can
call other Java applets on the same page and send /
receive data.
This allows creating custom Java applets that work with
Corvid to perform special functions, display data or access
data via Java API commands.
The Corvid Trace applet uses this technique to display the
trace information from a session. The Corvid XML
interface for the Applet Runtime also uses an external
applet to add the functionality.

272 13: Interfacing to External Programs


Obtaining data from an external applet requires knowledge of Java to build the applet. Applets can be built
using Oracle Sun’s free NetBeans development tools or other Java development tools.
For command details see section 13.8.

13.4 URL / External Program Command Details


URL commands can be used to read data from any
source that can be referenced by a URL, and can also
be used to call local programs. Embedded Corvid
variables can be used to build the URL dynamically or to
pass data to the called program.
To add a URL external data source command, open the
External Data Sources window and click the URL tab.

13.4.1 URL Syntax


The URL / External Program tab is used to build
commands to:

! Read a static file of data.


! Call a web program (CGI, Servlet, ASP, etc)
that returns data.
! Pass data to a web resource.
Reading a static file of data is the simplest type of
external interface URL and is the basis for many other external interface techniques. In this case, the file is just
a simple text file containing the content to return. Generally, the text file is located in the same folder as the
system CVR file and can be referenced just by name.

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.

13: Interfacing to External Programs 273


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. Normally, the called URL will return data,
however some external interfaces such as After Ask do not expect anything to be returned and the URL may be
used to just send data.

GET and POST


When Corvid sends data to a program via a URL, it uses the GET approach. This sends the data on the
URL, but only allows a limited number of characters to be sent. The limit depends on both the browser and
server, but is generally 1000-2000 characters or more. For most uses, this limit is not an issue. However, if a
system needs to send a large amount of data to the server, check the “Send data with POST” check box.
POST allows any amount of data to be sent, but the receiving program must be designed to receive data
using POST.
Unless it is necessary to send a very large amount of data, and the receiving program is designed to work
with POST, it is best to use the default GET approach.

13.4.2 Format of Returned Data


To Corvid, the data returned is just text returned from calling a URL. It does not matter to Corvid if the data is
from a static file or dynamic content returned from a servlet, CGI program, ASP or other on-line resource. All
that matters is that the content is in the correct form.
The returned data MUST just be text. It should not have a header or that will be interpreted as part of the
data. Likewise, an HTML page should not be used because it will have various tags wrapped around the text
of the data.
To create static files of data, use a program such as Notepad that produces simple text files. Do not use a
word processor such as MS Word unless you make sure to save the file as “text”.
Most external interface calls expect to receive a returned data string that will be used for a single purpose,
such as the prompt text for a variable or the value to assign to a specific variable. Some calls expect to
receive back multiple items of data, but still for a single purpose - such as the list of possible value options for
a Dynamic List variable or multiple items to add to a Collection variable. In these cases, the format of the
data returned is just the content needed with no additional identifier information. This can be in the static file,
or returned from the program called by the URL.
External calls to set the value of a variable can set the value of a single variable or multiple variables in the
same call. The returned data can be either:
! A single value with no identifier, in which case it will be assigned to the variable associated with
the external call.
! One or more name / value pairs that identify a variable followed by the data to assign to that
variable. The variable identifier is the name of the variable in square brackets, followed by a
space and the value to assign to that variable. There can be multiple name / value pairs, one per
line. The returned data can set the value for any variables in the system, but should also always
set the value of the variable associated with the external call.
Example: an external URL call to set the value for numeric variable [X] could lust return
123

which would set the value of [X] to 123. Alternatively, it could return
[X] 123
which would also set [X] to 123.

274 13: Interfacing to External Programs


However, using the second form, it could return
[X] 123
Temp] 77
[Price] 99.99
which would set the values of [X], [Temp] and [Price] in a single call.
If [X] was associated with the external call, returning

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.

13.4.3 Types of Returned Data


The format of the data returned for a variable depends on the type of variable.

Static List Variables


! The number of the value. (First value = 1, second = 2, etc)
! The short text, or if there is no short text, the full text of the value
! More than one value number or short text separated by the TAB character
! A numeric expression that evaluates to the number of a value
Example: Static List variable [Color] with values “Red”, ‘Blue” and “Green”
Returning Sets
1 Red
[Color] 1 Red
[Color] Blue Blue
2 3 (separated by Tab) Blue, Green
[Color] Red Green (separated by Tab) Red, Green
[Color] 1+1 Blue

Dynamic List Variables


! The number of the value. (First value = 1, second = 2, etc)
! More than one value number separated by the TAB character
! A numeric expression that evaluates to the number of a value
Example: Dynamic List variable [Car] with values “Chevy”, “Ford” and “Honda”
Returning Sets
1 Chevy
[Car] 1 Chevy
2 3 (separated by Tab) Ford, Honda
[Color] 1+1 Ford

13: Interfacing to External Programs 275


Numeric Variables
! A numeric value.
! An expression that evaluates to a numeric value.
Example: Numeric variable [Price]
! Returning Sets
! 45.23 45.23
[Price] 99.95 99.95
[Price] 90 + 10 100
String Variables
! A string value without quotes
Example: Numeric variable [Name]
Returning Sets
abcde abcde
[Name] Exsys Exsys

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

276 13: Interfacing to External Programs


Collection Variables
! A string value without quotes.
! Multiple string values separated by the TAB character.
! If returning the value for the collection, multiple values on separate lines.
Items added to a Collection variable are always added to the end of the list. To add items to a
collection using the other methods such as ADDFIRST or sort, read the returned data into a string
variable and then add the value to the collection using a SET command with a method in the
Command file.
Example: Collection variable [Coll]
Returning Sets
aaa Adds “aaa” to the end of the list
[Coll] aaa bbb (separated by Tab) Adds “aaa” and “bbb” to the list

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.

13.5 XML Command Details


13.5.1 Intro to XML and XPath
To select item(s) of data in an XML file, Corvid uses standard XPath commands that are processed by the
Java’s built in command parser. This provides a very standard and powerful way to utilize XML data.
XPath commands are often compared to SQL commands for databases. It provides a way to identify specific
data in the XML file. An XPath command may return a single item of data or multiple items, depending on the
nature of the command and the XML data file. Like SQL, relatively simple commands to read simple data
structures are easy, but commands to select items out of complex data structures can be complex.
Since XPath is a standard command syntax by W3C, there are many on-line XPath tutorials that can be found
by Googling “XPath Tutorial”. There are also various technical books on XPath. These can assist you in
understanding advanced XPath syntax and building complex XPath commands when that is needed.
However, most Corvid uses of XPath will be relatively simple XPath commands reading from simple XML data
structures, and this introduction should get you started.

Simple XPath Commands


XPath commands provide a way to specify one or more items in an XML data file. XML data is organized by
nested “tags”, much like the tags in HTML, but far more flexible. XML is a complex subject, and there are
many books devoted to it. This is only a VERY simplistic look at how data can be stored in XML and how
XPath commands can read that data.
XML data is defined by elements that structure the data. An element is indicated by a tag, a name in < > such
as <myData>, <Name>, <Price>, etc, similar to the way HTML is structured. The data for the element is
everything between the tag and its closing tag, which is just the tag name in </ ...>. (Note the backslash / in
the closing tag). So, a price of 123.45 would be entered as:
<price> 123.45 </price>
Closing tags must match the immediately preceding unclosed tag.

13: Interfacing to External Programs 277


Elements can contain data or they can contain other elements. This ability to put elements in elements is
what allows data to be structured with XML. For example, there might be information on a part:
<part>
<part_ID>X351</part_ID>
<price> 3.45 </price>
<color> blue </color>
<color> green </color>
<size> 1 inch </size>
</part>
Here there is a “part” element with other elements describing part, ID, price, color(s) and size, each within
their own tag. Each closing tag matches the preceding unclosed tag. The </part> tag closes the opening
<part> tag since all the tags between them are already closed.
Note that there are 2 <color> elements. There can be multiple occurrences of some elements. This allows
the <part> element to include multiple color options for the part. XML files have an associated “schema” that
defines what elements can occur where, when there can be multiple occurrences of an element, nesting, etc.
This simple introduction does not cover schema, but this important part of XML is well covered in XML books.
Programs for building and managing XML files check the XML data against the schema to make sure it is
correctly structured. Corvid does not check a file against its schema and it is the developer’s responsibility to
make sure that the XML data files provided are structurally correct.
In addition to the nested elements, individual elements can have attributes to provide other information and
ways to select data. For example, to add data on the part material, we could either add a tag for it:
<part>
<part_ID>X351</part_ID>
<price> 3.45 </price>
<color> blue </color>
<color> green </color>
<size> 1 inch </size>
<material> plastic </material>
</part>
or add an attribute inside a the part tag.

<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.

278 13: Interfacing to External Programs


A full list of parts would be made up of data on many individual parts each in its own <part> tag with its
associated elements:
<part_list>
<part>
....
</part>
<part>
....
</part>
<part>
....
</part>
</part_list>

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>

13: Interfacing to External Programs 279


The command /part_list/part/price would return a list of the prices for all the parts. To get the price of a
single part would require specifying an individual part. XPath provides many ways to do this. When there are
multiple items, specific one(s) can be selected by putting a selection test in [ ]. The simplest selection test is
just the number of the element when there are multiple occurrences of the element:
For example:
/part_list/part[1]/price
would return the price value for the first part in part_list. The XPath command /partList/part[2]/price
would return the price value for the second part.
The selection test can also be a boolean expression on the associated values.
/part_list/part[part_ID=”X351”]/price
would return the price of the part with the part_ID of “X351”, regardless of where it was in the list.
Commands can also return multiple values:
/part_list/part[color=”blue”]/part_ID
would return a list of the part_IDs for all parts that are available in blue.
/part_list/part[price > 3.00]/part_ID
would return a list of the part_IDs for all parts that cost more than $3.
There is MUCH more to XPath commands, but even this simple syntax allows many XML files to be parsed
and used with Corvid systems.

13.5.2 Building XML Commands


Corvid can read data from XML files or data sources. An XPath
command is used to select the data used by Corvid. To add a XML
external data source command, open the External Data Sources
window and click the XML tab.

Corvid XML commands are made up of 3 parts:

! The name of the XML file / URL to use (in quotes).


! The XPath command to select one or more values.
! Modifiers for the returned data, making it easier to use it with
Corvid.

XML(“Filename” XPath_command Modifiers)

11.5.3 XML Filename


The filename for the XML file can be local to the Corvid system CVR file or a URL referencing a file or
program somewhere on a network or the web that returns XML data.
The XML filename is optional, however if it is not specified, the file KBName.xml will be used (where KBName
is the name of the system CVD/CVR file) and the file must be in the same folder as the system CVR file. The
file name must be in quotes.
The filename can be either:

! A static file of XML data.


! A URL to a web program (CGI, Servlet, ASP, etc) that returns XML data.

280 13: Interfacing to External Programs


Reading XML data from a static file is the simplest type of XML file reference. In this case the file is just a file
containing the data in an XML form. If the XML file is located in the same folder as the system CVR file, it can
be referenced just by name.
For example: If there is a data file MyXMLData.xml that the system needs, it can be put in the
same folder as the CVR file. In the system, the “XML Filename” is just MyXMLData.xml.
All filenames are actually URLs. If the file is relative to the system CVR file, Corvid automatically builds the
full URL for it. Filenames that do NOT start with “http” are automatically taken as relative to the folder that the
system CVR file is in. XML files can also be in a subfolder by including the subfolder name, such as
DataFiles/MyXMLData.xml.
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 XML files 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 move them between servers or to run standalone. Full URL
addresses starting with “http://” are used for servlet, CGI and other server resources that will return XML data.
To pass the value of Corvid variables in the URL, include them in double square brackets, such as:
http://www.myServer.com/PartListXMLData?Model=[[Selected_Model]]

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.

13: Interfacing to External Programs 281


13.5.4 XPath Command
The XPath command can be anything from a simple command to return one item of data to a complex
command returning many items. The nature of how the external interface command is used determines how
Corvid will handle the returned data, and if Corvid expects one or multiple items of data. An individual
command can only return data for one purpose. Unlike some external commands, a single XML command
cannot set the value for multiple variables.
The XPath command can include the values of any Corvid variables by simply putting them in the command
in double square brackets - [[...]]. Corvid will replace the [[...]] with the value of the variable before evaluating
the XPath command.
For example, to add a command to find all the parts over a price stored in a Corvid variable [Min_Price]:
/part_list/part[price > [[Min_price]] ]/part_ID
NOTE: when using double square bracket embedded variables within XPath syntax that also uses
square brackets, be sure to put a space between the Corvid [[..]] and any XPath [ or ] characters.
Having 3 brackets together can result in ambiguous expression. As long as the Corvid variable [[..]]
has spaces around it, it will work correctly. So the above XPath command would be OK, but
/part_list/part[price > [[Min_price]]]/part_ID
would not since it has 3 bracket characters together without any spaces. The Corvid embedded
variables will be replaced by their value before the command is parsed as an XPath command, so the
Corvid brackets will not confuse the XPath parser.
When using Boolean tests to select items of data, spaces in the XML data can be an issue.
Sample XML data:
<part_list>
<part>
<part_ID>A111</part_ID>
<price> 3.45 </price>
<color> blue </color>
<material> plastic </material>
</part>
<part>
...
</part>
<part>
...
</part>
</part_list>
If the boolean test is numeric, spaces do not matter and

part_list/part[price > 5]/part_ID


will work correctly to select the part_IDs for the part where the price is greater than 5. It does not matter if the
data in the <price> tag has spaces around it.
However, for boolean expressions using string matching such as:
part_list/part[part_ID >"A111"]/price

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:

282 13: Interfacing to External Programs


part_list/part[part_ID >”A111”]/price
or
part_list/part[part_ID >'A111']/price
would be legal syntax. If using " causes a parsing problem in some situations, try using ' instead.
The XPath command is any legal XPath command that can be evaluated by the Java XPath parser. This
supports quite complex XPath syntax when needed.

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.

13.5.5 XPath Modifiers


Corvid’s special modifiers make it easier to use data returned from XPath commands in Corvid. These are
much easier to use than building a complex XPath command to return the same data.
Modifier: Corvid supports 3 modifiers that can be applied to the returned data:
! UNIQUE
! COUNT
! SEP=” “
UNIQUE
UNIQUE will parse the returned data and remove redundant values. This is used when the XPath command
may have multiple occurrences of the same value, and what the Corvid system needs is the unique values.
For example, you might want to get a list of the materials used for the parts in the list:
/part_list/part/material
would return the list of materials, but it would include “plastic” once for each part made of plastic, potentially
many times. This would also apply to each other material. Adding the modifier:
/part_list/part/material UNIQUE
causes Corvid to reduce the list to only include unique materials before returning the data. This could be used
to set the value options for a Dynamic List variable, allowing the end user to choose from the materials
actually in the parts list without redundancy.

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.

13: Interfacing to External Programs 283


COUNT can be used with UNIQUE to provide a count of the unique values:
/part_list/part/material UNIQUE COUNT
would return a count of the number of materials used for all the 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:

plastic & aluminum & steel

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.

284 13: Interfacing to External Programs


13.5.6 XML Command Samples
This is a small sample XML file and some sample XPath commands:
XML File:
<part_list>
<part>
<part_ID>A111</part_ID>
<price> 3.45 </price>
<color> blue </color>
<color> green </color>
<size> 1 inch </size>
<material> plastic </material>
</part>

<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>

Sample XPath Commands:


Selecting a part name by its numerical place in the list.
/part_list/part[1]/part_ID

Returns the Part_ID of the first part: A111

Selecting a part price by its part_ID.


/part_list/part[part_ID=”C333”]/price

Returns the price of the part with a Part_ID of “C333”: 9.55

13: Interfacing to External Programs 285


Getting a list of the part_ID of all the parts in the list.
/part_list/part/part_ID

Returns a list of all the Part_IDs:

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: A111 & B222 & C333 & D444

Getting a list of the materials used for parts in the list.


/part_list/part/material

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

Getting a count of the number of materials used in the list.


/part_list/part/material UNIQUE COUNT

Returns: 3

Getting a count of the number of parts in the list.


/part_list/part/part_ID COUNT

Returns: 4

286 13: Interfacing to External Programs


13.5.7 Embedded XML Commands
In addition to using XML commands associated with specific variable actions such as setting the value of a
variable, XML commands can be embedded in any text in a Corvid system. This can be done any place a
double square bracket replacement could be used.
The syntax for embedded XML commands is the same as XML commands to get other data, but the
command is surrounded by <#<...>#>.
<#<XML “Filename” XPath_cmd Modifiers>#>
The filename is optional, but if not included the KBName.xml will be used, where “KBName” is the name of
the system. In this case, the XML file must be in the same folder as the system CVR file. Filenames NOT
starting with “http://” will be considered to be an address relative to the folder with the CVR. Names starting
with “http://” will be full addresses to files anywhere on the web. If a file name is used, it must be in quotes.
The XPath command can be any XPath command that could be used to get data.
The optional Modifiers UNIQUE, COUNT and SEP=”..” can be used.
Embedded XML commands can be used in any text in a Corvid system such as Prompts, content in reports,
explanations to the end user, etc.
For example, a report might include a comment that:
The current part inventory includes parts made of X different materials
This could be added to a report by using the embedded XML command in the text to add the count of the
materials currently used:
The current part inventory includes parts made of
<#<XML “partInventory.xml” /part_list/part/material UNIQUE COUNT >#>
different materials

13.5.8 Using an XML File for MetaBlock Data


XML data can also be used to provide the data for
Corvid systems that use MetaBlocks. This allows
an XML file to be used in place of a tab-delimited
spreadsheet. The XML “file” used can be either a
static file or a URL that returns XML data. If an
external source or program is used, it must return
the same XML data each time it is called during the
session.
Selecting to use XML data is done from the
MetaBlock properties window. (This is displayed by
clicking the “MetaBlock” button on a Logic Block
window).

Click the “XML Interface” button to use an XML file.


(This will build a MetaBlock source file for the XML
Interface. If an XML interface file has already been
created, just click the “Edit” button to make any changes to it.

13: Interfacing to External Programs 287


13.5.9 Obtaining MetaBlock Data Using XPath Commands
To use an XML file for the the MetaBlock data, an XML MetaBlock Interface file must be created. This file will
tell the Corvid runtime the XML file to use and the XPath commands to use for each of the “columns” in the
MetaBlock spreadsheet. This can be a little complicated to visualize at first.
When a MetaBlock is based on an actual tab-delimited spreadsheet, there are actual rows and columns of
data. The columns have heading text that is used in the MetaBlock rules to reference the data in that column.
The rows are actual rows of data. When using an XML file for the data, commands build individual columns
of data. The columns are given names so that they can be referenced in the rules, and an XPath command
defines the data that goes in that column. Rows do not actually exist as such, but are actually a combination
of the nth item of data returned by each of the XPath commands for each column. Because of this, the XPath
commands each must return multiple values and they must be synchronized and consistent so that the nth
item of each column applies to the same product.
This is easier to see with an example. Using a small XML file:

<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.

288 13: Interfacing to External Programs


The second column is given the name “price” and the data comes from the XPath command:
/part_list/part/price

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.

The XML Interface to build the MetaBlock data is:


Column Name XPath Command for the Column Data
part_ID /part_list/part/part_ID
price /part_list/part/price
color /part_list/part/color
material /part_list/part/material

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.

13.5.10 Using XML Files for MetaBlock Data


The MetaBlock XML Interface specification
is kept in a text file. This file specifies the
XML file to use and the XPath command for
each column in the spreadsheet. This file is
built and edited from the MetaBlock XML
Interface window that is displayed by
clicking the “XML Interface” button on the
MetaBlock window.

The XML interface specification is kept in a


text file. This file specifies the XML file to
use and the command for each column in
the spreadsheet. Enter/browse the name of
the XML data file. Then enter MB column
names in the left column and associated
XPath commands in the right column.

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.

13: Interfacing to External Programs 289


XML Data File
Select the XML data file that will be used. Either enter the name of the file as a URL or browse to the file.
Any XML file or URL reference that could be used in other XML commands can be used. Clicking “Edit” will
open the XML file using the XML Editor program specified in “Properties” to view or edit 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 > [[Min_price]] ]/part_ID


However, these MUST be used consistently in all commands to make sure the data returned is consistent,
and the “price” data would have to be:
/part_list/part[price > [[Min_price]] ]/price
If the “price” data was instead something like:

/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.

Multiple Occurrences of an Element


All XPath commands should return single data items for each “record” or higher level XML element. If the
element has multiple instances of an internal element, it will return multiple values. For example, in the earlier
sample XML data, there were multiple occurrences of the “Color” element. This is legal XML provided it is
allowed by the schema for the file, but it will confuse the MetaBlock interface.
If there are multiple elements for some “parts”, it will throw the sync of the returned data. If the data is
structured this way, and it needs to be used in the system, build the MetaBlock using only the elements that
will return a SINGLE value for each “part”. Then in the actual Logic Block rules use embedded XML data
embedding (using <#<XML...>#>) to get the other data that can return multiple values using some unique

290 13: Interfacing to External Programs


reference to the record. The <#<XML will return the values as a single string that can be used in expressions
or to build reports.
For example, in the MetaBlock specification use:
/part_list/part/part_ID
to get the “part_ID” column data which is a single unique reference to each “part”. This column data is used
in the associated Logic Block by the column name in { }

{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.

Use Single XPath Command


A quick way to build consistent commands for simple XML files is with the “Use Single XPath Command”
option. This can only be used if the names of the columns exactly match the XML element names, including
upper/lower case letters.
Enter a XPath command up to the final element name in the “Use Single XPath Command” edit box and click
the “Update” button. Corvid will replace the XPath command for each column with the text entered, followed
by the column name.
In the example, enter:

/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.

13: Interfacing to External Programs 291


Save
When the XML MetaBlock specifications are input, click the “Save” button to return to the MetaBlock window.
The columns entered will be displayed in that window and can be used in building the Logic Block.

13.5.11 Using XML Commands with the Applet Runtime


The Corvid Servlet Runtime has the XML command functionality built into it. However, the Corvid Applet
Runtime does not. Instead the Applet Runtime uses a special “helper applet” program to process the XML
commands. This reduces the overhead both in size and Java requirements for the Corvid Applet Runtime.
In most cases, the special steps Corvid takes to process XML commands in the Applet Runtime are
transparent to the developer and users of the system. However, in some cases developers must make
special modifications to their HTML pages and the files distributed with their system.
When a system using XML commands is run with the Applet Runtime, Corvid must add a special XML
Interface applet to the HTML page used to run the system. The code for this applet is:
<APPLET
CODEBASE = "./"
CODE = "EXSYS_XML_Interface.xml_lookup.class"
NAME = "EXSYS_XML_Interface"
ARCHIVE = "EXSYS_XML_Interface.jar"
WIDTH = 0
HEIGHT = 0
HSPACE = 0
VSPACE = 0
ALIGN = middle
>
</APPLET>
This can be put anywhere on the HTML page, but just before the Corvid Runtime Applet tag is suggested.
The EXSYS_XML_Interface.jar file must also be included in the folder of files for the system, along with the
ExsysCorvid.jar, system CVR file and any other associated files.
When Corvid builds the default system
HTML file to run the system during
development, it checks to see if XML
commands are used. If they are, Corvid
automatically adds the XML Interface
applet tag and copies
EXSYS_XML_Interface.jar to the correct
folder.
For most systems, no special additional
actions are needed to use XML
commands with the applet runtime.
However, while Corvid checks the places
where XML commands would typically be
used, it does not check for embedded
XML commands in strings or external
files. If XML commands are used in such
places and Corvid does not automatically
include the XML Interface Applet, go to
the “Properties” window “Test Run” tab.
Check the “Add Exsys XML Interface Applet” check box. With this checked, Corvid will always add the XML
applet.

292 13: Interfacing to External Programs


If a custom HTML page is created to field the system, the XML Interface Applet tag must be added to that
window.

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.

13.6 Database Command Details


13.6.1 How the Corvid Database Interface Works
The Corvid Database Interface is a little more complicated than the other external interfaces due to Java and
security issues that have to be addressed in allowing the Corvid Applet to communicate with a server
database. While these issues really only apply to the Corvid Applet Runtime, to make systems more portable
between the Corvid Applet Runtime and Corvid Servlet Runtime, the same basic approach is used in both
delivery modes.

Servlet Support Requirement


The Corvid Applet Runtime cannot directly access a database on a server or execute SQL commands. The
actual execution of the database commands is done by a special Corvid Database Interface servlet running
on the server. This Java servlet program is provided with Exsys Corvid, but does require a server that
supports Java Servlets via Tomcat, Glassfish, Websphere or other “Servlet Container”. Without this server-
side program, the Corvid Applet Runtime cannot use database commands.
Note – Another factor to consider: Since a Java Servlet and a “servlet container” such
as Tomcat are required for systems using database commands from the Applet Runtime,
it may make more sense to just use the Corvid Servlet Runtime for systems using
database commands. The Corvid Servlet Runtime provides the higher levels of security
for systems that use database commands and provides many more user interface and
delivery options.
Database Command File
The Corvid Applet Runtime calls the server-side Corvid Database Interface program to execute SQL
commands. If the Corvid Database Interface program simply accepted SQL commands sent to it and
executed them, this would open serious security vulnerability since anyone knowing the correct URL could
execute any SQL command on a database. To prevent this, the Corvid Database Interface only will execute
specific SQL commands stored in a file on the server. These commands should be limited to only what the
system needs. The Corvid Database Interface is passed the identifier for a command in the file along with
any parameters that command needs. The Corvid Database Interface looks up the SQL command in the
command file associated with the identifier, checks that the parameters passed match correctly and executes
the SQL command.

13: Interfacing to External Programs 293


1. The Corvid Applet Runtime running on the end user’s computer sends a Corvid Database command
identifier and parameters to the Corvid Database Interface Servlet running on the server. This is only
the identifier for a SQL command and not the command itself.
2. The Corvid Database Interface program looks the identifier up in the SQL Command File to find the
associated SQL command
3. The actual SQL command and any restrictions on parameters is returned to the Corvid Database
Interface program. Any parameters passed from the Corvid Applet Runtime are validated against the
parameter restrictions.
4. The parameters passed are combined with the SQL Command to produce a full SQL command that
can be executed against the database. In some cases, this may add data to the database, but often
it obtains data from the database.
5. The data is returned to the Corvid Runtime Applet.

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.

294 13: Interfacing to External Programs


13.6.2 Server Files Required for the Database Interface
Various files are needed depending on your server, database and which Corvid Runtime is being used
(Servlet or Applet).
1. There must be some database software installed on the server. It can be any brand that supports
JDBC connections, such as MySQL, Access, Oracle, SQL Server and almost all other standard
databases.
2. There must be a database file that you will be using with your Corvid system.
3. The server needs to support Java Servlets. This requires a “Servlet Container” such as Tomcat,
Glassfish or IBM Websphere. Java servlets are required for the database interface even if the rest of
your system is being run with the Corvid Applet Runtime.
4. If the system is being run with the Corvid Applet Runtime, the servlet interface CorvidDB must be
installed. This is done by having the Servlet Container deploy the file CorvidDB.war. In the case of
Tomcat, this is done by putting CorvidDB.war in the Tomcat webapps folder. (If unsure how to deploy
java servlets on your system, contact your system administrator.) NOTE: If your system is being
run with the Corvid Servlet Runtime, CorvidDB.war is NOT needed and SHOULD NOT BE
INSTALLED on the server.
5. Your KB system files (.CVR) and any associated files. If you are running with the Corvid Applet
Runtime, the KB system files MUST be on the same server as you have running the CorvidDB
servlet. (Java security prevents you from having the Corvid KB system files on one server, but calling
the CorvidDB servlet on another server.) The system files should be in a subfolder off “root” or other
folder that can serve normal HTML web pages. The standard location of “root” on some popular
servers are:
IIS \inetpub\wwwroot
Apache wwwroot
Tomcat webapps/ROOT

13.6.3 Building Corvid Database Commands


Because of the SQL Command file approach
Corvid uses, building Corvid database commands
has 2 steps:
1. Defining the SQL command with its
identifier, parameters and restrictions. This
goes in the Corvid SQL Command File that
will be put on the server.
2. Building the command used in the actual
Corvid system that refers to the command
by its identifier and sets the parameters
using the values of Corvid variables.
In addition, the overall database interface
properties such as JDBC driver, database identifier
and sometimes passwords need to be setup.
These operations are done from the External
Interfaces window on the “Database” tab. The
“Database” tab has 3 additional tabs on the right
side. First “Command File” is to define the name of the SQL Command File that will hold the commands and
be put on the server, along with the Driver, identifier and password information when that is needed.

13: Interfacing to External Programs 295


The second tab, “Commands” displays the
commands that have been added along
with the Corvid variables that will be used to
fill in the parameters for the command. This
displays the commands in a readable form,
though they will actually be broken into 2
portions one in the Corvid system and one
in the SQL Command file on the server.

The 3rd tab is for special options that can be


added to some commands.

296 13: Interfacing to External Programs


New commands are added on the
Command tab by clicking the “Build New
Command” button. This opens the
command builder window:

This makes it easy to build SQL commands


that have replaceable parameters based on
Corvid variables.

13: Interfacing to External Programs 297


13.6.4 The Database “Command File” Tab
The database “Command File” tab is used to set
the name of the SQL Command file and connection
information, that will be used by all of the database
commands for the system.
The information on the Command File tab is
required whenever adding database commands to
a system.

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.

For MySQL, the standard driver is: org.gjt.mm.mysql.Driver


For SQL Server: com.microsoft.sqlserver.jdbc.SQLServerDriver

Check with your system administrator if in doubt.

298 13: Interfacing to External Programs


You also need to have the driver installed. On a server, the system administrator will probably already have
this installed. If you are running MySQL locally on your PC, you may need to install the mysql-connector-
java-5.1.37-bin.jar file that comes with MySQL. (The number part will vary) This can be put in your Tomcat/lib
folder.

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.

This will be something similar to:

Jdbc: sqlserver://ServerName;databaseName= MyDatabase


or
jdbc:mysql//localhost:3306/MyDatabase

In MS Windows, this may be a DSN

Check with your system administrator if in doubt.

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]]

13: Interfacing to External Programs 299


13.6.5 The Database “Commands” Tab
The "Commands" tab displays the SQL
commands in the command file. These are
the only commands your system will be
able to execute.
Commands are made up of standard SQL
along with Corvid variables. For a
particular database call, one of the
commands is selected. Adding database
calls to a system is a combination of
defining a command that can be used, and
then associating it with a particular
database action such as getting the value
of a variable.
The SQL command to execute can be any
SQL command starting with SELECT,
UPDATE, INSERT, DELETE, ALTER,
CREATE, DROP. In addition, some
databases and drivers may allow other
SQL commands.

First, a command must be added. This is done by


clicking the “Build New Command” button, which
displays the Database Command Builder.
As described at the start of the database interface
section, in order to provide a greater level of security
when using the database interface from the Corvid
Applet Runtime, the actual SQL commands are stored
in a file on the server. These commands are a
combination of standard SQL and replaceable
parameters. The Corvid Applet Runtime only sends the
name of the command to execute and the parameter
values. It is only possible to execute the specific
commands in the server database command file. This
allows the database to be accessed by the client-side
applet, while limiting the potential for other
unauthorized users to execute other commands. (For greater security, it is recommended that systems
needing the database interface use the Corvid Servlet Runtime rather than the Corvid Applet Runtime.)

300 13: Interfacing to External Programs


Building a database command calls for entering a
combination of SQL and parameters that will get their
value from Corvid variables. The Database
Command Builder makes this easy. The process is
best illustrated by an example of building a command
to get the price of a part from the database.
3. Create a new database command file and DSN as
described above. Here the command file is
PartDBInterface.cdb. The DSN is
“PartsDataConnection”.

2. Go to the “Commands” tab on the right side. To


add a command, click the “Build New Command”
button at the lower left.

3. This opens the window for building commands.


First enter an identifier. This can be any text,
but should be simple and easy to recognize.
For example, "GetPartPrice."

13: Interfacing to External Programs 301


4. In the "SQL Command" edit box start entering
the SQL command. This can be any SQL
command starting with SELECT, UPDATE,
INSERT, DELETE, ALTER, CREATE, DROP.
(In addition some databases and drivers
may allow other SQL commands.)
Here we want the command:

SELECT Price FROM PartData WHERE


Part='partID'
“partID” will be the name of the part and will come
from a Corvid variable.

Enter the portion of the SQL command up to where


the Corvid variable value would be added. Here
this will be:

SELECT Price FROM PartData WHERE Part='


5. Now add a replaceable parameter in the SQL
command and associate a Corvid variable with
it. The replaceable parameters in the SQL are
denoted by curly brackets { }. The brackets
contain a letter and a number. The letter
indicates the type checking and restrictions that
should be applied to the parameter value, and
the number is the number of the parameter in
the command (e.g. the first parameter is “1”, the
second is “2”, etc). These numbers match the
list of variables that Corvid will provide in
making the call.

To add the replaceable parameter, go to the


“Add Variables to SQL Command” section and
click the “Variable or String” drop down list.
This will display a list of the Corvid variables in
the system. Select the variable to use. Here this is the string variable [PartID].
(NOTE: Instead of selecting a variable, a string can be typed into the edit box. This is used with
commands that can be called in different ways and it is easier to just have a parameter be a string. This is
illustrated in more detail in the next example.)

302 13: Interfacing to External Programs


6. Now select the Validation Type for the
parameter value. Validation types allow you to
restrict the type of value that the command will
accept. When using the Corvid Applet Runtime
this is one more layer of protection against
inappropriate use of the command. When
using the Corvid Servlet Runtime, strongly
limiting the value is less important unless there
are ways for the end user to directly type in
values that will be passed to the command.
However, setting the Validation Type is always
a good idea. To set the Validation Type, click
the drop down list.

The Validation Types are:

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 ' _').

X No validation. String just passed through.

Some of the letters do not do type checking but instead do some form of conversion:

T Convert EQ,NE,LT,LE,GT,GE to =,<>,<,<=,>,>= respectively.

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.

7. Once the Validation Type is selected, click the


“Add to Command” button.

13: Interfacing to External Programs 303


The replaceable parameter {S1} will be added to the
SQL command and the lower list box will show that
{S1} corresponds to [PartID]. In the {S1} the “S”
indicates the validation type is String and the “1”
indicates this is the first replaceable parameter in the
SQL command.

If the SQL command required additional replaceable


parameters, you would continue entering the SQL
command up to the next command and then add that
Corvid variable the same way.

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.

This often makes it easier to check the command


and make sure the correct Corvid variables are
being used.

304 13: Interfacing to External Programs


Now that the new command is built, click the “OK”
button to return to the Command tab.
The command list now shows the command just
added and it is selected in the command list.

! The “Full Command” shows the command


with the replaceable parameters.

! The “Variables” list shows the variables


associated with the command in order.
! The “Command with Variables Embedded”
shows the command with the variables in
the command.
These are to make it easier to find and use
commands. They cannot be directly edited in this
window. To edit a command, select it and click
“Edit” to reopen the command builder window.

The command at the top of the screen is the actual


command that will be added to the Corvid system.
This is a CORVID_DB command. The “FILE=” is the name of the Database Command File on the server.
The “ID=” is the name of the SQL command to use from the command file. The “1=” is the value for first the
replaceable parameter and here that value comes from the variable [PartID]. If there were more replaceable
parameters, there would be a “2=”, “3=”, etc. with associated variables.

Clicking “OK” returns the external data interface command to wherever the interface command was built from:

As many database commands as needed may be


added to the system in the same way. When done,
be sure to move the command file (here,
“PartDBInterface.cdb”) to the server. (For the
Corvid Applet Runtime, put the Command File in
the CorvidDB folder created when the
CorvidDB.war servlet deploys. For the Corvid
Servlet Runtime, put it in the same folder as the
system CVR file.)

13: Interfacing to External Programs 305


13.6.6 Complex Commands with Replaceable Field Names
This example shows how to add a more complex command. Suppose the system needs to look up
information on a customer's address, but to help make sure it is the actual customer the system will check
both their name and one other item of information that the customer can select. This second item can be their
customer ID, home zip code or last order number. Also, the information on the customer’s address is stored
in different fields in the database and these should be read individually. This requires building a SQL
command that has replaceable parameters for:
! The field to read.
! The customer’s name.
! The second field to check.
! The value for the second field.
By building the command with replaceable parameters, this can be used in multiple ways.
The full SQL command will be:
SELECT {F1} FROM customerData WHERE CUSNAME='{S2}' AND {F3}='{S4}'
Remember that the replacement parameters are numbered. The numbers correspond to the parameters
passed on the URL line. The letters indicate the type of data. In this case the validations are “F” which checks
that the value is a valid field name for the database, and “S” which allows an alphanumeric string.
{F1} The field to return data from. This will be a string based on how the command is used.
{S2} The name of the customer. This will come from the String variable [Name]
{F3} The name of the second field to check. This will come from a Static List variable [ID_Type]
{S4} The value that the second field must match. This will come from the string variable [ID_data]

The first use of this command will be to get the


"Address" field, though the same command can then
be used later to get other fields from the database.
To build the command, go to the External Interface
window, Database tab and click “Build New Command”
Enter the portion of the SQL command up to the first
replaceable parameter – "SELECT".

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.

306 13: Interfacing to External Programs


This time the replaceable parameter does come from
a Corvid variable, so select the variable, [Name], from
the drop down list and the “S” type for a string value.
Add this to the command and continue out to the next
replaceable parameter.

This time the replaceable parameter is again a field


name, but it is limited to specific options in the Static
List variable [ID_Type]. Select that variable and the
“F” validation type for a field. This can continue to the
final 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.

13: Interfacing to External Programs 307


Click OK to add the CORVID_DB command as the
external interface command to get the value for the
variable [Address].

Notice that the actual command in the system is:

CORVID_DB FILE=customerData.cdb&ID=GetField&1=Address&2=[Name]&3=[ID_Type]&4=[ID_Data]

The command in the SQL Command File can be used


to get the value of any field in the database just by
making a small change in the command. If there is a
variable [City] that should be set by the “City” field in
the database, just copy the command, but change
“Address” to “City”

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.

Important Security Considerations:


If database field names are made into replaceable parameters, and the Corvid Applet Runtime is used, users
can potentially read any field in the database. Remember, the URL to the database interface servlet can be
typed by hand into a browser, therefore you cannot control what the parameters will be. If replaceable field
names are used, it is possible for users to access any field in the database. If this causes security concerns,
the field names should be "hard coded" into specific individual commands in the SQL Command Table and
called by name rather than using “generic” commands.
You should limit the allowed SQL commands to allow ONLY as much as you are willing to expose to outside users.
If the database contains sensitive information, the Corvid Servlet Runtime should be used. Even with the
Corvid Servlet Runtime, the replaceable field names should be set by logic in the system, such as specific
values from a Static List, rather than using a string value that the user types in.

308 13: Interfacing to External Programs


13.6.7 “Options” Tab
Each command can have a variety of options.
To set these options click on the Options tab.

Options apply to the individual use of the


command, so a single command can be used
multiple times with different options.

The command that the options apply to is


displayed at the top of the window. To select a
different command, click the “Commands” tab,
select a command and return to the “Options” tab.

A command can have multiple options.

Limit Number of Items Returned: NR=#


Sets the number of items of data being returned from a SELECT command. The default is to return all data
from the command, but in some cases it may be useful to limit this to only a particular number. If there is no
NR= command, the default is to return all data items. If NR= is used, the value must be greater than 0. This
command should only be used with a SELECT command.
Prefix String: PF=
This is a string that will be added before each row/record's data. It is a way to format data and add text as
needed before the returned value. The string will be part of a URL and should be URL encoded. For example,
a returned item of data added to a HTML report might need to have an HTML tag wrapped around it. Usually
there are other ways to handle this when the variable value is added, but this approach can be convenient.
Suffix String: SF=
This is a string that will be added after each row/record's data. Like the Prefix String, this is a way to format
data and is often used in conjunction with a prefix string. The string specified should be URL encoded.
Error Prefix String: E=
Normally if the SQL command produces an error, the returned error message will start with "Error: " but this
option allows you to specify an additional prefix for the error string so your system can detect and handle the
error in a more customized way. Remember this is a prefix, so you will still get the full text of the error
message. For situations where having the database call fail is likely, and not an error (e.g. not all fields in the
database are populated), use the O=Z option to return no data and no error. This will cause Corvid to instead
ask the value of the variable from the user.
Spreadsheet Header Line: SS=
In some cases, it is desirable to return data from the database in the form of a tab-delimited spreadsheet.
This is particularly useful for MetaBlocks that use real-time data from a spreadsheet. A MetaBlock requires a
tab-delimited spreadsheet with the first line having only column header information. These column headers
are referenced in the MetaBlock logic. A SELECT command can return a number data in tab-delimited form,
arranged by field and one record per row. The SS= command provides a convenient way to add a header to
this data. Using databases with MetaBlocks is described in section 13.6.11.
Variables to Receive Data: V=
Allows database calls to set the value for multiple Corvid variables. When a SELECT command returns the
values from multiple fields, these can be assigned to multiple Corvid variables. This option should only be
used with database commands to set the actual value of a variable, and not with other database calls such as
those used to set prompt text, or commands not using SELECT.

13: Interfacing to External Programs 309


If the SELECT command returns multiple values and this option is NOT used, the values will all be assigned
to the same variable associated with the command. The only type of variable that is usually assigned values
this way is a Collection variable.
The Corvid variables that will be assigned values are displayed in the list in the “List of variables to receive data”
section. The order of the variables must be the same as the order of the fields specified in the SELECT command.
To add a variable to the list, select the Corvid variables from the lower drop down list. Click the “Add Below”
button to add the new variable below the variable currently selected in the list. Click the “Add Above” button
to add the new variable above the variable currently selected in the list. If there is nothing in the list, either
button can be clicked to add the first item. To delete a variable in the list, select it and click “Delete”.
Make sure the variables in the list are in the same order as the data items that will be returned. Also make
sure that the returned data is correct for the variable’s type.
In the command that will be built, the individual Corvid variables will be separated by a "-" and NOT
include [ ].
For example,

SELECT Address, City, State FROM …. WHERE ...

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.

310 13: Interfacing to External Programs


13.6.8 Commands that Change the Database
SQL commands like SELECT return the selected value to Corvid. However, some SQL commands such as
INSERT, UPDATE, and DELETE make changes to the database itself. These commands will return the string
“Success” if the operation could be completed or an error message if it failed.
Usually, commands that change the database are used either in the Command Block or as an After Ask
command. It is not required to catch and check the return string, but it is generally a good idea and makes
debugging database interfaces much easier.
To check the return string, associate the SQL command with a string variable. This can be done by either:
! Having the command set the value for the string variable, and then using a DERIVE command to
force the system to get the value.

! 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.

13.6.9 Editing Commands


To edit an existing command, go to the External Interface
window Database tab. Select the command and click “Edit”.

The same window will open that was used to build the
command.

The text of the command can be directly edited in the edit


box. Additional replaceable parameters can be added by
positioning the cursor in the text, selecting a variable or sting
and validation type, and clicking “Add to Command”.
Exiting replaceable parameters can be changed by:
1. Select the parameter to change in the “Variables
Used in Command” list.
2. Select the new variable/string and validation type in
“Add Variables to SQL Command”.
3. Click “Replace in Variable List”.
This will change the selected parameter to the new one.
After editing there can be unused variables left in the “Variables Used in Command” list. To delete unneeded
ones, select them and click “Delete”.
Adding new parameters in the middle of the command can make the numbering of the replaceable
parameters not be in numeric order. It is not required that the numbering of the replaceable parameters be in
numeric order as long as the variables/strings in the CORVID_DB command match correctly. However, it is
easier to read the command if it is in numeric order, and clicking the “Fix Numbering” button will make any
changes needed to put it in numeric order.

13: Interfacing to External Programs 311


13.6.10 Batch Command Option
A single database command can perform several SQL commands by starting a list of commands with the
word BATCH, and separating the commands with a semicolon.
1. When building the SQL command, type the word "BATCH" in front of the list of SQL commands.
2. Type 2 or more SQL commands into the SQL command edit box. Separate each command
with a semicolon ";" character. The last entry does not need to end with a semicolon ";",
however a final semicolon will be ignored if present.
(e.g: BATCH UPDATE ...; INSERT ...; UPDATE ...; INSERT ...; DELETE ...)
Replaceable parameters can be added anywhere in any of the individual commands.
The only SQL commands allowed in the BATCH list are INSERT, UPDATE, and DELETE. However, some
databases and drivers also allow ALTER, CREATE, DROP and other similar commands. The SELECT
command is not allowed in a BATCH.
For example, suppose an expert system needs to add two rows of data to the table. For the SQL command
enter a command structured like:
BATCH INSERT INTO table_name VALUES ( 123 , 'Bill Smith' , '10 Main Street');
INSERT INTO table_name VALUES ( 456 , 'Tom Green' , '86 Central Avenue')
However the actual names and values would normally be replaceable parameters from Corvid variables.
Be sure to assign the returned value to a String variable, such as [database_status]. If all commands were
successful, then [database_status] will be "Success". If any error occurred, [database_status] will have a
single error message.
If an error occurs in one of the SQL commands, the remaining SQL commands may or may not be performed.
The behavior depends on your driver. Different driver manufacturers handle errors in different ways.

13.6.11 Using a Database Command for a MetaBlock Data “File”


MetaBlock systems analyze data in a tab delimited data file. Usually, this is a static file of data, but that can
be replaced by a CORVID_DB command that returns data in the form of a tab delimited file. Since the Corvid
Runtime reads the entire MetaBlock data file and stores it internally, only one database call is required to get
all the data.
To build a MetaBlock system that gets its data from a database:
1. Create a static file of data that has the correct structure and column labels that the system will
need. This can be created in a text editor such as Notepad, or built in a spreadsheet program
like Excel and saved as a tab-delimited file. Add a few rows of test data to use in building the
MetaBlock rules. Save this Sample File.
2. Create a new Logic Block and click the “MetaBlock” check box. Enter the name of the Sample
File as the source for the MetaBlock data. Build the rules as described in the MetaBlock
section of the manual. Test the system with the sample data in the file to make sure it runs
correctly.
3. When everything is working correctly, click on the “MetaBlock” check box to open the
MetaBlock window again. This time, select "Database Command" as the source. This will
open the window for adding database commands.
4. The command to get the data in the form needed by the MetaBlock is a standard SQL
command, but adding the header line requires using one of the command Options. This is
done by creating a special line in the database command file with the header information and
then adding that to a separate SQL command as on Option.

312 13: Interfacing to External Programs


5. Add a MetaBlock header line to the Database Command File. To do this:

! Click "Build New command".


! Enter an identifier (e.g. MetaBlockHeader).
! In "SQL Command" enter the tab delimited header line. Copy and paste
this from the top line of the static Sample File. It can also be entered
directly. (If entered directly, tab moves to the next edit field and Ctrl-tab
must be used to enter a tab in the edit box).
! Make note of the Identifier that was used and click OK to save the header
in the DB command file.

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.

13.6.12 Installing the CorvidDB Servlet


If your system is run with the Corvid Applet Runtime and uses database calls, it requires the installing the
CorvidDB servlet provided with Exsys Corvid. If your system will be run with the Corvid Servlet Runtime, the
Corvid DB servlet is NOT needed and should not be installed.
1. Your server must support running Java Servlets. This requires a “Servlet Container” such as
Apache Tomcat, Glass fish, IBM WebSphere or similar program. Check with your server
administrator if you are unsure if this support is provided.
2. The CorvidDB.war file is distributed with Exsys Corvid and can be found in the “Program Files/
Exsys/Corvid/ServerPrograms” folder.
3. Put the 'CorvidDB.war' file in the appropriate folder for your servlet engine and activate it.
4. For example, in Tomcat you usually put the .war file in the 'webapps' folder before you start or restart
Tomcat. (Check with your system administrator for details on installing servlets on your system.)
5. Be sure the database is installed on the server and a DSN is created on the server as a "System DSN".
6. If the expert system is to write to the database, make sure the DSN does not have 'read only'
selected.
7. Put the '.cdb' file in the 'CorvidDB' folder created when the CorvidDB.war file deploys.

13: Interfacing to External Programs 313


8. The .cdb file was created in the folder you specified when you built the database command.
9. Test from your browser. Go to the URL http://your_host:8080/CorvidDB/corviddbservlet.
(Where "your_host:8080" is the address to run the installed servlet. Check with your system
administrator for the naming conventions on your server.) This will display a form page where you
can test your database commands.
10. In your system, make sure the URL to CorvidDB is specified when building CORVID_DB
commands.

314 13: Interfacing to External Programs


13.6.13 Turning Off Database Calls During Development
Most external interface sources are easy to implement in the development environment since they apply to
both applet and servlet runtimes, or only require having a file in the system folder. However, database
interfaces (especially ones using the Corvid Servlet Runtime) can require changing the commands in a
system during development and then restoring them when the system is fielded. Often it is easier to simply
disable the database commands in the development environment.
If the system only uses the database to set the
values of variables, this will just result in these
values being asked of the end user. To disable
the database commands during development
and testing:

! Go to the Properties window.


! Select the “Test Run” tab.
! Check the “Do NOT make external
CGI or Database calls. Ask instead”.
When ready to deploy the system to an
environment that provides the database support,
uncheck this box and be sure to test in the full
database environment.
Some systems that have complex database interactions (such as Blackboards), will not function without full
database support and cannot be run with this option.

13.7 PARAM Command Details


13.7.1 PARAM Data
When using the Corvid Applet Runtime, an applet tag is automatically added to the HTML page used to run
the system. This tag looks similar to:
<APPLET
CODEBASE = "./"
CODE = "Corvid.Runtime.class"
NAME = "CorvidRuntime"
ARCHIVE = "ExsysCorvid.jar"
WIDTH = 700
HEIGHT = 400
HSPACE = 0
VSPACE = 0
ALIGN = middle
>
<PARAM NAME = "KBBASE" VALUE = "" >
<PARAM NAME = "KBNAME" VALUE = "MySystem.cvR">
<PARAM NAME = "KBWIDTH" VALUE = "700">
</APPLET>
Within the tag are “PARAM” name/value pairs that are used to pass the name of the Corvid system and applet
window width into the runtime. PARAMs are a standard way to set values that can be accessed from within
the applet.
PARAMs have a name and a value. Both the name and value are in quotes.
In addition to the required PARAM name/value pairs that Corvid automatically adds, other PARAM name/
value pairs can be added to the applet tag. The value of any PARAM is available in the system by
referencing the name in a Corvid PARAM command.

13: Interfacing to External Programs 315


Additional PARAM name/value pairs should be added after the ones Corvid automatically adds. For example,
adding:

<PARAM NAME = "TODAYS_SPECIAL" VALUE = "X123">


to the PARAM list would make this data available in the system.
PARAM commands can be used in the same places
any of the other external data source commands can
be used. To add a PARAM command, go to the
External Data Source window and select the “Param”
tab. Enter the PARAM Name - this must match
exactly in both spelling and case.
The PARAM command will set the associated value.
PARAM commands can only be used with the
Applet Runtime and have no meaning with the
Corvid Servlet Runtime. They provide an easy way
to modify data in a system just by changing the text of
the HTML page used to run the system. There can be
any number of PARAM name/value pairs. If the
HTML page is dynamically generated, such as with
Cold Fusion, these PARAM values can be set when
the page is created.

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.

13.8 APPLET Command Details


13.8.1 Custom Java Applets
The APPLET command is used to communicate between the Corvid Applet Runtime and other Java Applets
on the same HTML page. The Corvid Runtime Applet can send data to other applets, have those applets
perform some action and send data back to the Corvid Runtime. This allows the other applets to add to the
capabilities of the Corvid Runtime by providing other special interfaces to data sources, or even to provide
custom interactive graphics or user interfaces.

316 13: Interfacing to External Programs


Corvid uses inter-applet communication for the XML interface
in the Corvid Applet Runtime and the Corvid Trace applet.
The same technique used in these can be adapted to add
functionality with other custom applets.

13.8.2 APPLET Window


APPLET commands are built using the “Applet” tab in the
external command builder window.

Applet Name: This is the name of the applet to call. This


is set in the <APPLET> tag that includes the custom applet
in the HTML page with the Corvid Runtime Applet.

It will be something like:

<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.

13: Interfacing to External Programs 317


Normally, when Corvid calls an external applet, it waits for that applet to send data back. If this will not
happen, be sure to check the “Do Not Wait” check box. In that case, Corvid will pass the data to the applet
and continue running.
For example, a custom graphing applet could be called to display information from a Corvid system
repeatedly monitoring a process. Each time the Corvid system would finish a check, it would write data to the
graphing applet, which would display the data, but not send anything back to Corvid.

13.8.3 How to Create a Custom Applet


Building a custom applet requires a knowledge of Java and a development environment such as the free Oracle
Sun Netbeans tool. This manual is not meant to explain the Java language or how to build applets, and only
covers the special techniques used by Corvid to communicate with the applet to send and receive data.
Inter-applet communication can be done in various ways. Advanced techniques like pipes can be used when
applets need to be in constant communication running in parallel, but Corvid applications call an applet, and
must then wait for data before they can continue processing. This results in a more sequential process that
does not require the complexity of setting up pipes. Corvid uses a VERY simple and reliable technique that
can be added to an applet in just a few lines of code, and uses standard applet methods that are accepted by
all compilers.
Corvid passes data to the called applet using the applet.getName() and applet.setName() methods. This may
at first seem like an odd way to pass data, but it works extremely well and is very easy to implement.
In the custom applet:
! Create a boolean variable running that will indicate if the applet has finished its initialization.
! Create a string variable origName to hold the original name of the applet. This is set in the first time
init() is called.
public class GetMyData extends Applet {
boolean running = false; // has the system done the first init?
String origName; // Original system name
The init() method for the applet gets called when the applet first starts on the page and again when it is called
by Corvid to do something. To differentiate these calls, the running variable is used.
public void init() {
if (running == false) {
origName = this.getName();
running = true;
// any other code needed for init
}
else {
processDataRequest(this.getName());
this.setName(origName);
}

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.

318 13: Interfacing to External Programs


The processDataRequest() code is passed the data string from Corvid. This will be whatever string was
specified in the Data field when the APPLET command was built. Any embedded Corvid variables will have
been replaced by their values, and processDataRequest() must do whatever parsing is needed to separate
out values. The data passed can then be used to do whatever the applet is designed to do, including
obtaining data. Data may be obtained automatically from other sources invisibly, or an end user interface
may be displayed for user interaction.
Once the applet has determined the data to send back to Corvid, it should use the returnDataToCorvid()
method. This will pass the data back and tell Corvid to continue processing.

public void returnDataToCorvid(String s) { // return data to Corvid


Applet corvidRuntime;
corvidRuntime = getAppletContext().getApplet("CorvidRuntime");
corvidRuntime.setName(s);
corvidRuntime.start();
}

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.

13.8.4 Returned Data


The syntax for the returned data is similar to all other external data sources. If the context of the external call
indicates only a single string is expected (such as setting the Prompt text for a variable), the returned string
will be used in that way.
If the external call is to set the value for a variable, the returned data must set the value for that variable but
can also set the value for other variables at the same time. If the returned data is to set the value for the
calling variable, it only needs to be the value to assign. For example, if the external call to the applet was to
set the value for the numeric variable [X], the returned data could just be:

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:

[x] 123 tab [s] abc tab [color] red


would set [X] to 123, [s] to “abc” and [color] to red. In the Java code this would be:
returnDataToCorvid(“[x] 123\t[s] abc\t[color] red”)

13: Interfacing to External Programs 319


13.8.5 The External Applet Tag
The applet being called must be added to the HTML page used to run the system. It must be on the same
HTML page as the Corvid Runtime Applet.
The applet tag will be something like:

<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:

! Open the “Properties” window.


! Go to the “Test Run” tab.
! In the “Specific URL” edit box, enter the name of the custom HTML page or browse to it.
When the system is run, Corvid will use the custom HTML page that has the other applet included.

13.8.6 Uses for External Applets


There are many uses for external applets to enhance the capabilities of Corvid. The most common use is to
have an applet perform some special function or interface not built in to the Corvid Runtime. Corvid uses this
approach itself for the XML interface when using the Corvid Applet Runtime. The XML interface is built into
the Corvid Servlet Runtime, but since it significantly increases the size and Java requirements of the Corvid
Applet Runtime, and it is not needed in most systems, it makes more sense to have it as a separate applet
that can be included and called as needed.
External applets can also be used to do complex mathematical operations not easily handled within Corvid.
For example, if a Fourier transform was needed, it would be better to pass the data to an external applet that
could implement the transform algorithm in Java rather than trying to do it in Corvid.
External applets can also be used to display data or even interactively ask questions of the end user. Data
can be passed to an applet that could graph it or display it in ways not possible from within the Corvid
Applet Runtime.
It is even possible to have the actual Corvid Applet Runtime invisible and to do all the user interaction through
external applets. This is complicated and requires a good knowledge of Java, but can be done to create
special interfaces not otherwise possible with the Corvid Applet Runtime.

320 13: Interfacing to External Programs


Chapter 14: Reports
14.1 Types of Reports
Corvid supports various types of reports to display the system conclusions and advice to the end user.
The simplest type of report is just the Results screen in the Corvid Applet Runtime. This allows displaying
and formatting any of the variables in the system in the applet window that runs the system. Building this type
of screen is covered in the chapter on User Interface, and is built using the standard Corvid Screen
Commands.
This chapter focuses on other types of reports that are generally built using report “templates” to generate
HTML, RTF or PDF documents. These types of reports have many more options for formatting and
presentation, but are more complex to build and require either the Corvid Servlet Runtime or at least a server
support for the special Corvid Report Servlets that is used to build and display these types of reports.

Applet Window - “RESULTS” Command


! Easy to build and incorporate into a system.
! No server-side functionality required.
! Somewhat limited formatting options.

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.

14: Reports 321


PDF Reports
! Requires building the report in RTF template, and then converting it with a 3rd party program.
! Best done using the Corvid Servlet Runtime, but can be done with the Corvid Applet runtime and
the Corvid Report Servlets. Always requires some a server capable of running Java servlets.
! Wide range of formatting options comparable to a word processor document.
! Opens in Adobe Acrobat.
! Good for building documents that the end user can save locally, but NOT modify.

14.2 Creating Report Content


Corvid reports using HTML, RTF and PDF all require that the entire content of the report be created in a
single Corvid Collection variable. The content of this variable is then displayed using the report commands.
(Reports displayed using the RESULTS command in the applet window can include content from many
variables and are not required to build all the content in a single Collection variable.)
The main ways to build the content in a Collection variable is to add the content of a template file that
contains the report formatting, with embedded Corvid variables that will be replaced by simple text/numeric
content from the session. This can be done with a single ADDFILE command and Corvid will automatically
replace and double square bracket embedded variables.

14.2.1 Adding Content from a Template File


Using a template to build a report is generally the easiest approach. For HTML reports, it allows the report to
be designed with HTML editors and for RTF/PDF reports reports can be designed with standard word
processors and saved as RTF files.

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.

322 14: Reports


! An external interface command if one is associated with the variable.
! Asking the end user for 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

14: Reports 323


can always be reached, regardless of how the template is used.

For example a simple HTML template could be:


<!doctype html>
<html>

<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.

14.2.2 Adding Parts of a File with Key Strings


The ADDFILE command allows adding the entire contents of the template file, and for most templates this
is what is best. However it is also possible to add only a section of a file. This allows a single file to have a
variety of content and the ADDFILE command will only load a section(s) that is marked by an identifier. For
example a file might have various repair procedures, but only one of them is selected by the rules and
should be displayed in the results. Or a file might have versions of the advice in different languages and
the system should display the one in the end user’s language.

324 14: Reports


Adding a portion of a file is very easy. In the window for building ADDFILE
commands, there is an edit box labeled “Optional Key to identify portion of
file”. Enter an identifier key string in that box.
Within the file a section of text should be marked by:

<!-- Corvid_KEY=key_str -->


text to add
<!-- Corvid_KEY_END=key_str -->

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]:

[Col.ADDFILE] MyFile.txt, first key would add “aaa” to the file

[Col.ADDFILE] MyFile.txt, second key would add:

bbb
<!-- Corvid_KEY=another key -->
ccc

Since the Corvid_Key is a HTML comment, it would be invisible in HTML


The <!-- Corvid_KEY....--> and <!-- Corvid_KEY_END....--> markers should be on their own line in the file.
The key string can be any length and can include spaces.
They can also include Corvid_IF conditional inclusion sections (explained below).
If no "key" is specified, the entire contents of a file will be added to the Collection Variable.

14: Reports 325


14.2.3 Conditional Inclusion of Text
In addition to the the Corvid_Key option that allows a specific section of the file to be included by identifying it
with a key string, ADDFILE allows sections of the file to be included or excluded based on boolean tests using
the Corvid variables set in the system. This approach allows more complex sectioning of the file, and
sections can be included based on complex boolean tests rather than a simple key string.

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

326 14: Reports


If test1 is TRUE and test2 is FALSE, the lines included would be:
aaa
bbb
ddd
eee
If test1 is FALSE, the entire block will be excluded, and test2 will never be tested. The line included would be:
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.

Files with #Corvid_IF in the Middle of the Text


When using #Corvid_IF, the #Corvid_IF and following expression should be on a single line. However,
sometimes this can be difficult, such as if the contents of an HTML page are being added and your HTML
editors will add or remove line breaks. This can result in the #Corvid_IF being in the middle of a line, which
can lead to errors in parsing.
To solve this, the option:
BREAK_ON_CORVID_IF
can be added to the command following the name of the file to add. For example:
[COLL.ADDFILE] DATA.TXT BREAK_ON_CORVID_IF
With this option, the #Corvid_IF and #Corvid_ENDIF commands can be at any place in the text of the file.
however, to make it clear where the Boolean expression for the #Corvid_IF ends, the expression must be in
parentheses ( ). Corvid will pre-parse the file to break lines on the #CORVID_IF and #CORVID_ENDIF.
When possible, it is better to design the file with #CORVID_IF on individual lines. The file and boolean tests will
be easier to see and maintain. The BREAK_ON_CORVID_IF should only be used when this is not possible.

14.2.4 Adding Collection Content Incrementally


A system can have multiple rules that add content to a Collection variable
that will contain the full report. When the report is text, this is easy to do
since there is no underlying syntax, though there many be an order in
which the content should be added.
Individual rules add content using the .ADD and .ADDFIRST methods to
add strings to the Collection variable [Report]. The .ADD will add the
content to the end of the value list for [Report] and the .ADDFIRST will
add the content to the beginning of the value list for [Report].
To add content to the report when building the THEN part of a rule:
! Click the Collection variable for the report.
! On the right the “Collection” tab will be selected.
! Select “Add an item to start/end of the list”.
! Enter the text content to add.
By default, the new content will be added to the end of the Collection variable’s value list. To add the content
to the beginning of the value list, check the “Add as the first item in list” check box at the bottom of the
“Collection” tab.

14: Reports 327


If there are multiple rules that could each add the identical content, and report should not have the content
added more than once, check the “Do NOT add if identical item is already in the list”. This option can be used
with the option to add first or add last.
The content can be added from any rule that fires. This can be done using backward or forward chaining. In
backward chaining, having the rules add content to a report can be used to have a very extensive trace of
what rules fired. When used with forward chaining, it is easier to control the order in which rules will be tested
so that content will be added to the report in a specific order.
For more complex reports, it can be useful to have multiple collection variables that each build up pieces of a
report and which are then combined either by adding the content of one collection the overall report or using
templates.
The content text can include double square bracket embedded variables or properties. For MetaBlocks, the
MetaBlock data can be included by using column name in { }. For example:
IF
[X] > 0
THEN
[Report.ADD] The value of X is [[X]] and greater than 0
IF
Power light = off
THEN
[Report.ADDFIRST] The machine is not getting power.

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:

328 14: Reports


[Report.ADD] <ul>[[Problems]Before: <li> After:</li>]</ul>
If [Problem] had a value list of “aaa”, “bbb”, “ccc”, the value added to [Report] would be:
<ul><li> aaa </li><li> bbb </li><li> ccc </li></ul>
Provided the syntax of HTML is followed, very complex and graphically interesting reports can be built using
HTML. The page created must have a HEAD and BODY and all tags should match and be closed. Often
these are easier to add with templates that include blocks of text built in various collection variables. The
HTML page itself can include anything that any other HTML page can include, such as CSS, JavaScript,
Flash, video, etc.
Building a full, complex HTML by adding pieces is generally not the best approach. Usually the parts that are
need the details of being added incrementally can be added to some other collection or string variable and
then embed that variable in the main template that does the main formatting.

14.3 Displaying the Reports with the Corvid Servlet Runtime


Template based reports can be used in systems run with either the Corvid Servlet or Corvid Applet Runtime programs, but
there are differences in the programs needed to do this. For most Corvid systems, the servlet approach is recommended
due to the increasing Java security restrictions on applets and the inability to run applets on many mobile devices such as
iPads and iPhones.
Template files are used for HTML, RTF and PDF reports. The templates are created with an external program appropriate
to the report style such as an HTML editor or word processor. The template includes both the formatting for the report
along with the value of Corvid variables embedded using double square bracket replacement. This allows the value of
any Corvid variables to be included in the report.

14.3.1 Temporary Report File Folder


Corvid reports built from templates, use the SaveReport command to create a special report file in a folder on the server.
This temporary report file is later displayed with the DisplayReport command or can be passed to other special Corvid
Report Servlets that can display it in a way that can be bookmarked.
This requires that the folder for the temporary files be created and the location passed to the Corvid Runtime. The folder
can have any name, but make it easy to recognize like ExsysReports or MyExpertSystemReports.
There are 2 aspects to the report temporary folder:
• Creating the folder in a secure, but accessible location.
• Telling the Corvid servlet (and possibly CorvidRpt and ExsysFop servlets) to use that folder.

Report Folder Location


The folder for report files should be in a secure location that cannot be directly accessed by an external URL. Depending
on Tomcat settings, folders inside webapps can potentially be accessed externally via a browser. Check with your system
administrator if in doubt.
To avoid this problem, the folder should be at the same level as the Tomcat/webapps folder (NOT inside webapps) or
external to the Tomcat folder structures. For systems run on an ISP, folders outside of the Tomcat folder structure may
be protected and not accessible, and a folder at the same level as webapps may be the only option. Check with your
system administrator if in doubt.
In all cases, the temporary report folder must be created before you can use it - Corvid will NOT automatically
create this folder.
For example:
If you are running locally on your PC, or have complete access to your server, you could make the temporary
report folder:
C:/ExsysReports

14: Reports 329


If you want to put the reports in your Corvid development PC, in the Tomcat folder structure at the same level as
webapps, this could be:
..CorvidProjects/Apache-Tomcat-xx /ExsysReports

The CorvidReport.cfg File


The CorvidReport.cfg file tells the Corvid Servlet Runtime what folder to use for the temporary report files. When the
SaveReport or DisplayReport command is executed, Corvid will look up the name of the folder to use in the
CorvidReport.cfg file.
The CorvidReport.cfg is just a text file with a single line that has the name and location of the temporary file folder.
If your temporary report folder is C:/ExsysReports, the CorvidReport.cfg would just be one line with:
C:/ExsysReports
If your temporary folder on your local PC is in Tomcat at the same level as webapps, the CorvidReport.cfg would be
something like:
../CorvidProjects/Apache_Tomcat-xxx/ExsysReports
where ..CorvidProjects is the full path to wherever you have your CorvidProjects folder (e.g. C:/UserName/
CorvidProjects/Apache_Tomcat-xxx/ExsysReports).

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

and run from there.


When moving to a full online server, the CorvidReport.cfg will need to be changed to reflect the folders on that
server.

330 14: Reports


2. The alternate location for the CorvidReport.cfg file is in the CORVID servlet WEB-INF folder. This can be
found in:
..CorvidProjects/Apache-Tomcat-xx/webapps/CORVID/WEB-INF

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.

14.3.2 CorvidRpt and ExsysFop Servlets


The Exsys Corvid install includes 2 special servlets that can be used with the temporary files and template based reports.

CorvidRpt
This servlet provides the ability to save and display reports external to the Corvid Servlet Runtime.
It is needed only for:

• Using template based reports with the Corvid Applet Runtime


• Displaying HTML or RTF template based reports from the Corvid Servlet Runtime in a way that allows the report to
be bookmarked and returned to after the Corvid Servlet session has expired. (Template based reports that are
displayed at the end of a Corvid Servlet session, and are not intended to be bookmarked, do not require
CorvidRpt).

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).

14: Reports 331


14.3.3 Details of Template Based Reports with the Corvid Servlet Runtime

HTML Reports
There are 3 ways to display HTML template based reports:

1. Using just DisplayHTML


The first can be done very easily and displays template based HTML reports without using the CorvidRpt
servlet, CorvidReport.cfg or even the SaveReport / DisplayReport commands. However, this technique
applies only to the Corvid Servlet Runtime and does not work with the Applet Runtime and gives up some of
the extra functions of the SaveReport command.
1. Create an HTML template with double square bracket embedded variables. This can be created
with any HTML editor.
2. Call DisplayHTML to display the template. Corvid will read the file in, replace the embedded
variables and display the resulting HTML.
That’s all there is to it. The Command Block for the systems will look something like:

Commands to run logic


DisplayHTML “HTML_Report_Template.html"

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.

2. Using SaveReport / DisplayReport


Another approach to creating the HTML report is with the SaveReport /DisplayReport commands. This more
complicated approach does not have any real advantage for over the DisplayHTML approach described
above unless the option to allow the report to be bookmarked is implemented. (See Sect 14.5 for details on
building Report commands)

1. Create a template for the report as an HTML file.


2. Add the HTML template to a Collection variable with ADDFILE.
3. Call SaveReport for the Collection variable with TYPE set to “html” and “Call via Servlet” selected.
Corvid has the functionality to save reports built in and no “External Servlet” should be specified (if
one is added, it will be ignored). Save the return code in a string variable for the Report ID.
4. Call DisplayReport for the string variable with the Report ID. Again, no external servlet should be
specified.

332 14: Reports


When run, the HTML report will immediately display. The URL for the report page will be a Corvid Servlet
URL with the session ID. It cannot be bookmarked since the link used will no longer work after the user’s
session expires.

The Command Block for the systems will look something like:

Commands to run logic


SET [Report.ADDFILE] HTML_Report_Template.html
SaveReport [Report_ID] [Report] Type=“html” IP=0 Servlet=“”
DisplayReport [Report_ID] Servlet=“”

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.

3. Creating an HTML Report that Can be Bookmarked


To display the HTML report in a way that can be bookmarked external to the Corvid session, it is necessary to
call the CorvidRpt servlet and pass it the appropriate parameters. This is done with a special “redirect” file.
Because of the way servlets work, it is not possible to simply change the browser URL from the Corvid Servlet
running the system to a different CorvidRpt servlet URL. Instead, a special HTML page has to be displayed
by the Corvid Servlet that tells the browser to switch to the CorvidRpt servlet or displays a link to the
CorvidRpt that the user can select.

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

14: Reports 333


instructions for the end user to click on the link to display the page.
<a href=“http://localhost:8080/CorvidRpt/corvidreportservlet?OP=DISPLAY&[[report_ID.value]]”>
report link </a>

The Command Block for the systems will look something like:

Commands to run logic


SET [Report.ADDFILE] HTML_Report_Template.html
SaveReport [Report_ID] [Report] Type=“html” IP=0 Servlet=“”
DISPLAY_HTML “HTML_Redirect.html”

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.

Alternate Ways to Open the Report


There are other ways to open the report one the report ID is set by the SaveReport command.

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

334 14: Reports


processing document.

The Command Block for the systems will look something like:

Commands to run logic


SET [Report.ADDFILE] RTF_Report_Template.html
SaveReport [Report_ID] [Report] Type=“rtf” IP=0 Servlet=“”
DisplayReport [Report_ID]

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.

The PDF_Redirect.html is the same as the HTML redirect, but calls:

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:

14: Reports 335


<!doctype html>
<html>
<head>
<title>PDF Redirect</title>
<META http-equiv="refresh" content=“0;http://localhost:8080/ExsysFop/exsysfop[[report_ID.value]]”>
</head>
<body>
</body>
</html>

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:

Commands to run logic


SET [Report.ADDFILE] FO_Report_Template.html
SaveReport [Report_ID] [Report] Type=“pdf” IP=0 Servlet=“”
DISPLAY_HTML “PDF_Redirect.html”

The report will open in Adobe Acrobat which requires that the end user have Acrobat Reader or some other
PDF viewer.

14.4 Displaying Reports with the Corvid Applet Runtime

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.

14.4.1 Installation of the Corvid Report Servlet


Installing the Report Servlet

336 14: Reports


The Corvid Report program is a Java Servlet that was installed as part of the Corvid install. The “Install
Servlets” step in the configuration installed the Corvid Servlet Runtime and other Java Servlets used with the
applet runtime. These are installed on the local Tomcat install. When your system is fielded, the servlet
CorvidRpt.war will need to be fielded on your production server using Apache Tomcat, Glassfish, IBM
Websphere or comparable program.
Check with your server administrator to see if Apache Tomcat is available, or if it can be installed on your
server. Not all servers or ISP provide Tomcat. These instructions are written assuming that Tomcat is
installed. If you are using Glassfish, IBM Websphere or other program, check with your system administrator
on deploying Java servlets on your system.
Even if Tomcat is not available on your server, it is installed by Corvid on your local PC for development
purposes (though a server supporting Tomcat (or equivalent program) will eventually be required for fielding
the system). Having Tomcat installed locally makes development faster and easier for systems that build
reports since the Corvid system files can be directly edited and run, rather than having to move them up to the
server after each edit.

Installing the Corvid Report Servlet on an Online Server

Find the folder where Corvid installed Apache Tomcat.


Open the Tomcat folder. It will have various folders in it. Open the "webapps" folder. This will have the CorvidRpt.war
servlet program and a CorvidRpt folder (which is the deployed servlet files)

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.

14: Reports 337


Open a browser window and enter the URL.
http://localhost:8080/CorvidRpt/corvidreportservlet
This will be the location where the Corvid install deployed the servlet.
You will see a form that can be used to test the installation. If this
form is not displayed, the CorvidRpt servlet was not deployed or
there is a problem with the URL. These must be fixed before
proceeding.
In the 'Save Report' section:
Type the word "Exsys" in the 'code 1' slot.
Type "This is a report" in the 'report' slot.
Click the Submit button.

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.

Copy the filename to the clipboard by selecting it and clicking "Ctrl-C"

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.

338 14: Reports


14.4.2 Using Reports in an Applet System
Once the Corvid Report Servlet is installed, tested and working, it can be used with Corvid systems to build
reports. This requires understanding the restrictions Java places on an applet and how the Corvid Report
Servlet works.
When using the Corvid Report Servlet, the Corvid system being run MUST be served by the
same server. Java allows the applet program to call back to the same server that served the
applet. This means systems must be run from the “MySystems” folder (or some other folder
in webapps) to call the Corvid Report Servlet on that server. Systems cannot be run from
another server or location and call back to a different server for the report. Since Corvid
automatically moves systems to Tomcat this is not an issue in development, but may be when
moving the system to a production server.

There are 3 steps in creating a Corvid report:


! Putting all the report content in a single Collection variable.
! Calling the Report Servlet to save the report.
! Calling the Report Servlet to display the report in a new browser window.
The options for the first step is covered in Section 14.2 above. All the content must be in a single Collection
variable. This may consolidate the values of other variables or collections, but before the report can be built,
it must all be in a single variable.

Saving the Report


Java security prevents an applet from simply displaying content in a new browser window. The report content
has to first be sent to the server associated with the applet. Corvid does this with the Corvid Report Servlet.
1. First a Corvid system is
run in a browser window
with the Corvid Applet
Runtime. This MUST be
served from the same
server that will be used to
create the report.
2. The system uses the
SAVE_REPORT
command to send the
content of the report back
to the Corvid Report
Servlet running on the
server. This will include
the content and any restrictions on how or who can view it.
3. The Corvid Report Servlet creates a file in the temporary report files folder (the one specified by
CorvidReport.cfg). This fill will have the report content along with the restrictions on viewing. It will be
given a random name. An unique identifier for the file will be sent back to the applet running the
system. This is assigned to a Corvid string variable in the system for later use in displaying the report.

14: Reports 339


Displaying the Report
The report is displayed in a new browser window by having the Corvid Applet Runtime call the Corvid Report
Servlet again using the unique identifier for the report file that was created when the report was saved.

1. The Corvid Applet calls the


Corvid Report server passing
the unique report identifier.
This is sent as a URL to open
a new browser window.
2. The Corvid Report Servlet
checks that the identifier
matches a report file, recovers
the report content and checks
that any viewing restrictions
are met.
3. The report content is sent back
to the end user as the content
for a new browser page.

14.5 Building the Report Commands


The commands in a system to save and display a
report are built from the Command Block’s
command builder window, on the “Reports” tab.
There are 3 commands that can be built to:
! Save a report
! Display a saved report
! Delete a saved Report
All of these use the same Corvid Report Servlet.

Corvid Report Servlet


All of the report functions used with the Corvid
Applet Runtime call the Corvid Report Servlet on the server.
Make sure “Call via Servlet” is selected.
(The “Call via CGI” is an obsolete
approach no longer recommended. It is
included only for backward compatibility
with older version of Corvid and should
NOT be used for new systems.)
Enter the URL for the Corvid Report Servlet in the edit box. This will be something like:
http://localhost:8080/CorvidRpt/corvidreportservlet
for development or
http://www.MyServer.com/CorvidRpt/corvidreportservlet
for installations on a server.

340 14: Reports


It will be the SAME address used to test the Corvid Report Servlet above. You should be able to enter this
URL in a browser and see the Corvid Report test screen.
Once the Corvid Report Servlet address is entered once, it will be remembered and automatically filled in for
any other 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”.

14.5.1 Writing a Report to the Server


To write a report, select the Report tab. Make
sure the location for the Corvid Report Servlet is
entered in the “Program to Call” section. Click the
“Write and Save Report” radio button.
You will need 2 Corvid variables to write a report
- a Collection variable that contains the full text of the report, and a string variable that will contain the
identifier of the report file built on the server. The returned ID will automatically be saved in the string
variable.

String Variable to Save the ID


When a report is sent to the server to be saved, the Corvid
Report Servlet will return a unique, random identifier for the
report. This identifier will be needed in later commands to
display or delete that report. The identifier information must
be saved in a Corvid string variable. Any Corvid string
variable can be used, but it is a good idea to create a special
string variable that is used only for the report. Name this
something easy to recognize like “Report_ID”.
The first step in building the command to save the report is to select the string variable that will receive the
identifier. The “Save ID in” drop down list will display all the string variables in the system. Select the
variable to use. If necessary add a new string variable from the Variables window.

Collection Variable with the Report Text


The text of the report comes from a single Collection variable. This text can be built dynamically as the
system runs or built from a template using the ADDFILE method. With ADDFILE, a template of the report
can be built which has conditional inclusion of lines and embedded variables using [[ ]]. This can be a very
convenient way to build the text of the report. The text itself can be normal text, HTML or RTF depending on

14: Reports 341


the formatting to the report file and how it should be displayed.
When the “Write Report” command is called, the entire text of the Collection variable will be posted to the
Corvid Report Servlet. This must occur in a short time, so the complete text of the report must be in the
Collection variable before the “Write Report” command is called.
The “Write Collection Variable” drop down will display all the Collection variables in the system. Select the
Collection variable that has the report content.

Setting the Report Type


The last required step in building the command to save the report is to set the report type. For many
browsers this is not actually needed, but is a good idea since some commonly used browsers require it.
The browser must correctly recognize the document type
to know how to handle it and to know if it should be
passed to another program. For example RTF
documents are passed off to MS Word and PDF
documents are (typically) passed off to Adobe Acrobat.
Microsoft Internet Explorer 8 changed the way the
browser recognizes the “type” of a document. This
creates a special format for the URL Corvid uses to call
the Corvid Report Servlet so that it would work with all
current browsers.

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.

Access Limitation by IP Address


When a report is built, the system can control who can later access the report. The default is to limit this to
only the IP address that originated the report. This limits access to the report to ONLY the user that created
it (as identified by their IP address). In some cases, it is desirable to share a report among others, or to have
an expert system that dynamically builds a Web page that can be accessed by anyone - allowing the URL for
the report to be emailed to others.
The access level for the report is controlled from
the “Report can be accessed by” drop down list.
The options control how many numbers in the
IP address must match. If the originator is
selected, the full IP must match exactly. An IP
address is made up of #.#.#.# where the #
may be 1 to 3 digits. Each # is a group. The
author can select how many groups must match. If the people in an office all have the same first first
groups, it can be set to allow anyone in the office to access the report file by selecting “Same 1st group”.
The most commonly used options are “Only Originator” which is the default. Use this unless the report
should be shared with others, in which case the “Anyone” options is usually used unless the IP structure
make a more limited distribution practical.

Limiting to the Calling URL


As an additional security feature, a limit can be applied to specify the URL making the call to display the
report. This can prevent someone from calling a report that has no other access limitations from another
Web page. To specify the URL, enter a URL in the “Limit access to only specific URL”. This option is
rarely needed since if the report should be controlled, the “Limit to Originator” and Timeout options are a
better choice.

Making Reports Timeout


The report can be made to time out. With this option, the report can only be displayed by ANYONE

342 14: Reports


(including the originator) for a certain number of minutes. This provides an additional level of security since
the file cannot be accessed after the time limit. The time limit should be selected to be long enough for the
Corvid system to build and display the report. (Reports currently being displayed will not “disappear” at the
timeout, but the report will no long be able to be reopened.) The Timeout option can be very effective if the
expert system is using real-time data and the report conclusions may only apply some period of time.
When the time limit expires, the report will NOT be automatically deleted from the server. (To do that requires
a server program that is periodically run to remove files more than a specific age.) However, if the Corvid
display file command is called after the timeout period, the access will be refused and the file will be deleted
from the server.
To add a time limit, enter a number of minutes in the “Timeout” edit box.

14.5.2 Displaying a Saved Report


Displaying a report is much easier than saving it. All you need is the String variable that has the ID for the report.
The report can be displayed in a new browser window or a named frame on the same page as the applet.
To display a report, click the “Display Saved
Report” radio button.
Select the string variable with the report ID
created when the report was saved. The ID
string variable can be selected from the “ID
or report” drop down list.
The default is to display the report in a new
browser window. Optionally, the report can
be displayed in a named frame if the system is running in a frameset. Depending on the type of report, the
browser may pass it off to another program such as Adobe Acrobat or a word processor. In this case, that
program will control where and how it is displayed.

14.5.3 Deleting a Report


It is not required to delete a report, but it can be a practical way to make sure the report is gone and the
server is not getting cluttered. Remember that once the report is deleted the file for it is removed from the
server and it cannot be displayed by anyone.
To delete a report, click the “Delete Report
File” radio button and select the string
variable with the ID for the report from the
drop down list.

14: Reports 343


14.6 Creating PDF Reports Templates
PDF documents are a desirable format for Corvid reports because:
1. They allow very complex formatting, including matching legal documents.
2. They are quite portable across operating systems and browsers.
3. They are easy to print, save and distribute.
4. They cannot be edited by the end user.
PDF reports can better match the look of published documents and can use the capability of the expert
systems to build and fill-in complex forms. The other common formats for reports include .txt, .html, .xml,
and .rtf. While these work well in many cases, PDFs are best for complex and precise formatting of reports
that are intended to be saved or printed.

14.6.1 Corvid Server Programs Needed for PDF Reports


If you plan to build PDF reports you will need to install the ExsysFop servlet. This is an extension of the open
source FOP program. The Exsys extensions change the way the program is called and where files are
created on the server. The core FOP functionality is not changed. Since this is an open source program, the
source code for the Exsys modifications is also provided.

Install the ExsysFop Servlet on the Server


FOP is an open source program created by Apache. It converts .fo files (which are XML files) into .pdf files
which can be opened in a user’s browser. This is used as one of the steps in building PDF reports. Exsys
has created a customized version of FOP to make it easier to use with Corvid and to increase security.
The .war file needs to be fielded on the server. The .war file is part of the Corvid install and can be found in:
C:\ Program Files\Exsys\Corvid\ServerPrograms\ExsysFop.war

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.

14.6.2 Building PDF Reports


Building a PDF report is a little more complicated than reports in other formats and has 5 main steps:
1. Formatting the report using RTF.
2. Convert the RTF report template to an FO template.
3. Putting the report in a Collection Variable.
4. Saving the Report to the server.
5. Displaying the report via a URL.

1. Formatting the Report Using RTF


RTF (Rich Text Format) is used to design and build the structure of the report. The RTF will later be
converted to PDF, but reports must start with RTF because it has a much easier structure to read and work
with than PDF. Also, RTF documents can be easily built with MS Word and many other text editing programs.

344 14: Reports


RTF provides a wide range of formatting options allowing even complex reports and forms to be created.
However, some more advanced MS Word formatting options such as tables may not be supported in FOP.
RTF files are text. If you open one in Notepad (NOT WordPad or MS Word) you can see the text commands
and syntax that makes up the RTF document. Because of this, RTF documents allow double square bracket
embedding of variables that Corvid will then replace with content from the expert system. Also, sections of
RTF code can be combined to build a larger document, though this requires some knowledge of RTF syntax.
PDF files on the other hand cannot be easily opened and read. While PDF documents can also be directly
created from MS Word and other programs, these cannot be used directly with Corvid due to their complex
internal structure that does not preserve double square brackets [[ ]].
The easiest way to build an RTF document is in MS Word or the WordPad program that comes with MS
Windows. (NOTE: Do NOT use Notepad because it does not support RTF.) MS Word allows much more
complex formatting and layout than WordPad.

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.

Once the report is built, select "Save As" from the


"File" menu and select "Rich Text Format (RTF)" from
the drop down at the bottom of the window. Give the
file a name and save it with the files for your Corvid
system.
The same approach can be used in MS Word, which
provides many more formatting options for complex
documents. Again, save the document as RTF.
Any layout and formatting options can be used to
design the template. However, be very careful NOT to
change formatting such as font, size, color, etc options
in the [[..]] expressions. RTF syntax includes codes
whenever the text format changes and if these appear
in the [[..]], Corvid will not later be able to recognize the variable name. This will lead to a “Unrecognized
variable” error later when running the system.
If you get a runtime error or just want to check the file, open the file in Notepad. Notepad does not support
RTF and will display the RTF codes as text. This may be quite complex, but search the file for "[[" and make
sure that the [[..]] expressions only contain the name of the Corvid variable and do not have any additional
RTF codes. If they do have RTF codes in them, opening the document in Word or WordPad, selecting the full
“[[..]]” expression and setting the format for it should
get rid of the RTF codes in the variable name.

2. Convert the RTF Template to an FO Template


FO is a standard way to represent RTF as XML. This may seem like an odd thing to do, but the advantage of
FO is that it can be converted to PDF by the FOP program.
There are various ways to create the .fo template file. One of the easiest is to use an inexpensive third party
program called 'RTF_to_XML'. FO can also be created from a XHTML, XML, DocBook, or TEI document by
using an XSLT transform to create the FO file. It can also be created directly, though this requires a good
knowledge of FO syntax.
At the moment, the easiest way to build FO files is to use "RTF_to_XML", which is available from http://
www.rtf-to-xml.com. This is a third party program and not part of the Corvid package. The current price is

14: Reports 345


$40, and it can be ordered online. Since FO
is a standard, it is expected that there will
eventually be more ways to directly build FO
files via “Save As” options in text editing
programs.
To convert the RTF template to a .fo
template using RTF_to_XML, build the RTF
template as described above. Start
RTF_to_XML and select the .rtf file as the
Input File and pull down XML-FO as the
Output Format and click the Convert button
to create the .fo template file, which you will find in the same folder.
This will produce an FO template that we can use to build a PDF file.

3. Putting the FO Report in a Collection Variable


The next step is to put the content of the FO template into a Corvid Collection variable. This collection
variable must eventually contain the full report. It will be used with the SaveReport command to put the report
on the server.
If the report is based on a single FO template with
embedded [[..]] expressions this is very easy to do. Just
create a Corvid Collection variable to hold the report and
use the ADDFILE method to add the template file to that
collection." Here we have a Corvid Collection variable
named "report" and we are adding the FO template
named “ReportTemplate.fo"
Doing this causes a variety of things to happen
automatically. As Corvid adds the template, it will look
for all the [[..]] expressions. If Corvid has asked or
derived the values for the variables, the [[..]] expression
will be replaced by the value. If the value is not yet
known, Corvid will use backward chaining to derive the
values for the variables. This may involve asking
questions, using various rules, etc. Once all the [[..]]
variables in the template have been filled in, the report
with all the values will be in the collection variable. The individual [[..]] expression values can be short or long.
They can be a word or number or a long paragraph. FO XML tags can be included in the replaced value text,
but this requires knowledge of FO syntax. You may need to include many [[..]] expressions to build a
complex report with a lot of formatting.
A note on good system design, while it is certainly possible to just use the ADDFILE command and embedded
[[..]] variables to drive the logic of a session, this can result in a system that may not be easy for others to
maintain in the future. Since the requirement to set the variables is due to the ADDFILE, rather than
commands in the Command Block, it may not be obvious to others why the system is asking questions or
using backward chaining. If the ADDFILE is used to drive the logic, be sure to make some note that this is
driving the asking and derivation of the variables.
The other approach to building the report in the Collection variable is to have various sections of logic add
individual sections of FO code into the report. This approach allows more complex and dynamic reports, but
requires detailed knowledge of FO XML syntax to produce an overall report that is syntactically correct. It is
easiest to build the RTF sections in MS Word, convert them and then cut out the smaller sections with
Notepad and include them individually. This can be complicated, and the single template method works quite
well for most situations.

4. Save the Report

346 14: Reports


Once the report is in the Collection variable, it needs to be saved to the server and then displayed in a
browser window using a special URL that will call a server program to display the report. Java security
prohibits directly putting the report contents into a browser window, so the server route is required.
First build a standard SaveReport command. Click on the Reports tab in the Command Builder window.
! If you are using the Corvid Applet Runtime, enter the URL for the Corvid Report Servlet. This will be
something like: http://www.myserver.com/CorvidRpt/corvidreportservlet.
! If you are using the Corvid Servlet Runtime no external servlet is needed to save the report
The main location for stored reports is specified by the CorvidReport.cfg file. Optionally, you can next enter a
subfolder name. Subfolders provide a way to organize the report files that are created. This can be useful
when there are multiple Corvid systems that build reports.

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.

5. Display the Report


The final step is to display the report.
For the Corvid Applet Runtime, change the “Program to Call” at the top of the “Report” tab to the ExsysFop
program on the server. This will be something like: http://www.mysite.com/ExsysFop/exsysfop. (NOTE: for all
non-PDF reports, you would call the same CorvidRpt/corvidreportservlet as used in the SaveReport.
Only PDF files require calling the special ExsysFop to do the FO to PDF conversion.)

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.

14: Reports 347


14.7 Cannot Put .cfg File in WEB-INF
CorvidRpt and ExsysFop must know where the report is located. Normally, this is done by putting a
CorvidReport.cfg file into the WEB-INF folder. If the ISP does not allow this or if using a servlet container,
such as IBM WebSphere, which does not explode (unzip) the war file, then the .cfg file must be put inside
the .war file. Here are the instructions.
1. Create a new empty folder, such as C:\scratch.
2. Copy the 'CorvidRpt.war' or 'ExsysFop.war' file to that folder.
3. Open a Command Prompt window in that folder. (Start - All Programs - Accessories - Command
Prompt)
4. Type cd and the path to the new empty folder. For example:
cd \scratch
5. Type one of these:
jar xvf CorvidRpt.war
jar xvf ExsysFop.war
If jar was not found, specify its path. Jar is included in the Java JDK, which is free from
http://java.sun.com.
6. Put the 'CorvidReport.cfg' file in the WEB-INF folder that was created.
7. Type one of these:
jar uvf CorvidRpt.war WEB-INF\CorvidReport.cfg
jar uvf ExsysFop.war WEB-INF\CorvidReport.cfg
8. Type: exit to close the Command Prompt window.
9. The war file has been modified. Deploy the modified war file to the server.

348 14: Reports


Chapter 15: Running and Fielding Systems
15.1 Running a Corvid System
A Corvid system can be run and fielded several ways. In the development environment, a system can be run
(and fielded) as a:

! 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.

See Chapter 2 for more details on applets vs servlets.

To run a system from within the Corvid development


environment, click the blue “Run” triangle. By default, Corvid will
run the system as a Java applet using the default Exsys Corvid
HTML page and the Corvid Browser program.

15.1.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.

To select which mode to run in, either:

1. Under the “Run” menu, click either “Run as Applet” or “Run


as Servlet”. When the blue run triangle is clicked, the system
will run in whichever mode is selected.

You can also select to run with the trace options turned on by
clicking the “Run with Trace” to select it.

15: Running and Fielding Systems 349


2. In the menu bar, click on the “Properties” icon

In the window that opens, click the “Test


Run” tab. At the top there is a “Run As”
section. Click “applet” or “Servlet” to select
the mode to use. (There is also the option
to run as an “Application” which is not
available under the “Run” menu)

Trace can be turned on by checking the


“Run in Trace Mode” or “Enable Trace”
checkboxes.

15.2 Running as a Java Applet


Running a Corvid system as a Java Applet is the easiest approach to use when building and fielding systems.
Systems can be run in any standard browser window, both locally and when fielded over the web. Corvid
automatically builds all the required files. Just double clicking on the HTML page for the system will run it
locally, or when the required files are put on the server, it can be run the entering the URL for the HTML page.

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.

350 15: Running and Fielding Systems


The Controls on the ”Applet” tab set how the
system how the applet window will be
displayed in the HTML page.

Title and Author


A title and author for the system can
be entered. These are not normally
displayed in the runtime, but identify
the system when it is opened in the
development environment.

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”.

Applet Size and Position


The “Runtime Applet” box provides a way to specify the size and position of the Corvid Java Runtime
applet. The position on the HTML page is governed by the HTML command on that page, but the
actual space allocated to the applet is controlled by the applet call. The size to use is largely
determined by the design of the User Interface controls to ask questions and present results. The
applet will use scroll bars if graphics do not fit, but it is often better to choose a size for questions that
will work without scrolling. Some systems take a large part of the screen, others only ask short
questions and have simple results. The applet can even be a small ”banner” size window provided
the formatting has been designed for this size.
The “Width” and “Height” specify the applet window size in pixels. The “Align” option controls how
the applet will be aligned on the HTML page. The “VSpace” and “HSpace” control the spacing
between multiple applets on the window. This usually only applies to the trace applet and can
generally be left at the values of “0”.

15: Running and Fielding Systems 351


The HTML Templates
Corvid automatically generates a HTML page to run a system. By default, this uses the Exsys Corvid
template file “Corvid_Run_Template.HTML” . This file is installed with Corvid in the “Program Files/Exsys/
Corvid” folder.
The HTML pages that run Corvid systems as Java Applets include an “Applet” tag in the page. This is what
generates the Applet Window on the page. An actual Applet tag looks something like:

<applet code="Corvid.Runtime.class" name="CorvidRuntime"


archive="ExsysCorvid.jar" width=700 height=400 hspace=0 vspace=0
align=middle>
<param name="KBBASE" value="">
<param name="KBNAME" value="MySystem.CVR">
<param name="KBWIDTH" value="700">
The expert system would be running here but your browser has Java Applets
disabled or does not support Java Applets.
</applet>
While a full applet tag can be written by hand and included in a HTML page to run a system, it is much easier
to have Corvid use a template file and build the tag for you. This automatically sets the portions of the tag
that reflect the system name, or the various options set in the “Properties” window, “Applet” tab.
Corvid templates for applets are just standard HTML pages, but include the special text
“CORVID_RUNTIME_APPLET” wherever the actual applet tag should appear. Corvid will automatically parse
the template and replace the “CORVID_RUNTIME_APPLET” with the applet tag appropriate for the system
and the applet properties that were set.
Opening the “Corvid_Run_Template.HTML” file in a browser will show:
The text “CORVID_RUNTIME_APPLET”
can appear in the page as any displayed
text. It does not matter what size, font or
color the text is, however any positioning or
CSS positioning that applies to the text will
also apply to applet tag. The rest of the
page can be created using any standard
HTML commands and have any design or
look-and-feel that is preferred.
When Corvid runs a system, the template is
used to build a new HTML page “mySystem.html”, where “mySystem” is the name of your Corvid system.
This page will have the actual applet tag required to run your system. Once that page is built, the system can
be run by simply opening that page in a browser. The template files are ONLY needed in the development
environment to build the actual system HTML page.
Corvid always uses the “Corvid_Run_Template.HTML” file to run systems unless another template is
specified. The “Corvid_Run_Template.HTML” file can be modified with a HTML editor, or it can be copied and
modified to make a HTML template file for a specific system or with a specific look that is preferred for a group
of systems.
To use a different template file, go to the “Properties” window, “Applet” tab.

352 15: Running and Fielding Systems


In the “Applet Runtime HTML
Template” section, enter the name
of the template in the “Use
Custom” edit box, or click the
“Browse” button and select the
template. This should be a
template file with a
“CORVID_RUNTIME_APPLET”
text in it that will be replaced by
the actual applet tag for the
system. Since this template will
be used to build the actual HTML
page for the system which will be
named “MySystem.HTML” - DO
NOT name the template
“MySystem.HTML” (where
MySystem is the name of your
system).
If you wish to have the template share the same name as the other system files, using MySystem.tpt is a
good choice. This allows it to build the HTML page without conflict and still identifies it as one of the
system files.
Another option is to run a system with a static HTML page that is NOT a template and which contains a full
applet tag. This is generally not as convenient since changes in the “Properties” window will not be
automatically reflected in the system. The usual approach is to build a HTML page to run the system from a
template and then edit that page to add any special features or options. However, make sure to rename the
HTML page, since the page MySystem.HTML is automatically regenerated each time the system is run and
any changes would be lost.

To select to run with a static HTML page, open the


“Properties” window and select “Test Run”.
In the “Specific URL” section, enter or browse to
the HTML page to run the system. (This is most
often used with the Corvid Servlet Runtime to push
files to a location where they can be run with a
URL that calls the Servlet Runtime.)

15: Running and Fielding Systems 353


Corvid Browser vs Other Browser
By default Corvid uses the “Corvid Browser”
program to run systems. This is a very simple
browser. It functions to display HTML pages, but
does not have the normal browser navigation
options and does not support some of the more
advanced HTML options.
For simple pages, Corvid Browser works well,
however for more complex pages it is better to
select a full function browser. It is also a good idea
to always test web based content on various
browsers.
To select to run with a different browser, select the
“Properties” window, “Test Run” tab.
In the “Specific Browser” section enter the full path to a browser program or click the “Browse” button and
select a browser program such as Internet Explorer, Firefox, Safari or any other browser program on the
computer. When Corvid runs the system, it will build the files and call whatever browser is specified. To
return to the Corvid Browser, click the “Default CORVID window” radio button.

15.2.1 Running as a Java Application


Running a Corvid system as a Java Application is an alternate way to run systems. A Java application runs
like any other executable on the computer. An application is not as easily distributed via the web as an applet
(which just runs in an HTML page). However, Java Applications are not subject to some of the Java security
rules about reading and writing from the local computer file system. This is because, unlike web delivered
systems, applications must be explicitly started on the computer like other programs.
Certain Corvid commands that do not apply to Applet systems can be used when running as an application.
(See section 9.9.3 an 9.9.4 for commands to execute other programs and write files that require running as an
application.)
To run as a Java Application, open the
“Properties” window, “Test Run” tab and select
“Application”.
Then click the “Select Java.exe” button. This
will open a widow to browse the files to select
the file “java.exe”. (Make sure to select
java.exe, not javaw.exe or other programs)
On a MS Windows machine, this will probably be in:
Program Files -> Java -> Either jdk... or jre... -> bin
If the computer does not have java.exe, it can be downloaded for free from http://www.java.com. Just look for
the “Download” link.

354 15: Running and Fielding Systems


That is all that is needed to run as an
application. Click the same blue “Run”
icon to run the system.
The window running the system will
look and run exactly like the applet
window portion of the HTML page
when running as an applet. However,
there will not be any HTML outside of
the applet window, and the system will
not be running in a browser window.
The “Test Run” options for HTML
template, browser, etc have no
meaning when running as an
Application.
A second window will also be
displayed. This is the Java window
and it can be used for trace messages.
In MS Windows, this is a black “DOS”
window. If a finished system is fielded
as a Java Application, the Java window can be hidden, but it is quite useful during development since it can
display various trace and error messages.

15.2.2 Corvid Servlet Runtime


The Corvid Servlet Runtime is the other way to run systems. The servlet is the recommended way to field
system and it is easy to do all development using the servltt runtime, only switching to the applet runtime if the
more extensive trace feature is needed.

15.2.3 Other Controls


UNDO
When running a system, the Corvid Runtime
allows the user to step back either with the “Back”
button in the applet window, or the Browser “Back”
button if using the Servlet Runtime. To support
“Back”, the Corvid Runtime must maintain data
about the session for each question that is asked.
This takes up memory and increases resource
utilization. Corvid sets the default number of
steps back the user can take as 5. This can be
changed to any value. If unlimited steps back
should be allowed, click the “Unlimited” option in
“UNDO Levels”. If some number other than 5 is
preferred, just enter the number in the edit box.
Normally even unlimited backup steps is not a problem, but for large systems, or when running on hardware
with limited resources (e.g. a palmtop computer such as the iPAQ), the number of steps “Back” should be
limited to reduce resource use.

15: Running and Fielding Systems 355


Testing without Database or External Calls
Corvid systems can get data from databases or
other external sources. However, during
development these sources may not be available,
or the system may be run locally and not
connected to server resources. Rather than
removing the external and database commands
to run in this environment, they can be disabled
simply by selecting the “Do NOT make database
or other external calls” checkbox on the the “Test
Run” tab. In this case, all variables that would
normally get their value from a database or
external source will be asked of the end user
instead.

Extra PARAM to Pass Data


One of the ways to set a value for a variable is to
pass its value in when the applet is called. This is
done through PARAM. Open the “Properties”
window and select the “Param” tab.
When an applet is added to an HTML page,
various named identifiers can be given values that
can be accessed from within the applet. When
Corvid builds the call to the applet it uses this to
provide certain information to the applet such as
the name of the knowledge base to run.
The applet call will have a line similar to:

<PARAM NAME = "KBNAME" VALUE


= "my_system.cvR">
This assigns the value “my_system.cvR” to an identifier “KBNAME”. The applet can obtain the value of
“KBNAME” to know what system to run.
In addition to the PARAM that Corvid automatically adds, you can add others to pass in values for variables. If
the NAME specified is the name of a Corvid variable in [ ], the value from the PARAM command will be used,
instead of asking the user.
For example, if there is a Corvid variable [USER_NAME], adding:
<PARAM NAME = "[USER_NAME]" VALUE = "Bob Smith">
Would cause the runtime to assign “Bob Smith” to the variable [USER_NAME].
NOTE: The [ ] must be used around the variable name in the PARAM line.
Adding PARAM lines is done in the development environment to emulate the applet call being dynamically
built on an HTML page during runtime and passing in data. If the goal is just to assign a value to a Corvid
variable, there are much easier ways to do it from within Corvid. The PARAM lines provide a way to pass
data using dynamically built HTML pages created through Java Script or an HTML page content manager
(such as Cold Fusion). These pages can obtain data from databases or other sources before the applet is
called. This data can then be passed into the Corvid system. For example, based on a users login, there
may be certain data on the user available from a database. This information could be passed directly into the
application without Corvid asking it of the user.

356 15: Running and Fielding Systems


To add a PARAM line:
! Enter the full PARAM line in the edit box at the bottom the area labeled “Extra Corvid Runtime
Params”.
! Click the “Add” button to add it to the PARAM list.
To delete a PARAM line:
! Select the line to delete by clicking on it.
! Click the “Delete” button.
To edit a PARAM line:
! Select the line by clicking on it and click “Edit” or double click on the line to edit.
! This will move the line to the edit box.
! Make changes and click “Replace” to replace the old line with the edited one, or “Add” to add the new
line while keeping the original one.

Adding Other HTML Code


Sometimes it is desired to add other HTML code following the applet call. This is usually due to adding
another applet that the Corvid Runtime will communicate with. Any time additional HTML is required, creating
a Custom Template file to build the runtime HTML screen is an effective way to implement it. However, if it is
preferred to use a template to build the screen or the added applet call frequently changes, it may better to
add the extra HTML lines.
Open the “Properties” window and select the
“Other HTML” tab.
To add a HTML lines:
! Enter the HTML code in the edit box at
the bottom the area labeled “Other
HTML to Add After Applet”.
! Click the “Add” button to add it to the list.
To delete an HTML line:
! Select the line to delete by clicking on it.
! Click the “Delete” button.
To edit an HTML line:
! Select the line by clicking on it and click “Edit” or double click on the line to edit. This will move the line
to the edit box.
! Make changes and click “Replace” to replace the old line with the edited one or “Add” to add the new
line while keeping the original one.

15: Running and Fielding Systems 357


15.3 Corvid Files
A Corvid system is made up of several files. Some of these only apply to certain run modes or delivery
environments. For a system named “kbname”, there will be the following files:
kbname.CVD - This is the main development file for the system. This file has all of the information on the
system logic, variables structure. The CVD file is required to edit or modify a system using corvid.exe. It is
equivalent to the source code for the system. The CVD file is NEVER needed for distribution of a system
and should NOT be moved to a server or other location where it can generally accessed.

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.

358 15: Running and Fielding Systems


15.3.1 Files Required to Field a System

Delivery Mode Files Required

Applet Runtime (Local on Web) kbname.CVR


kbname.HTML
ExsysCorvid.jar
Image and Data Files (As needed)

Java Application (Standalone) kbname.CVR


ExsysCorvid.jar
java.exe (installed on computer)
Image and Data Files (As needed)

Servlet Runtime (on Web) kbname.CVR


Tomcat (or equivalent)
Corvid.war (installed)
Image and Data Files (As needed)
Servlet Template files (As needed)

15.4 Moving an Applet System to a Web Server


Moving a system that uses the Corvid Applet Runtime to a web server is quite easy. The files you will need to
move to the server are:
! ExsysCorvid.jar.
! Your_Kb.CVR (You do not need to move the .CVD file).
! Any image or data files called by your system.
Java security restricts what directories an applet can read. This makes Java a very secure environment, but does
require that files be arranged appropriately. A Java applet can ONLY access files in the same directory as the
applet’s Server directory or in directories below that directory. Consequently, it is usually best to put ExsysCorvid.jar
in a directory and create a subdirectory off that directory for all the other files specific to the system. (Alternatively,
they can all be put in the same directory, but if there is more than one system, this can get confusing.)
The applet call will need to be edited to reflect the locations on the server. Whenever Exsys Corvid runs in
the development environment, it builds a HTML page with an applet call that works on the development
machine. A typical applet call in the development environment looks something like:
<APPLET
CODE = "Corvid.Runtime.class"
NAME = "CorvidRuntime"
ARCHIVE = "ExsysCorvid.jar"
WIDTH = 600
HEIGHT = 450
HSPACE = 0
VSPACE = 0
ALIGN = middle
>
<PARAM NAME = "KBNAME" VALUE = "kb_name.CVR">
<PARAM NAME = "KBWIDTH" VALUE = "600">
</APPLET>

15: Running and Fielding Systems 359


This can be moved to a server provided the ExsysCorvid.jar file and system .CVR files are in the same
directory as the calling HTML page.
To simplify moving systems to other directories and servers, it is recommended that the .Jar, .CVR and calling
HTML page all be in the same directory. This will make moving systems MUCH easier and the KBBase and
Codebase lines are not required in the applet call.
If the ExsysCorvid.jar file must be kept in a different directory, a “CODEBASE” path can be added to its
location. This will be a HTTP address, rather than the local FILE address. This would be something like:
CODEBASE = http://www.mysite.com/Corvid
Likewise the location of the system CVR file needs to be specified the same way.
<PARAM NAME = "KBBASE" VALUE = "http://www.mysite.com/Corvid/MyDir/" >
With these changes, you should be able to run the system from any directory on the web server.
NOTE: Exsys Corvid always copies the current runtime program (ExsysCorvid.jar) to the directory
with the CVR file and builds the HTML page in that same directory. This makes the KBBase and
Codebase lines unnecessary. While generally not required, the KBBase and Codebase functions
are still supported and can be used. They are automatically added to the applet call, but are
commented out. If needed, convert “DELETE_CODEBASE” to “CODEBASE” and remove the
“<!-- -->” around the KBBase parameter.
It is a Java requirement that the CVR file MUST be in the same folder or a sub-folder from the JAR file.
For example, if the directory structure of drive C is:
Drive C
|_ MyFiles
|_ ExpertSystems
|_ System1
|_system1.CVR
|_ System2
|_ System3
To run a Corvid application system1.CVR from the directory System1, either:
1. Put the HTML page with the applet call, the ExsysCorvid.jar file and the .CVR file all in the System1
folder and remove the CODEBASE and KBBASE lines from the applet call.
2. Put the ExsysCorvid.jar file in the ExpertSystems folder. Put the HTML page with the applet call and
system1.CVR in the System1 folder and either:
! Make the CODEBASE = "C:Myfiles\ExpertSystems", and KBBASE= "System1\".
! Make the CODEBASE = "../", and KBBASE= "System1\".
If there are several expert systems, updating is easier when there is a single JAR file in a parent directory.
Also, if multiple systems are likely to be run in the same session, having a single JAR file will allow it to be
cached and downloaded only once.
If there is a problem running a system, open the browser’s “Java Console” window. If it reports a “Security
Exception”, it is probably because the files are not arranged appropriately. Check that the system files are in
the same folder or a sub-folder from ExsysCorvid.jar and that the applet calls are correct for your server. If
you are running on UNIX remember that file names are case sensitive. Check that all filenames and paths
exactly match.

360 15: Running and Fielding Systems


15.5 Running Standalone
Exsys Corvid systems can be run in a batch mode to process data from external sources, or in situations
where it is better to run as a Java application rather than an applet.
When a Corvid system is run “standalone”, it can mean two different things:

Standalone as an Applet in a Browser


Typically, a Corvid system is run from a Web server that uses a URL to call a HTML page that runs the system
on the client machine. The client machine downloads the applet, the knowledge base CVR file, and any other
image, data or link files required from the server. These are then run in the client machine using Java.
As long as all the files are all on a local machine, it is NOT necessary to have a server and the same files can
be run locally by the Browser program. The files required are:
! ExsysCorvid.jar - the Corvid Java Runtime.
! Kb_name.CVR - the system knowledge base file, where kb_name is the name of your system.
! Kb_name.HTML - the HTML page to run the system. Corvid automatically builds this.
! Any image, data, MetaBlock or linked files that the system uses.
The .CVR file must be in the same directory as the ExsysCorvid.jar or a directory below it. Make sure that the
path names specified are correct. Usually this is best done by putting all the files in a single directory and just
using the file name without a path. All filenames will be based off the directory to the ExsysCorvid.jar file.
Linked HTML pages can be anywhere, even across the Web provided that the browser has a Web connection.
To run the system locally, just start the Browser (with or without a Web connection) and enter the local path
and name of the Kb_name.HTML file. The browser may require that you specify the file with a full path
starting with drive ID (e.g. “C:\my_kb\my_system.html”). Do not use “HTTP:” if you are running locally. (It is
often easier to just double click the HTML page which should start the Browser program with the address of
the page. Then just copy the address from the browser.)
For frequently run systems a shortcut to the HTML page can be created that will call the browser and run
the system.

Standalone as a Java Application


Java makes a very important distinction between “applets” and “applications” - even though the same
program may function both ways. An applet is a Java program that can run in a browser. This is designed to
be part of an HTML page. Since such applets can suddenly start running on your machine just because you
browsed to a page, Java imposes VERY strict security limitations on what an applet can do. An applet cannot
access the files on your local machine - it cannot read or create files on your local hard disk, and cannot
access the printer. This protects you from destructive programs that would otherwise be possible via applets,
but it does limit what an applet can do. It is these limitations that prevent the Corvid applet from being able to
write local files or directly print reports.
Fortunately, Java provides another way to run programs as “applications”. These are run outside of a browser
and are installed and run like any other program on your computer. Since the user has control on running an
application, it is not subject to the same security restrictions as an applet, and can access local files and other
programs on the computer. This enables it to be used to process batch data and write reports.
A Java program can be designed to be run both as an applet or an application, depending on how it is started.
Exsys Corvid is designed to run both ways. See Section 15.1.2 above on running as an Application.
To run a Corvid system standalone as an application, you will need a Java virtual machine. To check for this,
search your computer for "java.exe". If you do not find this, you can download the program for free from
www.java.com.
To run Corvid as an application, use the command:
java -cp ExsysCorvid.jar Corvid.Runtime path CVR_file
where "path" is the full path to the directory the CVR file is in. cvr_file is the name of the CVR file, with

15: Running and Fielding Systems 361


the .CVR extension. NOTE: there is a space between the path and the cvr file. The path will be used as
the base directory and all references to files for images, etc will be made off this base path. For example, to
run "My_system.cvR" located in "c:\my_apps":
java -cp ExsysCorvid.jar Corvid.Runtime c:\my_apps\ My_system.CVR
NOTE: If the path has spaces, it will be necessary to put it in quotes. Since \" is a special character in
Java, you must end with \ " (A back slash, a space and a quote)
Applications running standalone will terminate and exit:
! when the EXIT command is executed
! when the end of starting Command Block is reached
The command to run the system can be used as a shortcut to start the system, or it can be added to a batch
file that runs the system along with other operations.

15.6 Embedding Corvid Systems in Emails


In addition to being able to generate an email from a Corvid system, a Corvid system can be embedded within
an email. This allows a new level of interactive content and fast recommendation/problem-solving response
for emails. Potential customers can be sent product selection expert systems that will assist them in making
purchasing decisions. They can be used in auto-reply emails for technical or product support as first-level
help desk response. Also, Exsys Corvid W.I.N.K.™ (What I Need to Know) systems can be emailed allowing
the recipient to select the information or content that is most appropriate to their needs. The user can interact
directly with the Corvid system in the email without having to link off to another site.
Embedding a Corvid system is quite easy to do provided the email includes HTML and the recipient can
accept HTML emails. They can be handled as HTML elements, included in tables, etc. All that is required is
to embed a Corvid applet call within the email with the location of Corvid applet referenced correctly.
To do this:
1. Build a system using Corvid and select to run it as an applet.
2. Use Notepad, or a similar editor, to open the file generated by Corvid named Kbname.HTML, where
Kbname is the name of your system.
3. Copy the actual applet section. This is the section between the <applet> and </applet> tags. It
should look something like:
<APPLET
CODEBASE = "./"
CODE = "Corvid.Runtime.class"
NAME = "CorvidRuntime"
ARCHIVE = "ExsysCorvid.jar"
WIDTH = 700
HEIGHT = 400
HSPACE = 0
VSPACE = 0
ALIGN = middle
>
<PARAM NAME = "KBBASE" VALUE = "" >
<PARAM NAME = "KBNAME" VALUE = "Kbname.CVR">
<PARAM NAME = "KBWIDTH" VALUE = "700">
The expert system would be running here but your browser does not support Java Applets.

</APPLET>

362 15: Running and Fielding Systems


4. Normally the applet parameter "CODEBASE" provides the path from the server location of the HTML
page containing the applet call to the location of the ExsysCorvid.jar file. These are typically in the
same folder, so the normal CODEBASE is "./" which indicates they are in the same folder.
Place the ExsysCorvid.jar file and all system files on your server just as if they were to be opened by
a normal HTML page. You should be able to run the system by going to the kbname.html page on the
server. In an email, there is no base HTML page, so there is no server location to work off of.
Consequently, the CODEBASE parameter must be the full path to the location of the ExsysCorvid.jar
file on the server. For example:
CODEBASE = "http://www.myserver.com/mySystem"
Notice that the CODEBASE should start with "http://" and specify the folder where ExsysCorvid.jar is
located. (The Corvid Runtime will automatically look for the ExsysCorvid.jar file in that folder.)
Also, the location is stated in terms of the Web server, not the actual directory structure of the server.
The "http://www.myserver.com" references a folder on the server that may be many levels deep in the
actual directory structure. In the example, "mySystem" would be a folder in that directory. This is
exactly the same as referencing a page or image on the server for use in a Web Site.

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.

15: Running and Fielding Systems 363


Chapter 16: Testing and Debugging a System
16.1 Testing
Any Corvid system should be extensively tested before it is distributed. Even seemingly simple logic can have
errors due to not considering all situations, typographical errors and many other sources. The nature of Corvid
expert systems that can analyze many different combinations of user input to provide situation specific advice
makes testing a system thoroughly a challenge. Corvid has built-in features to automate and simplify testing.
The most direct way to do tests is simply to run the system many times with different combinations of input
and make sure the conclusions are what is expected. For small systems this may be enough to assure that a
system is working correctly. However, as systems get larger, it becomes more difficult and time consuming,
and the automated validation features become more effective.
When testing, be sure to enter values that are the likely problem areas:

! 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.

16: Testing and Debugging a System 365


16.2 Check System
Corvid provides two ways to simplify testing. The first is a “Check System”
option that examines a system for likely problems. This looks for errors or
logical structures that are suspicious. It does not actually run the rules (that is
done with Validation), but checks the individual rules and structures. It is a
good idea to occasionally run “Check System” while building a system and it
should always be run when a system is completed. To run “Check System”,
select “Check System” under the “Run” menu.
“Check System” looks for:
! Variables that are defined but never used: It is not
an error to have an unused variable, but it often
indicates that some intended function or logic
associated with the variable never got added
! Static List variable values that are defined but
never used: These too are not always an error, but
suggest something may be missing. In some cases,
certain values may be in the value list for
completeness, but don’t really have any logical
meaning or implication in the system.
! Static List value groups that do not cover all
values: For example, if a Static List variable has 3
possible values, but branches were only created for 2 of them. This also is not always an error, but
should be checked.
! Incomplete rules that have an IF part without THEN: Having an IF with no THEN is allowed, but
often indicates incomplete logic. In a Logic Block, these branches would also be highlighted in red.
When there are many trees, or large trees, Check System is a quick way to find any incomplete rules.
! Illegal variable names: This is always an error and should be corrected. Normally the Corvid syntax
checker will prevent including undefined variables, but the syntax checker can be overridden with “Use
Anyway” or embedded variables that are used without syntax checking. If Check System finds any
illegal variable names, they should be corrected.
! Mismatched square brackets: This is always an error and should be corrected. This is also
checked by the Corvid syntax checker, but can occur if that is overridden.
If any potential problems are found, Corvid will display a window describing them.
Any displayed warning should be checked and either confirmed to not be an error or corrected.
The list of warnings can be printed for later use by clicking the “Print” button.

16.3 Validation Testing


Validation testing is an automated way to run large numbers of tests on the
actual logic of a system to check for many different types of problems. Unlike
“Check System” which just looks for suspicious structures in the logic,
Validation actually runs the rules with various data sets to reach actual
conclusions.
Even a medium size system can have hundreds of thousands of possible
unique combinations of input – far too many to attempt to input individually by
hand. Corvid’s validation function enables automating very large numbers of
tests, along with setting various warning tests to check for specific types of
issues in the system. Validation testing also allows a specific Logic Block or subset of a system to be tested,

366 16: Testing and Debugging a System


allowing thorough testing of even large systems.
Once the parameters for the validation test are set, the tests run automatically without additional user input.
Corvid will display the number of tests that will have to be run based on the selected parameters, and will
display the progress as the tests are being executed. For larger tests, they can be allowed to run over night
or longer as needed. A file is generated with any errors and problems that are detected and special system
warnings that are generated.
The validation test parameters can also be saved to a file, so that the same tests can be run again later to
check any modifications to the system.

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

16: Testing and Debugging a System 367


forward chaining, or selecting only certain goal variables and using backward chaining. Based on what is
selected, there will be associated variables. Each variable can be set to use only a single, or subset of
values. For numeric variables, values can be selected to test over a specific range. Corvid automatically
displays the number of test cases as the variable values are chosen to give an idea of how long the
validation test would take. Selecting the variables carefully allows sections of even complex systems to be
tested thoroughly.
While automated validation tests are not appropriate for every situation, they are a powerful tool to use in
testing a system - and MUCH faster than trying to test by hand.

16.3.1 Selecting the Portion(s) of the System to Run


The Run Mode controls in the upper left of the Validation window determine how the rules will be tested. Ideally,
validation tests are run on the entire set of rules in a system, and that should be done when possible. However,
in many cases, testing the entire system would take too long, and individual sections can be tested
independently.
For example, a specific Logic Block may be used to set the value for a variable based on user input. It may
be easier to test this block separate from the rest of the system to make sure it is always setting the valid
values. This allows focusing on this detail without the influence of the rest of the system. Once that part is
validated, the variable’s value can be used to test other sections without repeating all the lower level tests.
The Run Mode options are:
! Run specific Logic or Action Blocks in forward chaining.
! Use backward chaining to derive the values of the variables selected for output.
! Run a specific Command Block.
Forward Chain Logic / Action Blocks
This option allows one or more Logic or Action blocks to be selected to run using forward chaining. The rules
in each selected block will be tested in the order they occur in the block. This is useful for systems that run in
forward chaining to set the value for one or more variables. This mode is often a good choice for systems that
only use Action Blocks since those are always run in forward Chaining. If a system is structured so that
individual Logic or Action Blocks perform independent functions, they can often be validated independently. If
a system uses backward chaining, or uses many Logic Blocks to set the values of individual variables, one of
the other Run Modes should be selected.
! Click the “Forward Chain Logic or Action Blocks” radio button.
! The list below the button will display all the Logic and Action Blocks in the system.
! Click one or more Logic/Action Blocks. (Use Shift-Click and Ctrl-Click to select multiple blocks).
As blocks are selected, Corvid will automatically display the list of all the variables used in the IF conditions in
those block(s). These are all the IF variables that are used in the selected the block(s) and are the only
variables needed to test the block(s). The test values for those variables can then be set.

Derive Output Variables


This mode allows full control over what variables will be tested and what variables will be derived. It uses
backward chaining to derive the values for the variables selected in the “Output” section at the bottom of the
window. Since any of the variables in the system may be needed to derive certain other variables, the full set
of variables can be used for the tests.
! Select the “Derive Output Variables” radio button.
! In the “Output” section, select the variables that should be derived via backward chaining. This can be
groups of variables (e.g. all confidence variables) or specific variables.
When this option is set, Corvid will display all the variables in the variable list in the middle, allowing complete
flexibility in setting variables that may be needed by the logic, or to be passed to external programs. However,
based on the developers knowledge of the system, variables that are not actually needed to directly derive one

368 16: Testing and Debugging a System


of the output variables can be locked at a single value and will not needlessly increase the number of test cases.

Run a Specific Command Block


This is the most powerful of the modes, since it allows full control on the range and scope of the validation
tests. Usually, a special “Validation Command Block” should be created that can combine running specific
blocks, deriving variables and other operations as needed. Sometimes this is just a modified version of the
Command Block used for normal runs.
To add a special Command Block of commands to use for validation, just build the Command Block like any
other Command Block, but do NOT make it the Starting Command Block. When running in validation, Corvid
will let you select a temporary Starting Command Block which will call this block.
NOTE: If the commands in the block include “DISPLAY”, or “ASK” commands, this will cause the
system to pause while those commands are executed. This can be used to watch runs one at a time,
but if a continuous batch run is desired, these commands should not be used. DERIVE commands
can be used to get values. ASK is not needed, since if the value of the variable is needed, it will be
obtained from the validation data file.
The temporary Validation Command Block will automatically handle sequentially reading data from the data file
and writing out results to the output file. DISPLAY or other output commands are not needed. Your custom
Command Block should ONLY include commands to execute the rules and set the values of variables.
! Click the “Run Command Block” radio button.
! Select the block to run.
Corvid will display all the variables in the variable list to set values for the tests.

16.3.2 Set the Value Ranges for Each Variable


The next step is to select the variable values that Validation will test across. This will determine the number of
test cases needed for the validation tests. The number of values to test across should be kept as small as
practical, but still cover the values needed for a worthwhile set of tests.
The number of possible test cases are the product of the number of values selected. If there are 3 variables that
have 3, 4 and 5 values each, the number of test cases to test all combinations are 3*4*5 or 60. If there are 10
variables with 2 values each it would take 2*2*2*2*2*2*2*2*2*2 or 1024, test cases test all possible cases.
Corvid displays the number of test cases at the bottom of the “Set Value Ranges for Variables” controls.
When the number of test cases starts to get large, the message will become red. This is not an error, but
indicates that the number of test cases is getting large and will take some time to run.
The top left window in the “Set Value
Ranges for Variables” section lists the
variables that can have values set.
If the “Forward Chain” selected blocks
option was chosen in for the “Run
Mode”, the list will be limited to only
the variables in the IF conditions in
those Logic Blocks. If for some
reason, additional variables are needed (such as for embedded variables, or variables that are needed in the
THEN part of the rules), click to “All Variables” button to add all other variables to the list.
If the Backward Chain or custom Command Block was chosen for the Run Mode, all the system variables will
be displayed in the list.
To set the values to test across, click on a variable in the list and then set its test values. Any variable whose
value will be needed to run the tests should have at least one value set. If a variable does not have any
value set, and it is needed to run the system, Corvid will ask for the value when the system runs. This
will stop the run until a value is entered. If a variable is asked, it should be assigned a value in the Validation
Test window so that the tests can run uninterrupted.

16: Testing and Debugging a System 369


In some cases where a variable’s value can be derived from other rules through backward chaining, the “Derive
value from other rules” radio button can be selected. This may require adding other variables to the list.
The value options for setting the value depend on the type of variable. The variables most often used for
validation tests are Static List and Numeric. Other variable types such as String and Date generally are not
used to drive the logic of a system and can be assigned a single value.

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

Other Types of Variables


For all other types of variables, enter a single value in the Single Value edit box. Corvid does not allow testing
across ranges for string or date variables. These can often be tested by using another variable. For
example, if the number of days between 2 dates is used in the logic, work with the numeric variable that has
the “number of days” value and test that over ranges. Validating that this variable is correctly getting its value
from 2 dates can be checked by hand.
Dynamic List variables are more difficult to use in validation since their value list must also be set. Often
testing these requires either emulating them with a static list or modifying the Command Block to preload the
value list before values are assigned.

370 16: Testing and Debugging a System


16.3.3 Select the Output
Validation tests produce a file of information on the test case runs. This is a standard text file that can be
examined and searched with a text editor. The default name for the output file is KBName.ValOutput (where
KBName is the name of your system). This can be changed by editing it in the “Output File” edit box.
When all the test cases have
been run, the output file will be
opened with a text editor. The
default one is Notepad, but this
can be changed by selecting a
different text editor in the “Display
Results With” edit box, or
browsing to selected a text editor.
There are many options for the
content put in the file.
Normally, the output will include
the input values used for the specific test case. In addition it can include the values set for:
! All Static List, Dynamic List, Numeric, String and Date variables.
! All Confidence Variables.
! All Confidence variables over a threshold value.
! All Collection Variables.
! Specific variables that have been added to the “Specific Variables” list.
There are check boxes on the left side of the “Output” section for these options. As many as needed can be
checked. If the Confidence variables over a threshold is selected, enter the threshold value in the edit box.
To output the value for specific variables, select the variable from the drop down list in the “Specific Variable”
section and click “Add” to add it to the list. The specific variables to display will be shown in the list. Variables
can be deleted by selecting them in the list and clicking “Delete”. They can be reordered by selecting a
variable and clicking the “Up” and “Down” buttons to reorder the list. The output will display the specific
variables in the order they appear in the list.
Each test case will display the input values along with whatever data is selected for output. This can be
examined by the developer to make sure the results are correct. It can also be searched using a text editor to
find specific values and look at the input which produced them.
Another way to use the validation file is to generate output that includes all variables. This file can then be
saved. In the future if changes are made to the system, the same validation tests can be run and the 2 output
files compared. Any differences between the file can be used to highlight changes in the system
recommendations due to the new logic.

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.

16: Testing and Debugging a System 371


To add a warning:
! Select the type of test from the radio buttons in the lower right of the “Output” section.
! Enter the parameters needed for that test.
- For Confidence variable tests, enter the threshold value
- For Variable values, for Static List variables, select the value from the drop down list. For all
others enter a value.
- For Boolean tests, enter any valid Boolean test. This can be a complex test using Corvid
variables, AND/OR. Any Boolean expression that could be used in the rules can be used here.
! Click the Add button.
There can be as many warning tests set as desired.
The warnings can be used in addition to the standard output of other variables. The standard output for each
test will display any warnings that trigger. Another way to use warnings is to ONLY include a test case in the
output file if a warning test triggers. To do this check the “Only include Session if there is a Warning”
checkbox. This will cause the validation run to include ONLY sets of input data in the output that produce a
warning. If this checkbox is selected, no input will be produced (even if other Output options are set)
unless there is a warning.

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.3.4 Running the Tests


Once all the test parameters are set, there are a few steps that are needed
before the tests are run.
1. The tests are run using the Corvid Applet Runtime running as a Java
Application. (This is required to have the validation tests create an output file
on the local computer.) This requires that Java.exe be installed on the
computer. If the “Select Java.exe” button has a red border around it, either
Java in not installed, or the path the java.exe has not been selected. Click the
“Select Java.exe” button and browse to where java.exe is located. (This will
probably be “Program Files/java/versionNumber/bin/java.exe, where
versionNumber is the version of Java installed).
If Java has not been installed on the computer, it can be downloaded for free
from Oracle/Sun at http://www.java.com. (This site changes frequently, but
look for the download of the JRE for Windows). Once Java is installed, set
the path to it as described above.
2. When running tests, Corvid creates input and output data files. The
default filenames are kbname.testdata and kbname.ValOutput. These
can be changed if desired by entering new names, or clicking the “Browse”
buttons next to the “Output” and “Data” files edit boxes. However, leaving
the default names is recommended.

372 16: Testing and Debugging a System


3. When the system completes the validation run, the output file is displayed using Notepad to allow
searching. If a different text editor is preferred, it can be selected by clicking the “Browse” button next to the
“Display Results With” edit box. The program chosen should be one that the display text files.
4. Once the parameters are set, click the “Run Tests” button. Corvid will:
! Build a data file with the test cases.
! Corvid will add some temporary variables to the system for validation.
! Add a special validation Command Block to the system and run it in application mode.
! The Java console window will be displayed and show the progress of the system.
! When done the results will be displayed in the display program that was selected.
5. The validation report should always be searched for the word “ERROR” and “WARNING”. Corvid will
automatically include any error or warning message in the output file, regardless of output parameters.
Looking for these words allows quickly finding the input that produced the error. (NOTE: If only sessions
triggering specific warning tests are output, test cases that produced errors, but did not trigger the warning
test will not be output.)

16.3.5 Exit / Clean Up


When done, click the “Exit” button. This will remove the temporary variables and the Command Block that
was added to the system. NOTE: This is important to remove the temporary variables that Corvid
automatically adds to run validation.

16.3.6 Practical Applications of Validation


Validation can be used in many ways. Here are a few examples:
A Corvid system will diagnose a problem and recommend an action to take. This is done using Confidence
variables for the possible recommendations. The system has been designed so that any set of input should
produce at least one Confidence variable with a value greater than 5. To make sure this is true, run validation
to warn if a Confidence variable does not get a value over 5.
! Open the Validation window.
! In “Run Mode” select “Derive Output Variables”.
! In “Output” select “All Confidence Variables”. (If Confidence variables are used for other purposes
than the possible pieces of advice, select the “Advice” Confidence variables individually.)
! Set the ranges for the variables to test over a wide range of possible user inputs. (Remember to
check the number of cases that need to be run to make sure it is not excessive.)
! In the “Warn IF” section, click “No Confidence Variable assigned a value over” and enter “5” in the edit
box. (Again, make sure Confidence variables are not used for other purposes in the system. If they
are it would be necessary to write a more complex Boolean test for the “Advice” variables.)
! Select “Only include session if there is a warning” to have the output only include the problem cases.
! Make sure java.exe is selected.
! Click “Run Tests”.
When done, if any problem cases are reported, check the logic and make any needed corrections.
A system is designed to configure a machine and calculate a price. Expected prices are a few thousand
dollars. A user reports that when they ran the system, it gave a price of only $10, but they can’t remember the
input they used to get the clearly incorrect answer. To find possible causes, follow the same steps as above,
but in step #3 set the system to derive the variable [PRICE], and in step #5 add a “Warn If” Boolean test for
“[PRICE] < 100”.

16: Testing and Debugging a System 373


A system is completed and ready to be fielded, but needs a final test.
! Make a copy of the main starting Command Block.
! Edit the copy to remove ASK and DISPLAY commands.
! Set the Validation Run Mode to run the new Command Block.
Search the output validation file for the words “ERROR” and “WARNING”. If they are found, check the input
that produced them to see why that combination is producing an error.

16.3.7 Save / Load Files


The validation test parameters set can be saved to or loaded from files with the “Save” Load” buttons. This
saves all the parameter for a test so a variety of tests can be easily saved and loaded when needed. Saving
the data allows rerunning the validation tests – however, if a variable’s name or value lists are changed it may
invalidate the saved validation test parameters. If a set of saved parameters is loaded to a system that has
been edited, remember that while it will detect some changes that may have been made in the system, the
values should be checked to make sure they are still consistent with the new system.
To save validation test parameters, click the “Save test parameters” button and select a file name.
To load test parameters, click the “Load test parameters” button and select the file.

14.3.8 Building Custom Validation Command Block (Advanced)


When the “Run” button is clicked, Corvid will build the data file and a custom Command Block to execute the
tests. Corvid adds some temporary validation variables and a special Command Block that will sequentially
read the data file and output the report.
If you wish to build a special validation Command Block to allow you to customize it to run specific validation tests:
! Click the “Run Command Block” radio button in the “Run Mode”.
! Select any Command Block (this will be changed later), here we just want the variable list.
! In the variable list, set the ranges for all variables that will be needed in the custom tests.
! Select a name for the data file and click the “Just Build Data File” button.
! Click the “Just Build Command Block” button. Corvid will display a message that the Command Block
“Validation Test Commands” have been built. Click OK.
! Click the “Exit Validation” button.
! Corvid will ask if the system should be left in Validation Mode. Select “Yes”.
! You will be reminded to return to the Validation window to remove temporary validation variables.
Click OK.
! When the Validation widow disappears, open the Command Block ‘Validation Test Commands”.
! Most of the commands in the block should NOT be modified. The 4th line is an EXEC command. This
command can be replaced by other commands to run your system. The other commands handle
reading and writing data. It is recommended that they not be modified, but they can be for customized
validation functions. However, using the “Run Command Block” option in the “Run Mode” is a better
option for virtually all cases.
! Set the “Validation Test Commands” as the “Starting Command Block” and set the system to run as an
“Application”.
! Run the system.

374 16: Testing and Debugging a System


The output file will be created, but not automatically opened. Open it with a text editor.
When done, reopen the Validation window and click “Exit Validation” to have Corvid remove the temporary
variables and Command Blocks.

16.4 Trace

16.4.1 Trace Applet


Corvid provides a way to run systems in conjunction with a “Trace Applet” that allows examining the status of
variables, rules, Logic Blocks and the goal stack, along with a detailed history of the session.
To use the Trace Applet, the system must be being run with the Applet Runtime. The Servlet Runtime and
running as an Application only support the portion of trace that is the history of the session - not the interactive
examination of variables and rules.
Activating Trace
To activate the Trace Applet open the Properties window
and either:

1. Open the “Test Run” tab and select “Add Trace


Applet / Enable Trace”.

or

2. Open the “Applet” tab and select “Enable Trace”.

These two options are identical and selecting /


unselecting one of the checkboxes will select / unselect
the other automatically.

16: Testing and Debugging a System 375


Running the System with Trace
When the system is run the Trace Applet will
automatically be added under it and communicate with
the system being run.
NOTE: For the trace, the system should be run with
either the default Corvid template or a modified
template that uses the
“CORVID_RUNTIME_APPLET” marker rather than
hard coding the apple tag. Corvid will automatically
add the trace applet along with the applet running
the system to replace the
“CORVID_RUNTIME_APPLET”.

Trace Applet Tabs


The Trace Applet has 4 tabs at the top that allow examining various information about the session. In
addition, the bottom of the window always displays the current Command Block command and current Logic
Block line being executed. In some cases where the Command Block command does not require use of a
Logic Block (such as an ASK or RESULTS command), the Logic Block line may be blank.

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.

376 16: Testing and Debugging a System


Variables Tab
The Variables Tab allows examining both the current backward chaining Goal List and the value of any
variable in the system.

Variables
The “Variables” list in the center of the
window displays all the variables in the
system.

To see the current value of any variable,


just click on it. The current value will be
displayed in the “Value” window and an
explanation of how the value was set will be
displayed in the “How value was set”
window. This can include the value coming
from the end user, external sources,
assignments or rules in the system.
When the value comes from a rule, the IF/
THEN syntax of the rule is changed to
SINCE/THEN since the rule will have had
the IF conditions determined to be TRUE
and will have fired. The SINCE/THEN
syntax is easier to read. Also, even if the rule
had multiple THEN assignments, only the one for the specific variable selected will be included.
The explanation of the how the value was set is the same as the .HOW property for the variable. (When
running with TRACE, the data needed for .HOW is automatically maintained.)
The Variables tab makes it easy to examine the immediate value and status of any variable 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.

16: Testing and Debugging a System 377


Rules Tab
The Rules tab displays the current status
of any rule in the system with the
conditions color coded to indicate if the
they are True, False or Unknown.
An IF condition that has not yet been
determined to be either True or False will
be displayed without a highlight color.

If an IF condition has been determined to


be True, it will be highlighted in green. If
it has been determined to be false, it will
be highlighted in light red.
When the IF conditions for a rule are all
True, the THEN conditions will be
highlighted in green indicating that the
assignments in those condition have or
will be made. Checking the “Logic Block”
line at the bottom of the Trace Applet
window will show if the system is
currently making assignments from that
rule’s THEN conditions. (Normally,
unless the assignments require asking
for user input, all of the THEN conditions
highlighted in green will have been made.)
If the set of IF conditions are False, the
THEN conditions will be highlighted in light red. These assignments will NOT be made since the IF part was
False.

Current Active Rule


If the “Current Active Rule” checkbox is selected, the Rule tab will always display
the rules that are currently being tested (IF condition) or used to make
assignments (THEN condition). This rule will change dynamically as the
system runs.
To examine the status of a specific rule,
uncheck the “Current Active Rule”
checkbox and the “Specific Rule”
options will be enabled.
These allow selecting any rule in any
Logic Block to examine. To select a

378 16: Testing and Debugging a System


rule first select the Logic Block it comes from. Then select the rule in that Logic Block. The rules in a Logic
Block are defined by the line number of the first THEN node for the rule.
So if a Logic block has a rule where the first
THEN node is on line 3 and another rule where
the first THEN node is on line 6, the Rule drop
down will display 3 and 6 for the rules.
Once in a Logic Block, another way to quickly
step through the rules in that block is to click
the “<“ and “>” buttons which will move to the
previous and next rule in the block. This allows quickly examining multiple rules in a system.
Once a specific rule is selected, the Rule tab display will only show that rule until another rule is chosen or the
“Current Active Rule” checkbox is selected.
Selecting a specific rule allows watching that rule as the system runs to check its status during the session.

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.

Logic Block Tab


The most powerful way to examine the status of
a system as it is running is the Logic Block tab.
This displays the actual Logic Blocks in a system
highlighted to indicate what nodes are True,
False and Unknown.
Logic blocks can be selected from the drop down
list or by clicking the “<“ and “>” buttons to select
the previous / next Logic Block in the system.
Nodes are marked with the same bracket and
arrow icons as are used in the Logic Block
development environment. IF nodes that have
not yet been determined to be True or False are
not highlighted. THEN nodes that have not had
the IF associated IF nodes determined to the
True/False are highlighted with a light gray to
make it easier to differentiate IF and THEN nodes.

16: Testing and Debugging a System 379


If nodes that have been determined to be true are highlighted in
green and IF nodes that have been determined to be false are
highlighted in light red. (Same as in the Rules tab.) THEN nodes
that are associated with IF nodes determined to be True are
displayed in green on black and THEN nodes that are associated
with False IF nodes are displayed in light red on black. (The
reverse black always indicates a THEN node).
Selecting a Logic Block during a run allows watching the status of the
node change as the system executes. Details of individual sections
can be examined in more detail in the Rule and Variable tabs.

Action Block Rules


If a system uses Action Blocks, at runtime these are converted
to equivalent Logic Blocks that are processed by the runtime
program. The Logic Blocks created are displayed in the Trace.
While these are logically equivalent to the Action Blocks, they
look quite different in Logic Block form. The individual lines
are converted into separate rules in the Logic Block and “Go
To” statements are converted into fairly complex expression
that cause some of the rules to be skipped when a “Go To”
command is executed.
It can be more difficult to follow the trace with Action Blocks
since there is not an exact correlation with a system Logic
Block. When tracing Action Block systems, the “Variables” tab
is the most useful, though since the IF conditions correlate
with the Action Block, it is still possible to use the “Rule” and “Logic Block” tabs too. Fortunately, Action Block
logic is generally simple and straightforward, and Trace is generally not needed to follow the execution of
Action Blocks.
The TRACE command can be added to the “Action” portion of an Action Block to pause the system at that
point and allow examination of the value of the variables.

The TRACE Command


The Trace Applet allows examining the value of
variables and the state of the rules and Logic
Blocks in a system at a particular point during a
run. However, the Trace Applet is constantly
interacting with the Corvid Runtime Applet during a
session receiving updates on the status. Because
of this, the Trace Applet can only be used when
the system pauses to either ask a question or
display a results screen. Normally this is not a
problem, since it is at these points that the
developer most needs to check on the value of
variables and rules. However, for some systems it
is desirable to be able to pause the session so that
the Trace Applet can be used to examine the
current state.
This can be done with the TRACE command.
The TRACE command is a standard Corvid
command that can be added in the THEN part of
rules or in a Command Block. It is built from the

380 16: Testing and Debugging a System


“Control” tab on the Corvid Command Builder. It allows a string to be added which will be displayed when the
TRACE command is executed. This can be used to identify the specific TRACE command and indicate
where in the system session it is.

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.

Security Issues with TRACE


Since the new Trace Applet allows the user to examine the internal structure of a system it could reveal more
information about the internal working, logic and structure of a system than some developers may want to. To
prevent this, the Trace Applet will ONLY work with a special CVR_TRACE file that Corvid generates when
running in the Trace mode. This CVR_TRACE file contains special data and encoding required by the Trace
Applet. The Trace Applet cannot run with the normal CVR file.

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.

16: Testing and Debugging a System 381


Trace Applet Window Logic Block Refresh
The Trace Applet displays the Logic Blocks using a Java object. This updates the status of the nodes in the
Logic Block quite rapidly and in some browsers, this can cause the text of the nodes to occasionally not be
drawn correctly. This seems to be a Java / browser issue and has only been seen on Safari. If the Logic
Block display appears garbled, click on the “Logic Block” tab to refresh it. This will redraw the display and
should solve any display problems.

16.4.2 Trace to Java Console


When running as a Java application, the trace applet
cannot be used. In this case, the trace messages can
be sent to the Java Console.
! Open the “Properties” window, “Applet” tab.
! Check the “Trace to Java Console” checkbox.
! On the “Test Run” tab select to run as a Java
Application and enter the location of java.exe.
It is not necessary to click the “EnableTrace” box,
though this can be done if you wish to trace both when
running as an applet and a Java application.
When the system is run as an application, the Java
console window will be displayed. The trace messages will be displayed in that window.
Unlike the Trace applet, tracing to the
Java console will not turn red when an
error is reported and does not have the
find buttons. Depending on your
browser, tracing to the console may be
faster than the trace applet, but systems
that produce a large trace (such as
MetaBlock systems) may slow down
considerably with either approach.

382 16: Testing and Debugging a System


16.5 Using .HOW
The .HOW property for any variable displays how that variable’s value was set. This can be from multiple rules.
For example, if a system had a Confidence variable
[Recommendation] whose value was set by 2 rules,
the [Recommendation.HOW] might output:
The .HOW property shows the final value, followed
by the rules that set the value. These If/Then rules
have been converted to “SINCE” / “THEN” statements. Since these rules fired, it is not “IF”, but “SINCE”.
Each “SINCE” is preceded by the Logic Block name and line number in the block of the associated rule.
Using .HOW makes it easy to see what rules fired and set the value for the variable.

.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.

To display the .HOW property for a variable in the results,


open the Results Screen Commands window and in the
“Variables” section click the “Prop” button to use a Property
of the variable.

16: Testing and Debugging a System 383


In the window that opens, select the variable to use and then
click the .HOW property on the right.

This will add a command to display the .HOW property of the


variable in the Results window.

16.6 Custom Tracing


If the standard Corvid trace options do not provide enough information to debug the logic in a system, custom
tracing can be added. To do this:
Create a new Collection variable named “Trace” (or whatever you prefer)
Open the Logic Blocks and add commands to write trace information into the new collection variable in the
THEN part of any questionable rules.
The information added can include double square bracket embedded variable values.
In the results, display the [Trace] variable for a custom trace of the execution. Another option is to embed the
[Trace] variable in the screen for questions so that the custom trace can be examined as the system runs.

384 16: Testing and Debugging a System


Chapter 17: Exsys Corvid Servlet Runtime
17.1 Overview
Systems built with Exsys Corvid can be fielded online in two
ways - the Corvid Applet Runtime and the Corvid Servlet
Runtime (both included with Exsys Corvid). Both use Java for
portability and compatibility, but one uses Java Applets
running on the end user’s computer and the other uses Java
Servlets running on a server sending HTML pages to the end
user’s browser. Both approaches incorporate the same
Corvid Inference Engine and systems built with Corvid can be
fielded using either delivery option.
The Corvid Applet Runtime works very well, but the end users
browser and security setting may block Java Applets. The
Corvid Servlet Runtime, provides many more end user
interface design options including HTML and Adobe Flash.
Far more complex user interfaces can be created and
systems can be better integrated into advanced web sites.
With the Corvid Servlet Runtime, the full range of HTML
(including CSS, JavaScript, AJAX, etc) options are made
available for the end user interface, providing the opportunity
for many advanced design options and integration into web
sites.
All system processing is done on the server so there is no
client-side Java support required, allowing systems to run on
iPads and other mobile devices. Since all system files reside only on the server, system security is
enhanced, and integration with other server-side programs is simplified.
The Exsys Corvid Servlet Runtime can also be used to integrate Corvid systems with an Adobe® Flash®
user interface for the most complex RIA applications. (See chapter 18)

Corvid Servlet Runtime Benefits:

! 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.

17: Corvid Servlet Runtime 385


Capability Applet Runtime Servlet Runtime

End User Interface Design

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

Support for CSS, Java Script, Spry, None Full


Ajax, HTML5

Support for Adobe Flash None Full

Support for Tables Very limited Full

Implement standard site look-and- Set style properties that HTML templates with replaceable parameters
feel apply to all questions

System user interface Applet window in HTML Full HTML page


page

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

Where system is run End user machine Server

System CVR (runtime) file sent to Yes No


end user machine

Other system files Must be available on Access to files can be blocked


server via a URL

Database

Database interface Requires server Internal - no potential external ability to run


program and file to limit commands. Higher security
commands that can be
run

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

Email

Automated support None Yes

Commercial Systems

Suitability Limited due to High - Also ideal for subscription based systems
increasing browser and
Java security issues

386 17: Corvid Servlet Runtime


17.2 System Requirements
The Corvid Servlet Runtime is a Java Servlet. This means it must run on a server with support for Java
Servlets provided by Apache Tomcat, Glassfish, IBM Websphere or comparable software. Check with your
server administrator to make sure that your server environment supports Java Servlets.
Apache Tomcat is available for free from http://tomcat.apache.org. It provides an excellent servlet
environment and can be installed on either a server, or a local PC - which will give that PC some server
functionality and allow development and testing of Corvid Servlet Runtime systems on the local PC.
These instructions are written for Apache Tomcat, but can be applied to any other servlet container. If in
doubt about how to field Java Servlets on your server, contact your server administrator.
The Corvid Servlet Runtime can be used with the templates provided with Corvid without knowing
HTML. However, to build or edit custom templates does require some knowledge of HTML. This
chapter assumes some familiarity with HTML. Since most systems run with the Corvid Servlet
Runtime use templates that apply to many screens in a system, often the HTML coding of a few
templates can be done independently of the expert system logic by a web designer.

17.3 Installing and Starting the Corvid Servlet Runtime

17.3.1 The Servlet License File


The Corvid Servlet Runtime program is installed with Corvid and can be checked from the Configuration
window.
When run locally, the Corvid Servlet Runtime does not require any special license file. However, when run
from a true online server, it does. Running from:
http://www.MyServer.com/CORVID/corvidsr
Where “MyServer” is name of your server, Corvid will display a screen saying it cannot find a license file and a
IP address. This is what is expected at this stage and indicates the CORVID.war file deployed correctly and is
running. If this (or some other Corvid screen) is not displayed, it indicates a problem installing or deploying the
CORVID.war file.

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

17: Corvid Servlet Runtime 387


case sensitive, so be sure to have it be exactly “CorvidLicenseCodes.txt” and make sure it is a simple text file.
Put the CorvidLicenseCodes.txt file in the same folder as the CORVID.war file, or the “CORVID” folder
created when CORVID.war deployed.
The license file can hold multiple license codes, and one must match the IP of the server that is calling the
servlet. If a server is referenced by multiple IP addresses, such as an external IP and a different internal LAN
IP address, each should have a license code in the file. Each license code is a numeric string and each
should be on a different line in the file.
Technical NOTE: The Corvid Servlet Runtime checks in two folders for the license file. The Java
code getServletContext().getRealPath is used to find the location of the servlet on the server.
Different servlet engines return different relative addresses for the Java command. To compensate for
this, Corvid looks in the returned folder and the folder above it. One of these should be the location
where the CORVID.war file is located, and a convenient place for the license file.
Now start the Corvid Servlet Runtime again using:
http://www.MyServer.com/CORVID/corvidsr
This will result in 1 of 3 screens:
1. You should get a screen saying that there was
“No KBNAME Specified”. At this stage, that is
actually a good screen to get. It means that the
license file was found and the license code was
correct for the server. If any other screen is
displayed, correct the problem until this is the
screen displayed.

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.

3. If you get a message that the license code cannot be


found in the file, then the license file was correctly found, but
the code in the file does not match the server IP address.
Check that the license code from Exsys Inc was put in correctly
and that the IP address displayed in the error matches the IP
used for the license code.

388 17: Corvid Servlet Runtime


TECHNICAL NOTE: If your system cannot find the license file, there is another option. The license file
can be placed anywhere on the server and given any name. It then must be called once when the servlet
runtime is installed using the normal call to start the servlet runtime, but with LICENSE=fileID added:
www.myServer.com/Corvid/corvidsr?LICENSE=fileID
The fileID is the full URL to the license file and should be URL encoded if needed. The fileID can start
with file: or http: depending on where the license file is stored. If this approach is used, it only has to be
called ONCE after the servlet is installed for each IP address that is used. The license info will carry over
for that IP until the servlet runtime is installed or Tomcat is restarted.

17.3.2 Where to Put Your Systems - Important Security Issues


Once your system is displaying the “KBFILE not specified” screen, the
next step is to decide where to put your system files so the Corvid Servlet
Runtime can use them. Your knowledge base files will need to be put in a
folder(s) relative to this Corvid folder. It is recommended that you not put
your knowledge base files in the Corvid folder, since in at least some
cases, this will cause problems when reinstalling a new .war file.
With Tomcat, there are 2 main options:
! In a folder in “webapps” at the same level as the “CORVID”
folder.
! In a folder in “Catalina” at the same level as “webapps” or at a lower level with Tomcat.
In a many Tomcat installations, the first option (in “webapps”) may allow your Corvid system files to
be viewed externally and downloaded. If your system has sensitive information, either in the Corvid
files or data files, do NOT put them in a subfolder of the “webapps” folder unless your server
administrator has taken steps to make sure they are secure.
It is more secure to put any system or data files in a folder at the same level as “webapps” or a folder at the
same level as Tomcat. However, many options in Tomcat can be controlled and configured by your system
administrator, and other servlet containers have their own expected structure.
Check with your system administrator to confirm that a folder location is secure.
With the Corvid Applet Runtime, all the files needed by the system were typically in the same folder. Corvid
systems run with the Corvid Servlet Runtime have 2 different types of files, and they need to be in different
locations.
Files needed by the Corvid Inference Engine to run the system logic: This is the system .CVR file with
the rules along with any data files needed by the rules to run. This includes static data files, metaBlock data,
XML files, database command files (.cdb) and any other files that are needed by the system logic, but which
will NOT be directly displayed to the end user. This also includes the system template files which will be used
to build screens that the user will see, but the user will not see the templates themselves which are processed
by the Corvid Servlet Runtime. These must be with the system files in the Tomcat folder and should be
in a location that is NOT served to a browser via a URL.
Files needed for the user interface: The Corvid Servlet Runtime will build HTML pages that are displayed to
the end user. Those HTML pages are displayed via the end user’s browser program. Any content needed by
the HTML page for display such as image files, CSS files, JavaScript files, Flash swf files or any other part of
the HTML page referenced by a URL. These must be in a location that CAN be accessed via a URL and
a browser.

17: Corvid Servlet Runtime 389


Create a folder named Corvid_apps (or whatever
name you like) and move the knowledge
base .CVR file, the HTML templates used by
that system and any other data files that the
system may need (e.g. MetaBlock spreadsheets,
data files, XML files). The folder can be
anywhere on the server that can be referenced
by the Corvid Servlet Runtime, but should be a
folder that is not “served” as web content.
Any files used by the system’s end user interface
that are referenced as URL links (e.g. images,
linked pages, CSS, etc) MUST be put in a
section of the server (or another server) that is
able to serve Web pages. (This is generally
NOT the same section of the server that
holds your Corvid system files (e.g. .CVR)
since if the image files can be viewed with a
URL, your system file would also be viewable
and downloadable.) The URL content files
should be in a location on the server that would be used if a standard web page were to be added to your site.
(Check with your system administrator if unsure about the location.)
It is NOT necessary to move the .CVD file to the server. The CVD is equivalent to the “source code” for the
system and should be controlled as such. The CVD is ONLY needed by someone editing the logic of the
system. Unless the folder is in a location on the server that is secure and cannot be accessed externally, the
CVD file should never be placed on the server.
Previous versions of Corvid generated .CVRU files. These are now obsolete and it is not necessary to move
the CVRU file to the server.

17.3.3 Starting Your Systems


The call to start a Corvid system with the Corvid Servlet Runtime is done with a URL. The syntax is:
servlet_engine_path/CORVID/corvidsr?KBNAME=cvr_file
The servlet_engine_path depends on how your servlet engine references the servlets it has installed. For
Tomcat "servlet_engine_path" is something like http://www.exsys.com or for local installations of Tomcat,
http://localhost:8080. “CORVID/corvidsr” will call the actual Corvid servlet. This is case sensitive.
If the folder with your system (“MyApps”) is in the webapps folder, the link to start a system would be:
http://www.myServer.com/CORVID/corvidsr?KBNAME=../MyApps/MySystem.cvr
If the folder with your system (“MyApps”) at the same level as the “webapps” folder, it would be:
http://www.myServer.com/CORVID/corvidsr?KBNAME=../../MyApps/MySystem.cvr
The "../" is a reference off the Corvid folder in Tomcat. A single "../" moves down one level and into the
MyApps folder, if it is in the webapps folder. A double "../../" is needed to move down one level of folders more
if your MyApps folder is at the same level as webapps. (This is more secure) If your folder is in a different
location, use as many "../" as needed to move to the correct level and then up into the correct folder.
NOTE: The application files MUST be referenced off the location of the Corvid runtime in the
CORVID folder.
The link used to start the Corvid system can be used anywhere a URL link is legal - off text, image, image
maps, etc on other pages.
Until the system is modified to work with the servlet runtime, it may not run correctly, but it should at least start.

390 17: Corvid Servlet Runtime


17.4 Moving to the Corvid Servlet Runtime
Both the Corvid Applet Runtime and the Corvid Servlet Runtime use the same Corvid Inference Engine and
run systems the same way. The same system rules and logic will apply, the same questions will be asked,
and the same results and conclusions will be reached. The difference between the Applet and Servlet
Runtimes is in the user interface.
In the Corvid Applet Runtime, all screens are designed using the Corvid Screen Commands for questions,
results and other informational screens displayed by the system. Most applet screens/commands that have
been added to a system become part of the system and will be used whenever the system is run via the
Applet Runtime. However, the Screen Commands do NOT apply to the Corvid Servlet Runtime.
When running a Corvid system via the Servlet Runtime, the screens that the system displays to the end user are
HTML forms and pages. Most are built using "Template" screens that are designed using HTML and special
Corvid commands and parameters. Modifying a system to run with the Corvid Servlet Runtime primarily
involves defining the HTML screens that the user will see, and creating/applying templates to a system.
Corvid comes with some simple templates that can be used to run most systems with a very simple look-and-
feel. These can be used to test systems and as the basis for more complex, system specific templates. The
sample templates provided with Corvid illustrate various styles of user interface. These can be edited with
any HTML editor. The templates can also include CSS, JavaScript, Flash or any other functions that are
supported by your browser.
Most templates are designed to be generic with replaceable parameters, and a single template can apply a
standard design to all the questions in a system. Typically a system can be fielded with the Corvid Servlet
Runtime by just adding 2 templates - a template that is used to ask questions and a template that is used to
display results. Many more templates can be added if the user interface design requires it, but most systems
can be run using only 2 templates.

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: Corvid Servlet Runtime 391


Building Systems for Servlet Delivery
Building a system in Corvid for delivery via servlet or applet is essentially the same except for the user interface.
The logic of the system is designed exactly the same way using the Logic and Command Blocks. Regardless of
delivery mode, the first step is always to get the logic of the system working correctly. This can be done with the
Corvid Applet Runtime without needing to move files to the server. First make sure the system asks the correct
questions and arrives at the correct conclusions. If there are errors in the logic, correct them before spending
time on the user interface - there is no point in fielding a system that is not giving the correct results.
Once the system is arriving at the correct results, it is time to add the user interface. This is where the steps
for servlets are quite different from those for applets and stand-alone systems. Servlet delivery requires that
template files be added that define how questions will be asked and how results will be displayed. Sample
templates are provided and custom templates can easily be created. Applet delivery requires that Corvid
Screen Commands be added to the system to define the look and controls used to ask questions within the
applet. A system can be designed to run in both servlet and applet modes by adding both Custom Screen
commands for applet delivery and templates for the Servlet. These are added in different ways and will not
conflict with each other.

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.

392 17: Corvid Servlet Runtime


17.5.1 Specifying the System Default Template to Ask Questions
The knowledge base system default
template file for asking questions is set from
the “Properties” window. Click on the
"Servlet" tab. This will display a page for
setting the knowledge base defaults related
to the Corvid Servlet Runtime.
In this window you can select a system
default template. If a template already
exists, click on the Browse button in the
"Default Template to Ask Questions" box
and select the template to use.
If you wish to edit the template file or create
a new one from within Corvid, you will need
to use an external HTML editor. To do this,
first you must select the HTML editor you
prefer. This can be anything from a
sophisticated HTML editor such as Adobe
Dreamweaver to something as simple as
Notepad.
Click the Browse button in the HTML Editor
box and locate the editor you wish to use.
Once an HTML editor is selected, you will be
able to click the “New/Edit” button for a
template and it will open a new file with your
selected HTML editor, or if a template file
has already been selected, it will be opened
for editing.
NOTE: The template files can have any
name and extension - including .HTML.
Your templates do not need to have
an .HTML extension but some HTML editors will only work correctly if you give the file an .HTM or .HTML
extension.

17.5.2 Specifying a Template for an


Individual Variable
In addition to the system default template, any variable
can have an individual template specified to use when
asking the user to input the value for that variable.
Open the “Variables” window and select the specific
variable. Select the tab on the upper right labeled
"Servlet". The Servlet tab allows assigning a specific
template to be used when asking the user for the value
of the individual variable. Enter the template for the
variable in the "Template to Use" edit box (This is also
used for the Flash interface). This can be selected by browsing to a file. If an HTML editor has been
specified in the “Properties” window, you can use it to edit the template or create a new one by clicking the
"New/Edit" button. If you had a template selected and then decide to just use the default, click the "Use
Default" button, which will clear the edit window and change some internal settings.
NOTE: The “Use Default” button only needs to be used to clear an existing template. If the edit box is
empty, the system default template will be used.

17: Corvid Servlet Runtime 393


17.5.3 Templates to Display Results
In addition to the templates used to ask questions,
most systems will have at least one template that is
used to display the system results. This is typically
associated with the Corvid Command Block
command "RESULTS" or "DISPLAY".
The commands may have Corvid Screen
Commands associated with them, but those apply
only when running with the applet runtime. The
Servlet runtime requires a template, which is
specified by "SERVLET=template_file" following the
RESULTS or DISPLAY command, where
template_file is the name of the template to use.

This servlet portion can be added from the


command builder for the RESULTS command:
When building a command, enter the name of the
Servlet Template file to use for the RESULTS and
DISPLAY commands.
When running with the Corvid Applet Runtime or as a standalone application, the "SERVLET=" part will be
ignored, and the system will use the Corvid Screen Commands associated with the command.
When running with the Servlet runtime, the Corvid Screen Commands will be ignored and the specified
template will be used. If there is no "SERVLET=template_file" added to 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. 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.

17.5.4 Final Screen Template


In addition to the RESULTS template, a Final
screen template can be added to a system. This
is a screen that will be displayed when the
system has completed the run. In most systems
this will not be necessary since a RESULTS
screen will be displayed at the end of the run. If
that page allows only a "Restart" or exit from the
system, there will be no way to reach the Final
screen. However, if you wish to have a screen
after the results or if there are multiple ways to
exit a system and the results might not be
displayed, then the Final screen can be used.
To add a final screen to a system, open the
Properties window and select the Servlet tab.
In the "HTML Page to Display at End of Run" box enter the name of the HTML page to use. The Browse
button allows selecting an existing file. If a HTML editor has been specified, the "New/Edit" button allows
creating a new page, or editing the one that is selected.
If the system requires a Final screen, and none is specified, a very generic screen will be displayed. This is
an overall Corvid default and should not be modified. It is automatically installed with the Corvid Servlet
Runtime in the CORVID folder named “CORVID_Final_Default.html”.

394 17: Corvid Servlet Runtime


17.6 Templates to Ask Questions
Question template files are a combination of HTML, special Corvid commands in HTML comments and Corvid
replaceable parameters. The Corvid commands and replaceable parameters allow a template to be generic.
This enables the single template to work for many variables, and on any server. A system using a very
generic template often only requires only a single template for all questions, and it is easy to maintain. The
extent to which a template is “generic” and designed using replaceable parameters determines how wide a
range of variables it can be used for.
A template can be built with no variable replaceable parameters, but it will be limited to a specific variable.
Sometimes this is desirable, especially when using image maps or some other design that would apply only to
a single variable.
A single generic templates that applies to all the questions in a system can be very effective and applies a
consistent look-and-feel to all the questions in an easily maintained way. However, there is no reason not to
have as many templates as needed to deliver a system with the desired end user interface.

17.6.1 Template Structure


Question templates are always an HTML form that will submit value(s) back to the Corvid Servlet Runtime.
The question HTML form will always have:
! A <form> tag with an “action” to send the data back to the Corvid Servlet Runtime.
! One or more controls that allow the end user to input or select a value.
! A “Submit” button or action that will cause the data to be sent back.
! A way for the data sent back to include an identifier for the user’s Corvid session .
In addition to this, there can be any HTML code that the browser supports.
Corvid makes it easier to build these required items by using replaceable parameters and special Corvid
commands.
The Corvid commands are added to the template as HTML comments - text between "<!--" and "-->". This
makes it easy to add them with HTML editors. Most of the commands mark a section of the HTML code that
is only included in certain cases (e.g. only for certain variables or only if a Boolean test is true) or mark a
block that is to be used repeatedly (e.g. repeated for each value in a Static List variable's value list).
The replaceable parameters are used to automatically assign text and values for the system. For example, a
question template for a variable can use the replaceable parameter "VARIABLE_PROMPT". This will
automatically be replaced with the actual prompt text for the variable. The "VARIABLE_PROMPT" string can
be styled in the HTML page to set its style, color, size, etc. and that formatting will apply to the actual text of
the prompt when it is replaced. If the prompt text is changed in the system, the template screen will
automatically use the new text.
There are many replaceable parameters that can be used in templates to handle the prompts and values of
variables, information on the server and trace information.
The template files can have any name and extension, though ..html and .tpt are two commonly used ones.
Your templates are not required to have an .html extension but some HTML editors will only work correctly if
you give the file a .html extension. A .tpt extension can be used with some editors and make it easier to
recognize a template rather than a static .html page.

<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.

17: Corvid Servlet Runtime 395


There are 4 main sections to the form:
1. The <form> tag. This specifies a HTML form and marks the start of the form section.
2. The body of the form will have one or more controls that the user will use to provide input. This is
usually done with one or more sections marked with “CORVID_ASK” commands that indicate
sections of HTML code that should be used to ask certain variables.
Within the CORVID_ASK section(s), there are usually Corvid replaceable parameters that will be
replaced with the Prompt and Value, etc. from the variable.
3. A “Submit” button(s) must be part of the form. This sends the data back to the Corvid Servlet
Runtime.
4. The closing </form> tag indicating the end of the form.
If you are familiar with HTML forms, the template can be built using a simple text editor such as Notepad, but
it is generally easier to use an HTML editor.

17.6.2 <FORM> tag


The <FORM…> tag indicates the start of the form. All of the controls on the form must be between the
opening <FORM> and closing </FORM> tags.
The typical form tag is:
<form method="post" action="CORVID_SERVLET" name="CorvidForm" onsubmit="return
submit_form()">
Looking at the parts:
method="post"
The “method” portion of a <form> tag controls how much data can be sent back. In Corvid, all data
should be sent back to the Corvid Servlet Runtime using “post”. This assures that any amount of
user input can be sent, even if large blocks of text are entered in an edit box, or there are many
questions on a screen.
action="CORVID_SERVLET"
The action portion of a form tag tells the browser program where to send the data. This depends on
the server location and the individual session. Corvid will automatically replace the
“CORVID_SERVLET” with the correct information for the system and session. All you need to add is:
action=”CORVID_SERVLET”
and Corvid will do the rest. If you look at a HTML page built from the template, you will see this
converted to something more like:

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”

396 17: Corvid Servlet Runtime


onsubmit="return submit_form()"
The “onsubmit” is optional, but highly recommended. It calls a provided JavaScript function on the
page that blocks the end user from inadvertently sending the same data multiple times, which will
lead to the Corvid Servlet Runtime reporting an error. This is easily fixed with the standard Corvid
JavaScript to add to the page. This also requires that the form be named “CorvidForm”.

17.6.3 Controls and Replaceable Parameters


Within the “form” tag (between the <form ...> and closing </form> ) there can be HTML controls that allow the
end user to select or enter values. This can include all the standard form input controls such as edit boxes,
radio buttons, check Boxes, drop down lists, etc.
These are all added with the HTML <input>, <textarea> (larger blocks of text) and <select> (drop down lists)
tags.
In the <input> tag, the type of control is determined by the “type=” value. For example:
<input type=”text”...> will be an edit box
<input type=”radio”...> will be an radio button
<input type=”checkbox”...> will be a checkbox
In all cases, the “name” for the control MUST be the name of the Corvid Variable in square brackets.
This is how the Corvid Servlet Runtime knows what variable should be assigned the input value.
For example, a text box control:
Temperature: <input type=”text” name=”[TEMP]”>
would create an edit box labeled “Temperature:” and the value the user entered would be used to set the
value of the Corvid variable [TEMP]
For radio buttons, the “value=” is used to specify the value for that radio button:
The color is
<input type=”radio” name=”[COLOR] value=”1”> Red
<input type=”radio” name=”[COLOR] value=”2”> Green
would create 2 radio buttons labeled “Red” and “Green”. The selecting the first would select the first value for
the [COLOR] variable and the second would select the second value.
While controls can be added to templates in this way, it is very cumbersome and requires that the templates
be carefully matched and coordinated with the system variables. Whenever the variables are edited, it would
require changes in the templates and there would have to be a template for each variable. Corvid greatly
simplifies this, and allows generic templates to be built, through replaceable parameters that can be used in
the controls:
There are 5 replaceable parameters that greatly simplify building controls:

VARIABLE_PROMPT - Replace by the variable’s prompt text.


VARIABLE_NAME - Replaced by the variable’s name (Be sure to use in square brackets).
VARIABLE_VALUE_TEXT - Replaced by the variable’s value text (This is done in a
CORVID_REPEAT loop that steps through each value for a Static of Dynamic List variable).
VARIABLE_VALUE_NUM - Replaced by the variable’s value number (also done in the
CORVID_REPEAT loop).
VARIABLE_VALUE_SHORT - Replaced by the variable’s value short text (also done in the
CORVID_REPEAT loop).

17: Corvid Servlet Runtime 397


With these replaceable parameters, the control for [TEMP]:
Temperature: <input type=”text” name=”[TEMP]”>
can be rewritten:
VARIABLE_PROMPT <input type=”text” name=”[VARIABLE_NAME]”>

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

398 17: Corvid Servlet Runtime


</option>
<!-- REPEAT_END -->
</select>
This will build a list of values for the end user to select from.
By using the replaceable parameters, it is easy to build a template that can be applied to many different
variables and which will automatically pick up the text from the system. This greatly simplifies the maintenance
on the user interface. In addition to the template HTML code for the <form> and controls, the rest of the
template can be anything that can be written in HTML. It can implement any design or look-and-feel. This allows
creating a template that matches a site, but which can still be applied to many variables in a system.

17.6.4 Templates to Handle Different Types of Variables - CORVID_ASK


The last section described how to create “generic” templates that can be applied to all Static / Dynamic List
variables, or all Numeric, String and Date variables, but Corvid also allows creating a template that has
sections that will be included based on the individual variable type or name. This allows creating a single
template that can be applied to all variables, with different controls for different types or even different controls
for specific variables. The single template can implement a complex look-and-feel for all variable questions,
while still being easy to maintain and automatically picking up the text from the system.
This is done with the CORVID_ASK command. Like the CORVID_REPEAT, this is added to the template
HTML code as a HTML comment.
Everything in the template between a <!-- CORVID_ASK VarID --> and the closing <!-- ASK_END --> will
ONLY be added to the HTML page that is built if the variable matches the variable ID, VarID.
The Variable ID can be broad (a type of variable) or a specific variable.

The allowed values for VarID are:

VARIABLE All variables

STATIC_LIST All Static List variables

DYNAMIC_LIST All Dynamic List variables

CONTINUOUS All numeric, string and date variables

NUMERIC All numeric variables

STRING All string variables

DATE All date variables

[VARNAME] The specific variable varname

[VARMASK] All variables fitting the mask pattern

17: Corvid Servlet Runtime 399


If a mask pattern is used, the standard Corvid mask characters are used:

CHARACTER MATCHES

? Matches any character

* Matches the rest of the string

character Matches itself

# Matches any digit 0-9

{abc} Matches any single character in the brackets { }

{X-Z} Matches any single character between X and Z

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:

<!-- CORVID_ASK [COLOR] --> Section 1 controls <!-- ASK_END -->


<!-- CORVID_ASK [C*] --> Section 2 controls <!-- ASK_END -->
<!-- CORVID_ASK STATIC LIST--> Section 3 controls <!-- ASK_END -->

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:

<!-- CORVID_ASK CONTINUOUS --> Section 1 controls <!-- ASK_END -->


<!-- CORVID_ASK VARIABLE --> Section 2 controls <!-- ASK_END -->

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.

400 17: Corvid Servlet Runtime


To expand the template above to handle all variables that will be asked in a system:

<!-- CORVID_ASK CONTINUOUS -->


VARIABLE_PROMPT <input type=”text” name=”[VARIABLE_NAME]”>
<!-- ASK_END -->
<!-- CORVID_ASK VARIABLE -->
VARIABLE_PROMPT <br>
<!--CORVID_REPEAT-->
<input type=”radio” name=”[VARIABLE_NAME]” value=”VARIABLE_VALUE_NUM“>
VARIABLE_VALUE_TEXT
<!--REPEAT_END -->
<!-- ASK_END -->

17.6.5 Submit, Undo and Restart Buttons


Somewhere in the <form> tag, there must be a submit button. This is an <input> with the type set to “submit”:
! <input type="submit" name="submitButtonName" value=" OK ">
When this button is clicked, the value(s) selected are sent back to the Corvid Servlet Runtime. The “value” is
the label that will appear on the button. This is set to “OK” in the default templates but can be changed to
anything else, especially if the system is running in a language other than English.
The “name” is set to “submitButtonName”. It should NOT be changed since it is used in the default
JavaScript for the page.
The submit button MUST appear in the page between the <form> and closing </form> tags.
The last screen in a system (typically a result screen) may have no "OK" button, and instead have only a
RESTART button (described below) or a link back into your overall web site. This is recommended whenever
there is no further processing to be done by the system, and the only action the user can take is to restart
another session, or go to another page.
To do this, on the final screen a system will display, do NOT add an OK button, but only add the “Restart”
button described below.
If the system needs to work in multiple languages, a double square bracket, [[ ]], replacement can be used for
the name of the button. This variable would be set to a value appropriate to the language. Such as:
<input type="submit" name="submitButtonName" value="[[OK_Btn_label.VALUE]]">
In addition to the submit button that sends data, there can be 2 other special submit buttons: UNDO and
RESTART. These also must be in form between the <form> and </form> tags.

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.

17: Corvid Servlet Runtime 401


The “name” is set to ~UNDO. This must NOT be changed. The ~UNDO is the special flag to tell the Corvid
Servlet Runtime to process the input as an UNDO action.
The UNDO button can be placed anywhere on the screen. If UNDO is added to a template that will be used
for many questions, Corvid will automatically disable the UNDO button for the first screen since there is
nowhere to step back to. The button will be enabled in all screens where an UNDO is possible. Do not worry
if the first question screen in a system has the UNDO disabled.
The UNDO action can also be achieved by the end user clicking the “Back” button on their browser. Corvid
will automatically interpret this as an UNDO.
Corvid embeds a hidden value in each page to identify how to handle UNDO (or browser back) actions and
the Corvid Runtime Servlet stores certain data on the server about the sessions. The amount of time that the
server keeps this data available varies with the installation of the servlet engine and options that can be set.
If a user waits a long time (typically over an hour) and then tries to go back to an earlier Corvid session, the
needed data may no longer be available and UNDO will not work. Likewise, bookmarks for a specific
question will not work after the session data is gone and will instead require restarting the system.
If it necessary for the user to return to a session days later and have access to their earlier data, that data will
need to be stored to a database for permanent storage and recovered when the user returns.

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.

17.6.6 Multiple Submits and JavaScript


When data is sent back to the Corvid
Servlet Runtime, it can take a few
moments for it to be processed and a
new HTML page sent back to the end
user. If the user clicks the “Submit”
button again while Corvid is
processing the data, it can produce
an error since Corvid has already
started using the data from the first
“submit”. This will result in Corvid displaying a “Multiple Submits” error and the end user will have to step
back and try again. This can be annoying for the end user and is easy to prevent with a little JavaScript.

402 17: Corvid Servlet Runtime


In the <head> tag add the JavaScript:
<script type="text/javascript">
<!--
function submit_form ( )
{
document.CorvidForm.submitButtonName.disabled = true;
return true;
}
// -->
</script>
This assumes that the <form> tag has a name of “CorvidForm” and the submit button has the name
“submitButtonName”. If those have been changed, make the corresponding change in the JavaScript line to
disable the button.
Then in the <form> tag add a “onsubmit” action:
<form onsubmit="return submit_form()" method="post" action="CORVID_SERVLET"
name="CorvidForm">
This will call the JavaScript function when the form is submitted, and that function will disable the submit
button so it cannot be pressed again.
This will disable the button, but if the end user clicks their browser “Back” button to return to the earlier form,
the submit button will still be disabled and not able to be used. To fix this, add an “onunload” to the <body>
tag of the form:
<body onunload="document.CorvidForm.submitButtonName.disabled = false;">
This will enable the submit button as the form is unloaded, making it available if the end user goes back to
it later.
The JavaScript to block multiple submits is optional, but highly recommended. The Corvid default templates
have the JavaScript included, and it should be kept when those templates are modified for a specific system.

17.6.7 CSS in the Default Template


The Corvid templates use CSS to set the style and position of text and controls. The default question
template uses:

<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;

17: Corvid Servlet Runtime 403


text-indent: 75px;
}
.VariableEditBox {
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
font-weight: bold;
width: 200px;
text-indent: 75px;
}
</style>

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.

17.6.8 Images in the Template


A question template file often will incorporate image files for backgrounds or other design elements. Normally
an HTML page is a physical page on a server, and images can be put in the same folder or a subfolder. This
allows the images to be referenced using the location of the page as a base address. For example, if a page
uses an image named "my_image.jpg" and that image is in the same folder (directory) as the page, the page
HTML can just use "my_image.jpg" and the Browser will automatically look in the same folder as the page.
However, a page displayed from the Corvid Runtime Servlet is created dynamically and does not really have
a physical location on the server. Consequently, image files cannot be specified by relative location to a page
and a more complete URL address is required. In addition, the template file usually will not be in a location
on the server that allows Web browsing (though it can be), however, the image files MUST be in a section that
is accessible via Web browsers. (See section 17.3.3 above)
The image files in a template can be referred to in several ways:
Full URL
If you know where the image is located on a server, just include the full URL to that image. This
requires that the image be in a location that can be referred to by a URL - entering the URL in a Web
browser must display the image.
For example:
<IMG SRC="http://www.mysite.com/images/myImage.jpg">
Use BASE to set a Base URL for Images
If all the images are in one folder (or subfolders of a folder) you can use the
<BASE href="…">
tag in the template. The <BASE> tag indicates the location to use for all images and links. Any
image file or link that is not specified by a full URL starting with "http://" will use this base address as
the starting location. The BASE tag must occur in the HEAD section of the template - that is between
the <HEAD> and </HEAD> tags. The base URL can be hard coded such as:
<BASE href="http://www.mysite.com/images/">
Then the image can be referenced from that base:
<IMG SRC="myImage.jpg">

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

404 17: Corvid Servlet Runtime


template and Corvid will replace it with a value set in the system.
If a template has:
<BASE href="CORVID_LINK_BASE">
The <BASE> value will be set to the value set in the system for “CORVID_LINK_BASE”.
The CORVID_LINK_BASE parameter is set
from the Servlet tab in the Properties window.
If a system has multiple templates, using this
approach makes it easy to change all the pages
that will be built from the templates simply by
changing one value in the system. It also
makes it easier to use the same templates for
multiple systems since the <base> value does
not have to be hard coded.
For example, if all the images in the template
are in "http://www.mysite.com/images/", just use
<BASE href="Corvid_LINK_BASE"> in each
template and in the “Properties” window enter
"http://www.mysite.com/images/" for the value of
Corvid_LINK_BASE. This value will be used to replace Corvid_LINK_BASE where it is used in the templates.
NOTE: Using CORVID_LINK_BASE puts the location in the CVR file and will require modifying the
system with Corvid if it is moved to a different server. The benefit is that if there are multiple templates,
they are all changed with one modification in Corvid. The disadvantage is that Corvid is REQUIRED to
move a system, rather than just changing the HTML templates in a text editor. If systems need to be
moved by IT staff that do not have Corvid, CORVID_LINK_BASE may not be a desirable approach.

17.6.9 Other HTML Content in the Template


A template must have the required Corvid sections described above to function as a template, but any other
content in the template is just passed through to the HTML page it creates. This means that ANYTHING
that could be in a legal HTML page can be added to the template and it will appear in the resulting HTML page.

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.

17: Corvid Servlet Runtime 405


17.7 Advanced Templates to Ask Questions

17.7.1 Single Variable Templates


Corvid provides various ways to implement more advanced features using templates. These provide a large
degree of flexibility and if something very special is needed, a “template” can always be created for the
individual question.
A “template” for a single variable is not really a template since it will not be used in various ways. It can be
designed to ask the specific variable any way that is required. The one “template” parameter that is required,
even when only for a single variable is the action=”CORVID_SERVLET” in the <FORM> tag:
<form method="post" action="CORVID_SERVLET" >
The name and JavaScript can be left off if desired, but the action MUST remain CORVID_SERLVET which
will be replaced by the actual value by the Corvid Servlet Runtime. This cannot be hard coded into a page
because the actual value is not known until runtime.
It is also recommended that the “method” remain “post” (It will actually work with “get”, but there is no real
benefit to the change and it limits the amount of data that can be sent. Since Corvid sends some hidden data
to keep track of the session, it is best to not limit the amount of data that can be sent, even if the controls on
the page do not send much data on their own.

17.7.2 “Also Ask” in the Template


The Servlet Runtime supports the "Also Ask" feature of Corvid, which allows multiple questions to be easily
asked on one screen. As with the Applet Runtime, just go to the “Also Ask” tab on the variable's properties
and select the other variables to ask at the same time. When the selected variable is asked, each variable in
the Also Ask list will be asked on the same screen.
In the servlet version, all questions will be
asked with the same template associated with
the initial variable being asked. That template
MUST have sections appropriate for each
variable that will be asked in the “Also Ask”
group. That means there must be a
CORVID_ASK section that will match each
variable in the Also Ask list.
The CORVID_ASK sections for each Also
Ask variable in the template screen can be in
any order. The initial variable will be asked
with its associated CORVID_ASK section,
followed in order by each of the Also Ask
variables asked with their associated
CORVID_ASK sections.
For example, using the CORVID_ASK
section:

<!-- CORVID_ASK [COLOR] --> Section 1 <!-- ASK_END -->


<!-- CORVID_ASK [C*] --> Section 2 <!-- ASK_END -->
<!-- CORVID_ASK STATIC LIST--> Section 3 <!-- ASK_END -->

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:

406 17: Corvid Servlet Runtime


[COLOR] asked Section 1 used to ask [COLOR]
[INPUTS] asked with Section 3
[OUTPUTS] asked with Section 3
[COST] asked with Section 2
The template for the initial variable to ask is used for all variables in the Also Ask list - even if that is not the
template associated with those individual Also Ask variables. This allows a variable to be asked in different
ways. If the variable [COST] is asked as an Also Ask from [COLOR], it will use the section of the template
associated with [COLOR] that matches [COST]. If no input is provided for [COST], and the value is needed
by the system, it would be re-asked using the template associated with [COST]. The second time [COST] is
asked, you could use a different template that reminds the user that this input was not previously provided.
(This ability to ask a question different ways can easily be done in the servlet version, but is not easy to do
using applets.)

17.7.3 Advanced Controls to Ask Static and Dynamic List Variables


Static List variables have more options in the controls that can be used than any other type of variable. They
can be asked with radio buttons and check boxes (as seen above), but when there are many possible values,
or the screen space is limited, list controls are a good alternative. Static List controls can also be asked using
buttons, where as soon as the user clicks on a button the value is sent to Corvid, without having to click the
submit button.

Static and Dynamic List Variables


Static and Dynamic List variables have a set of defined possible values that the user must select among.
This requires multiple controls (check boxes, radio buttons or buttons) or a list with multiple entries. HTML
code must be generated for each of the possible values. Corvid templates have special commands to allow
CORVID_ASK sections to be used to handle any number of values associated with a variable.
When asking the user for input on a Static List or Dynamic List variable that has multiple values, the <input>
and <select> tags can be used to build controls.
As with all controls (except buttons), the "name=" parameter for the control must be the name of the variable
being asked, in square brackets. In addition each control (check box, radio button or value in a list) has a
"value=" parameter. This must be associated with the matching value for the variable. The "value="
parameter for a control MUST be the number of the associated value or the short text of the associated value.
Since Dynamic List variables do not have a short text for the values, they can only use the value number.
For example, if there is a variable [WEATHER] and the 3rd value is "Rain or sleet", with short text for the
value "rain", the following check box controls could be used:
<input type="checkbox" value="rain" name="[COLOR]">Rain or sleet
or
<input type="checkbox" value="3" name="[COLOR]">Rain or sleet

Note that even if the numeric value is used, it is a string in quotes.


To ask a question that provides the user with a group of values to select among, requires a set of check boxes
or radio buttons, each with the same name, but different values. The template for a Static List variable can be
"hard coded" into the template screen. To ask for [COLOR], you could use:
The color is
<input type="checkbox" value="1" name="[COLOR]">Reddish
<input type="checkbox" value="2" name="[COLOR]">Bluish
These checkboxes would return the value "1" or "2" for the variable [COLOR]. The labels for the checkboxes
would be "Reddish" and "Bluish".

17: Corvid Servlet Runtime 407


In practice, having to build a screen for each variable, and keep it up-to-date would be tedious and difficult to
maintain. Instead generic templates can be designed for all Static and Dynamic List variables.
The replaceable parameters VARIABLE_PROMPT and VARIABLE_NAME can be used to make generic
templates. To handle Static List variables, there are 3 additional replaceable parameters:
VARIABLE_VALUE_TEXT The full text of a value
VARIABLE_VALUE_NUM The number of a value
VARIABLE_VALUE_SHORT The short text of a value (Static List only)
With these a generic form of the tag can be written:
<input type="checkbox" name="[VARIABLE_NAME]" value="VARIABLE_VALUE_SHORT">
VARIABLE_VALUE_TEXT
or
<input type="checkbox" name="[VARIABLE_NAME]" value="VARIABLE_VALUE_NUM">
VARIABLE_VALUE_TEXT

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

408 17: Corvid Servlet Runtime


20, it does not matter, the appropriate number of checkboxes will be created for each.
If you look at the template with an HTML editor, it will look like:

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:

<!-- CORVID_ASK STATIC_LIST -->


<font size="6"> VARIABLE_PROMPT<BR></font>

<!-- VALUE 1 -->


<input type="checkbox" value="VARIABLE_VALUE_SHORT"
name="[VARIABLE_NAME]"><font size="5"> VARIABLE_VALUE_TEXT </font><BR>

<!-- VALUE 2 -->


<input type="checkbox" value="VARIABLE_VALUE_SHORT"
name="[VARIABLE_NAME]"><font size="4"> VARIABLE_VALUE_TEXT </font><BR>

<!-- VALUE 3 -->


<input type="checkbox" value="VARIABLE_VALUE_SHORT"
name="[VARIABLE_NAME]"><font size="3"> VARIABLE_VALUE_TEXT </font><BR>

<!-- ASK_END -->


This will work for variables that have 3 or less values. If the system had variables with more than 3 values,
more VALUE # sections would need to be added.

17: Corvid Servlet Runtime 409


If you look at this template in an HTML editor, or browser, it will look like:
Unlike a CORVID_REPEAT template, there is a line for each possible
value.

If this were applied to a Static List variable, it would look like:


In most cases, this type of formatting is not needed and a CORVID_REPEAT is easier to
use. However for special design situations, a VALUE # approach can be very useful. It is
often used for putting values into a table, for example to have multiple rows with 2 values
each. (There is also a way to do this with CORVID_REPEAT and CORVID_IF)
The VALUE # approach and the CORVID_REPEAT approach cannot be used in the same
CORVID_ASK section, but can be used in different CORVID_ASK sections on the same template.
The parameters VARIABLE_VALUE_TEXT, VARIABLE_VALUE_NUM, and VARIABLE_VALUE_SHORT
should only be used within a CORVID_REPEAT or VALUE # section. They do not have any context or
meaning outside of these sections.

Checkbox vs Radio Button - Automatic Switching


In many systems, some variables are only allowed to have a single value and should use radio buttons (or
lists), and should not use checkboxes that may allow more than one value to be selected at the same time.
Other variables can accept multiple values and should use checkboxes. To allow the template to be generic,
always design templates with checkboxes unless radio buttons should always be used. For those
variables that are limited to only a single value, Corvid will automatically convert the checkbox controls to
radio buttons for that variable. Variables that can have multiple values will use the checkboxes.
A variable is set to allow only a single value from the Variable
window by clicking the Options tab. Set the "Maximum Number
of Value that be Assigned" to "Single Value". Then any
CORVID_ASK section that is specified for "checkbox" will
automatically have it converted to "radio".
If the control is set for:
type="checkbox"
and “Single value” is selected, Corvid will automatically convert
the “checkbox” to “radio”.
NOTE: The “Ask With” tab options for specifying a radio button or checkbox ONLY apply to the Corvid
Applet Runtime and do not change the control used by the Servlet.

Control Layout
To ask for the value of all Static List variables with one value per line, add a <BR> in the
CORVID_REPEAT:

<!-- 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 -->

If the <BR> in the CORVID_REPEAT section was removed, the template would put all values on one line.

410 17: Corvid Servlet Runtime


For more complex formatting of the values, such as multiple rows with 2 values each, use VALUE # in a table,
such as:
VARIABLE_PROMPT<BR>
<table border="0" cellpadding="0" cellspacing="2" width="462">
<tr>
<!-- VALUE 1 --->
<td><input type="checkbox" value="VARIABLE_VALUE_SHORT" name="[VARIABLE_NAME]">
VARIABLE_VALUE_TEXT
</td>
<!-- VALUE 2 --->
<td><input type="checkbox" value="VARIABLE_VALUE_SHORT" name="[VARIABLE_NAME]">
VARIABLE_VALUE_TEXT
</td>
</tr>
<tr>
<!-- VALUE 3 --->
<td><input type="checkbox" value="VARIABLE_VALUE_SHORT" name="[VARIABLE_NAME]">
VARIABLE_VALUE_TEXT
</td>
<!-- VALUE 4 --->
<td><input type="checkbox" value="VARIABLE_VALUE_SHORT" name="[VARIABLE_NAME]">
VARIABLE_VALUE_TEXT
</td>
</tr>
<tr>
<!-- VALUE 5 --->
<td><input type="checkbox" value="VARIABLE_VALUE_SHORT" name="[VARIABLE_NAME]">
VARIABLE_VALUE_TEXT
</td>
<!-- VALUE 6 --->
<td><input type="checkbox" value="VARIABLE_VALUE_SHORT" name="[VARIABLE_NAME]">
VARIABLE_VALUE_TEXT
</td>
</tr>
</table>

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:

17: Corvid Servlet Runtime 411


Drop Down Lists
Drop down lists are a very convenient way to set the value for a Static or Dynamic List when there are a large
number of values or screen space is limited. Lists are built with the HTML <select> and <option> tags:
<select name="[VARIABLE_NAME]" size="#">
<!-- CORVID_REPEAT -->
<option value="VARIABLE_VALUE_SHORT"> VARIABLE_VALUE_TEXT
</option>
<!-- REPEAT_END -->
</select>
This will create a list of values. The “size” value is the number of rows that will be displayed in the control. If
the size is set to 1 (size="1"), then the control will be a drop down list with only the selected value displayed.
If the size is set to a higher value, the control will be a list with the number of rows displayed equal to the size
value and a scroll bar if needed.
The OPTION tag defines the values in the list. It should be used within the CORVID_REPEAT command to
add all the values into the list.
If the system has Dynamic List variables that may be asked using the template, the replaceable parameter
VARIABLE_VALUE_SHORT should be changed to VARIABLE_VALUE_NUM since Dynamic List variables do
not have short value text and must be referenced by number.
For example, to ask for the value of all Static List variables:

<!-- CORVID_ASK STATIC_LIST -->


VARIABLE_PROMPT <BR>
<select name="[VARIABLE_NAME]" size="1">
<!-- CORVID_REPEAT -->
<option value="VARIABLE_VALUE_SHORT"> VARIABLE_VALUE_TEXT
</option>
<!-- REPEAT_END -->
</select>
<!-- ASK_END -->
Using this to ask for the variable [COLOR] would look like:
Clicking on the down arrow next to "Red" would drop down to display the other values
that could be selected.

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.

! <select name="[VARIABLE_NAME]" size="5" multiple>


If the variable only allows a single value to be selected, Corvid will automatically remove the "multiple" and
build a list control that only allows a single value. Adding "multiple" makes a more generic control that will
work correctly for all Static and Dynamic List variables. If all the variables in a system only allow a single
value the "multiple" option can be left off.

412 17: Corvid Servlet Runtime


Buttons to Ask Questions
Buttons provide one more way to build questions screens for Static List variables.
Most of the question controls require that the user select a value from a list or by checking an item, and then
click the “OK” button. That approach has the advantage that the end user can review their input and make
changes before submitting it. However, for some systems, a better end user interface is one that just allows
the user to click on a button and have the system immediately take the input. This is especially true if the
system asks multiple Yes/No or True/False questions, or systems running on touchscreen kiosks.
With buttons, as soon as the end user clicks on a button, the value is immediately sent to Corvid, and no
“submit” button has to be clicked. This should be used when there is only a single question asked on the
screen.
Buttons can be added using the <input> tag with the type=”submit” . However, unlike the standard “submit”
button, this one has the “value” set to the expression:
value="[VARIABLE_NAME]=VARIABLE_VALUE_NUM”
When the parameters are replaced by actual variable values, his would be converted to something more like:
! value="[Color]=2”
Note, this is different than other controls where the “value” is just the value number of short text. Here it is an
expression to assign the value to the variable.
The “name” for the <input> set to the text for the value. This will become the label on the button.
! name="VARIABLE_VALUE_TEXT"
The HTML to ask any Static List with buttons would be:

VARIABLE_PROMPT<BR>
<!-- CORVID_REPEAT -->
<input type="submit"
value="[VARIABLE_NAME]=VARIABLE_VALUE_NUM" name="VARIABLE_VALUE_TEXT">
<!-- REPEAT_END -->

For example:

If the text is too long to put on the button, it can be put


next to the button, with the button having an "*", image
or some other generic label. This can be done with:

VARIABLE_PROMPT<BR>
<!-- CORVID_REPEAT -->
VARIABLE_VALUE_TEXT
<input type="submit"
value="[VARIABLE_NAME]=VARIABLE_VALUE_NUM" name="X">
<!-- REPEAT_END -->

17: Corvid Servlet Runtime 413


17.7.4 Advanced Controls to Ask Numeric, String and Date Variables
Simple One-line Text Edit Box
When asking for the value of Numeric, String or Date variables, the end user is typically presented with a prompt
and an edit box where they can input the value. If their input is reasonable short, this can be done with:
<input type="text" name="[VARIABLE_NAME]">
This allows a single line of text, which will be assigned to the variable. The tag allows an optional size="#"
parameter that sets the size of the edit field, where # is a numeric value. The positioning of the edit field is
done using HTML formatting commands or CSS outside of the tag. The prompt for the variable can be
displayed to the left of this tag or above it and should use the VARIABLE_PROMPT replaceable parameter.
For example, a template section that would work for all numeric variables:
<!-- CORVID_ASK NUMERIC -->
VARIABLE_PROMPT <input type="text" name="[VARIABLE_NAME] size="12">
<!-- ASK_END -->

Using this to ask for the temperature would look like:

Larger, Multiline Edit Box


For a larger, multi-line edit box, use the <textarea> control.
<textarea name="[VARIABLE_NAME]" cols="#" rows="#"> </textarea>
This allows inputting multiple lines of text, and handles scrolling etc. The value entered will be assigned to
the variable. The cols="#" parameter that sets the number of columns in the edit box (width) and rows="#"
sets the number of rows, where # is a numeric value. The positioning of the edit field is done using HTML
formatting commands or CSS outside of the tag. The prompt for the variable can be displayed to the left of
this tag or above it and should use the VARIABLE_PROMPT replaceable parameter.
Note that the tag requires the closing </textarea> tag to mark the end. If you wish to have text already in
the edit box when it is displayed, put it before the </textarea> marker. In most cases you will want the edit
field will be blank and there will be no text between <textarea…> and </textarea>.

To ask for the value of all string variables:


<!-- CORVID_ASK STRING -->
VARIABLE_PROMPT <BR>
<textarea name="[VARIABLE_NAME]" cols="60" rows="5"> </textarea>
<!-- ASK_END -->

Using this to ask for a note would look like:


The <textarea> control can also be used to
display content generated by the system and
in a variable.
For example you could display a comment
generated by the system to see if the user
wishes to add to it. The system generated comment is in the variable [SysComment] which is included with
double square bracket, [[ ]], embedding. This is put before the closing </textarea>.
The user's modified note will be sent to the variable [UserNote] (In this case hard coded into the template):

Please enter any notes you wish to add:


<textarea name="[UserNote]" cols="60" rows="5"> [[SysComment]]
</textarea>

414 17: Corvid Servlet Runtime


Password Edit Box
If a system needs an edit box for a password or other text that should not be displayed on the screen, use:
<input type="password" name="[VARIABLE_NAME]">
This allows a single line of text, which will be assigned to the variable. It is similar to the simple edit box
above, but the edit box will echo back "*" or some meaningless symbol instead of the user's input. This hides
the text that is typed in and can be used for passwords. The tag allows an optional size="#" parameter that
sets the size of the edit field, where # is a numeric value. The positioning of the edit field is done using HTML
formatting commands or CSS outside of the tag. The prompt for the variable can be displayed to the left of
this tag or above it and should use the VARIABLE_PROMPT replaceable parameter.
For example, to ask for the value of all variables starting with "PASSWORD":

<!-- CORVID_ASK [PASSWORD*] -->


VARIABLE_PROMPT <input type="password" name="[VARIABLE_NAME]>
<!-- ASK_END -->

Using this to ask for a password would look like:

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.

17.8 Customizing Text Used in Question Templates

17.8.1 Alternate Static List Value Text


When using Static List variables with a servlet template, special HTML code associated with the individual
values can be added. This HTML code is used only by the Corvid Servlet Runtime and can be used either in
place of the normal value text or in addition to it.

! Open the Variables window and


make sure the “Advance Options”
check box at the bottom of the
window is checked.
! Click on a Static List variable to
select it.
! In the “Static List” tab, enter text or
HTML code in the “Servlet - Use
HTML for Value in Ask” edit box. Text
can be added for each value
individually. The text will apply to
whatever value is currently active.
The text should be normal HTML and
should not include any Corvid
commands or replaceable
parameters.
! The HTML code/text will be used to replace “VARIABLE_VALUE_TEXT” for this value if the “Use
Instead” radio button is selected.
! The HTML code/text will be used to replace “VARIABLE_EXTRA_TEXT” for this value if the

17: Corvid Servlet Runtime 415


“VARIABLE_EXTRA_TEXT” radio button is selected. In that case, “VARIABLE_VALUE_TEXT” will still
be replaced by the normal value text.
For example:
To add a graphical element, such as an arrow, before each value in the list:
Add an IMG SRC tag, such as <IMG SRC="arrow.jpg"> in the edit box and click the
"VARIABLE_EXTRA_TEXT" radio button. This will need to be done for each value in the value list.
Modify the template to include the “VARIABLE_EXTRA_TEXT” in the CORVID_REPEAT section:
<!-- CORVID_ASK STATIC_LIST -->
VARIABLE_PROMPT <BR>
<!-- CORVID_REPEAT -->
<input type="checkbox" value="VARIABLE_VALUE_SHORT" name="[VARIABLE_NAME]">
VARIABLE_EXTRA_TEXT VARIABLE_VALUE_TEXT <BR>
<!-- REPEAT_END -->
<!-- ASK_END -->
For each variable, the arrow will be added before the value text. This could also be done only for
some values that should be highlighted with the arrow. If there is no text, the
VARIABLE_EXTRA_TEXT will have no effect on that value
To use an image in place of the value text
Add an IMG SRC tag, such as <IMG SRC="value_1_image.jpg"> in the edit box and click the "Use
instead of Value" radio button. This will need to be done for each value in the value list, adding its
associated image file.
The template will NOT need to be modified since now the “VARIABLE_VALUE_TEXT” in the
CORVID_REPEAT section will insert the <img> tag with the appropriate images file.

<!-- 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 -->
For each variable, the image file will be displayed in place of the value text.
Any HTML code can be added in the edit box provided that when added to the template it makes syntactically
legal HTML overall. This can be used to modify the value HTML code to add graphics or control arrangement
such as adding tags to control placement in tables.

416 17: Corvid Servlet Runtime


17.8.2 CORVID_REPLACE in Templates
In addition to the standard replaceable
parameters such as VARIABLE_PROMPT or
VARIABLE_VALUE_TEXT, each variable can
have an additional 10 CORVID_REPLACE_#
parameters that can be used for additional
customization of the template.
CORVID_REPLACE strings can be any text or
HTML code that you wish to have added to the
template in a variable’s CORVID_ASK section.
There can be up to 10 CORVID_REPLACE stings
for each variable, and each of the 10 can have up
to 5 alternates for different languages or user
interfaces.
Open the Variables window and make sure the “Advanced Options” check box at the bottom of the window is
checked. Click on a variable to select it.
To use CORVID_REPLACE:
! Click on the Servlet Tab for the variable.
! The counter next “CORVID_REPLACE_” will display “1”. In the edit box, enter any text or HTML code
that you want to add to the template. The CORVID_REPLACE text can be any text or HTML code, but
should not include Corvid commands such as CORVID_IF. The text can include double square
bracket embedded variables, embedded XML or resource strings.
! In the template, add the text “CORVID_REPLACE_1” where this text/code should be inserted. This
must be in the CORVID_ASK section that will be used for this variable. When the template is used for
the variable, the text “CORVID_REPLACE_1” will be replaced by the text that was entered.
! To add a second CORVID_REPLACE, click the “>” arrow. This will change the counter to “2”. Enter
text that will be used to replace the string “CORVID_REPLACE_2” in the template. This can be done
for up to 10 CORVID_REPLACE strings. If a particular variable does not have a matching
CORVID_REPLACE string, the “CORVID_REPLACE_#” in the template will be replaced by a blank.
This can be done as many times as needed to add up to 10 CORVID_REPLACE strings.
For example, suppose you wish to keep the prompt text for your variables simple, but a variable should
display an image before the prompt.
Select the variable in the Variables window
Open the “Servlet” tab.
In CORVID_REPLACE, make sure the counter is at “1”
Enter the <img> tag for the image. (e.g. <img src=”var1image.jpg”> )
The template find the CORVID_ASK section for the variable and add the CORVID_REPLACE_1

<!-- CORVID_ASK STATIC_LIST -->


CORVID_REPLACE_1 VARIABLE_PROMPT <BR>
<!-- CORVID_REPEAT -->
<input type="checkbox" value="VARIABLE_VALUE_SHORT"
name="[VARIABLE_NAME]">VARIABLE_VALUE_TEXT <BR>
<!-- REPEAT_END -->
<!-- ASK_END -->
(NOTE: This could also be done by adding the IMG SRC command to the prompt text itself, but that
would make the prompt more difficult to read, and would result in the image being displayed wherever

17: Corvid Servlet Runtime 417


the prompt is used. The CORVID_REPLACE approach allows the image to be shown when the
questions are asked, but the prompt can be used without the image in reports.)
The CORVID_REPLACE content can be as long as needed, but must be syntactically correct when placed
into the template at the insertion point.
Multiple Languages: Each of the 10 CORVID_REPLACE strings can have up to 5 variations for different
languages. If the prompt for the variable has an “Alternate Prompt Key Variable” selected on the Prompt tab,
the “Prompt Key Var Value” options will be enabled at the bottom of the Servlet tab. For each
CORVID_REPLACE, click the arrows next to the “Prompt Key Var Value” to select the number to match the
alternate prompts. Then enter the CORVID_REPLACE string. When the variable is asked, the
CORVID_REPLACE_# that matches the key variable value will be used.

17.8.3 CORVID_ASK and [.PROPERTY]


Any text in the CORVID_ASK section can include a property of the variable currently being asked with that
section. Any property can be added generically by using [.property] or [[.property]]. This is converted to
[varname.property] or [[varname.property]] for the variable being asked. This allows the template to include
more information on the variable, but still be generic and apply to multiple variables.
For example to generically have the CORVID_ASK section for Static List variable tell the user how many
values they can choose from, you could use the [varname.COUNT] property that returns the number of values
that the variable has. To use this in the Static List CORVID_ASK section that will apply to multiple variables,
just use [[.COUNT]]

<!-- CORVID_ASK STATIC_LIST -->


Select among the [[.COUNT]] values below. <BR><BR>
VARIABLE_PROMPT <BR>
<!-- CORVID_REPEAT -->
<input type="checkbox" value="VARIABLE_VALUE_SHORT"
name="[VARIABLE_NAME]">VARIABLE_VALUE_TEXT <BR>
<!-- REPEAT_END -->
<!-- ASK_END -->

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.

17.8.4 Conditional Inclusion of Content in the Template


Sections of a template file can be included based on a Boolean conditional test using Corvid variables. This
can be done in both templates to ask questions and those to display results. This is done using:
<!-- CORVID_IF expr --> … <!-- END_IF -->
The expression expr can be any Corvid Boolean expression that will evaluate to true or false. (e.g. [X] > 0).
If the expression is true, all the code up to the associated END_IF will be included. If the expression is false,
all code up to the associated END_IF will be ignored and not included in the page produced.
This is very similar to the #CORVID_IF used when adding files to a Collection variable (See Sect 14.2.4), but
here it is part of a template and made into a HTML comment.
The expression can include [.property] values to make it generic across multiple variables, but this must be
done in a CORVID_ASK section for the specific variable being asked.

418 17: Corvid Servlet Runtime


CORVID_IF blocks can be nested, but each must have an associated END_IF. (In place of END_IF, IF_END
can also be used for consistency with other commands.)
A CORVID_IF that does not use [.property] can be either in a CORVID_ASK section, or outside of it, but must
be either entirely in or outside the CORVID_ASK section.
The following are legal:
<!-- CORVID_IF expr -->
<!-- CORVID_ASK var -->
...
<!-- ASK_END -->
<!-- END_IF -->

<!-- CORVID_ASK var -->


...
<!-- CORVID_IF expr -->
….
<!-- END_IF -->
...
<!-- ASK_END -->

<!-- CORVID_IF expr -->


...
<!-- END_IF -->
<!-- CORVID_ASK var -->
...
<!-- ASK_END -->

The following are NOT legal because they cross CORVID_ASK sections:
<!-- CORVID_IF expr -->
<!-- CORVID_ASK var -->
<!-- END_IF --> …..
<!-- ASK_END -->

<!-- CORVID_ASK var -->


<!-- CORVID_IF expr -->

<!-- ASK_END -->
<!-- END_IF -->
The expression in the CORVID_IF can be any Boolean expression using Corvid variables. The HTML code
within the CORVID_IF section will be included if the expression is true and ignored if the expression is false.
For numeric variables the expressions are simple Boolean tests such as:
[X] > 0
[X] < ([Y] / [Z])
For Static List variables, the easiest approach is to compare the .VALUE with the text of a value in quotes.
For example, if Static List [Color] could have value “Red” set, a CORVID_IF could be:
<!-- CORVID_IF ([COLOR] = “Red”) -->
The ( ) around the expression is not required, but makes the expressions easier to read.
The expression in the CORVID_IF should NOT contain variables that do not have values and which would

17: Corvid Servlet Runtime 419


need to be asked of the user. Since the expression will be evaluated midway through the generation of the
page, Corvid cannot simply change and ask another page, which would mix the 2 pages. Make sure any
variables used will have been asked or derived before the screen will be displayed.
For example, the system might initially ask if the user is running from an iPhone. If the answer is YES,
screens formatted for a smaller size might be used. If the answer was no, full screens could be used.
If a system might sometimes not be able to provide advice with high confidence, it could have a variable
[Advice_found] that could be tested. If it had a value of “Yes” the advice would be displayed. If it was “No” a
screen with other general options might be displayed.
<!-- CORVID_IF ([Advice_found] = “Yes”) -->
HTML to display Advice
<!-- END_IF -->
<!-- CORVID_IF ([Advice_found] = “No”) -->
HTML to display alternate general options
<!-- END_IF -->

17.8.5 Corvid Commands in a Template


The same Corvid commands that are executed in a Command Block can be executed from within the
template. Just include:
<!-- Corvid_CMD command -->
where command is any single command that is legal in a Command Block. The Command Block commands
FOR, WHILE, FOR_EACH and IF are not allowed since they can only be used in the context of the Command
Block. The commands can use any Corvid variables and their properties. To assign a value, use the SET
command.
For example, to keep track of how many times a question is asked, a specific template could be associated
with the variable. It could include:
<!-- Corvid_CMD SET [COUNT] ([COUNT] + 1) -->
Initialize [COUNT] to 0 at the start of the system. Then each time the screen is displayed, [COUNT] will be
incremented. If the user did not input a valid input for the questions, [COUNT] would get larger. This could be
used with a CORVID_IF test to change the way the question is asked if [COUNT] gets large, indicating the
user does not understand the question or needs more details. If the question was not answered the first time,
the system could automatically ask it in more detail the next time. This could also be used to provide more
details if the user input was not in a valid format to be accepted. For example, if a date variable had to be re-
asked, it could ask with more detail on the expected input format. You could even build a system with an
attitude by adding something like:
<!-- CORVID_IF [COUNT] > 5 -->
I've asked this [[COUNT]] times - how about an answer!<BR>
<!-- END_IF -->
NOTE: Any Corvid command can be included in the template, including ones that control the logical
functioning of the system. However, ONLY commands related to the appearance of the user interface
SHOULD be used. Including commands that control the logic will cause a system to run differently in
the servlet mode than when run as an applet (which would not use the template). It would also be
much more difficult to understand why the system was doing something, which might be dependent
on a particular screen being displayed, complicating development and maintenance.

420 17: Corvid Servlet Runtime


17.8.6 Special Buttons that Trigger Command Blocks
A special button can be added to a screen with the name set to:
~EXEC_CMD_BLOCK=BlockToRun
such as:
<input type="submit" name="~EXEC_CMD_BLOCK=BlockToRun" value="Save">

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.

17.8.7 TRACE with Templates


In the Corvid Applet Runtime, TRACE information can be displayed in a separate applet window.
TRACE can also be used with the Corvid Servlet Runtime with new trace information displayed in each
screen as it is displayed.
There are 2 special replaceable parameters that can be used to display the Corvid system trace. These
should be used only when developing the system and removed before final release.

The parameter CORVID_TRACE will be replaced


by the full trace information. This is the same
trace that would be echoed to the trace window in
the applet version.
! In the “Properties” window “Servlet” tab,
select the "Enable Trace in Servlet"
checkbox. This turns trace on. (If trace is
not active, the CORVID_TRACE
parameter will be replaced by a blank.)
! In the templates that you wish to include a
trace, add the replaceable parameter
"CORVID_TRACE" where the trace is to
be displayed. This can be anywhere in the
page, but normally this is at the bottom of
the page after the end of the form (</FORM> tag) but before the end of the body (</BODY> tag)
! The trace will be displayed in the same font and color as specified for the CORVID_TRACE
parameter, however if an error is detected, the trace color will be changed to red. The background
selected for the trace should allow it to be readable if it changes to red. The CORVID_TRACE can
also be styled with CSS for more display options.

17: Corvid Servlet Runtime 421


For example:
</form>
<p class=”TraceStyle”>CORVID_TRACE</p>
</body>
</html>

CORVID_TRACE will put the entire trace up to


that point in the screen. This can get rather
long for some systems (especially MetaBlock
systems). To see a shorted version of the
trace, use the replaceable parameter
CORVID_TRACE_CLEAR. This will display
the trace up to that point, and then clear the
trace so the next CORVID_TRACE or
CORVID_TRACE_CLEAR will only show the
trace since the last screen and will skip earlier
portions. This can be easier to read, while still
including the main information for the last step.
CORVID_TRACE and
CORVID_TRACE_CLEAR can be used in
combination to show larger blocks of trace
when needed, then clearing the already
displayed parts.

Another way to do trace is to trace to the servlet


log file. Selecting “Trace to Java Console” in the Properties window for the system can do this. Since often
there is no Java console for the servlet, the trace is echoed to the log and can be read there. This should
ONLY be used in development and ONLY when there is only a single user running the system. If there
are multiple users, the traces will intermingle producing a very difficult to read trace.

17.8.8 Using Image Maps to Ask Questions


In most cases, the HTML screens that ask a user to answer a question are forms that use POST to return the
data to the servlet. However, a system can also use simple HTML links to send data to the servlet. This
includes image maps and individual images or text that have associated HTML links.
The key to doing this is creating a link that calls back to the Corvid Servlet Runtime, with information that
identifies the session and the data to be returned. Corvid provides a simple replaceable parameter that
allows you to do this easily:
CORVID_SERVLET_GET
The parameter CORVID_SERVLET_GET will be replaced by a call to the Corvid Servlet Runtime along with
information that will identify the place in the session. The link back to the Corvid Servlet Runtime must NOT
be hard coded, since the additional information will not be known until the system is run.
The GET approach will be used to send the data. Unlike the POST approach normally used in the templates,
this approach adds the data to the URL that is created. Corvid will automatically add some additional
information, which is normally passed as hidden fields in the POST data sent by the forms.
To use CORVID_SERVLET_GET:
! Add a normal URL link to an image map, image or text that should returns a value to Corvid.
! Make the link "CORVID_SERVLET_GET " followed by the name of the variable in [ ], an "=", and the
value to assign. If there are multiple values, separate them with "&". There should not be any spaces

422 17: Corvid Servlet Runtime


between data. If there are spaces or other characters in the value that require URL encoding, they
should be encoded.
For example, a link off an image (or section of an image map) that sets the value of [X] to 5 might be:
<a href="CORVID_SERVLET_GET [X]=5">
Corvid will replace the CORVID_SERVLET_GET parameter with the correct address, plus a "?", the session
identification, an "&", and the data you provide.
For Static List variables, the value assigned can be a numeric value that is the number of the value, or the
short text of the value. For Numeric variables, the value would be numeric. For string variables, the value
would be a string. It would not need to be in quotes, but might require URL encoding if it includes spaces or
other characters that need to be encoded.
For a generic template that asks a question and assigns the value 5, you could alternatively use:
<a href="CORVID_SERVLET_GET [VARIABLE_NAME]=5">
This would be unusual since almost all cases that would use this technique will require a specific image or
image map. Normally image map screens are not used generically and are associated with only a single
variable, so using the actual variable name is more standard. However, using VARIABLE_NAME in templates
does allow the variable's name to be changed in the system without having to edit the template.
If you wished to return data for more than one variable, you can make a list of values separated by "&", for
example to set [X] to 5 and [Y] to 2:
<a href="CORVID_SERVLET_GET [X]=5&[Y]=2">
Remember not to add any spaces and to URL encode any characters that require it.

An example of a page that uses an image map to ask a question is:


<html>
<head>
<title>Image Map Demo</title>
</head>
<body>
<BASE href="Corvid_LINK_BASE">
<div align="center">
<img src="MyImage.gif" width="620" height="120" border="0" usemap="#map1162e6c">
<map name="map1162e6c">
<area shape="rect" coords="497,29,613,115" href="CORVID_SERVLET_GET [X]=1">
<area shape="rect" coords="377,31,488,114" href="CORVID_SERVLET_GET [X]=2">
<area shape="rect" coords="255,29,368,114" href="CORVID_SERVLET_GET [X]=3">
<area shape="rect" coords="138,27,249,111" href="CORVID_SERVLET_GET [X]=4">
<area shape="rect" coords="12,27,126,114" href="CORVID_SERVLET_GET [X]=5">
</map>
</div>
</body>
</html>
This image map has 5 specified regions with associated links. A click on any of the regions will trigger the link
and set the value of the variable [X].
Using image maps is quite easy with an HTML editor that allows defining the regions and links. This allows

17: Corvid Servlet Runtime 423


very advanced user interfaces to be created. An alternative to an image map is to have several image files
(jpg or gif) on a page with the same type of CORVID_SERVLET_GET link off them. A click on any of the
images would set the associated value. This provides another way to ask questions with images. Any URL
link on a page can use the CORVID_SERVLET_GET approach to send data to Corvid.

17.8.9 Eliminating the OK button


Another way that links can be used is to build a screen that has no OK button. In the forms approach to
templates, the user selects an answer and then must take the second step of clicking the OK button to submit
the data, or must click on a button associated with the answer. There are advantages to this since the user
has a chance to review and correct any incorrect selections. However, in some systems the desired interface
is to have the system immediately take the user's input and continue the session without buttons. This
happens automatically with image maps and approaches that use the link approach to return data.
For example, if a system asked a series of "Yes/No" questions, graphics could be used with links that would
return that data. This can even be used generically, provided that the variables in the system are all designed
to use the values of "Yes" and "No" consistently.
A simple screen that would use this approach is:
<html>
<head>
<title>Link Demo</title>
<BASE href="Corvid_LINK_BASE">
</head>
<body >
<!-- CORVID_ASK STATIC_LIST -->
VARIABLE_PROMT<BR><BR>
<a href="CORVID_SERVLET_GET [VARIBLE_NAME]=YES">
<img src="yes.jpg">
</a>
<a href="CORVID_SERVLET_GET [VARIBLE_NAME]=NO">
<img src="no.jpg">
</a>
<!-- ASK_END -->
</body>
</html>
This template could be associated with any Static List variable that had "Yes" and "No" as the possible values.
The system will display the text of the prompt and 2 images for "Yes" and "No". A click on either image would
immediately return the data to the Corvid Servlet Runtime.

424 17: Corvid Servlet Runtime


17.9 Templates to Display Results
In addition to questions, Corvid
templates provide a flexible way to
display the system results and
recommendations in a variety of ways.
It is easy to build very attractive Results
screens in HTML, and with the powerful
commands available even very complex
screens can be built.
Templates to display results are in many
respects very similar to the templates to
ask questions. The main difference is
that instead of presenting multiple
options for the user to select among, the
template must display the appropriate
items of information as a result or
recommendation.
System results are typically displayed
with the Corvid Command Block
command "RESULTS" or "DISPLAY".
The commands may have Corvid
Screen Commands associated with
them, but those apply only when running with the applet runtime. The Corvid Servlet Runtime requires a
template, which is specified by "SERVLET=template_file" following the RESULTS or DISPLAY command,
where template_file is the name of the template to use.

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.

17.9.1 Forms for Results


Results screens can be a simple HTML page or an HTML form.
If a simple HTML page is used, it MUST be the last screen in the system and come from the last command in
the Command Block, since there will be no way to return to Corvid for additional processing.
Most results screens and reports should be HTML forms. This means that they have a
! <form method="post" action="CORVID_SERVLET">
content
<input type="submit" name="submitButtonName" value="OK">
</form>
where the content is the actual report or results. The
method="post" action="CORVID_SERVLET"
is required to return to the Corvid servlet engine so it can continue processing the system.

17: Corvid Servlet Runtime 425


Any report or information screen that is displayed before the system is finished MUST be a form and MUST
include a submit button. A screen displayed at the end of a run often will not have an OK button, but will
generally have a RESTART button or a link to some other page.
The only exception to using a form is a screen displayed at the very end of a run, where the end user is not
going to be given an option to restart the system. In that case, the screen does not need to be a form, but
can still use all of the Corvid servlet commands for building the report. Such a screen should have some way
for the user to navigate through links to other parts of the site.

17.9.2 SaveReport and DisplayReport Commands in the Servlet Runtime


The techniques used for creating and displaying reports in shown in Chapter 14 can also be used from the
Servlet Runtime. The SaveReport and DisplayReport commands are built into the Corvid Servlet Runtime
and do not require the external CorvidRpt servlet for HTML reports, but do require it for RTF reports.
HTML reports are easier to build and display with the Corvid Servlet runtime. The complication when using
the Corvid Servlet Runtime for RTF and PDF reports is that browsers may not recognize that the “type” for the
document is RTF or PDF. The type tells the browser how the document should be handled or what program
to pass it off to. Because of this the command sequence for reports is slightly different when using the Corvid
Servlet Runtime.
NOTE: A report displayed with SaveReport / DisplayReport will NOT have a link to continue the
sessions, so it MUST be the last screen in a system.

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>

426 17: Corvid Servlet Runtime


This is a blank page that only does a redirect to the actual report page. The page redirected to is
[[ReportID]] , whose value was set in the SaveReport command. The address from SaveReport will be
embedded into the redirect.html when it is created and displayed. This will immediately display the saved
report with the correct type to have the browser open it in MS Word (or whatever program is associated with
RTF reports.) (NOTE: It would seem like just displaying the [ReportID] link would work, but it fails in all
common browsers at this time.)

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.

17.9.3 Displaying Variable Values in Results


The intent of a results screen is to display the values of certain variables that had values set during a run, and
to format this data in specific ways. Results and reports typically display Confidence or Collection variables
set during a session, though other types of variables can also be included.
The easiest way to display results is to embed the individual variables, with double square brackets [[ ]]
embedded in the text. This allows any data in the system to be displayed.
For example, if the goal of a system was to set the value for [AMOUNT] based on various factors and logic,
and that value was all the user needed to know, a Results screen could just contain the text :
"The amount to add is [[AMOUNT.VALUE]]"
If this was part of a Result template, the derived value of [AMOUNT] would be embedded. Note that
the .VALUE property is used to have only the value added. Otherwise, the prompt and value would be
displayed. If the prompt for [AMOUNT] was the string you wish to use in the results, just [[AMOUNT]] could
be used with no additional text.
Using double square bracket, [[ ]], embedding is often a very effective way to build reports, especially if the
main content of the results was built in a Collection variable.
However, many times there are a large number of possible variables to display, and only certain ones should
be displayed. For example, all the confidence variables that received a value of greater than 50.
Corvid provides a way to have a section of the template that is repeated for multiple variables. This is done
using:
<!-- FOR_EACH VarID --> … <!-- EACH_END -->
This allows a section of the template to be applied to each variable specified by the “VarID”. The values of VarID
are the same as those used in CORVID_ASK when asking a question, plus additional values to display
Collection and Confidence variables.
The VarID indicates which variable(s) the code applies to. The allowed values are:

VARIABLE All variables

STATIC_LIST All Static List variables

DYNAMIC_LIST All Dynamic List variables

17: Corvid Servlet Runtime 427


CONTINUOUS All numeric, string and date variables

NUMERIC All numeric variables

STRING All string variables

DATE All date variables

CONFIDENCE All Confidence Variables

CONFIDENCE_ASCENDING All Confidence Variables, sorted in order of value, with


lowest values first

CONFIDENCE_DECENDING All Confidence Variables, sorted in order of value, with


highest values first

COLLECTION All Collection variables

[VARNAME] The specific variable varname

[VARMASK] All variables fitting the mask pattern

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:

<!-- FOR_EACH CONFIDENCE -->


<!-- CORVID_IF ([.VALUE] > 20) -->
[[.FULL]]<BR>
<!-- END_IF -->
<!-- EACH_END -->

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".

To display the values of all variables in the system, just use:


<!-- FOR_EACH VARIABLE -->
[[.FULL]]<BR>
<!-- EACH_END -->

428 17: Corvid Servlet Runtime


15.9.4 Collection Variable Values
Collection variables are a powerful tool for handling expert system results. The Collection variable provides a
freeform way to combine and sort recommendations and build reports. One very powerful technique is to
assign string values to a Collection variable that are HTML commands with HTML tags, etc. This allows the
full value of the Collection variable to be a block of HTML code that can just be double square bracket, [[ ]],
embedded in the report. This technique can be used to create complex interfaces such as building a table that
displays the results. Just build the table in a collection variable as the system runs and then embed the value in
the report. For some complex formatting, this can be much easier than using FOR_EACH commands.
The individual values in a Collection variable can be displayed using commands very similar to the way Static
List values are handled in CORVID_ASK screens.
The CORVID_REPEAT command can be used to step through each value in a Collection variable's value list.
The syntax is the same as in screens to ask questions:
<!-- CORVID_REPEAT --> … <!-- REPEAT_END -->
however, here it is used with a FOR_EACH command to define the variable it applies to.
(NOTE: The FOR_EACH must be used even if there is only a single Collection variable being
displayed. The FOR_EACH defines the context for the CORVID_REPEAT)

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.

VARIABLE_VALUE_TEXT Text of the specific individual value

VARIABLE_VALUE_NUM Number of the individual value

VARIABLE_VALUE_SORT Sort value (Value must have been


added to the Collection with
ADDSORTED)

For example, to display all the values in a Collection variable [Comment] as a numbered list:

<!-- FOR_EACH [Comment] -->


<!-- CORVID_REPEAT -->
VARIABLE_VALUE_NUM: VARIABLE_VALUE_TEXT <BR>
<!-- REPEAT_END -->
<!-- EACH_END -->
If [Comment] had values "aaa", "bbb", and "ccc", this would display:
1: aaa
2: bbb
3: ccc

The "FOR_EACH [Comment]" is required even though there is only a single variable to set the context for the
CORVID_REPEAT.

17: Corvid Servlet Runtime 429


If the values in a Collection variable [Notes] had been built with the values sorted using ADDSORTED, the
values with a sort value of greater than 25 could be displayed with:
<!-- FOR_EACH [Notes] -->
<!-- CORVID_REPEAT -->
<!-- CORVID_IF (VARIABLE_VALUE_SORT > 25) -->
VARIABLE_VALUE_TEXT <BR>
<!-- END_IF -->
<!-- REPEAT_END -->
<!-- EACH_END -->
A second way to display specific values in a Collection variable is with the VALUE # command. This is very
similar to the way specific values are reference when asking for Static List values with CORVID_ASK. The
syntax is:
<!-- VALUE # -->
In a FOR_EACH section for a Collection variable, all code between <!-- VALUE 1 --> and <!-- VALUE 2 --> will
apply to the first value in the Collection variable's value list. All code between <!-- VALUE 2 --> and <!--
VALUE 3 --> will apply to the second value in the list, etc. If there is no matching value for the one specified,
the section will be skipped.
For example, to display the first 3 values of Collection variable [Notes] in decreasing font size:
<!-- FOR_EACH [Notes] -->
<!-- Value 1 -->
<font size="5"> VARIABLE_VALUE_TEXT <BR>
<!-- Value 2 -->
<font size="4"> VARIABLE_VALUE_TEXT <BR>
<!-- Value 3 -->
<font size="3"> VARIABLE_VALUE_TEXT <BR>
<!-- EACH_END -->
If [Notes] had values "aaa", "bbb", "ccc", this would display:

aaa
bbb
ccc

17.9.5 Title and Information Screens


Title and information screens can be displayed in a system with the Corvid Servlet Runtime.
The command to display a title screen is the TITLE command in a Command Block, and other HTML screens
can be displayed with the DISPLAY_HTML command. While these commands are similar in intent, they are
handled quite differently in Corvid.
The TITLE command is intended to display a title screen. This is defined with Corvid Screen Commands that are
used only in the applet runtime. The command can have a "SERVLET=" parameter added which provides the
name of the template to use for the title when running with the servlet runtime. This template can use all of the
commands that are supported for templates, including conditional inclusion of sections, display of variables, etc.
The TITLE command should be used with the appropriate template. This template should be a form with
"action=CORVID_SERVLET" and an OK submit button. (The same as a question template, but without
necessarily asking a question).
When running with the Corvid Servlet Runtime, there could be multiple TITLE commands, since each has a
"servlet=" parameter that could specify a different template. However, when run with the Applet Runtime,

430 17: Corvid Servlet Runtime


there is only one title screen specified with the Corvid screen commands, and it would be used each time the
TITLE command was used, regardless of "servlet=" parameter. If you wish to have a system that will run the
same with either applet or servlet runtime, only use a single TITLE command.
The DISPLAY_HTML command can also be used to display an HTML title or other informational screen. Unlike
the TITLE or RESULTS command, screens displayed with the DISPLAY_HTML command are not parsed
for Corvid commands. However, they are parsed for the “CORVID_SERVLET” replaceable parameter.
This is to allow compatibility between the applet and servlet runtimes. In the applet runtime a
DISPLAY_HTML command simply opens the specified page in a new browser window. In the servlet runtime,
the page is simply displayed in the user's browser. However, to allow the displayed page to return to the
Corvid servlet to continue the system, there must be a <form> tag and action command. If the page has no
<form> tag, the Corvid servlet will automatically add one with an OK button at the bottom of the page. This
will have the link to return to the servlet.
If placing the OK button at the bottom of the page is not desired, the page MUST have a <form> in the page.
If a <form> tag is found, Corvid will not add its own OK button.
To add your own form, the displayed page should have:
! <form method="post" action="CORVID_SERVLET">
content
<input type="submit" name="OK" value="OK">
</form>
The "value="OK" sets the label for the button and can be any name. It is also possible to use an image map
or link to return. (See the section on image maps for details.) In that case, include a <FORM> and </FORM>
tag, but no content in the form. If this is done, Corvid will not add its own OK button.
Remember that if a form is added to an informational page, it will not work correctly when run with the applet,
so for most cases it is better to allow Corvid to add the OK button when using the servlet. This allows the
same page to be used with both applet and servlet runtimes.

17.9.6 Links to Other Pages


Any of the screens displayed by the Corvid servlet can include links to other HTML pages. However, only the
page displayed by the Corvid Servlet Runtime will have the embedded information needed to return to the
servlet engine. If a link takes the user to another page using the same browser window, they would need to
use their browser Back button to return to the page displayed by the servlet to continue the session. This
would not be a good user interface. Instead, it is best to have links open a new page in a separate browser
window or a separate frame. This will allow the links to be viewed, but keeps the form and controls that will
continue the session available.
It is easy to have a link open the page in a new window by using:
target="_blank"
in the link.
For example:
<a href="page_to_display.html" target="_blank">link text</a>

17: Corvid Servlet Runtime 431


17.9.7 JavaScript, CSS, etc.
Any of the templates that are used by Corvid can contain JavaScript, CSS or any other code that is supported
by the browser. The script can include any of the replaceable Corvid parameters. It can appear in
CORVID_REPEAT or other blocks. Corvid only processes the specific Corvid commands, such as
CORVID_ASK, CORVID_IF, CORVID_REPEAT and the replaceable parameters. It does not parse or
"understand" any of the code that may be between these command sections. It simply echoes it back out,
with any replacements. To Corvid, it does not matter if the code between commands is HTML, CSS,
JavaScript or any other code that may appear in the future.
The use of JavaScript in the templates allows some very complex effects.
Remember that the processing is being done on your server, so do not include any server-side script that
could cause security problems.

17.9.8 Final Screen


A screen that will be displayed at the end of the run can be specified in the Properties window, Servlet tab.
This provides a simple way to display results or other information. In most cases, it is better to do this in the
Results screen, but if there are several ways to terminate a session, the overall Final Screen may be
desirable. This can be a simple "Thank you for running …" screen with no link back into the system, or one
that includes a RESTART button to start a new session.
The screen can use any of the Corvid commands that are supported in templates. Replaceable parameters
can be assigned. This screen can be used as a results screen, but if that is done, the system will not have a
result screen when run with the applet runtime. If you wish to run the system in both modes, always use the
RESULT command that is supported in both applet and servlet environments.
To add a final screen to a system, open the
Properties window and select the Servlet tab.
In the "HTML Page to Display at End of Run"
box enter the name of the HTML page to
use. The Browse button allows selecting an
existing file. If a HTML editor has been
specified, the "New/Edit" button allows
creating a new page, or editing the one that
is selected.

Default Final Screen Template


If there is no final screen template specified,
a system default template will be used. This
is a generic template that is named
CORVID_Final_Default.html. This file is
automatically installed by the war file that
installs the Corvid servlet. It should not be modified or deleted since it is the last option to use as a “Final”
screen if the system reaches the end of the Command Block and another Final Screen is not specified. In
most systems, this screen would not be used once the system is fielded, but can be useful for development.
To have the system not display the Final Screen, end the controlling Command Block with a RESULTS, or other
command that displays a screen which does not allow the session to continuing processing. This is typically a
screen with only a RESTART button or one with no form, and only a link to another part of your web site.

432 17: Corvid Servlet Runtime


17.9.9 Using Report Commands when Asking Questions
Any of the report commands can be included in templates which are used to ask questions. This allows the
questions to provide information on the system status as it runs, or to provide the systems advice up to that
point as questions are asked.

For example, to display all the variables that currently


have a value on a screen that asks a question use:
The data in the system so far is:
<BR>
<!-- FOR_EACH VARIABLES -->
[[.FULL]]<BR>
<!-- EACH_END -->
<BR><BR>
Now tell me:<BR>
<!-- CORVID_ASK STATIC_LIST -->
…………
<!-- ASK_END -->
This can be a way to provide the user with intermediate
feedback.

17.10 EMAIL Functions


Exsys Corvid has the ability to have a system automatically compile, generate and send an email. Running a
system with the Corvid Servlet Runtime is required for this capability. The EMAIL functions are not supported
in the applet runtime.
Building the email commands is done from the "Email" tab in the Command Block command builder.
There are typically 6 steps to sending an email,
and 6 commands are needed. All, except the
actual EMAIL_SEND command apply until they
are changed by another command. Each is a
separate command in a Command or Logic
Block and must be added individually.

1. Set the email server


Click the "Email Server" radio button and
enter the name of the mail server (e.g.
mail.mysite.myserver.net". This server will
be used for all emails until another Email
server command is executed. Click the OK
button. This will build an EMAIL_SERVER
command. The mail server should be a
standard mail server, such as used to send
other emails. It must allow emails to be sent
from a servlet program.

17: Corvid Servlet Runtime 433


2. Set the Address for the sender
Click the “Sender Address” radio button and enter an email address. This address will appear as the
sender. Typically this is your email address, though a special address can be used. If the recipient’s
address is not valid, or the email fails for some other reason, the mail server will send the failure
message to this address. This will build an EMAIL_FROM_ADDRESS command. Click the OK
button.

3. Set the Recipient's address


Click the Recipient Address radio button and enter the address to send the email to. This must be a valid
address or the email will bounce, typically with a message sent back to the sender address. This will build
an EMAIL_TO_ADDRESS command. Click the OK button.

4. Set the Subject


Click the "Subject" radio button and enter the subject line for the email. This will build an
EMAIL_SUBJECT command. Click the OK button.

5. Set the content type


Click the "Content Type" radio button and enter the type for the message. The two most common types
are "text/plain" (normal text emails) and "text/html" (an email that has HTML code in it). NOTE: Not all
email programs, or recipients, accept HTML emails. This will build an EMAIL_CONTENT_TYPE
command. Click the OK button.

6. Enter the Message Body and Send the Email


Click the "Send Message" radio button and enter the body of the message to send. This will build an
EMAIL_SEND command. Often the message is the content of a Corvid variable, particularly a Collection
variables. To add a variable(s) to the message, click the "Variables" button and select the variable to add.
Unlike the other email commands which set parameters that are used later, when this command is
executed it actually sends the email using the message content and parameters that have already been
set. All other parameters must be specified before the EMAIL_SEND is executed. When a variable
is used for the message it should be added in double square brackets - [[varname]]. The message can
also contain any text or HTML commands with multiple Corvid variables embedded in it using [[ ]]. Click
the OK button.

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]]

434 17: Corvid Servlet Runtime


Collection variables are a convenient way to build messages to send. This can be text, where each item in
the collection should be sent as a single line. To build the message with a new line character between lines,
use:
[[COLLECTION_VAR.concat "\n"]]
Messages can also use HTML codes to format the message. Most modern email programs can accept
HTML messages, but some recipients may have turned this capability off. If you are sending HTML, it is a
good idea to have the Corvid system ask if the recipient can (or wants) to accept HTML emails and select
either a text or HTML message appropriately.
An HTML email has essentially the same content as an HTML Web page. If an HTML email has been built in
a Collection Variable, it can be included in the EMAIL_SEND as [[COLLECTION_VAR.concat ]] without the
"\n", since the HTML does not care if the entire message is on one line.
The email commands are simple to use and very powerful. A system that builds a report for a user, can
simply email it to them rather than presenting a large HTML page. Information on sessions can be emailed to
a developer to check system use, or warn of problems detected by the system. If a system developer wants
to know if certain rules fire or variables get particular values, they can add a test in the Command Block for
the condition and send themselves an email if needed.

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:

SET [REPORT_COLLECTION.ADDFILE] ReportTemplate.tpt


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/html
EMAIL_SEND [[REPORT_COLLECTION.concat]]

17: Corvid Servlet Runtime 435


17.10.1 Email Commands for Server Authentication
Some email servers require authentication of the
user’s ID and password to send mail. To handle
these, there are 2 special email commands.
These are built from the same Command Building
Window as other email commands.

The section at the bottom of the window allows


entering the user name and password.

As with all the other email commands these are


added to the Command Block one command at a
time, and the command applies to all subsequent
email commands until it is changed.
Most email servers will NOT require
these commands, and they should
ONLY be used if needed. Hard coding a
password into a system should be used
only as a last resort. If a system requires
using passwords, it is best to setup a dedicated email account specifically for the system so that the password
cannot be used in other contexts.

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.

436 17: Corvid Servlet Runtime


If this option is checked, cookies will be used to pass data. If a user has their browser set to not accept cookies,
the system will not work on that browser. Unless there are specific reasons why you need to use cookies, it is
strongly recommended that this option not be checked.

17.12 Passing Data at Servlet Runtime Startup


Initial data can be passed to the Corvid Servlet Runtime when it is started using a URL. The normal link to
start the Corvid Servlet Runtime is:
http://www.server.com/Corvid/corvidsr?KBNAME=../MyApps/MySystem.cvr
Data can be passed to Corvid by adding it to the end of the URL. The format is:
[VarName]=value
where “VarName” is the name of the Corvid variable to assign the value to and “value” is the value to assign
to it. If the value includes any characters that need URL encoding, they must be encoded (This includes
spaces and other special characters). The data assignment is separated from the KBNAME string by "&". If
there are multiple items of data to assign, they should be separated by "&", without any spaces.
For example, to pass the value of variables [X] and [Y] at startup:
http://www.server.com/Corvid/corvidsr?KBNAME=../MyApps/sys.cvr&[X]=1&[Y]=5
Static List variables can be assigned the number of a value or the short text of the value.
This ability to pass data at startup allows integration of the Corvid Servlet Runtime with other pages on a site.
Those pages could be used to ask questions with a form, or interface to content management or
personalization software, which could provide the information to the expert system.
If a form external to Corvid is used to start the system, it should use the GET method to pass the data as part
of the URL.

17: Corvid Servlet Runtime 437


Chapter 18: Integrating Corvid with Adobe
Flash

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.

18: Integrating Corvid with Adobe Flash 439


18.2 Using Flash for the User Interface
There are 3 main architectures for using Flash as the interface of an Exsys system. All can be done, but
some require more code than others.
Single Interaction
The simplest is when a system has a fixed set of questions that are always asked. All the user input
is collected in a single SWF file and then all sent to the Corvid system on the server in a single call.
Corvid processes the data and sends back results/conclusions in XML which is processed and
displayed by the Flash SWF. The system can be rerun as needed, but all session data is retained in
the Flash program.
Interactive, Single SWF
The next level is a system that may ask many questions but the ones needed for a particular session
are set dynamically based on user input. Some questions will be asked, and some will not be needed
and can be skipped in a particular session. In this case, the SWF asks initial questions and sends
this data to the Corvid Servlet Runtime on the server. Corvid sends back XML data which either
describes additional questions to ask or results/conclusions. The SWF file must process the returned
XML and determine if another question(s) need to be asked, or if the system is done and results
should be displayed. The SWF must reconfigure the screen appropriately. If additional questions are
asked, the SWF must ask the question, send the additional data to the Corvid Runtime and process
the new returned XML. This can happen interactively as many times as needed by the system. In this
case, session data is maintained in the Corvid Runtime and the SWF will send and process data
multiple times.
Interactive, Multiple SWF
The most complex level is an interactive system as above, but requiring multiple SWF files for special
effects or to ask questions in very different ways. In this case, the XML data returned from Corvid
both can have parameters of additional questions or results, but also an identifier for a different SWF
file that should be used at that point. The code to switch SWF is provided in the instructions and it is
not difficult to switch, but it is more complicated and requires generating multiple SWF files.

18.2.1 Single Interaction Systems


Many type of advisory systems only require a
single interaction between the Flash SWF and
Corvid Servlet Runtime. They are very well
suited to systems for product selection or
advice where the end user can set their
preferences or requests on a single screen
and that is all the user information the Corvid
system needs to make an analysis.
For example, this system to recommend
which islands in the Caribbean would be best
for someone to visit based on the activities
they are interested in. The end user ranks
their interest in each activity on the upper left
with sliders. When the “Where should I go”
button is clicked. All the activity data is sent
to a Corvid system on the server. It analyzes
the data in a MetaBlock system and returns
the rankings for each island as XML data.
The Flash SWF then takes this XML data and
uses it to put orange dots on the top ranked
islands. Clicks on the dots display information
on that island in the lower portion of the Flash screen.

440 18: Integrating Corvid with Adobe Flash


Once the data has been run, the “Show Top” drop-down can be used to display more or less islands based on
the activity values that were provided for the run. This is done by just displaying more or fewer islands using
the existing XML data rather than rerunning the system.

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”.

18: Integrating Corvid with Adobe Flash 441


18.2.2 Interactive, Single SWF Systems
While some systems always ask the same questions, most are interactive and ask or skip some questions
based on the answers to previous questions. This is typical for systems that emulate a conversation with a
human expert for diagnostics, regulatory compliance or any area where the sequence of questions is
dynamic.
For interactive, multi-question systems, the main difference in the Flash - Corvid interaction is only that
session data must be sent in addition to the user input. However, the Action Script in Flash to handle the
multiple questions can be much more complex.

For example, this system to provide information


on Corvid, asks questions dynamically to drill
down in areas of interest to provide the end
user with content specific to their interests.

The user makes selections on a screen and


clicks the “Enter” button. Their input is sent to
the Corvid Servlet Runtime which processes it
in conjunction with other input that the user has
provided, and sends back XML data to Flash on
the next question to ask. Flash displays a short
animation, reconfigures part of the screen to
ask the next question and updates the
“Progress” bar based on variable values sent
back in the XML. This is done repeatedly to
dynamically ask a series of questions.

442 18: Integrating Corvid with Adobe Flash


When all the required questions have
been asked, the system builds an
HTML report with content customized
for the user outside of Flash and
display the report in a new browser
window.
When this type of system runs:
1. The Flash application uses the
various controls and graphic
options to ask the starting
question.
2. When the user has answered
that question, 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, passing
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. The Corvid Runtime sends
back XML with data on the
next question to ask. The
question sequence is controlled by the user input and system logic. The XML includes the prompt,
value list, restrictions and anything else needed to ask the question. The XML can also include the
value of Corvid variables that can be used to display progress bars or for any other reason. The
XML also includes a session identifier so Flash can later send additional data for that session.
6. The Flash program processes the XML to reconfigure the screen to ask the new question. This can
involve animations or any other Flash graphics.
7. The user answers the next question. This time Flash constructs a URL that has the new data along
with the session identifier.
8. Corvid recovers the session, adds the new data and continues processing. This may require asking
additional questions or the system may have reached conclusions/advice. Corvid sends back XML
data on the next step for Flash to implement. The system keeps sending questions to ask, and
receiving user input as many times as needed.
9. When complete, the Corvid Runtime system either creates a report external to Flash (as in the
sample) or creates XML data that contains the results and recommendations which is sent back to the
Flash application as XML data and it is presented in Flash.

To see this system actually running, go to:

http://www.exsys.com/demomain.html

and run the “Exsys Web Site Concierge WINK System”.

18: Integrating Corvid with Adobe Flash 443


18.2.3 Interactive, Multiple SWF Systems
The Flash interface for a Corvid system can use more than one SWF file. This is actually never required,
since Flash is quite flexible in its ability to reconfigure, but it may be easier to build multiple SWF files rather
than a single large one with the complex Action Script needed for a major reconfiguration.

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.

444 18: Integrating Corvid with Adobe Flash


18.3 Exsys / Flash Interaction Overview
There are 3 steps in the process of using Flash SWF files as the user interface for the Corvid Servlet Runtime.

1. Sending Data to the Corvid Servlet Runtime


Each of the questions in the system will be asked via the SWF file(s) and will send data to the Corvid Servlet
Runtime. This may be multiple questions on one screen or the value for a single question. Each question
screen sends data to the Runtime using POST.

All POSTs to the Corvid Servlet Runtime will be:

Corvid Servlet Address ? Data to send


The Corvid Servlet Address will be the same as when using the Corvid Servlet Runtime and HTML forms. it
will be something like:
http://www.myserver.com/CORVID/corvidsr
http://localhost:8080/CORVID/corvidsr
The “Data to Send”:

A. MUST always start with:


RUNMODE=FLASH
This tells the Corvid Servlet Runtime to send back XML data rather than a page generated with an
HTML template form.

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 &.

“Data to Send” for first call to the Corvid Servlet Runtime:

Corvid Servlet Address?RUNMODE=FLASH&KBNAME=ExsysKBLocation&[var1]=value1& [var2]=value2...

“Data to Send” for all subsequent posts in that session:

Corvid Servlet Address?RUNMODE=FLASH&~SCRNUM=scrnum&[varX]=valueX&[varY]=valueY...

NOTE: The first call has the parameter “KBNAME=ExsysKBLocation”.


All subsequent posts have the session parameter “ ~SCRNUM=scrnum”

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.)

18: Integrating Corvid with Adobe Flash 445


The variable / value pairs are also the same as in non-Flash systems. The variable name must be in [ ]
followed by “=” followed by the value(s). For Static List variables, if there are multiple values they should be
separated by commas. There can be as many variable/value pairs as needed but each pair must be
separated by “&”.

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.

Set the request.data to the data string that was built.


request.data = dataToSend;
A URLLoader object is created to send the data.
var loader:URLLoader = new URLLoader();!
! loader.dataFormat = URLLoaderDataFormat.TEXT;
“Listeners” must be configured for the URLLoader. The only required listener is for the COMPLETE event
because that is when the XML data sent back from Corvid will be available, but others can be used as desired
to show progress, check for errors, etc.
configureListeners(loader);

! function configureListeners(dispatcher:IEventDispatcher):void {
! ! dispatcher.addEventListener(Event.COMPLETE, loadCompleteHandler);
! }

Set the method to POST and send the header.

! // call Exsys on the server


! request.method = URLRequestMethod.POST;
! request.requestHeaders.push(header);

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);

446 18: Integrating Corvid with Adobe Flash


!} catch (error:Error) {
!! trace("Unable to send data to Corvid Servlet Runtime: " + error);
}

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 (exsysData.data) { // if there is data returned


! ! try {! ! !
! ! var returnedData:String; // data returned from Exsys
! ! returnedData = exsysData.data;
! ! nextScreenXMLData = XML(returnedData);
This now converts the data sent back from Corvid to an XML object, which can be used to determine what to
do, which SWF file to use next, how to reconfigure controls, etc. Corvid can send a variety of information
based on the situation and parameters set by the system developer. (These are explained in more detail
below). There are a few items of data that are needed for most systems. The easiest way to use the XML
data is via Flash’s E4X syntax.
The first thing to check is for errors. If the Corvid system detected any error in processing the data, it will set
“nextScreenXMLData.action.type” to “ERROR“ with the explanation of the error in
“nextScreenXMLData.error” to the error string. If this occurs there is some problem in the system that needs
to be examined and fixed.

! // if an error was returned


! ! if (nextScreenXMLData.action.type == "ERROR") { !
! ! ! trace(nextScreenXMLData.error); ! // display the error
! ! ! return;
! ! // exit
! ! }

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.

18: Integrating Corvid with Adobe Flash 447


! ! if (nextScreenXMLData.action.type == "ASK")
! ! ! // display the next screen

! ! 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);
! ! !

3. Communication Between SWF Files


Most systems will only use a singe SWF file that will reconfigure for each question, however Corvid supports
using multiple SWF files when needed.
When a system uses multiple SWF files, the XML data sent back from Corvid specifies the SWF to load next.
That SWF must be loaded and the data passed to it. This is probably the most complicated aspect of
integrating Flash with Corvid because it uses capabilities of Flash not typically used for most Flash
applications, and it requires using events in a precise (somewhat non-intuitive) way or the technique will not
work. This operation is NOT needed if the system uses only a single SWF file. The data is sent between SWF
files with the Action Script 3 LocalConnection object. (As with many things in Flash, there may be other ways
to achieve the same result - but this is the approach we recommend)
Each SWF should have a sending and receiving LocalConnection object:
! var sendingLC:LocalConnection;
! var receivingLC:LocalConnection;

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.

! function loadNextScreen (fileToLoad:String, dataToPass:String) {


This is done by creating a new Loader object.
var nextScreenLoader:Loader = new Loader();
This Loader requires two event listeners - one for INIT and one for COMPLETE. The problem here is that as
the new SWF is loaded, the old one becomes inactive. Data has to be sent with LocalConnection in the brief
interval when the old SWF is still active and can send data, and the new SWF has become active enough to
receive the data. The trick to doing this is to establish the connection on the Loader’s INIT event, but to send
the data on the COMPLETE event.

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.

448 18: Integrating Corvid with Adobe Flash


The INIT part is:

! 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;

18: Integrating Corvid with Adobe Flash 449


Try to receive the data sent by the previous SWF file under the label “CorvidData”. If this fails, report an error.
!

! 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]=” +...

450 18: Integrating Corvid with Adobe Flash


18.4 The Action Script Code in Detail
This Action Script code can be copied into a system. A copy of it is installed with Corvid in the folder:/
ProgramFiles/Exsys/Corvid/SampleFlashActionScript.txt
Required imports to handle Flash events, and call URLs
! import flash.events.*;
! import flash.net.URLLoader;
! import flash.net.URLRequest;
! import flash.net.URLRequestHeader;
! import flash.net.URLRequestMethod;
! import flash.net.URLVariables;

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.)

import flash.net.LocalConnection; ! // Send and receive data

Add imports for whatever controls will be used in the system


import fl.controls.RadioButton;
! import fl.controls.RadioButtonGroup;

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.

18: Integrating Corvid with Adobe Flash 451


try {
!receivingLC.connect("CorvidData");
! } catch (error:Error) {
! ! trace( "Receiving LocalConnection Error: Can't connect");
! }
This is the function specified by LocalConnection.send from in the previous SWF file. This function will be
passed the data sent. It just converts it into the global Flash XML object, receivedXMLData, for use later,
closes the local connection and calls the buildUI() function to use the XML data to layout the controls. This is
not needed in first SWF or if there is only a single SWF.
! 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 buildUI() function (or whatever name is preferred) uses the passed XML data to configure the user
interface - set Prompt text strings, add labels to buttons, arrange components, etc. The degree to which this
is needed depends on how specific/generic the SWF file is. Very general purpose SWF files may do
significant reconfiguration to work with various questions. SWF files dedicated to a specific question may not
need to do anything.
function buildUI():void {
! ! // create and arrange components
}
Add handler(s) to send data to Exsys. This sample system assumes a simple design with 2 radio buttons and
an “OK” button. The system will send the value of the selected radio button to Exsys. A real system can have
as many controls and control types as desired. The point here is that the OK button (or some other action)
indicates that the input is complete and data is to be sent to Exsys.
This event handler detects a click on the OK button (labeled “btnOK”) to build the data string to send to Exsys.
This may involve collecting data from multiple controls/objects.
! btnOK.addEventListener( // if the OK button is clicked
! ! MouseEvent.CLICK,
! ! function processInput() {
! ! ! var numSel:uint;
! ! ! ! // number of the radio button selected
! ! ! var dataToSend:String = "";
! ! ! ! // string that will be sent to Exsys
! ! ! if (radio1.selected == true)
! ! ! ! // if radio button 1 set value to 1
! ! ! numSel = 1;
! ! ! else! // otherwise set the value to 2
! ! ! numSel = 2;

452 18: Integrating Corvid with Adobe Flash


Once data is collected, it will be sent to the Corvid runtime for processing. This is done with a URLLoader.
var loader:URLLoader = new URLLoader();
! ! ! //setup loader for next screen
! ! ! loader.dataFormat = URLLoaderDataFormat.TEXT;

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.)

! var header:URLRequestHeader = new URLRequestHeader("pragma", "no-cache");

Point a URLRequest to the Corvid Runtime using the ExsysRuntimeLocation variable.

var request:URLRequest = new URLRequest(ExsysRuntimeLocation);


The data to send to Corvid should be setup as a series of name=value pairs separated by &.
The first parameter passed to Corvid MUST be RUNMODE=FLASH. This tells Exsys to return XML data
rather than the normal HTML.
For the first call to Exsys, the second pair MUST be the KBNAME=name. This can be done using the
ExsysKBLocation variable defined at the top of the code. For subsequent calls to Exsys, the second pair
MUST be:
! ~SCRNUM = receivedXMLData.scrnum
where the receivedXMLData will be sent back from Exsys. This passes back the screen number used by Exsys.
After that as much data as desired can be added using [varname]=value separated by &. This can be
repeated for multiple variables. The variable name MUST be in [ ]. The variable name can be obtained from
the XML data that Exsys sends or hard coded. For the first SWF file it must be hard coded since no data is
normally passed in.
In this example, the Exsys variable [Color] is assigned the value selected from the radio button.
dataToSend = "RUNMODE=FLASH&KBNAME=”+ ExsysKBLocation+”&[Color]="+numSel;
Set the request.data to the value string that was built
request.data = dataToSend;
Set the method to POST and send the header.
! // call Exsys on the server
! request.method = URLRequestMethod.POST;
! request.requestHeaders.push(header);
Try to load the request, which will pass the data to Corvid, catching and displaying any error that occurs.
try {
! loader.load(request);
! } catch (error:Error) {
! trace("Unable to post data to Corvid Servlet Runtime." + error);
! }

18: Integrating Corvid with Adobe Flash 453


Once loader.load() is called, the system has to wait for Exsys to process the data and send back the results.
This may be only moments or some time, depending on server, system size, number of rules, etc. The
listeners assigned to the loader will activate when it is done (or warn if it fails). In the meantime, clean up the
screen and if desired, display some form of “in process” graphic to let the user know the system is running.

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.

// remove or hide controls from this screen


! myPrompt.visible = false;
! removeChild(radio1);
! removeChild(radio2);! ! !
! removeChild(btnOK);
!}
! );
This configures the listeners for the loader object. Only the COMPLETE event is required, but the others can
be used to report problems or indicate progress to the user.
// only the COMPLETE event is required. Others can be used as desired
function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.COMPLETE, loadCompleteHandler);
dispatcher.addEventListener(Event.OPEN, openHandler);
dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, ! !
securityErrorHandler);
dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS,
httpStatusHandler);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
}
The loader COMPLETE event gets the XML data sent back from Corvid, stores it and creates and XML object
from it that can be used in other parts of the system.
function loadCompleteHandler(event:Event):void {
! var exsysData:URLLoader = URLLoader(event.target);

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 (exsysData.data) { // if there is data returned


! ! try {!!
! ! var returnedData:String;
! ! ! ! // data returned from Exsys!
! ! returnedData = exsysData.data;
! ! nextScreenXMLData = XML(returnedData);
! ! ! // parse XML data to decide what to do next

454 18: Integrating Corvid with Adobe Flash


The XML data returned from Exsys has an Action Type value that can be used to determine what to do next.
This should be parsed and used to determine what to do. (More on the XML below)

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);
}

18: Integrating Corvid with Adobe Flash 455


function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
}
Load the next SWF file. If the template approach is used, this should instead reconfigure the controls in the
existing SWF file.
// load the next screen and pass the XML data
! function loadNextScreen (fileToLoad:String, dataToPass:String) {
! ! var nextScreenLoader:Loader = new Loader();

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.

On INIT the new SWF must setup the LocalConnection.


! // on INIT make Local Connection
! nextScreenLoader.contentLoaderInfo.addEventListener (Event.INIT ,
! function(evt:Event):void {
! ! sendingLC = new LocalConnection();
! ! sendingLC.client = this;
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 data
will be gone.
! ! try {
! ! sendingLC.connect("CorvidData");
! ! } catch (e:Error) {
! ! trace("Local Connection error : " + e);
! ! }
}
);
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.
! // on COMPLETE add the SWF file and send the data
! nextScreenLoader.contentLoaderInfo.addEventListener (Event.COMPLETE,
! function(evt:Event):void {
! ! addChild(nextScreenLoader);

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

456 18: Integrating Corvid with Adobe Flash


! nextScreenLoader.load(new URLRequest(fileToLoad));
! }
The new SWF screen will be loaded and the process can be repeated as needed. When the action.type =
“RESULTS”, then the SWF to display the results screen should be loaded. It will parse the normally more
complex result XML data and display it.

18.5 The XML Data Sent by the Corvid Servlet Runtime


Whenever a Flash SWF posts data to the Corvid Servlet Runtime, Corvid sends back XML data that can be
used by the SWF. This XML data can be easily converted to a Flash XML object with:
! nextScreenXMLData = XML(returnedData);
and then incorporated into your Flash code using Flash’s E4X syntax.
E4X provides a very convenient way to refer to the XML data that Exsys sends and even allows you to extend
it with your own XML tags unique to your system.
The type of data varies with the action being performed, and the options selected in the development
environment.
The data Exsys sends is always wrapped in an <exsysdata> tag. There are some additional tags that are
always sent, along with some optional ones.
The XML data will always be:
<exsysdata>
! <scrnum> Exsys Screen Identifier </scrnum>
! <action>
! ! <type> Action to take ASK, RESULTS, DISPLAY_HTML or ERROR </
type>
! ! <target> Target for the Action </target>
! ! <template> SWF file to use for the next action </template>
! </action>
! <error> Any Error Text or blank if there is no error </error>

! <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

18: Integrating Corvid with Adobe Flash 457


<action>
Inside the <exsysdata> tag, there will always be a <action> tag. This is to indicate what type of action is to be
performed next and how to perform it. The <action> tag always has 3 parts:
<action>
<type> Action to take ASK, RESULTS, DISPLAY_HTML or ERROR </type>
<target> Target for the Action </target>
<template> SWF file to use for the next action </template>
</action>
The <type> tag indicates the type of action is to be performed using the other tags. The possible values are:

ASK Ask the user the the value of the Corvid variable named in <target>
using the SWF file specified in <template>

RESULTS Display the results using the SWF specified in <template>


DISPLAY_HTML Display the html page specified in <target>
ERROR An error occurred. Display the error message in
receivedXMLData.error

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.

The <exsysvar> tag


The <exsysvar> tag is used to provide information on a Corvid variable. This may be to provide the
information needed to ask the value of the variable in an ASK action, or to provide the final value set as part
of the advice and recommendations in a RESULTS action. There can be multiple <exsysvar> tags in the
XML data when that is needed to ask multiple questions on the same screen, or when the results require the
value of multiple variables.

458 18: Integrating Corvid with Adobe Flash


The <exsysvar> can have the following tags in it. (Not all tags are used in all cases.)

<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>

<defaultValue> Default value </defaultValue>

<control> Type of Control to use when asking </control>

<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>

<currentValue> The current value set for the variable </currentValue>


<other> Other info the developer sends - could be other XML tags </other>
</exsysVar>

18: Integrating Corvid with Adobe Flash 459


<name>
Within an <exsysVar> item, there will always be a <name> tag with the name of the Corvid variable. This will
NOT be in [ ].
<name> varname </name>
In cases where there are multiple <exsysvar> tags in the XML to describe multiple variables, the name tag is
the most convenient way to refer to individual variables with E4X. For example, to get the prompt for the
Corvid variable [color] :
! nextScreenXMLData.exsysVar.(name == “color”).varPrompt
To get the current value of the Corvid variable [color] :
! nextScreenXMLData.exsysVar.(name == “color”).currentValue
When the nature of the system guarantees that there will be only a single <exsysvar> tag, this is not needed
and a simpler format can be used:
! nextScreenXMLData.exsysVar.varPrompt

<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.

460 18: Integrating Corvid with Adobe Flash


<possibleValues>
<count> number of values </count>
<valueText> value 1 </valueText>
<valueText> value 2 </valueText>
<valueText> value 3 </valueText>
...
</possibleValues>

<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>

18: Integrating Corvid with Adobe Flash 461


If there is an Also Ask list, there will be separate <exsysVar> tags for each of the variables in the list, which
can be used to get the parameters for each variable. The data for each variable can be obtained by reading
the name in the list and then using E4X syntax to specify the properties for that named variable, such as:

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>

462 18: Integrating Corvid with Adobe Flash


If there is a <maxDaysPast> value, the input date input must not be more than that number of days in the past
from the current date when the system is run. If the <maxDaysPast> value is blank, there is no such
restriction.
If there is a <maxDaysFuture> value, the input date input must not be more than that number of days in the
future from the current date when the system is run. If the <maxDaysFuture> value is blank, there is no such
restriction.

<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.)

16.5.1 Asking Questions


When the action is to ask a question, the XML data will be:
<exsysdata>
<action>
<type> ASK </type>
<target> Name of the main Corvid Variable to ask </target>
<template> SWF file to use to ask the question </template>
</action>

<error> Any Error Text or blank if there is no error </error>


<exsysVar>
Data on one or more Exsys Variables
</exsysVar

<trace> trace data if that is turned on </trace>

</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

18: Integrating Corvid with Adobe Flash 463


The SWF file to use to ask the variable will be in the action template tag:
! SWFtoUse = receivedXMLData.action.template
The SWF file to use for asking a question can be specified in the Corvid development environment. If no
template was specified, the default SWF will be ask_varname.swf. So, for the Corvid variable [color], the
default SWF would be ask_color.swf and this would be the value of the action template tag unless another
file had been specified.
Inside the <exsysdata> tag, there will be one or more <exsysVar> tags. These provide the information for
asking questions and displaying results. There will always be an <exsysVar> tag for the main variable
specified as the action target. If that variable has associated “Also Ask” variables, each of those will also
have its own <exsysVar> tag with the data on that variable. The developer may also have specified that other
<exsysVar> tags should be added.
The prompt value for a the main target variable can be retrieved with E4X by:
nextScreenXMLData.exsysVar.(name == nextScreenXMLData.action.target).varPrompt

18.5.2 Displaying Results


When displaying results, Exsys sends similar XML data as in ASK, but the list of variables is specified by the
developer in Corvid. Since this is not a screen to ask questions, many of the parameters that are only needed
for questions are not included.
<exsysdata>
<action>
<type> RESULTS </type>
<target> </target>
<template> SWF file to use to display the results </template>
</action>

<error> Any Error Text or blank if there is no error </error>

<exsysVar>
Data on one or more Exsys Variables to use in the results
</exsysVar

<trace> trace data if that is turned on </trace>


</exsysdata>
The list of variables to include in the results XML and the SWF file to use is specified in the Corvid
development environment. It can be a single variable up to all the variables in the system. Each variable will
have its own <exsysVar> tag. If no list of variables is specified in the RESULTS command (using
“FlashXML=”), all the variables in the system will be sent and the SWF file to be used will be
kbname_results.swf
For each of the variables included, there will be an <exsysVar> tag but the tags <possibleValues>, <control>,
<alsoAsk> and <limits> are NOT included since these are only for asking questions.
The <name> <type> <varPrompt> <curentValue> and <other> are always sent.

464 18: Integrating Corvid with Adobe Flash


At the developer’s option, other tags and their associated data can be sent. Default is to NOT send these
tags. These are set in the Corvid development environment.

<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

18.5.3 Displaying an HTML Page


Some systems display their results by dynamically building an HTML page. This is stored on the server and
the URL for the page is sent to the SWF file for display in a new browser window. This has the advantage
that the results page can be easily printed and bookmarked with the Browser program.

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>

<error> Any Error Text or blank if there is no error </error>

<trace> trace data if that is turned on </trace>

</exsysdata>

18: Integrating Corvid with Adobe Flash 465


18.5.4 Error Reporting
If the Corvid Servlet Runtime encounters an error when processing the data that has been sent to it, the XML
data it sends back will report the error.
In this case the XML data is very simple since it only needs to report the error.
<exsysdata>
<action>
<type> ERROR </type>
<target> </target>
<template> </template>
</action>

<error> The explanation of the error </error>

<trace> trace data if that is turned on </trace>

</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.

18.6 Specifying the Flash Interface Parameters in Corvid


In the “Variables” window “Servlet” tab, the edit box
that is used for entering the HTML template to use
when running with the Corvid Servlet Runtime, can
also be used to specify the Flash SWF file to use
when running with a Flash interface. When Corvid is
run with Flash, the SWF file specified will be used in
the XML data as the action template tag for this
variable.
For systems using the non-Flash HTML interface
with the Corvid Servlet Runtime, the name of the
HTML template to use can still be entered.
If no SWF file is entered, the file ask_varname.swf
will be used, where “varname” is the name of the variable. (e.g. ask_color.swf would be used to ask the
variable [color].)
At the bottom of the “Servlet” tab, an edit box allows adding custom content for the XML <other> tag for this
variable. Any special text or information required by the Flash interface can be included. This will be in the
<exsysVar> tag for the variable in its <other> tag. The text can be any string, and can include double square
bracket embedding of other Corvid variables. The string can also use other XML tags of your design to include
multiple items of data in a way that makes them easy to recover in the Flash using E4X syntax. If other XML
tags are used, make SURE that all tags have matching closing tags and are correctly nested. If they are not, the
Action Script commands to create XML objects from the data will fail. For example, if the “Other” text is:
<item1>aaa</item1><item2><x>123</x><y>456</y></item2>
You could recover the value of item2 x for the variable [MyVar] using:
! nextScreenXMLData.exsysVar.(name == “MyVar”).other.item2.x

466 18: Integrating Corvid with Adobe Flash


18.6.1 XML Data to Include with Results
The Command Builder window “Results” tab has controls to support Flash systems.
The “Display Default Results Screen” and “Display File of
Corvid Screen Commands” each have Flash “Flash Data
To Send” options. These allow specifying which variables
will be included in the XML data for the results, and to
specify what data will be sent for each variable.
The information on what to send is stored in special files,
which can be easily created or edited from within Corvid.
The file name will be added to the Corvid Command as
“FlashXML=filename”.
When adding a Flash XML specification file for either of
the Results screens, either click “New” to create a new
one, “Browse” to find an existing one, or “Edit” to edit the
one currently entered in the edit box. This will open a
window for specifying which variables are to be included in
the XML sent to Flash when the command is executed.
The window for adding or editing the XML specification is:
1. Specify the SWF file to use at the top of the window.
This can be any SWF file. Normally the SWF file(s)
will be in the same folder as the Corvid CVR file and
other system files. This makes paths unnecessary,
and makes it far easier to move all the required files
to the server.
2. Select the variables to include. All the variables in
the system will be in the left list. You can limit the
variables displayed in the left list using the “Restrict
to” check boxes to display only certain types of
variables, or use the “Find” to find variables with the
search text in them. Select the variable(s) to include
and click the “>” button to add them to the “Selected”
list. All the variables can be moved to the “Selected”
list by clicking the “>>” button. Variables can be
removed from the “Selected” list by clicking on them
and clicking the “<“ button or the “<<“ button to
remove all the variables in the “Selected” list.
3. Select which items of data on the variables are to be included in the XML. The <name>, <type>,
<varPrompt>, <currentValue> and <other> values are always sent. The optional tags allow other
information on the variable to be sent. Items should only be included if they will be used in some way in
the Results display.

<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>

18: Integrating Corvid with Adobe Flash 467


The same tags will be sent for all the variables in the “Selected” list.
4. When done, if this is a new file, Corvid will ask you to specify a name for this XML specification file.
Save it with your system files (CVR file) and move it to the server in the same folder as the CVR file
when the system is fielded. When the system is run, the RESULTS will have and <exsysVar> tag for
each of the selected variables, with the tags specified.

Display HTML Page


The “Display HTML Page” edit box works essentially the same as for non-Flash systems, but when the Corvid
Servlet Runtime is running in Flash mode, the command will automatically cause the runtime to send XML
data with the action type tag set to “DISPLAY_HTML” and the action target tag set to the URL specified.

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.

468 18: Integrating Corvid with Adobe Flash


Appendix A - Expressions and Functions
A.1 Corvid Expressions
Most of the logic in a Corvid system is built using expressions. These may be either boolean expressions that
evaluate to “True” or “False”, or expressions that evaluate to a numeric, string or date value that is being
assigned to a Corvid variable. Boolean expressions are used in the IF part of rules, the tests in Action Blocks
and in the “IF” and “WHILE” tests of Command Blocks. Expressions to set the value of a variable are used in
the THEN part of rules, the actions in Action Blocks and in Command Blocks.
Corvid expressions are very similar to expressions in many computer languages and Algebra. They often
include the value of Corvid variables by having the name of the variable in square brackets (e.g. [varname])
and can also include any of the properties of a variable by using [varname.PROPERTY].
Most of the windows for building expression have a
“Variables” button that will display a special window for
adding variables to the expression.
Click on a variable in the list on the left side. All of the
properties for that variable will be displayed on the right.
If a property is desired, click on it. Then click “OK”. If
no property or method is required, just double click on
the variable.
A few properties require a numeric parameter. These
have a # in the property. If one of these is selected, fill
in the value of # in the edit box.
The variable will be added to the expression editing box
at the current cursor point, in [ ]. The list of variables can
also be displayed by pressing Ctrl-Alt-V.

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.

Appendix A - Expressions and Functions 469


Parenthesis and Order of Precedence
The precedence order in evaluating expressions is the usual one: raising to a power has the highest priority
and is followed by division and multiplication, then addition and subtraction. Expressions are evaluated left to
right. However, use of parenthesis is strongly encouraged to make expressions clear, easy to read and to
avoid confusion.
For example: The order of precedence rules will evaluate a/b*c as (a/b)*c. If you wish to have a / (b * c), use
parenthesis to change the order that the operations are performed. Generally it is good to include
parenthesis even if it does not change the standard order of precedence. Other developers reading or
maintaining a system may not be familiar with the order of precedence rules and could misinterpret the way
complex expressions will be evaluated.

Logical Operations
The supported logical operators are:

less than <


less or equal <=
greater than >
greater or equal >=
equals ==
not equals !=
approx equal ~=
NOT !
AND &
OR |

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.

470 Appendix A - Expressions and Functions


Approximately Equal ~=
Corvid supports an approximately equal boolean operator. This has 2 meanings depending on the type of
expressions being compared:
String ~= String
Performs a case insensitive string comparison of the 2 string expressions. (The normal String = String
comparison is case sensitive) (The UCase() conversion function can also be used to do case insensitive
comparisons)
For example, "hello world" ~= "Hello WORLD" is true
"hello world" = Hello WORLD" is false
Numeric ~= Numeric
Tests if two numerics are approximately equal. The deviation allowed depends on the size of the numbers
involved. For positive numbers, it tests if the difference of the 2 numbers is within .005% of their sum. The
actual algorithm allows negative numbers too.
For example, 1000000000 ~= 1000100001 is true
1000000000 ~= 1000100006 is false
This allows a comparison of calculated numbers where roundoff error may have made them very slightly
different.
The actual algorithm used is:
d = ( |x| + |y| ) * 0.00005
if max(x,y) - min(x,y) < -d
then return -1
if d < max(x,y) - min(x,y)
then return 1
else return 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

TRUE Value is TRUE Boolean or numeric 1

FALSE Value is FALSE Boolean or numeric 0

TAB The tab character String

CR The Carriage Return character String

LF The Line Feed character String

CRLF The Carriage Return and Line Feed characters String

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.

Appendix A - Expressions and Functions 471


A.3 Functions
Corvid supports a wide range of functions that can be used to build the expression needed in systems. These
range from the standard trigonometric functions found in most computer languages to specialized functions
for parsing strings and dates.

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:

SIN(1 + (([X] + [Y]) / [Z]))


SIN( SQRT([X]))

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.

A.4 Numeric Functions


SIN(x)
Sine of angle in radians
Returns: Numeric Argument: Numeric
Example: SIN(.5) SIN([X] + 1)

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])

472 Appendix A - Expressions and Functions


ASIN(x)
Arc sine. Returns a value in radians
Returns: Numeric Argument: Numeric
Example: ASIN(.5) ASIN([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

Appendix A - Expressions and Functions 473


ROUND(val, fraction)
Rounds a value off to the nearest integer, or if a fraction is specified, to the nearest value of that fraction.
Returns: Numeric Arguments: Numeric

val The number to round


fraction An optional parameter
The fractional value increment to round off to. The fraction does not have to be
less than 1, but it does have to be positive and non-zero.

ROUND(x) Rounds x to nearest integer


ROUND(x, y) Rounds x to the nearest multiple of y
Examples:
ROUND(10.6)=11
ROUND(10.6, 0.5)=10.5
ROUND(10.7, 0.25)=10.75
ROUND(17.339, 0.1)=17.3
ROUND(256, 100)=300

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

474 Appendix A - Expressions and Functions


Assign a Value Based on Various Curve Types
Special functions allow a value to be defined by several standard statistical curve types. This is
particularly useful in assigning confidence values that implement membership function fuzzy logic. The
actual membership functions can be defined by the curves.
The “Curve” functions combine a Corvid variable whose value will determine the point in the line whose
value will be returned, and other parameters that define the line. The first argument in the functions is
typically a Corvid variable, but can be any numeric value or expression returning a numeric value.
All “Curve” functions return a numeric value and all arguments are numeric.
line([var], x1, y1, x2, y2)
The line is defined by the two points (x1, y1) and (x2, y2).
The value returned will be the Y value for the specific X
coordinate defined by the value of the variable [var]. The
line extends infinitely in both directions with the same slope.
The line cannot be vertical (i.e. x1 can not be equal to x2)
For example: line([X], 1,1, 3,3) will return a value of 2 when
the variable [X] is 2.

lineSegs([var], x1, y1, x2, y2, ….)


The LineSeg() function behaves very much like line(), but
allows the line to be made up of a series of connected line
segments. There can be as many line segments as
needed to define the graph. The function will return the Y
value for the specific X coordinate defined by the value of
the variable [var]. This may fall in any line segment.
Individual segments can have the Y value increase or
decrease, (positive or negative slope), but must be
connected and the X values must not decrease. A [var]
value less than x1 or greater than the highest X value will
return a value based on the extrapolation of the first or last
segment. The first or last segment cannot be vertical, but
vertical segments are allowed internal to the graph. The
value on the vertical segment will be the Y value of the first
point with that x value.

Appendix A - Expressions and Functions 475


bell(var, mean, standardDeviation)
The bell() function implements a standard bell curve
(Gaussian Distribution) defined by a mean and
standard deviation. The function used is:

bell( )= (1 / sqrt(2 * PI * sd^2)) * E^(-1 * (x -


mean)^2 / (2 * sd^2))

This is a very useful function for assigning


probabilities based on a Gaussian. The mean is the
center of the peak. The larger the sd (standard
deviation), the wider (more spread out) the bell
shape.

exponential(var, base, xd, yd, r)


The exponential () function implements an exponential
curve. The function used is:

exponential( )= (base ^ (r * x - xd)) + yd


yd shifts the graph up (or down for negative values)
if (r*x - xd) is negative, then the graph is mirrored
about the y-axis
y=base when (r*x-xd)=1 and yd=0 The base
affects the y position and how fast the graph grows.
xd shifts the graph right (or left for negative values)

logarithm(var, base, xd, yd, r)


The logarithm () function implements a logarithmic
curve. The function used is:
logarithm( )= log base(r * x - xd) + yd
yd shifts up (or down if negative)
xd shifts right (or left if negative)
The bigger the base, the faster it flattens out (as you
move to the right)

476 Appendix A - Expressions and Functions


A.5 String Boolean Tests
The boolean comparison operators have a different meaning when applied to strings. The comparison is
case insensitive (upper and lower case letters are equivalent). For strings A and B, the operators are:
A=B True if string A is the same as string B
A >= B True if A is the same or alphabetically greater than B
A <= B True if A is the same or alphabetically less than B
A>B True if A is alphabetically greater than B
A<B True if A is alphabetically less than B
A != B True if string A is not the same as string B
A <INSTR> B True if string A is a substring of string B

A.6 String Functions


Corvid string functions are primarily for the parsing of strings that contain information needed by a
system, or to build reports.

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.

Appendix A - Expressions and Functions 477


The comparison is case sensitive – a lower case letter will NOT match an upper case letter. To do a
comparison that is not case sensitive, force both strings to upper case with the UCASE() function.
(e.g. UCASE([s]) in UCASE([t]) would check to see if the string value of [s] is in [t] ignoring case.)
This can be used anywhere a Boolean expression is allowed.
Both return the position of string A in string B, or 0 if string A does not occur in string B. This can be used
as a boolean test since 0 is equivalent to “False” and any non-zero value is equivalent to “True”. It can
also be used in numeric expressions that need the position of string A in string B.
Example:

"hello" in "hello world" would return a value of 1 or “True”


“x” in “abc” would return a value of 0 or “False”
“x” <instr> “abc”
“a” in “ABC” would return a value of 0 or “False” – cases do not match
“abc” in [s] would return the position of “abc” in the value of variable [S] or
0 if “abc” does not occur in the value of [S]. This can be use to
test if “abc” is in the value of [S].

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.

478 Appendix A - Expressions and Functions


Example:
FINDCHR("abcdefghij", "bx") returns 2
FINDCHR("abcdefghij", "xyz") returns 0
FINDCHR("abcdefghij", "df") returns 4

REPLACE(sourceStr, searchStr, replaceStr, case_sensitive, numToReplace)


Search a string and replaces occurrences of a search string with a replacement string.
Returns: String Arguments: See below
sourceStr The string to search
searchStr The pattern string to replace
replaceStr The string to use to replace the searchStr
case_sensitive An optional boolean parameter.
By default, all matches of the searchStr are case sensitive (must match upper/lower case). To have the
match be case insensitive, set this parameter to "FALSE" or the numeric value of 0. A value of "TRUE", a
numeric value other than 0, or not including this parameter would make the matching test case sensitive.
numToReplace An optional numeric parameter.
The default is to replace all occurrences of the searchStr with the replaceStr. If only a specified number
of occurrences of the searchStr should be replaced, set the numToReplace parameter to the numeric
value of the number of cases to replace. A value of 0 or a negative value means to replace all
occurrences. If the value is not an integer, it will be rounded down to an integer. If this parameter is
included, the case_sensitive parameter must also be included.
Returns a string with all (or the first numToReplace) occurrences of searchStr replaced with replaceStr.
The search is case sensitive unless case_sensitive is "FALSE".
Both case_sensitve and numToReplace are optional. If they are omitted, the search will be case
sensitive and will replace all occurrences.
The function does not search in the replacement string recursively, so replace("l", "l", "ll") is "ll" and not
"llllll..." infinitely.
sourceStr, searchStr and replaceStr are strings and should either be the value of a string variable, a
string expression or a string in " ".
The parameter case_sensitive is optional, and if present is a Boolean, including "TRUE" or "FALSE" or a
numeric value (0=FALSE).
The parameter numToReplace is optional, and if present is a numeric value.
Examples:
REPLACE("abcdefghij", "def", "xyz") returns "abcxyzghij"
REPLACE("abcdefabcdef", "abc", "xyz") returns "xyzdefxzydef"
REPLACE("abcdefabcdef", "abc", "xyz", TRUE, 1) returns "xyzdefabcdef"
REPLACE("abcdefABCdef", "ABC", "xyz", TRUE) returns "abcdefxyzdef"
REPLACE("abcdefABCdef", "ABC", "xyz", FALSE) returns "xyzdefxyzdef"

REPLACECONTENTS(sourceStr, openStr, closeStr, replacementStr, case_sensitive,


number_to_replace, exclude)
Searches a string and replaces occurrences of a search string with a replacement string. The search
string is identified by the starting and ending strings, rather than by the full string as is used in the
REPLACE() function. (To do a simple replacement of one string for another, use the simpler REPLACE( )
function.)
sourceStr The string to search
openStr The substring that marks the start of the search string

Appendix A - Expressions and Functions 479


closeStr The substring that marks the end of the search string
replaceStr The string to use to replace the search string
case_sensitive An optional boolean parameter
By default, all matches of the search string are case sensitive (must match
upper/lower case). To have the match be case insensitive, set this parameter
to “FALSE” or the numeric value of 0. A value of “TRUE”, a numeric value
other than 0, or not including this parameter would make the matching test
case sensitive.
numToReplace An optional numeric parameter
The default is to replace all occurrences of the search string with the
replaceStr. If only a specified number of occurrences of the search string
should be replaced, set the numToReplace parameter to the numeric value of
the number of cases to replace. A value of 0 or a negative value means to
replace all occurrences. If the value is not an integer, it will be rounded down
to an integer. If this parameter is included, the case_sensitive parameter
must also be included.
exclude An optional boolean parameter
If the optional 'exclude' is true, the text matching the 'openStr' and 'closeStr'
is part of the text replaced. If the optional 'exclude' is false, the text matching
the 'openStr' and 'closeStr' is not part of the text replaced and remains in the
returned string. By default exclude is true.
Returns a string with all (or the first numToReplace) occurrences of the search string replaced with
replaceStr. The search string is defined as any string starting with the openStr, followed by any
characters, followed by the closeStr.
The search is case sensitive unless case_sensitive is “FALSE”.
Both case_sensitve and numToReplace are optional. If they are omitted, the search will be case
sensitive and will replace all occurrences.
The function does not search in the replacement string recursively, so
replacecontents (“ll”, “l”, , “l”, “lll”)
is “ll” and not “llllll...” infinitely.
sourceStr, openStr, closeStr and replaceStr are strings and should either be the value of a string
variable, a string expression or just a string in “ ”. The parameters case_sensitive and exclude are
optional, and if present is a Boolean, including “TRUE” or “FALSE” or a numeric value (0=FALSE). The
parameter numToReplace is optional, and if present is a numeric value.
Examples:
REPLACECONTENTS(“abcdefghijk”, “cd”, “gh”, “XXX”) returns “abXXXijk”
REPLACECONTENTS(“abcdefghijk”, “cd”, “gh”, “XXX”, TRUE, 0, FALSE) returns
“abcdXXXghijk”
REPLACECONTENTS(“abcdefabcdef”, “b”, “e”, “XXX”, TRUE, 0) returns “aXXXfaXXXf”
REPLACECONTENTS(“abcdefabcdef”, “b”, “e”, “XXX”, TRUE, 1) returns “aXXXfabcdef”
REPLACECONTENTS(“abcdefABCDEF”, “b”, “e”, “XXX”) returns “aXXXfAXXXF”
REPLACECONTENTS(“abcdefABCDEF”, “b”, “e”, “XXX”, false) returns “aXXXfABCDEF”

parse(sourceStr, patternStr)
Create a Tab-Delimited String Based on a Pattern String
Returns: String Arguments: String
sourceStr The source string

480 Appendix A - Expressions and Functions


patternStr The pattern to parse with
Returns a tab-delimited string based on parsing the source string relative to the patternStr.
The tab-delimited string is generated by a patternStr, which is a text string with markers in it. The
markers are indicated by {#} where # is a number starting with 0. There can be multiple {#} markers,
but the # must be sequential integers and must start with 0. The order of the {#} in the string is not
required to be in numeric order.
Parse() finds a match between the sourceStr and the patternStr and where {#} occurs, the matching
sub-string becomes a tab delimited element of the returned string. If the pattern cannot be matched to the
source or if the {#}'s do not start with 0 or skips one, then it returns an empty string.
The patternStr should have no extra { or } characters. It must have an equal number of closing brackets
'}' as opening brackets '{ '.
This tab-delimited string can be assigned to a Collection variable. The operation is the reverse of the fill()
function. This command is a very effective way to parsing structured text strings such as error messages.
Example:
PARSE("10 part#12345 at $12.35", "{0} part#{1} at ${2}")
returns "10tab12345tab12.35"

PARSE("ERROR 99-bad widget:12345", "ERROR {0}-{1}:{2}")


returns "99tabbad widgettab12345"

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"

Appendix A - Expressions and Functions 481


MATCHES(sourceStr, patternStr)
Test if a String Matches a Pattern
Returns: String Arguments: String
sourceStr The string to test
patternStr The pattern to test against
Returns TRUE if the sourceStr can be matched against the patternStr. If the pattern does not match, it
returns FALSE. In a numeric context TRUE is 1 and FALSE is 0.
This uses the same pattern matching syntax as when creating a mask for a variable or block name.
Masks are specified by a string that indicates which character(s) is acceptable:
Character Matches
? Any character
* The rest of the string
character Itself
# Any digit 0-9
{abc} Any character in the { }
{X-Z} Any character between X and Z
Examples:
MATCHES("abc123", "a?c###") returns TRUE
MATCHES("abc123", "ab*") returns TRUE
MATCHES("abc", "{a-f}{qbn}c") returns TRUE

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.

482 Appendix A - Expressions and Functions


Example:
If the Collection variable [collection_var] had values:
wrench
valve
a leak
water
FILL("Use the {0} to fix the {1} to prevent {2}", [collection_var.tabdelim]) returns
"Use the wrench to fix the valve to prevent a leak"

TOKENIZE(sourceStr, breakSet, skipSet, trimSet)


Create a Tab-Delimited String Based on Tokens
Returns: String Arguments: String
sourceStr The source string
breakSet The characters to break on
skipSet The characters to skip
trimSet Optional parameter. The characters to trim
Returns a tab-delimited string based on tokens created from the sourceStr. It can be a complicated
command to use, but very powerful. This can be used to add values to a Collection variable.
The algorithm used to generate tokens is: Copy characters from the sourceStr into the current token until
you find a character in breakSet and then skip any characters from the skipSet. The search for the next
token starts with the last character that was not skipped. If you do not want to include the break character
in the token, put that break character in the skipSet. The trimSet string is optional, but if present it
behaves as if trim() was applied to each individual token.
Examples: (In these examples tab is the tab character)
TOKENIZE("one two three four", " ", " ") returns "onetabtwotabthreetabfour"
TOKENIZE("c:/aaa/bbb/ccc.dat", ":/", "/") returns "c:tabaaatabbbbtabccc.dat"
TOKENIZE("abc:12345.67", ":.", ":.") returns "abctab12345tab67"
TOKENIZE(" #abc:12345.67m", ":.", ":.", " #m") returns "abctab12345tab67"

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.

Appendix A - Expressions and Functions 483


A.7 Date Boolean Tests
Date values can be compared using '<', '>' and '=' or '==' and '!=' and '~='.
The date times compared are precise to a millisecond.
[date1] < [date2] is true if date1 occurs before date2
[date1] > [date2] is true if date1 occurs after date2
[date1] = [date2] is true if date1 is at the same time as date2
For example:
[date1] < [date2]
NOTE: This is identical to doing: [date1.msec] < [date2.msec]

A. 8 Date and Time Functions


TIME( )
Returns the current time as a string - hours:minutes:seconds. This can be used as a string or assigned to
a date variable which will set it to the current day at the time specified. For more formatting options, set
the Date variable to NOW() and use the date variable formatting methods.
Returns: String Arguments: None
Example:
[S] = “Started at: “ + TIME()

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,

484 Appendix A - Expressions and Functions


Example:
[X] = NOWMSEC()
DATE(str)
DATE(Year, Mth, Day)
DATE(Year, Mth, Day, Hour, Min, Sec)
DATE(Year, Mth, Day, Hour, Min, Sec, Msec)
Date(…) can be used to create a date value in an expression without having to create a date variable.
Date(str) can be used for a date where s is a string representation of the date. If the string is empty
DATE(), the date is the current day and time.
DATE(Year, Mth, Day) can be used to create a date from the numeric values of year, month and day
values.
DATE(Year, Mth, Day, Hour, Min, Sec) can be used to create a date from the numeric values of year,
month, day, hour, minute and second values.
DATE(Year, Mth, Day, Hour, Min, Sec, Msec) can be used to create a date from the numeric values of
year, month, day, hour, minute, second and millisecond values.
Returns: Date value Arguments: See below
The syntax of the string expression parameter can be any of the formats in the Regional Settings.
Examples:
DATE("March 1, 2011”) creates the date "March 1, 2011"
DATE("3/1/2011") creates the date "March 1, 2011"
DATE( ) creates a Date for the current date and time
DATE(2011, 3, 1) creates the date "March 1, 2011” numeric components of
the date: year, month, day
DATE(2011, 3, 1, 11, 10, 07) creates the date "March 1, 2011 11:10:07"
DATE(2005, 3, 1, 11, 00, 00, 1) creates the date 1 millisecond after "March 1, 2005
11:00:00"

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.

Appendix A - Expressions and Functions 485


CREATEDATE(date, y_offset, m_offset, d_offset)
CREATEDATE will return a new date based on a starting date and an offset of years, months and days.
The offsets can be positive or negative.
Returns: Date string Arguments: Date and numerics
date The starting date
y_offset The number of years to add
m_offset The number of months to add
d_offset The number of days to add
Each of the offsets must be an integer, but can be 0 or negative.

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

A.9 File Functions


EXISTS(filename)
Returns TRUE if the file exists, otherwise FALSE. This can be used to check to see if a file exists before
trying to read it.
Returns: Boolean (False=0, True=1) Argument: String
Example:
IF ( Exists(“data.txt”) )

486 Appendix A - Expressions and Functions


Appendix B: Variable Properties and Methods

B.1 What are Properties


All of the variables in a system have a value. However, they also have other properties, which provide
additional information about the value or provide ways to display the variable in various formats. These other
properties are obtained by using the notation:
[varname.property]
The property may be a single word, or a word plus a modifier.
Each variable has a default value that is used when there is no property specified. This value is used when
the variable name is used:
[varname]
Variables can be assigned values in many ways. The value of the variable is the only aspect of the variable
that can be changed in the system logic. All properties are read-only. A value can be assigned to the
variable itself. The values of the properties are derived from that variable’s value. For example, the
Confidence variable [X] could be assigned a value of 5, but [X.LOCKED] could not be directly assigned a
value. The LOCKED property would be automatically assigned by the value assigned to [X] in conjunction
with the locking rules for [X].
Properties are most often used:
! When displaying results.
! In expressions.
! Embedded in text with [[ ]] - Any variable and property can be embedded in any string using double
square brackets. Any place [[var]] can be used, [[var.property]] can be used.
In addition to properties, Collection variables have “Methods” that change a variable’s value in various ways.
Methods only apply to Collection variables and control how values are added to the Collection variables value
list. These methods are used when assigning values to a Collection variable. Since there are many ways to
assign a value to a Collection, all Collection value assignments use Methods.

B.2 TIME and AGE Properties


The TIME and AGE properties apply to all variables regardless of type.
These are used to document when a value was set and measure how old the data is.

.TIME - Time the value was set


The property .TIME will return a string stating exactly when the value for the variable was last set or changed.
For example:
[PRICE.TIME]
would return when the value was set:
Fri Sep 08 14:37;20 MST 2000
This can be useful in documenting when a system was run.

Appendix B - Variable Properties and Methods 487


.AGE - Milliseconds since the value was set
The property .AGE will output the number of milliseconds since the value of the variable was set or last
changed. This can be useful for systems that have access to real-time data streams. If a value is determined
to be too “old”, it can be cleared and replaced with a new value.
This can also be used to keep track of how long it takes to run a system.
[Seconds_To_Run] = ( [Last_Question.AGE] - [First_Question.AGE] ) / 1000

B.3 HOW Property


The HOW property applies to all variables regardless of type.
The .HOW property will output a full explanation of how the value for a variable was set. This is the same
explanation that is displayed in the Trace Applet “Variables” tab. This text can be used in result screen to
explain how conclusions were reached. This can be very useful when debugging a system
The .HOW property requires the Corvid Runtime to keep a large amount of data as it runs. By
default, the .HOW property is DISABLED. Few systems use .HOW and this reduces resource
use. To use .HOW add the ALLOW_HOW special command as the first command in the
starting Command Block. (See the Command Block chapter 9 for the ALLOW_HOW command.)

B.4 DISPLAY_WITH_RESULTS Property


The property DISPLAY_WITH_RESULTS will return 1 (TRUE) or 0 (FALSE) based on the “Display with
Results” flag for that variable. This can be used in tests to select only variables that have the flag set.
Example:
IF
[x.DISPLAY_WITH_RESULTS]
THEN
....
will return 1 if the display with results option was set for variable X, and 0 if it was not.
This property can be used with any type of variable, and can be used as an alternate way to flag a group of
related variables.

B.5 Static List Properties


Static Lists are variables with a fixed set of possible values. Each value has a short text and a full text, which
may be different. For the examples below, there is a Static List variable:
Name = [PRICE]
Prompt = The price of the item is
Value 1:
Short Text: high
Full Text: significantly higher than the customer’s budget
Value 2:
Short Text: at_budget
Full Text: about equal to the customer’s budget

488 Appendix B - Variable Properties and Methods


Value 3:
Short Text: low
Full Text: significantly less than the customer’s budget
The variable has value 2 (“at_budget”) set.

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.

.FULL - Prompt and Full Text of all values set


The property .FULL is the full text of the prompt followed by the full text of any values set connected with “AND”.
Example:
[PRICE.FULL]
would output:
The price of the item is about equal to the customer’s budget.

.NUM - Number of first value set


The property .NUM is the number of the FIRST value set.
Example:
[PRICE.NUM]
would output:
2
This value is numeric and can be used in math expressions, such as
[PRICE.NUM] > 1
or
[X] = [Z] + [PRICE.NUM]

Appendix B - Variable Properties and Methods 489


.COUNT - number of values set
The property .COUNT is the count of the number of values set.
Example:
[PRICE.COUNT]
would output:
1
since only a single value had been set.

This value is numeric and can be used in math expressions, such as


[COLOR.COUNT] > 2
or
[X] = [Z] + [COLOR.COUNT]

.SVALUE - Short text of all values set


The property .SVALUE is the SHORT text for each value set. If there is no separate short text, the text will be
the same as the value text for the values that are set.
If there are multiple values set, the values will be separated by a comma and space
Example:
[PRICE.SVALUE]
would output:
at_budget
This can be useful for passing shorter data between programs.

.VALUE - Full text of all values set


The property .VALUE is the FULL text for each value set. If there are multiple values set, the values will be
separated by a comma and space
Example:
[PRICE.VALUE]
would output:
about equal to the customer’s budget
This can be useful for passing shorter data between applets.

.CHECK # or .CHECK value - True if value is set


The property .CHECK followed by a number or short text of a value returns a “1” if that value is set and “0” if
it is not.

490 Appendix B - Variable Properties and Methods


Examples:
[PRICE.CHECK 1]
would return:
0

[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.

B.6 Dynamic List Properties


Dynamic lists are variables with a set of possible values that are established at runtime, either from the logic of
the system or from an external source such as a database or XML file. Each value only has a full text, with no
associated short text. Most of the same properties that apply to Static List variables apply to Dynamic Lists.
For the examples below, there is a Dynamic List variable that is part of a “car recommendation” system for a
used car dealer. The variable will let the end user select the type of car they desire, but will only offer types of
cars that are currently on the dealer’s lot. This information is stored in a database and changes regularly.
Name = [CARS_ON_THE_LOT]
Prompt = The type of car desired is a
The values for this variable are set dynamically at runtime from a spreadsheet of the types of cars currently
available. The values set at runtime are:
Value 1: Sedan
Value 2: SUV
Value 3: Convertible
The user has selected value 2.

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”

Appendix B - Variable Properties and Methods 491


This form can also be used when building more complex expressions:
( [CARS_ON_THE_LOT] = “SUV” ) & ([X] > 0)

.FULL - Full text of prompt and all values set


The property .FULL is the prompt followed by the text of any values set connected with “AND”.
Example:
[CARS_ON_THE_LOT.FULL]
would output:
The type of car desired is a SUV

.NUM - Number of first value set


The property .NUM is the number of the FIRST value set. If there are multiple values set, the .NUM will be
the number of the first one in the value list that is set
Example:
[CARS_ON_THE_LOT.NUM]
would output:
2
This number can be used in math expressions, such as
[CARS_ON_THE_LOT.NUM]> 1
or
[X] = [Z] + [CARS_ON_THE_LOT.NUM]

.COUNT - Number of values set


The property .COUNT is the numeric count of the values set.
Example:
[CARS_ON_THE_LOT.COUNT]
would output:
1
since only a single value had been set.
This number can be used in math expressions, such as
[CARS_ON_THE_LOT.COUNT] > 2
or
[X] = [Z] + [CARS_ON_THE_LOT.COUNT]

.MAX - Total number of Values


This property returns the total number of values in the variable’s list regardless of their being set. (To get the
number of selected values, use .COUNT)

492 Appendix B - Variable Properties and Methods


Example:
[CARS_ON_THE_LOT.MAX]
would output:
3

.VALUE - Text of all values set


The property .VALUE causes the text of the value to be output for each value set. If there are multiple values
set, they will be separated by a comma and space
Example:
[CARS_ON_THE_LOT.VALUE]
would output:
SUV

.CHECK # or .CHECK value - True if value is set


The property .CHECK followed by a number or text of a value returns “1” if that value is set, and “0” if it is not.
Example:
[CARS_ON_THE_LOT.CHECK 1]
would output:
0
[CARS_ON_THE_LOT.CHECK 2]
would output:
1

[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.

.LIST # - Text of value #


The property .LIST # causes the text of the value # to be output regardless if the value was set or not
Example:
[CARS_ON_THE_LOT.LIST 1]
would output:
Sedan

.INCLUDES text - True if text is a value


The property .INCLUDE text will output “1” if the text matches any value in the variable’s value list, and “0” if it
does not.

Appendix B - Variable Properties and Methods 493


Example:
[CARS_ON_THE_LOT.INCLUDES SUV ]
would output:
1

[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.

.NOTINCL text - True if text is NOT in the list


The property .NOTINCL text is the opposite of .INCLUDES. It will output “0” if the text matches any value in
the variable’s value list, and “1” if it does not.
Example:
[CARS_ON_THE_LOT.INCLUDES Sedan ]
would output:
0

[CARS_ON_THE_LOT.INCLUDES Wagon ]
would output:
1

B.8 Continuous Variable Properties


The Continuous variables include Numeric, String and Date Variables.
For the examples below:
[PRICE] is a numeric variable with prompt The price of the item is and a value 123.45
[NAME] is a string variable with a prompt The user name is and a value of Bob

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”

494 Appendix B - Variable Properties and Methods


.FULL - Full text of prompt and all values set
The property .FULL is the prompt followed by the value.
Example:
PRICE.FULL]
would output:
The price of the item is 123.45

.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

.FORMAT fmtStr - Formatted output of value


The property FORMAT allows a numeric variable’s value to be formatted to control the number of digits to the
right of the decimal, leading, and trailing 0’s, etc. The format string must be in square brackets. NOTE: if the
formatted value is to be used as a numeric, it must be only numbers, plus, minus and period.
Otherwise it will be a string value.
The format string fmtStr, is a string that specifies the format and follows the standard Java Decimal Format
syntax:

Character Meaning

0 A digit

# A digit, but don’t show leading or trailing spaces

. Location of decimal separator

, Location of grouping separator

; 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 ;

Appendix B - Variable Properties and Methods 495


Character Meaning

- Negative prefix

% Multiply by 100 and show as percent

Other Char Echo in output string

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)

.PFORMAT fmtStr - Formatted output with Prompt


The property PFORMAT is the same as .FORMAT, but the value is output with the prompt.
The format string fmtStr, is the same as in the .FORMAT property.
For example:
[PRICE.PFORMAT $###.##]
would output
The price of the item is $123.45

496 Appendix B - Variable Properties and Methods


Special Format Properties for Date Variables
Date variables have special output format properties:
[D.FORMAT fmtStr]
will output the date formatted by the format string.
The meaning of the fmtStr is dependent on the system localization. The options are:

DATE_SHORT The shortest form of a date (e.g. 4/5/01)

DATE_MEDIUM A longer form (e.g. 05-Apr-01)

DATE_LONG A long form of the date (e.g. April 5, 2001)

DATE_FULL The longest form of the date (e.g. Thursday, April 5, 2001)

TIME_SHORT The shortest form of a time (e.g. 2:20pm)

TIME_MEDIUM A longer form (e.g. 2:20:34pm)

TIME_LONG A long form of the time (e.g. 2:20:34PM MDT)

TIME_FULL The longest time format (e.g. 2:20:34 o'clock PM MDT)

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.

.MSEC - Convert Date to Milliseconds


The property MSEC returns the number of milliseconds since Jan 1, 1970. This can be used to do
calculations of time between dates stored in Date variables. This is applicable only to Date variables.
For example: [D.MSEC]

.DOW - Convert Date Variable to Day of Week


The property DOW returns a number corresponding to the day of the week. Sunday=1, Monday=2…
Saturday=7. This can be used in logic that needs to know the day of week based on a date. This is
applicable only to Date variables
For example: [D.DOW] = 2

Appendix B - Variable Properties and Methods 497


B.9 Confidence Variable Properties
Confidence variables are used to calculate the likelihood or confidence of a particular item being an
appropriate solution or recommendation of the system. The actual value is numeric and has most of the
same properties as a Numeric variable.
Unlike numeric variables, when Confidence variables are assigned a value, it does NOT replace the current value,
but is combined with any other values assigned based on the confidence mode selected for that variable.
For the examples below:
[Good_Fit] is a Confidence variable with the prompt “The likelihood that the item is appropriate for the
intended use is” with an overall value of 82.5

.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

.FULL - Full text of prompt and all values set


The property .FULL is the prompt followed by the values.

Example:
[Good_Fit.FULL]
would output:
The likelihood that the item is appropriate for the intended use is 82.

.PROMPT - Just the prompt for the variable


The property .PROMPT causes the text output to be the prompt without an associated values. This can be
used to output what the confidence variable “means” without the confidence value, which may not have
meaning to the end user.
Example:
[Good_Fit.PROMPT]
would output:
The likelihood that the item is appropriate for the intended use is

.VALUE - Value
The property .VALUE causes the value to be output, without the prompt.
Example:
[Good_Fit.VALUE]
would output:
82.5

498 Appendix B - Variable Properties and Methods


.FORMAT fmtStr - Formatted output of value
The property FORMAT allows the value to be formatted to control the number of digits to the right of the
decimal, leading, and trailing 0’s, etc. The format string is the same as for Numeric variables.
For example:
[Good_Fit.FORMAT ###]
would output
82

[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)

.PFORMAT fmtStr - Formatted output


The property PFORMAT allows a numeric value to be formatted to control the number of digits to the right of
the decimal, leading and trailing 0’s, etc. This value is output with the prompt.
The format string fmtStr, is the same as in the .FORMAT property.
For example:
[Good_Fit.PFORMAT ###]
would output
The likelihood that the item is appropriate for the intended use is 82

.LOCKED - TRUE if value was locked


The property .LOCKED will return “1” (True) if the value for the Confidence variable has been locked by one
of the optional locking rules for the confidence mode. If it has not been locked, “0” will be returned.

Appendix B - Variable Properties and Methods 499


B.10 Collection Variable Properties
A Collection Variable is a variable whose value is a list of strings. These value strings can be assigned in
various ways by the Collection variable Methods. The individual strings in the list can have an optional sort
value the determines where the string is in the list - the higher the sort value, the higher the string appears in
the list (Closer to the top of the list)
For the examples below:
[DOG] is a Collection variable with prompt The best breed of dog for you is and a list of values set by
the rules:
Beagle
Labrador Retriever
Golden Retriever

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

.VALUE Separator - All values, with a separator string


The property .VALUE is the text of the value(s). If the optional separator text is added, this will be included
between values. 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. (For a similar property with more control, see
the .CONCAT property below)
Example:
[DOG.VALUE ]
would output:
Beagle Labrador Retriever Golden Retriever

[DOG.VALUE OR]
would output:
Beagle OR Labrador Retriever OR Golden Retriever

500 Appendix B - Variable Properties and Methods


.COUNT - Number of values
The property .COUNT is the number of values in the value list.
Example:
[DOG.COUNT]
would output:
3

.FIRST - First item in list


The property .FIRST is the first string in the value list.
Example:
[DOG.FIRST]
would output:
Beagle

.LAST - Last item in list


The property .LAST is the last string in the value list.
Example:
[DOG.LAST]
would output:
Golden Retriever

.ITEM # - Item # as a string


The property .ITEM # is the value string number # in the value list. The first item in the list is 1. If the list does
not have # items in it, the text output will be an empty string.
Example:
[DOG.ITEM 2]
would output:
Labrador Retriever

.CONCAT Separator - Concatenate to a string


The property .CONCAT is the list of values concatenated into a single string.
The syntax is [coll.CONCAT str] where str is an optional separator string, which will be included between
values. Unlike the similar .VALUE property, the separator string will NOT be padded on each side with a
space if it is put in quotes, providing more control. If the separator string is not included, the values will be
separated by a space.
Example:
[DOG.CONCAT AND]
would output:
Beagle AND Labrador Retriever AND Golden Retriever

Appendix B - Variable Properties and Methods 501


The optional separator string can include the following line control characters:
\n New Line
\r Carriage Return
\t Tab
If the separator string is in quotes, the exact quoted string (without the quotes) will be used to separate
values. If the string is not in quotes, the values will be separated by a space, str, and a space.
For example, if there is a collection variable [coll], with values "aaa", "bbb", "ccc" and no prompt text:
[Coll] aaa bbb ccc
[coll.concat AND] aaa AND bbb AND ccc
[coll.concat "AND"] aaaANDbbbANDccc (Only quoted string added without spaces)
[coll.concat "\r\n"] aaa
bbb
ccc (one value on each line)

.TOP # - Top # items


The property .TOP # is the top # items from the list of values. The values will be separated by a space. This
is most useful when the values in the Collection Variable were sorted since it will return the top # that had the
highest sort values
Example:
[DOG.TOP 2]
would output:
Beagle Labrador Retriever

.INCLUDES text - TRUE if text is in the list


The property .INCLUDE text will be “1” (TRUE) if the text matches any value in the variable’s value list and
“0” (FALSE) if it does not. The entire text must match, but it is not case sensitive.
Properties that return True or False can be used in IF nodes or other Boolean tests. They can also be used
in numeric expressions.
Example:
[DOG.INCLUDES Beagle ]
would output:
1

[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.

502 Appendix B - Variable Properties and Methods


.NOTINCL text - TRUE if text is NOT in the list
The property .NOTINCL text is the opposite of .INCLUDES. It will output “0” (FALSE) if the text matches any
value in the variable’s value list and “1” (TRUE) if it does not.
Example:
[DOG.NOTINCL Beagle ]
would output:
0

[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.

Collection Variable "Vector" Properties


Corvid has a way to use Collection variables that allow them to emulate vectors or simple flat file databases.
This is done by structuring the data in the Collection variable so that it has a repeating pattern. The list
should have an identifier item followed by repeating set of entries that have other data in a specific order.
The GETAFTER property can be used with the ASSIGNAFTER and REPLACEAFTER methods (described
below) to change the data in the collection and assign a set of variables with one command. Data can be added
to the collection using the normal .ADD method which will add data to the end of the collection. The GETAFTER
property does not care about the location in the list as long as the order of items in list is maintained.
For example, suppose you want to have data with the name, zip code and phone number of a group of
people. The entries in the SampleData Collection variable could be:
Bob
87110
505-889-9494
Fred
11234
315-555-3334
Mike
96785
444-222-8888

The structure allows referencing specific items of data in the Collection using the Collection variable methods.

Appendix B - Variable Properties and Methods 503


Return Entry Referenced by Index
[COL.GETAFTER indexStr, num]
indexStr The index string to find in the Collection
num The number of entries past the index to return
This property finds first occurrence of indexStr in the Collection variable's value list, returns the value of the
item in the collection value list num values from the index. The value is returned as a string.
indexStr must be a single quoted string. The string in the quotes cannot contain any additional quotes. It
cannot be an expression, but can be a variable in [[ ]]. Note, when using a variable in [[ ]] for indexStr, the
full string must still be in quotes.
num must be an integer number or a variable in [[ ]] that returns a numeric value. num cannot be an
expression. num normally would not be greater than the number of items of structured data, but is allowed to
be any value.

For example, using the SampleData collection above:


[SampleData.GETAFTER "Fred", 2]
returns second value after the index value "Fred". This would be the phone number "315-555-3334". Due to
the structure of the data, the second item would always be the phone number.
The following are legal uses of GETAFTER:

[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]] ]

Values of a Collection Variable as a Tab-Delimited String


Tab delimited lists are needed for some interfaces. To convert a Collection variable’s value list to a tab
delimited string, use the .TABDELIM property.
The tab delimited string can be used in string parsing and replacement functions.
For example, if Collection variable [COL] has values "aaa", "bbb", and "ccc".
[COL.TABDELIM] would return "aaatabbbbtabccc", where tab is the tab character.

504 Appendix B - Variable Properties and Methods


B.11 Collection Variable Methods
In addition to the properties of Collection variables, there are
Methods used to add values to the variable’s value list, or make
other changes in the value list. These methods are usually called
in the THEN part of Logic Blocks.
The syntax of the Collection variable methods is:
[var.METHOD] data
The Method selected indicate what to do with the data that follows
the closing ].
The best and easiest way to add Collection variable methods is
from the Logic Block command building window. This is
automatically displayed when adding a Collection variable to the
THEN part of a Logic Block.
When adding THEN nodes, if a Collection variables is selected, the
“Collection” tab will be active. Select the Method to use from the
pull down list next to "Command:"

.ADD - Adding an Item to the Start or End of the List


Select "Add an item to the start/end of the list" from the command
pull down list.
Enter the text to add to the collection in the edit box. The item will
be added to the end of the list (last item) unless the "Add as first
item in list" checkbox is selected.
Selecting the "Do not add if identical item is already in the list"
causes Corvid to check if the item to add is already in the list. If it
is, no action is taken. If it is not already in the list, it will be added.
To be excluded, an item must exactly match the text of an item
already added to the collection, but the match is NOT case
sensitive.
Depending on the check boxes, Corvid will build
a .ADD, .ADDFIRST, .ADD_UNIQUE or .ADDFIRST_UNIQUE
method.

.ADD - Add to end of list


The method .ADD adds the text following the ] to the end of the list of values.
[X.ADD] Albuquerque
would add the string Albuquerque as the last item in the value list.

.ADDFIRST - Add to the top of list


The method .ADDFIRST adds the text following the ] to the top of the list of values.
[X.ADDFIRST] San Francisco
would add the string San Francisco as the first item in the value list.

Appendix B - Variable Properties and Methods 505


.ADD_UNIQUE - Add to end of list, if not already in the list
The method .ADD_UNIQUE adds the text following the ] to the end of the list of values if the item is not
already in the list as an individual value string.
[X.ADD_UNIQUE] Albuquerque
would add the string Albuquerque as the last item in the value list if not already in the list.

.ADDFIRST_UNIQUE - Add to the top of list, if not already in the list


The method .ADDFIRST_UNIQUE adds the text following the ] to the top of the list of values.
[X.ADDFIRST_UNIQUE] San Francisco
would add the string San Francisco as the first item in the value list if not already in the list.

.ADDVAR - Adding the Value of a Variable


Select "Add the value of a variable" from the command pull down
list. To add a variable with a property, select the “>> Variable with
Property <<“ and select the variable and property from the
window that will be displayed.
The item will be added to the end of the list unless the "Add as
first item in list" checkbox is selected.
Selecting the "Do not add if identical item is already in the list"
causes Corvid to check if the item to add is already in the list. If it
is, no action is taken.
The method .ADDVAR adds the value of the variable [var] to the
end of the list.
The [var] string can include properties for a variable.
[X.ADDVAR] [CITY]
would add the value of [CITY] as the last value in the list.
[X.ADDVAR] [PRICE.FORMAT $###.##]
would add the value of [PRICE] formatted by the format string as the last item in the Collection variable’s
value list.

.ADDVARFIRST] [var] - Add the variable to top


The method .ADDVARFIRST is the same as .ADDVAR, but the value is added to the top of the
Collection variable’s value list. It is built by checking the “Add as first item” checkbox

.ADDVAR_UNIQUE] [var] .ADDVARFIRST_UNIQUE] [var] - Add only if not in list


These methods add the item and the last/first item in the list, but only add it if the text of the variable /
property is not already in the list.

506 Appendix B - Variable Properties and Methods


ADDSORTED - Add a Value Sorted
The value strings in the Collection can be sorted based on a
numeric sort value added with each item in the value list. Items
will be placed into the list based on the sort value. The one with
the highest sort value will be first and the one with the lowest sort
value will be last. As new items are added to the list, they will
automatically be inserted based on their sort value.
NOTE: When ADDSORTED is used, all “adds” to that
Collection variable MUST be done with ADDSORTED. Do
not mix ADDSORTED with ADD, ADDFIRST, etc.
To add a text string with a sort value:
Select "Add an item sorted" from the command pull down list.
Enter the text to add in the edit box. This can include double
square bracket embedding of other variables if needed.
The item will be added to the list based on the sort value. The sort
value can be the number or the value of a numeric variable. To
select a numeric variable, pull down the lower drop down list and
select a variable. If a simple numeric value is preferred, just enter it in the edit box at the top of the pull down.
Corvid will check through all the items that are in the list and add the new item based on the sort value. The
highest sort value is placed at the start of the list. The lowest sort value is placed at the end of the list.
Selecting the "Do not add if identical item is already in the list" causes Corvid to check if the text to add is
already in the list. If it is, no action is taken.
The command built separates the text to add from the sort value with a comma. The text to add can include
commas. Corvid will use the final comma to mark the sort value. The text to add can also be put in quotes
which will be removed before the value is added.
For example, if you start with a Collection variable [X] that has no values, and rules fire with the commands:
[X.ADDSORTED] AAA, 5
[X.ADDSORTED] BBB, 10
[X.ADDSORTED] CCC, 3
the resulting value list will be:
BBB
AAA
CCC
The sortVal can be a variable and this is the standard approach for MetaBlocks. Suppose a MetaBlock
analyzes each row in a spreadsheet and sets a Confidence variable [Good_match] based on criteria in the
row, and the customer’s needs. To add the text in the column headed Name based on a sort value of
[Good_match] use:
[X.ADDSORTED] {Name}, [Good_match.value]
(Name is in { } because it is a MetaBlock parameter from the spreadsheet.)
This would produce a sorted value list with the best recommendations at the top.

Appendix B - Variable Properties and Methods 507


.ADDFILE - Add Values from a File
A very useful way to build reports is to add the text from a file
into a Collection variable. Any double square bracket
embedded variables in the file text will be replaced by their
actual values when they are added to the Collection.
Each separate line in the file will be a separate item in the
Collection value list.
To add the contents of a file.
Select "Add items from a file" from the command pull down list.
Select the file to copy from in the middle edit box, or click the
Browse button and browse to the file. The file can be local for
a standalone or Corvid Servlet Runtime system, but most files
will be reference by a URL off a Web server. The file can be on
any server, provided it is accessible through a URL. To test
this, enter the URL in your browser and the file should be
displayed.
If running with the Corvid Servlet Runtime, a URL or a path
relative to the knowledge base files on the server can reference
the file. The easiest approach is to put it in the same folder as the .cvr file for the system, and just reference it
by name not with path.
Each item from the file is added to the end of the list - producing the same order as the file.
Selecting the "Do not add if identical item is already in the list" causes Corvid to check if each item to add is
already in the list. If it is, that item is not added, but other lines from the file not already in the list will be added.
An optional key string can be used to select a portion of the file to add. If a key string is added, only the section
of the file between key markers will be added. The “key string” can be a double square bracket embedded
Corvid variable. The markers are HTML comments, and generally used with HTML, but can be used in any file.
<!-- Corvid_KEY=key_str -->
text to add
<!-- Corvid_KEY_END=key_str -->
All text between the marker <!-- Corvid_KEY=key_str --> and the closing <!-- Corvid_KEY_END=key_str -->
will be added to the file.
Only the first CORVID_KEY section for a key string will be included. If there are later CORVID_KEY sections
for the same key, they will not be included. (Use conditional inclusion if multiple sections of the same file
need to be added at one time.)
Since the start and end markers are associated with a specific key, they can overlap, and can also include
Corvid_IF conditional inclusion sections. If no "key" is specified, the entire contents of a file will be added to
the Collection Variable.
This provides a very simple and effective way to use a file as a report template. The logic of a system can
determine when and if a particular file should be included. The file itself can be divided into nested sections
that are included only if a test condition is met. The file text can use embedded Corvid variables to include
actual system values. The format of the file can be simple text, HTML commands, an RTF document or any
other form of text file.
Once the Collection Variable has had a file added to it, the variable value can be displayed or (in stand-alone
mode) output to a file on disk and displayed with a word processor or browser.
NOTE: Java security prevents an applet from writing to the local disk, so only standalone systems
running as applications can create and display RTF or HTML files without additional server-side
programs - see the Reports Chapter 14.

508 Appendix B - Variable Properties and Methods


The file should be a text file, including RTF and HTML files. The text in the file can contain embedded Corvid
variables in [[ ]], and properties of variables indicated by [[name.property]].
The value of the variable will be used to replace the [[ ]] expression at the time the file is read. Normally
variables that do not have a value will lead to the value being derived or asked. If the current value should be
used, without any attempt to ask or derive a value, use [[*name]].

Conditional Inclusion of Text


In addition to the "key" markers that limit the ADDFILE to a part of a file, or sections of the file can be included
or excluded based on boolean test expressions.
The syntax for conditional inclusion of text is:
#Corvid_IF expression
text to include
#Corvid_ENDIF
NOTE: The i#CORVID_IF commands must be on their own line in the file and should be the only text
on the line. If this cannot be done, use the BREAK_ON_CORVID_IF option described below.
The text to include can be any length and any number of lines.
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.
Inclusion tests can be nested. 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.
For example:
#Corvid_IF test1
aaa
bbb
#Corvid_IF test2
ccc
#Corvid_ENDIF
ddd
#Corvid_ENDIF
eee

If test1 is TRUE and test2 is TRUE, the lines included would be:
aaa
bbb
ccc
ddd
eee

Appendix B - Variable Properties and Methods 509


If test1 is TRUE and test2 is FALSE, the lines included would be:
aaa
bbb
ddd
eee
If test1 is FALSE, the entire block will be excluded, and test2 will never be tested. The lines included would be:
eee
The content to include must be designed so that various sections of text can be included or excluded and still
produce valid syntax.

Files with #Corvid_IF in the Middle of the Text


The normal #Corvid_IF approach works well for data files where the #Corvid_IF and following expression are
always on a single line. However, if the contents of an HTML page are being added, the line breaks have no
meaning and many HTML editors will add or remove line breaks. This can result in the #Corvid_IF being in
the middle of a line, which can lead to errors in parsing. To solve this, the option:
BREAK_ON_CORVID_IF
can be added to the command following the name of the file to add. For example:
[COLL.ADDFILE] DATA.TXT BREAK_ON_CORVID_IF
With this option, the #Corvid_IF and #Corvid_ENDIF commands can be at any place in the text of the file. To
make it clear where the Boolean expression for the #Corvid_IF ends, the expression must be in parentheses ( ).

COPY- Copy Values from Another Collection


The items in one Collection variable can be copied to another as
a single block of text or in a way that the individual items from
the first collection remain individual items in the second.
Select "Copy the items from a Collection" from the command pull
down list. All the Collection variables in the system will be
displayed in the lower list. Select a Collection variable from the
list. Each item from that variable's value list will be added, in
order, to the end of the current variable's value list.
Selecting the "Do not add if identical item is already in the list"
causes Corvid to check if each individual item in the list to add is
already in the list. If it is, that item will not be added, though
other items not already in the list will be added.
For example: If there are two Collection variables, [A] and [B]
[A.COPY] [B]
would add each of Collection variable [B] value’s to [A]’s value
list as individual items.
NOTE: To add a Collection variable’s values as a single item, use the .ADDVAR with the .CONCAT
property set for the variable being added.

510 Appendix B - Variable Properties and Methods


.REMOVE - Remove a Value from the List
Items can be removed from the list either by specifying the text
of the item to remove, the number of the item to remove or
removing the first/last item in the list.
To remove an item by text, select "Remove an Item" from the
command pull down list.
Enter the text of the item to remove. The item should match the
text of an item in the list, but the match is NOT case sensitive.
If the items are not in the list, it has no effect.
For example:
[X.REMOVE] beagle
would remove the item beagle from the list if it was there.

Removing Items by Number


An item can also be removed by its number in the list. To
remove a specific item, in the text box, enter #x where x is the
number of the item to remove.
For example:

[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.

Remove First Value From the List


The first item in the list can be removed with the technique
above, but a special command removes the first item.
Select “Remove first item” from the drop down list.
This method, .DROPFIRST, will remove the top item off the list,
making the next item the top item. If there is nothing in the list,
the command has no effect.
This can be used in a WHILE loop to process items in a list from
top, removing them until the list is empty.

Appendix B - Variable Properties and Methods 511


Remove Last Value From the List
The “Remove Last Item” is the same as the “Remove first” but
removes the last item in the list. It too can be used in a WHILE
loop to process items from a list.
The method .DROPLAST will remove the last item off the list. If
there is nothing in the list, the command has no effect.

CLEAR - Remove All Values From the List


To remove all items from a list use CLEAR.
Select "Clear List (Remove all items)" from the command pull
down list.
The method .CLEAR removes all items from the list.

Assigning Values to a Group of Variables


Collection variables can be used as an ordered group or series
of vectors. Values can be assigned to a group of variables
based on their order in the collection. This enables a Collection
variable data to be structured and serve as a very simple flat
database.
Data related to an identifier item can be added and changed by
just knowing the identifier item, without needing to know the
actual placement in the list.
Unlike other Collection variable methods, the ASSIGNAFTER
method does not change the collection’s value list, but instead
takes values from the collection and assigns them to specific
variables. This can be used with REPLACEAFTER to change
the values in the list.
Select "Assign from an index Point" from the command pull down
list. Enter an index value to find in the Collection's value list.
Make a list of variables to assign subsequent values to. This is
done by selecting a value from the lower drop down list and
clicking the "Add" button. The "Delete" button removes a variable
from the list. The Up and Down buttons allow reordering the list, by moving the selected variable up or down
in the list.

512 Appendix B - Variable Properties and Methods


This method requires that the values in the Collection variable are ordered in such a way that the position in
the list is relative to an index that has specific meaning.
For example, suppose the items in the Collection variable's value list are arranged so that there is a part ID,
followed by the part cost, followed by the part weight. This pattern is repeated for many parts:
Part 1425
23.67
5 lb
Part 88765
199.45
7.5 lb
Part 15543
53.82
1.2 lb
Using the ASSIGNAFTER method allows a group of values to be assigned with a single method. For
example:
[Col.ASSIGNAFTER] "Part 88765",[PRICE],[WEIGHT]
would search the value list to find the first occurrence of a value "Part 88765". The next value in the list
(199.45) would then be assigned to the variable [PRICE] and the one after that ("7.5 lb") assigned to the
variable [WEIGHT].
There can be any number of variables in the list. The values assigned should be of a type consistent with the
variable - numeric variables should be assigned numeric values. The values in the Collection can be built
dynamically, read from a file or set by any other means.

Replace Values in an Ordered Collection


This method works with ASSIGNAFTER to allow a collection
variable to be used as an ordered group or series of vectors.
This method allows values in the list to be changed
dynamically. Values in the list can be replaced based on their
order in the collection. This enables a Collection variable to be
used as a simple database with all values in memory.
Select "Replace from an index Point" from the command pull
down list.
Enter an index value text to find in the Collection's value list.
Enter the number of values PAST the index value that you wish
to replace. Enter the replacement value. This is a string, but
can include the value of variables by embedding them in [[ ]].
This method requires that the values in the Collection variable
are ordered in such a way that the position in the list relative to
an index has specific meaning.

Appendix B - Variable Properties and Methods 513


For example, suppose the items in the Collection variable's value list are arranged so that there is a part ID,
followed by the part cost, followed by the part weight. This pattern is repeated for many parts:
Part 1425
23.67
5 lb
Part 88765
199.45
7.5 lb
Part 15543
53.82
1.2 lb
The REPLACEAFTER method allows changing a value, such as the PRICE. For example:
[Col.REPLACEAFTER] "Part 88765",1,"188.23"
would search the value list to find the first occurrence of a value "Part 88765". It would then go 1 value farther
in the list and change the value to 188.23.
The values in the Collection can be built dynamically, read from a file or set by any other means.

514 Appendix B - Variable Properties and Methods


Exsys Inc.
6565 America’s Parkway. NE
Suite 200
Albuquerque, NM 87110
U.S.A.

www.exsys.com
All rights reserved.

Appendix B - Variable Properties and Methods 515

S-ar putea să vă placă și