Introduction and Purpose
Installation
Tech Support and Enhancements
The Problem
The Solution
System Architecture
A Sample Tech Support Session
Logic-Base Contents Overview
Logic-Base Execution Overview
Building the Logic-Base
Debugging Logic-Bases
Syntax Summary
Upgrading to Amzi! Prolog + Logic Server
Enhancements and Bug Fixes by Release
WebLS (pronounced webbles) is a system that can answer tech support questions, diagnose problems, recommend configurations, advise web surfers and similar tasks. This implementation focuses on answering tech support questions, but you are encouraged to use it for anything you can dream up. (If you need additional features to support your efforts, let us know).
WebLS is implemented using the standard CGI or Win-CGI interface. WebLS interprets your 'logic-base' which consists of facts, rules and fragments of HTML that comprise the questions and the answers. Your logic-base is written in a custom scripting language that is designed specifically for building intelligent, web-based components. When WebLS interprets your logic-bases, its goal is to find an answer. To do this it applies rules to the facts at hand and dynamically constructs HTML documents that ask questions to obtain additional facts. All you need to construct your own logic-bases is any text editor, a web browser and a web server.
If this explanation isn't clear, why not give WebLS a try by running Amzi!'s Problem Resolver. Instructions are here.
WebLS is an application that was built using Amzi! Prolog + Logic Server, with some support functions written in 'C'. Prolog is a language with powerful built-in search and pattern matching capabilities and is the heart of WebLS (although you will not see it). The Amzi! Logic Server can also be used to embed intelligent components and agents in C/C++, Java, Delphi, Visual Basic and many other languages and tools.
The purpose of this manual is to show you how to build your own logic-bases using WebLS. This manual assumes you are familiar with HTML (especially forms) and with the CGI or Win-CGI interface. This manual does not attempt to teach you how to build the WebLS application itself. That documention will be forthcoming in the near future.
WebLS is licensed according to the terms of the file license.htm. In essence, WebLS may be used freely by any individual or organization for adding logic-bases to web pages. It may be redistributed only in its entirety, and at no charge (except a nominal media and shipping fee). The included 'C' and Prolog source code (not the logic-bases) may be used only in conjunction with a properly licensed, registered copy of Amzi! Prolog + Logic Server.
The following files are included in the WebLS package:
Extract the files from the archive which will create a top-level directory called WebLS and these subdirectories:
To complete installation, do the following:
If you are anxious to get started right away skip to the section titled 'Building the Logic-Base'.
We also welcome any suggestions you have for enhancement, and we are available on a consulting basis to assist you in building your own logic-bases.
Send you questions, comments and queries to mary@amzi.com. Kindly include the word 'WebLS' in the subject line of your message. Thank you.
Another requirement is that the state of the dialog needs to be maintained throughout the information gathering process with the user. As multiple users will be using the logic-base simultaneously, the state for each of them must be kept separately. (Netscape's 'cookies' could be used for this purpose but as cookies are not yet widely supported, a different approach is used.)
Finally, and most importantly, an intelligent web page will only be useful if it can be kept up-to-date. And it can only be kept up-to-date if the rules in the logic-base are easy to maintain. In addition, the logic-base needs to take advantage of existing resources, such as other on-line documents, pictures, databases, search engines, etc.
Figure: WebLS Architecture
HTML forms are ideal for gathering information from the user. Multiple pieces of information can be gathered at the same time by having multiple fields on a form. HTML documents can be constructed a piece at a time. And, most importantly, they can readily point to other resources, such as other documents, a particular place in another document, other files, directories of files, etc.
A logic-base ties everything together. It contains facts gathered from the user, and rules to determine the problem from the facts. The rules are easy-to-read and declarative so they are easy to maintain.
The logic-base is completely independent of the other two subsystems. In fact, it is stored as a separate source code file which is loaded by the inference engine. This is the piece you will be developing for your own intelligent components and agents.
The inference engine is designed specifically for gathering facts and reaching a conclusion based on those facts, and for efficient integration with the web server using the CGI interface. The CGI interface itself is a set of Prolog predicates (functions) for reading the CGI input from the web server and returning the HTML output. The Inference Engine and CGI Interface are provided in an .EXE file, an .XPL file (Amzi! Logic Server load module) and a DLL (for Windows). If you are a licensed owner of Amzi! Prolog + Logic Server, you can modify the EXE and XPL as well. Documentation on this will be forthcoming separately. For the time being, see the comments in the code.
First, you will see an HTML form asking for general information about the your environment and the problem area. In answer to "What program are you running?" answer the "Amzi! IDE". Leave everything else as the default answer. Press submit.
Next, a short dialog takes place between the user and the system in order to narrow down the problem and gather specific details. In this case, for the problem select "Screen/printer font size is too small/large." Press submit.
Once the problem has been determined an answer is presented. The answer can be a couple of paragraphs, or it can be another web document. In this case, a couple of sentences describes how to change the font size.
Facts are gathered from the user, or distilled from other facts. Examples of facts are: the error message, the program version, and the operating system. Rules are of the form if-then and check the values of facts to determine the problem. Methods define how to perform input and output using HTML.
Below is an example of each. This is how we ask for the 'errorCode' fact. The 5 is the HTML form field length.
attr(errorCode, [ prompt = $What error code was displayed or 'none'?$, ask = field, length = 5 ]).
This is how we ask for a value from a list. The square brackets are used to bracket the list of choices.
attr(environmentNameVer, [ prompt = $What environment are you running under?$, ask = menu(['Windows 3.x', 'Windows 95', 'Windows NT', 'DOS', 'Linux']) ]).If you wanted to ask for all the environments you create a multivalued fact as shown below. This allows the user to select multiple values from the list using the [ctrl] key and the mouse. You use the 'include' comparator to check multivalued facts (see If-Then Rules below).
attr(environmentNameVer, [ multivalued, prompt = $What environment are you running under?$, ask = menu(['Windows 3.x', 'Windows 95', 'Windows NT', 'DOS', 'Linux']) ]).
This is how we ask a yes/no question:
attr(usingDCG, [ prompt = $Are you using DCG in your Prolog module?$, ask = yesno ]).
Here is how related facts are added to the fact attributes:
attr(environmentNameVer, [ prompt = $What environment are you running under?$, ask = menu(['Windows 3.x', 'Windows 95', 'Windows NT', 'DOS', 'Linux']), related = [memSize, processorType] ]).
This says that 'memSize' and 'processorType' are related to 'environmentNameVer'. When the rules are executed, if WebLS is going to ask the user for environmentNameVer, it will also ask for the other two facts as well.
if errorMessage = 'Code too long to load' then problem = srcbufTooSmall.
It says if the fact 'errorMessage' has the value specified then the problem is 'srcbufTooSmall'. Now there is nothing particularly difficult or remarkable about this rule, nor is there about most of the rules in WebLS. What is notable is that the rules are easy to read and can appear in the logic-base in any order. The WebLS 'inference engine' (that's a fancy way to say search and pattern matching engine) scans the rules looking for ones that 'succeed.' A rule is said to succeed when all of the facts on the 'if' side match correctly.
Before we examine the inference engine, lets look at some more rules and how answers are outputted.
if languageTool = 'Visual C++' or languageTool = 'Borland C++' or languageTool = 'Watcom C++' then language = 'C/C++'.
This rule distills the fact 'language' from the user-provided fact 'languageTool'. This allows us to simplify rules such as the following:
if language = 'C/C++' and apiFunction = 'lsInit' and ((errorMessage = 'GPF (General Protection Fault)' and environmentNameVer = 'Windows 3.x') or environmentNameVer = 'DOS') then problem = cLargeModelRequired.
Note here that more of the power of the rule language becomes evident. We can use 'and', 'or' and parenthesis to check facts. Also, not shown here, is the ability to check if an fact is 'not equal' to a particular value. You can use these comparators: =, \= (not equal), >, <, >= and <=. For checking multivalued facts use 'include' as follows:
if (languageTool = 'Borland C++' or languageTool = 'Borland C') and symptoms include 'Errors linking with the Logic Server libraries' and applicationMode = '16-bit' and releaseDate <= '19960302' then problem = borlandStatic16.
Notice that rules that have determined an answer end with 'problem='. The logic-base has one final piece, that is outputting the answer.
Lets look at some examples. First outputting HTML text:
answer(cLargeModelRequired, [ text = [$16-bit C/C++ applications require the large memory model. $, $Failure to use it leads to immediate GPFs.$] ]).
When the problem is 'cLargeModelRequired', the specified text is outputted. The dollar signs are used around strings in the logic-base, and the square brackets are used around lists. So this answer is a list of two strings. The answer text is bracketed by the CGI interface with the following header:
Content-type: text/html <HTML><HEAD><TITLE> Title </TITLE></HEAD> <BODY><H2> Title </H2>and footer:
<P><HR>Footer<FONT SIZE=-1><CENTER><I>WebLS Freeware by <A HREF="http://www.amzi.com/">Amzi!</A></I> </CENTER></BODY></HTML>The system definition for Title is inserted where the word Title appears, and the systems definition for Footer is inserted where the word Footer appears.
If you would rather keep the answers in separate HTML documents, you can send them out as shown in this example:
answer(lsxNotLoaded, [ htmlFile = 'lsxintro.htm' ]).
The third approach is to redirect the user to another document. This lets you keep your answers in searchable, browseable documents and use tags to direct the user to the right place. For example:
answer(componentNotInstalled, [ url = 'http://www.amzi.com/install#delphi_component' ]).
note(debugEmbed, [ text = [$For more information on debugging embedded Prolog modules $, $we suggest you see <A HREF="ftp://ftp.amzi.com/pub/users/amzi/articles/APIDEBUG.TXT">Debugging Hints</A>.$] ]).Notes are used by adding a notes list to the answer. Remember lists are enclosed by square brackets. For example:
answer(cLargeModelRequired, [ text = [$16-bit C/C++ applications require the large memory model. $, $Failure to use it leads to immediate GPFs.$], note = [debugEmbed, cLibraries] ]).
Lets examine these steps in some detail.
The Prolog-CGI interface reads the form values from the CGI input file and asserts the facts in the logic-base. The initial form is designed such that the fact names are simply taken from the name of the form field. For example:
<INPUT NAME="errorCode" TYPE="TEXT" VALUE="none" ROWS=1 SIZE="10" ALIGN=left>
This gets the value for the fact 'errorCode'.
The first time WebLS is invoked, the web server uses the GET method. Subsequent invocations use the POST method. This makes it easier to distinguish a new problem solving session from an existing one, and fits within the spirit of GET and POST as subsequent forms may cause data to be written to various external files (see 'Future Directions'). The initial form's and all subsequent questions form's headers looks like this:
<FORM METHOD=POST ACTION="\cgi-bin\amzicgi.exe">
WebLS writes the initial form to the CGI output file and exits. When the submit button (on the form) is pressed by the user, WebLS is started again and the form values are sent to it via the CGI interface.
If the problem is not found, then we enter a dialog with the user to gather more information.
<HTML><HEAD><TITLE> Your Title </TITLE></HEAD> <BODY> <H2> Your Title </H2> Your Introductory Text <FORM METHOD=POST ACTION="/cgi-bin/amzicgi.exe"> Your Questions <INPUT NAME="submitProblem" TYPE="Submit"> </FORM> </BODY></HTML>
When naming your HTML form fields, we recommend you start with a lowercase letter and not use any special characters. This allows you to use the fact names in your rules without surrounding them with single quotes. (See syntax below). Also to avoid naming conflicts we recommend you NOT use field names of the form
Try to keep to a single page of questions and think carefully about the default answers if the user doesn't select one. The default answers will become facts in your logic-base and you don't want unexpected results because the user skipped over a couple of questions.
Also if you can get some information (like an error number or message) that leads directly to an answer, try to fit that on as well.
You will find that the initial form changes a lot as you develop your rules.
Before you start writing rules, there is some required header information. It reads as shown below. The first four lines define new operators in WebLS and should not be changed or deleted and they must remain at the start of the file.
The next lines define a number of system variables that are used by the inference engine. These let you set the title and the location of various files and directories. Under Windows they might look like this:
Under BSD the file and directory names might look like this:
The system variables are as follows:
Fact and value are 'atoms.' As such if they begin with an uppercase letter, have spaces in them or contain any characters other than letters, numbers and underscores, then they must be enclosed in single quotes ' '.
The answer in this simple case is a list of strings. Strings in WebLS are enclosed in dollar signs $ $. A list of strings is separated by commas and enclosed in square brackets [ ].
Save your rules as 'logicbse.pro' and put that file in your Windows CGI directory or whatever the current directory is when amzicgi is executed.
Test your logic-base by adding a link to a web page that launches amzicgi. This link can look like this:
If your logic-base is not working, see the section on debugging logic-bases.
Now you should have a logic-base that looks like this:
Menu choices are also atoms and must be quoted if they do not follow the rules outlined above.
The most important performance enhancement you can do with your logic-base is to group related facts together. This is done as follows:
This says the list containing fact2,3 and 4 is related to fact1. Whenever WebLS asks for the value of fact1, it will ask for the other three values as well. This should optimize the number of times WebLS is invoked and greatly reduce the amount of time your users spend answering questions in order to obtain a resolution to their problem.
Examples of each of these follows below. Make sure you put these with the other answers or notes in your logic-base.
There are a number of other things you can do with your rules. You check if a value is not equal. For example:
You can use and, or and parentheses to group facts and values. For example:
Line breaks are not important. The critical part of the syntax is the word if followed by fact value checks followed by the word then and an fact set equal to a value, followed by a period. Don't forget the period.
The second rule will never succeed because if a1 = v1 the first rule will be checked first and will always succeed. In practice, rules of this form are probably poorly written.
Another consideration is that performance will be slightly enhanced if you check facts from the initial form first in the 'if' part of the rule. You can see this for yourself if you look carefully at a trace of your logic-base (see the section on debugging below).
Everytime tech support writes up an answer for a customer, it forwards it to the logic-base developer who incorporates it into the rules in the appropriate section, and then adds the answer definition for the problem. If the rule requires some new facts, attr definitions (or rules) are created for each one.
The most important consideration when adding new rules, is to use related facts lists wherever possible. This reduces the number of interactions with the users, resulting in less frustration for them, and less load on the web server.
In general you will find that logic-bases for technical support are generally 'flat'. This means that most rules won't depend on multiple layers of distilled facts. So debugging the rules is generally straight-forward.
Syntax errors are reported by WebLS in your browser. The indicator <- NEAR HERE -> will give you an idea of where the error is in the text of your logic-base.
A typical debugging session has you fill-in the answers on the form (in the same manner your users would), then see the trace to determine how the answer was reached, or why another set of facts is being asked for.
Below is a small logic-base and the trace of a particular run of lilrules.pro.
Figure: A Sample Logic-Base
You can see in the listing above the three main parts of the logic-base. There are the rules. These are followed by the attr declarations and the answer declarations.
Figure: Trace of the Sample Logic-Base
This trace illuminates the 'backtracking' search that is inherent in the Prolog language and implemented in the WebLS inference engine. You can see the first rule matches on the errorCode ('600') but fails on the programType. The second rules matches on both and succeeds; that is, it identifies the problem as 'sampleXPL.'
Note each item must be followed by a comma, except the last one. Also note the careful placement of []'s, ()'s and the ending . period.
Expression consists of:
where operator is either = (equal), \= (not equal), < (less than), > (greater than), <= (less than or equal), >= (greater than or equal) or include. The 'include' operator can only be used with 'multivalued' facts. Expressions can be grouped with parentheses (), and linked together with 'and' and 'or'.
If you would like to do any of these things (or any of the other ideas you dream up that we don't implement), you can purchase the Personal or Professional Edition of Amzi! Prolog + Logic Server. This product includes an Interactive Developer's Environment for developing your logic-base and Prolog inference engine. It also has a compiler for you to compile your logic-base (which usually results in a 10x improvement in execution speed). And it includes the Logic Server libraries that let you embed Prolog components in C/C++, Java, Delphi, Visual Basic, Access, SmallTalk and many other tools and environments. It also has extensions for the Sockets API and ODBC. See our web site, http://www.amzi.com, for product details and pricing information.
Release 0.3 Enhancements
Release 0.2 Enhancements
Release 0.2 Bug Fixes
Copyright ©1996 Amzi! inc. All Rights Reserved.
Logic-Base Header Information
Your logic-base is kept in a file called 'logicbse.pro'. You might want to look at 'lilrules.pro' as a skeleton for a logic-base.
:- op(790, fx, if). % prefix operator
:- op(780, xfx, then). % infix operator
:- op(775, xfy, or). % infix that can be linked
:- op(770, xfy, and). % infix that can be linked
:- op(700, xfx, <=). % infix operator
:- op(700, xfx, include). % infix operator
%system('Log File', 'C:\\WebLS\\logs\\trace.htm').
%system('Log File URL', 'file:///C:/WebLS/logs/trace.htm').
system('Results File', 'C:\\WebLS\\logs\\results.pro').
system('Initial Form', $C:\\WebLS\\html\\rptprob.htm$).
system('Temp Directory', $C:\\WebLS\\temp\\$).
system('Body Args', $bgcolor=#CEFAFF text=#000000$).
system('Title', $Amzi! Problem Resolver$).
system('Footer', $<FONT SIZE=-1>Copyright ©1996 Amzi! inc. All Rights Reserved.$).
system('Form Action', 'Executable Path').
system('Goal', 'problem').
Note double backslashes are needed under Windows because backslash \ is the 'escape' character in strings (exactly like 'C') so \n means a newline character.
system('Log File', '/usr/web/amzi/WWW/trace.htm'),
system('Log File URL', 'http://amzi.harvard.net/trace.htm'),
system('Results File', $/usr/web/amzi/logs/results.pro$)),
system('Initial Form', $/usr/web/amzi/WWW/rptprob.htm$),
system('Temp Directory', $/usr/web/amzi/temp/$),
Writing the First Rule
Now with the preliminaries out of the way you can write your first rule. Start by using one of the facts on your initial form. Here's the basic structure:
if fact = value
then problem = problemID.
answer(problemID,
[
text = [$ resolution for problemID $,
$ more resolution for problemID $]
]).
Press here to <A HREF="\cgi-win\amzicgi.exe">Try Me</A>
Or under BSD Unix
Press here to <A HREF="/cgi-bin/amzicgi ">Try Me</A>
Asking for Additional Facts
Next write a rule that needs to obtain additional information from the user. In addition to the if-then rule and answer defined above, you also need to add an attr definition to generate the HTML form field that asks the question.
attr(fact2,
[
prompt = $ fact2 question text $,
ask = menu([choice1, choice2, choice3])
]).
if fact = value and
fact2 = value2
then problem = problemID.
answer(problemID,
[
text = [$ answer text for problemID $,
$ more answer text for problemID $]
]).
Related Facts
attr(fact2,
[
prompt = $ fact2 question text $,
ask = menu([choice1, choice2, choice3]),
related = [fact2, fact3, fact4]
]).
Overall Logic-Base Organization
You must keep all the like items together in your logic-base. That is all the if-then rules must be contiguous, as must all the attr, answer and note declarations. So your logic-base looks generally like this:
% Operator definitions
:-op( . . .
% System variables
system( . . .
% Fact Attributes
attr( . . .
attr( . . .
% Rules
if . . . then . . .
if . . . then . . .
% Answers
answer( . . .
answer( . . .
% Notes
note( . . .
note( . . .
No Answer and Special Notes
Before you add more rules, there are some optional items you might want to define in your logic-base. There is one special answer:
There are two special notes:
answer(noAnswer,
[
text = [$We are unable to diagnose your problem at this time. $,
$Please e-mail a description of your problem to $,
$<A HREF="mailto:support@amzi.com">support@amzi.com</A>. $,
$You should receive a reply in 48 hours or less.$]
]).
%
% systemError is a special note that is appended to an error message
%
note(systemError,
[
text = [$<HR>Please write down the above message and what you were $,
$doing when this problem occurred, including the values you $,
$typed into the forms. E-mail this information $,
$to <A HREF="mailto:info@amzi.com">us</A>. Thank you.$]
]).
%
% answerHeader and answerFooter are special notes that are used to
% bracket the output from sendAnswer
%
note(answerHeader, []). % this means there is no header
note(answerFooter,
[
text = [$<P><HR><P>This is an experimental version of our new automated $,
$technical support system. We are very interested in hearing $,
$your feedback at <A HREF="mailto:info@amzi.com">mary@amzi.com</A>. $,
$We would be especially grateful if this system does not provide you an answer, if you $,
$can tell us what your form inputs were and describe your problem. $,
$We'll e-mail you an answer and try to add it to this system.$,
$<P>Thank you! $,
$<P><FONT SIZE=-1>Copyright ©1996 Amzi! inc. All Rights Reserved.$]
]).
More Details on Rules
if fact \= value
then problem = problemID.
You can also compare values using >, < >=, <=. This sorts by the ASCII character codes so 'A' < 'B', 'c' > 'D', '2' < 'E'. For example:
if fact > value
then problem = problemID.
if fact <= value
then problem = problemID.
if fact1 = value1 and (fact2 = value2 or fact3 /= value3)
then problem = problemID.
If you use the HTML tag 'MULTIPLE' on a list in your initial form or add the declaration 'multivalued' to your attr definition, then your users can select multiple values from that list. You can check if a value has been selected with the 'include' operator. For example:
if fact include value
then problem = problemID.
Design Considerations
One of the nice features of a logic-base is that the rules can be kept in any order. However you do have to take care that you don't have rules like:
if a1 = v1 then problem = p1.
if a1 = v1 and a2 = v2 then problem = p2.
Logic-Base Maintenance
On-going maintenance of the logic-base is very straight-forward. The Amzi! tech support logic-base is organized by problem area. There is a section based on error message alone, then a section on the Amzi! samples, a section on the Amzi! IDE, a section on Prolog predicates, a section on Logic Server API calls and then sections for each of the tools and languages that Amzi! Logic Servers can be embedded into. The rules, attrs and answers follow the same organization.
Debugging Logic-Bases
Syntax Errors
The most common problem you will encounter is typing errors in your logic-base. The two most likely will be missing the period at the end of a rule or output function, and forgetting to quote facts and values that do not start with a lowercase letter, or contain characters other than letters, numbers and underscores.
Trace Facility
WebLS includes a trace facility to assist in testing and debugging logic-bases. The trace lists all the known facts, and then shows each rule being tried, indicating which facts match, and which rule or hypothesis matches. When tracing is enabled (by defining a log file at the top of your logic-base), a URL pointing to the output is included on the bottom of each page generated by WebLS. This allows you to examine the trace directly in your browser.
% ------------------------------------------------------------------- %
% The Rule-Base %
% ------------------------------------------------------------------- %
%
% Required definitions for Amzi! Do not change or remove.
%
:- op(790, fx, if). % prefix operator
:- op(780, xfx, then). % infix operator
:- op(775, xfy, or). % infix that can be linked
:- op(770, xfy, and). % infix that can be linked
:- op(700, xfx, <=). % infix operator
:- op(700, xfx, include). % infix operator
system('Log File', 'C:\\WebLS\\logs\\liltrace.htm').
system('Log File URL', 'file:///C:\\WebLS\\logs\\liltrace.htm').
system('Results File', $C:\\WebLS\\logs\\lilrslts.pro$).
system('Initial Form', $C:\\WebLS\\html\\lilrules.htm$).
system('Temp Directory', $C:\\WebLS\\temp\\$).
system('Body Args', $bgcolor=#CEFAFF text=#000000$).
system('Title', $Amzi! Little Problem Resolver$).
system('Footer', $<FONT SIZE=-1>Copyright ©1996 Amzi! inc. All Rights Reserved.$).
system('Form Action', 'Executable Path').
system('Goal', 'problem').
attr(errorCode,
[
prompt = $What error code was displayed or 'none'?$,
ask = field,
length = 5
]).
attr(programType,
[
prompt = $What program are you running?$,
ask = menu(['other', 'Amzi! Hello Program', 'Amzi! Sample Program',
'Amzi! IDE', 'My Program', 'Windows Application'])
]).
if errorCode = '600' and
programType = 'Amzi! Hello Program'
then problem = helloXPL.
if errorCode = '600' and
programType = 'Amzi! Sample Program'
then problem = sampleXPL.
if errorCode = '600' and
programType = 'My Program'
then problem = missingXPL.
answer(helloXPL,
[
answer = [$The program is unable to locate the Amzi! Prolog object module, an XPL file. $,
$Make sure the AMZI installation directory is in your path, and that HELLO.XPL file $,
$exists in the path or the current directory.$]
]).
answer(sampleXPL,
[
answer = [$The program is unable to locate the Amzi! Prolog object module, an XPL file. $,
$Some of the Amzi! samples include source only, $,
$and the PRO file needs to be compiled and linked $,
$into an XPL file.$,
$<P>If the XPL file exists, then it must be in your $,
$path or the current directory.$]
]).
answer(missingXPL,
[
answer = [$The program is unable to locate the Amzi! Prolog object module, an XPL file. $,
$Make sure the the XPL file exists in your path $,
$or the current directory.$,
$<P>Note: Some development environments such as Visual Basic and $,
$Delphi set the current directory to a directory you might not $,
$have expected.$]
]).
Logic-Base Debugging Trace
system($Input File$,$C:\WEBSITE\CGI-TEMP\287WS.INI$).
system('Content File','C:\WEBSITE\CGI-TEMP\287WS.INP').
system('Output File','C:\WebSite\cgi-temp\287ws.out').
. . .
system('Log File','C:\AmziCGI\logs\lilrun.htm').
system('Title',$Amzi! Problem Resolver$).
system('Initial Form',$C:\AmziCGI\html\rptprob.htm$).
system('AmziCGI Directory',$C:\AmziCGI$).
system('Form Action','Executable Path').
system('Goal',problem).
cgi('Content Length','191').
cgi('Content Type','application/x-www-form-urlencoded').
. . .
cgi('Executable Path','/cgi-win/cgirun.exe').
cgi('Request Method','POST').
cgi('Request Protocol','HTTP/1.0').
fact(submitProblem,'Submit').
fact(programType,'Amzi! Sample Program').
fact(errorCode,'600').
Processing input file C:\WEBSITE\CGI-TEMP\544WS.INI
Opened fact file: submitProblem
Processing POST method (subsequent times through
---> Calling logic-base for the first time
Trying problem = helloXPL
Trying errorCode = 600
Matching errorCode is 600
Trying programType = Amzi! Hello Program
Failing problem = helloXPL
Trying problem = sampleXPL
Trying errorCode = 600
Matching errorCode is 600
Trying programType = Amzi! Sample Program
Matching programType is Amzi! Sample Program
Matching problem = sampleXPL
---> Logic-base succeeded in finding an answer: sampleXPL
Error Messages
In addition to the trace facility, WebLS reports when attr is not defined for a needed fact and when answer is not defined for a reached conclusion. These errors are returned on an HTML error page designed for the purpose.
Syntax Summary
Below is a summary of all the major parts of the logic-base. Items in italics are provided by you. Items separated by vertical bars | indicate any one of the choices may be selected. Curly brackets {} are used around optional items. Note the placement of square brackets [] to indicate lists and the closing period.
Fact Attributes
attr(fact-name,
[
prompt = $prompt-text$,
ask = field | yesno | menu(['choice1', 'choice2', ... 'choiceN']),
{related = [fact1, fact2, ... factN]}
{multivalued}
]).
Rules
if expression then goal = answer.
fact operator value {and | or fact operator value}
Answer Definitions
answer(answer-name,
[
{text = $short-answer-text$,}
{text = [$long-answer-text-string1$,
$long-answer-text-string2$,
. . .
$long-answer-text-stringN$],}
{url = 'uniform-resource-locator',}
{htmlFile = 'html-filename',}
{note = [note1, note2, ... noteN]}
]).
Answers follow the same syntax as fact attributes. Note each item must be followed by a comma, except the last one. Also note the careful placement of []'s, ()'s and the ending . period.
Notes
note(note-name,
[
{text = $short-answer-text$,}
{text = [$long-answer-text-string1$,
$long-answer-text-string2$,
. . .
$long-answer-text-stringN$],}
]).
Upgrading to Amzi! Prolog + Logic Server
WebLS is a complete system for implementing small to medium sized tech support systems. As your logic-base grows you might want to increase its speed by compiling the rules, and you may want to add additional features not supported by WebLS. These features might include:
Enhancements and Bug Fixes by Release
Enhancements
Release 1.0 Enhancements
Bug Fixes
Release 0.4 Bug Fixes