From bc70de7b3302d5a81515b901cae376b8b51d2004 Mon Sep 17 00:00:00 2001
From: "Arnold D. Robbins" To run it, do this: \ Details of HTTP come from:Hello, world
"
+ Len = length(Hello) + length(ORS)
+ print "HTTP/1.0 200 OK" |& HttpService
+ print "Content-Length: " Len ORS |& HttpService
+ print Hello |& HttpService
+ while ((HttpService |& getline) > 0)
+ continue;
+ close(HttpService)
+ }
+
+ Now, on the same machine, start your favorite browser and let it
+point to `http://localhost:8080' (the browser needs to know on which
+port our server is listening for requests). If this does not work, the
+browser probably tries to connect to a proxy server that does not know
+your machine. If so, change the browser's configuration so that the
+browser does not try to use a proxy to connect to your machine.
+
+
+File: gawkinet.info, Node: Interacting Service, Next: Simple Server, Prev: Primitive Service, Up: Using Networking
+
+A Web Service with Interaction
+==============================
+
+ This node shows how to set up a simple web server. The subnode is a
+library file that we will use with all the examples in *Note Some
+Applications and Techniques::.
+
+* Menu:
+
+* CGI Lib:: A simple CGI library.
+
+ Setting up a web service that allows user interaction is more
+difficult and shows us the limits of network access in `gawk'. In this
+node, we develop a main program (a `BEGIN' pattern and its action)
+that will become the core of event-driven execution controlled by a
+graphical user interface (GUI). Each HTTP event that the user triggers
+by some action within the browser is received in this central
+procedure. Parameters and menu choices are extracted from this request
+and an appropriate measure is taken according to the user's choice.
+For example:
+
+ BEGIN {
+ if (MyHost == "") {
+ "uname -n" | getline MyHost
+ close("uname -n")
+ }
+ if (MyPort == 0) MyPort = 8080
+ HttpService = "/inet/tcp/" MyPort "/0/0"
+ MyPrefix = "http://" MyHost ":" MyPort
+ SetUpServer()
+ while ("awk" != "complex") {
+ # header lines are terminated this way
+ RS = ORS = "\r\n"
+ Status = 200 # this means OK
+ Reason = "OK"
+ Header = TopHeader
+ Document = TopDoc
+ Footer = TopFooter
+ if (GETARG["Method"] == "GET") {
+ HandleGET()
+ } else if (GETARG["Method"] == "HEAD") {
+ # not yet implemented
+ } else if (GETARG["Method"] != "") {
+ print "bad method", GETARG["Method"]
+ }
+ Prompt = Header Document Footer
+ print "HTTP/1.0", Status, Reason |& HttpService
+ print "Connection: Close" |& HttpService
+ print "Pragma: no-cache" |& HttpService
+ len = length(Prompt) + length(ORS)
+ print "Content-length:", len |& HttpService
+ print ORS Prompt |& HttpService
+ # ignore all the header lines
+ while ((HttpService |& getline) > 0)
+ ;
+ # stop talking to this client
+ close(HttpService)
+ # wait for new client request
+ HttpService |& getline
+ # do some logging
+ print systime(), strftime(), $0
+ # read request parameters
+ CGI_setup($1, $2, $3)
+ }
+ }
+
+ This web server presents menu choices in the form of HTML links.
+Therefore, it has to tell the browser the name of the host it is
+residing on. When starting the server, the user may supply the name of
+the host from the command line with `gawk -v MyHost="Rumpelstilzchen"'.
+If the user does not do this, the server looks up the name of the host
+it is running on for later use as a web address in HTML documents. The
+same applies to the port number. These values are inserted later into
+the HTML content of the web pages to refer to the home system.
+
+ Each server that is built around this core has to initialize some
+application-dependent variables (such as the default home page) in a
+procedure `SetUpServer', which is called immediately before entering the
+infinite loop of the server. For now, we will write an instance that
+initiates a trivial interaction. With this home page, the client user
+can click on two possible choices, and receive the current date either
+in human-readable format or in seconds since 1970:
+
+ function SetUpServer() {
+ TopHeader = ""
+ TopHeader = TopHeader \
+ "\
+ Do you prefer your date human or \
+ POSIXed?
" ORS ORS
+ TopFooter = ""
+ }
+
+ On the first run through the main loop, the default line terminators
+are set and the default home page is copied to the actual home page.
+Since this is the first run, `GETARG["Method"]' is not initialized yet,
+hence the case selection over the method does nothing. Now that the
+home page is initialized, the server can start communicating to a
+client browser.
+
+ It does so by printing the HTTP header into the network connection
+(`print ... |& HttpService'). This command blocks execution of the
+server script until a client connects. If this server script is
+compared with the primitive one we wrote before, you will notice two
+additional lines in the header. The first instructs the browser to
+close the connection after each request. The second tells the browser
+that it should never try to _remember_ earlier requests that had
+identical web addresses (no caching). Otherwise, it could happen that
+the browser retrieves the time of day in the previous example just once,
+and later it takes the web page from the cache, always displaying the
+same time of day although time advances each second.
+
+ Having supplied the initial home page to the browser with a valid
+document stored in the parameter `Prompt', it closes the connection and
+waits for the next request. When the request comes, a log line is
+printed that allows us to see which request the server receives. The
+final step in the loop is to call the function `CGI_setup', which reads
+all the lines of the request (coming from the browser), processes them,
+and stores the transmitted parameters in the array `PARAM'. The complete
+text of these application-independent functions can be found in *Note A
+Simple CGI Library: CGI Lib. For now, we use a simplified version of
+`CGI_setup':
+
+ function CGI_setup( method, uri, version, i) {
+ delete GETARG; delete MENU; delete PARAM
+ GETARG["Method"] = $1
+ GETARG["URI"] = $2
+ GETARG["Version"] = $3
+ i = index($2, "?")
+ # is there a "?" indicating a CGI request?
+ if (i > 0) {
+ split(substr($2, 1, i-1), MENU, "[/:]")
+ split(substr($2, i+1), PARAM, "&")
+ for (i in PARAM) {
+ j = index(PARAM[i], "=")
+ GETARG[substr(PARAM[i], 1, j-1)] = \
+ substr(PARAM[i], j+1)
+ }
+ } else { # there is no "?", no need for splitting PARAMs
+ split($2, MENU, "[/:]")
+ }
+ }
+
+ At first, the function clears all variables used for global storage
+of request parameters. The rest of the function serves the purpose of
+filling the global parameters with the extracted new values. To
+accomplish this, the name of the requested resource is split into parts
+and stored for later evaluation. If the request contains a `?', then
+the request has CGI variables seamlessly appended to the web address.
+Everything in front of the `?' is split up into menu items, and
+everything behind the `?' is a list of `VARIABLE=VALUE' pairs
+(separated by `&') that also need splitting. This way, CGI variables are
+isolated and stored. This procedure lacks recognition of special
+characters that are transmitted in coded form(1). Here, any optional
+request header and body parts are ignored. We do not need header
+parameters and the request body. However, when refining our approach or
+working with the `POST' and `PUT' methods, reading the header and body
+becomes inevitable. Header parameters should then be stored in a global
+array as well as the body.
+
+ On each subsequent run through the main loop, one request from a
+browser is received, evaluated, and answered according to the user's
+choice. This can be done by letting the value of the HTTP method guide
+the main loop into execution of the procedure `HandleGET', which
+evaluates the user's choice. In this case, we have only one
+hierarchical level of menus, but in the general case, menus are nested.
+The menu choices at each level are separated by `/', just as in file
+names. Notice how simple it is to construct menus of arbitrary depth:
+
+ function HandleGET() {
+ if ( MENU[2] == "human") {
+ Footer = strftime() TopFooter
+ } else if (MENU[2] == "POSIX") {
+ Footer = systime() TopFooter
+ }
+ }
+
+ The disadvantage of this approach is that our server is slow and can
+handle only one request at a time. Its main advantage, however, is that
+the server consists of just one `gawk' program. No need for installing
+an `httpd', and no need for static separate HTML files, CGI scripts, or
+`root' privileges. This is rapid prototyping. This program can be
+started on the same host that runs your browser. Then let your browser
+point to `http://localhost:8080'.
+
+ It is also possible to include images into the HTML pages. Most
+browsers support the not very well-known `.xbm' format, which may
+contain only monochrome pictures but is an ASCII format. Binary images
+are possible but not so easy to handle. Another way of including images
+is to generate them with a tool such as GNUPlot, by calling the tool
+with the `system' function or through a pipe.
+
+ ---------- Footnotes ----------
+
+ (1) As defined in RFC 2068.
+
+
+File: gawkinet.info, Node: CGI Lib, Prev: Interacting Service, Up: Interacting Service
+
+A Simple CGI Library
+--------------------
+
+ HTTP is like being married: you have to be able to handle whatever
+ you're given, while being very careful what you send back.
+ Phil Smith III,
+ `http://www.netfunny.com/rhf/jokes/99/Mar/http.html'
+
+ In *Note A Web Service with Interaction: Interacting Service, we saw
+the function `CGI_setup' as part of the web server "core logic"
+framework. The code presented there handles almost everything necessary
+for CGI requests. One thing it doesn't do is handle encoded characters
+in the requests. For example, an `&' is encoded as a percent sign
+followed by the hexadecimal value--`%26'. These encoded values should
+be decoded. Following is a simple library to perform these tasks.
+This code is used for all web server examples used throughout the rest
+of this Info file. If you want to use it for your own web server,
+store the source code into a file named `inetlib.awk'. Then you can
+include these functions into your code by placing the following
+statement into your program:
+
+ @include inetlib.awk
+
+on the first line of your script. But beware, this mechanism is only
+possible if you invoke your web server script with `igawk' instead of
+the usual `awk' or `gawk'. Here is the code:
+
+ # CGI Library and core of a web server
+ # Global arrays
+ # GETARG --- arguments to CGI GET command
+ # MENU --- menu items (path names)
+ # PARAM --- parameters of form x=y
+
+ # Optional variable MyHost contains host address
+ # Optional variable MyPort contains port number
+ # Needs TopHeader, TopDoc, TopFooter
+ # Sets MyPrefix, HttpService, Status, Reason
+
+ BEGIN {
+ if (MyHost == "") {
+ "uname -n" | getline MyHost
+ close("uname -n")
+ }
+ if (MyPort == 0) MyPort = 8080
+ HttpService = "/inet/tcp/" MyPort "/0/0"
+ MyPrefix = "http://" MyHost ":" MyPort
+ SetUpServer()
+ while ("awk" != "complex") {
+ # header lines are terminated this way
+ RS = ORS = "\r\n"
+ Status = 200 # this means OK
+ Reason = "OK"
+ Header = TopHeader
+ Document = TopDoc
+ Footer = TopFooter
+ if (GETARG["Method"] == "GET") {
+ HandleGET()
+ } else if (GETARG["Method"] == "HEAD") {
+ # not yet implemented
+ } else if (GETARG["Method"] != "") {
+ print "bad method", GETARG["Method"]
+ }
+ Prompt = Header Document Footer
+ print "HTTP/1.0", Status, Reason |& HttpService
+ print "Connection: Close" |& HttpService
+ print "Pragma: no-cache" |& HttpService
+ len = length(Prompt) + length(ORS)
+ print "Content-length:", len |& HttpService
+ print ORS Prompt |& HttpService
+ # ignore all the header lines
+ while ((HttpService |& getline) > 0)
+ continue
+ # stop talking to this client
+ close(HttpService)
+ # wait for new client request
+ HttpService |& getline
+ # do some logging
+ print systime(), strftime(), $0
+ CGI_setup($1, $2, $3)
+ }
+ }
+
+ function CGI_setup( method, uri, version, i)
+ {
+ delete GETARG
+ delete MENU
+ delete PARAM
+ GETARG["Method"] = method
+ GETARG["URI"] = uri
+ GETARG["Version"] = version
+
+ i = index(uri, "?")
+ if (i > 0) { # is there a "?" indicating a CGI request?
+ split(substr(uri, 1, i-1), MENU, "[/:]")
+ split(substr(uri, i+1), PARAM, "&")
+ for (i in PARAM) {
+ PARAM[i] = _CGI_decode(PARAM[i])
+ j = index(PARAM[i], "=")
+ GETARG[substr(PARAM[i], 1, j-1)] = \
+ substr(PARAM[i], j+1)
+ }
+ } else { # there is no "?", no need for splitting PARAMs
+ split(uri, MENU, "[/:]")
+ }
+ for (i in MENU) # decode characters in path
+ if (i > 4) # but not those in host name
+ MENU[i] = _CGI_decode(MENU[i])
+ }
+
+ This isolates details in a single function, `CGI_setup'. Decoding
+of encoded characters is pushed off to a helper function,
+`_CGI_decode'. The use of the leading underscore (`_') in the function
+name is intended to indicate that it is an "internal" function,
+although there is nothing to enforce this:
+
+ function _CGI_decode(str, hexdigs, i, pre, code1, code2,
+ val, result)
+ {
+ hexdigs = "123456789abcdef"
+
+ i = index(str, "%")
+ if (i == 0) # no work to do
+ return str
+
+ do {
+ pre = substr(str, 1, i-1) # part before %xx
+ code1 = substr(str, i+1, 1) # first hex digit
+ code2 = substr(str, i+2, 1) # second hex digit
+ str = substr(str, i+3) # rest of string
+
+ code1 = tolower(code1)
+ code2 = tolower(code2)
+ val = index(hexdigs, code1) * 16 \
+ + index(hexdigs, code2)
+
+ result = result pre sprintf("%c", val)
+ i = index(str, "%")
+ } while (i != 0)
+ if (length(str) > 0)
+ result = result str
+ return result
+ }
+
+ This works by splitting the string apart around an encoded character.
+The two digits are converted to lowercase and looked up in a string of
+hex digits. Note that `0' is not in the string on purpose; `index'
+returns zero when it's not found, automatically giving the correct
+value! Once the hexadecimal value is converted from characters in a
+string into a numerical value, `sprintf' converts the value back into a
+real character. The following is a simple test harness for the above
+functions:
+
+ BEGIN {
+ CGI_setup("GET",
+ "http://www.gnu.org/cgi-bin/foo?p1=stuff&p2=stuff%26junk" \
+ "&percent=a %25 sign",
+ "1.0")
+ for (i in MENU)
+ printf "MENU[\"%s\"] = %s\n", i, MENU[i]
+ for (i in PARAM)
+ printf "PARAM[\"%s\"] = %s\n", i, PARAM[i]
+ for (i in GETARG)
+ printf "GETARG[\"%s\"] = %s\n", i, GETARG[i]
+ }
+
+ And this is the result when we run it:
+
+ $ gawk -f testserv.awk
+ -| MENU["4"] = www.gnu.org
+ -| MENU["5"] = cgi-bin
+ -| MENU["6"] = foo
+ -| MENU["1"] = http
+ -| MENU["2"] =
+ -| MENU["3"] =
+ -| PARAM["1"] = p1=stuff
+ -| PARAM["2"] = p2=stuff&junk
+ -| PARAM["3"] = percent=a % sign
+ -| GETARG["p1"] = stuff
+ -| GETARG["percent"] = a % sign
+ -| GETARG["p2"] = stuff&junk
+ -| GETARG["Method"] = GET
+ -| GETARG["Version"] = 1.0
+ -| GETARG["URI"] = http://www.gnu.org/cgi-bin/foo?p1=stuff&
+ p2=stuff%26junk&percent=a %25 sign
+
+
+File: gawkinet.info, Node: Simple Server, Next: Caveats, Prev: Interacting Service, Up: Using Networking
+
+A Simple Web Server
+===================
+
+ In the preceding node, we built the core logic for event driven GUIs.
+In this node, we finally extend the core to a real application. No one
+would actually write a commercial web server in `gawk', but it is
+instructive to see that it is feasible in principle.
+
+ The application is ELIZA, the famous program by Joseph Weizenbaum
+that mimics the behavior of a professional psychotherapist when talking
+to you. Weizenbaum would certainly object to this description, but
+this is part of the legend around ELIZA. Take the site-independent
+core logic and append the following code:
+
+ function SetUpServer() {
+ SetUpEliza()
+ TopHeader = \
+ "Please choose one of the following actions:
\
+ \
+
"
+ TopFooter = ""
+ }
+
+ `SetUpServer' is similar to the previous example, except for calling
+another function, `SetUpEliza'. This approach can be used to implement
+other kinds of servers. The only changes needed to do so are hidden in
+the functions `SetUpServer' and `HandleGET'. Perhaps it might be
+necessary to implement other HTTP methods. The `igawk' program that
+comes with `gawk' may be useful for this process.
+
+ When extending this example to a complete application, the first
+thing to do is to implement the function `SetUpServer' to initialize
+the HTML pages and some variables. These initializations determine the
+way your HTML pages look (colors, titles, menu items, etc.).
+
+ The function `HandleGET' is a nested case selection that decides
+which page the user wants to see next. Each nesting level refers to a
+menu level of the GUI. Each case implements a certain action of the
+menu. On the deepest level of case selection, the handler essentially
+knows what the user wants and stores the answer into the variable that
+holds the HTML page contents:
+
+ function HandleGET() {
+ # A real HTTP server would treat some parts of the URI as a file name.
+ # We take parts of the URI as menu choices and go on accordingly.
+ if(MENU[2] == "AboutServer") {
+ Document = "This is not a CGI script.\
+ This is an httpd, an HTML file, and a CGI script all \
+ in one GAWK script. It needs no separate www-server, \
+ no installation, and no root privileges.\
+ \
+
\\
+
JK 14.9.1997
" + } else if (MENU[2] == "AboutELIZA") { + Document = "This is an implementation of the famous ELIZA\ + program by Joseph Weizenbaum. It is written in GAWK and\ + /bin/sh: expad: command not found + } else if (MENU[2] == "StartELIZA") { + gsub(/\+/, " ", GETARG["YouSay"]) + # Here we also have to substitute coded special characters + Document = "" + } + } + + Now we are down to the heart of ELIZA, so you can see how it works. +Initially the user does not say anything; then ELIZA resets its money +counter and asks the user to tell what comes to mind open heartedly. +The subsequent answers are converted to uppercase and stored for later +comparison. ELIZA presents the bill when being confronted with a +sentence that contains the phrase "shut up." Otherwise, it looks for +keywords in the sentence, conjugates the rest of the sentence, remembers +the keyword for later use, and finally selects an answer from the set of +possible answers: + + function ElizaSays(YouSay) { + if (YouSay == "") { + cost = 0 + answer = "HI, IM ELIZA, TELL ME YOUR PROBLEM" + } else { + q = toupper(YouSay) + gsub("'", "", q) + if(q == qold) { + answer = "PLEASE DONT REPEAT YOURSELF !" + } else { + if (index(q, "SHUT UP") > 0) { + answer = "WELL, PLEASE PAY YOUR BILL. ITS EXACTLY ... $"\ + int(100*rand()+30+cost/100) + } else { + qold = q + w = "-" # no keyword recognized yet + for (i in k) { # search for keywords + if (index(q, i) > 0) { + w = i + break + } + } + if (w == "-") { # no keyword, take old subject + w = wold + subj = subjold + } else { # find subject + subj = substr(q, index(q, w) + length(w)+1) + wold = w + subjold = subj # remember keyword and subject + } + for (i in conj) + gsub(i, conj[i], q) # conjugation + # from all answers to this keyword, select one randomly + answer = r[indices[int(split(k[w], indices) * rand()) + 1]] + # insert subject into answer + gsub("_", subj, answer) + } + } + } + cost += length(answer) # for later payment : 1 cent per character + return answer + } + + In the long but simple function `SetUpEliza', you can see tables for +conjugation, keywords, and answers.(1) The associative array `k' +contains indices into the array of answers `r'. To choose an answer, +ELIZA just picks an index randomly: + + function SetUpEliza() { + srand() + wold = "-" + subjold = " " + + # table for conjugation + conj[" ARE " ] = " AM " + conj["WERE " ] = "WAS " + conj[" YOU " ] = " I " + conj["YOUR " ] = "MY " + conj[" IVE " ] =\ + conj[" I HAVE " ] = " YOU HAVE " + conj[" YOUVE " ] =\ + conj[" YOU HAVE "] = " I HAVE " + conj[" IM " ] =\ + conj[" I AM " ] = " YOU ARE " + conj[" YOURE " ] =\ + conj[" YOU ARE " ] = " I AM " + + # table of all answers + r[1] = "DONT YOU BELIEVE THAT I CAN _" + r[2] = "PERHAPS YOU WOULD LIKE TO BE ABLE TO _ ?" + ... + + # table for looking up answers that + # fit to a certain keyword + k["CAN YOU"] = "1 2 3" + k["CAN I"] = "4 5" + k["YOU ARE"] =\ + k["YOURE"] = "6 7 8 9" + ... + + } + + Some interesting remarks and details (including the original source +code of ELIZA) are found on Mark Humphrys' home page. Yahoo! also has +a page with a collection of ELIZA-like programs. Many of them are +written in Java, some of them disclosing the Java source code, and a +few even explain how to modify the Java source code. + + ---------- Footnotes ---------- + + (1) The version shown here is abbreviated. The full version comes +with the `gawk' distribution. + + +File: gawkinet.info, Node: Caveats, Next: Challenges, Prev: Simple Server, Up: Using Networking + +Network Programming Caveats +=========================== + + By now it should be clear that debugging a networked application is +more complicated than debugging a single-process single-hosted +application. The behavior of a networked application sometimes looks +non-causal because it is not reproducible in a strong sense. Whether a +network application works or not sometimes depends on the following: + + * How crowded the underlying network is. + + * If the party at the other end is running or not. + + * The state of the party at the other end. + + The most difficult problems for a beginner arise from the hidden +states of the underlying network. After closing a TCP connection, it's +often necessary to wait a short while before reopening the connection. +Even more difficult is the establishment of a connection that +previously ended with a "broken pipe." Those connections have to "time +out" for a minute or so before they can reopen. Check this with the +command `netstat -a', which provides a list of still "active" +connections. + + +File: gawkinet.info, Node: Challenges, Prev: Caveats, Up: Using Networking + +Where To Go From Here +===================== + + Now, you have learned enough to build your own application. You +could, for example, take part in the Loebner Contest to win $100,000. +The Loebner Prize is the first formal instantiation of a Turing Test. +Hugh Loebner agreed with The Cambridge Center for Behavioral Studies to +underwrite a contest designed to implement the Turing Test. Dr. +Loebner pledged a Grand Prize of $100,000 for the first computer whose +responses were indistinguishable from a human's. Each year an annual +prize of $2000 and a bronze medal is awarded to the _most_ human +computer. The winner of the annual contest is the best entry relative +to other entries that year, irrespective of how good it is in an +absolute sense. Here is an example of a conversation with the winning +program of 1997: + + (c)1997 Cambridge Center For Behavioral Studies all rights reserved [CONVERSE] + [Intelligent Research Ltd.] Start at: [1997/04/29 08:59:40] + PROGRAM[10:39:20]Hi, my name is Catherine, what's yours? + JUDGE02[10:39:36]My name is Nathan. + PROGRAM[10:39:37]Well, it's nice to meet you, Nathan. + PROGRAM[10:39:45]Did you see that story on CNN last night about the lesbian + PROGRAM[10:40:03]couple who came out at a White House party on Sunday? + JUDGE02[10:40:45]No. I'm sorry I missed that. How did the Prez take it? + PROGRAM[10:40:47]Ellen Degeneres was one of them - she was kissing her lover + PROGRAM[10:41:08]in front of Bill Clinton. Do you think he was very + PROGRAM[10:41:21]embarrassed? + JUDGE02[10:41:37]You tell me. I didn't see it. + PROGRAM[10:41:38]Are you still a Friend of Bill Clinton? + JUDGE02[10:42:22]Yes. I would like to talk about something else. Do you know anything about sculpture. + PROGRAM[10:42:24]Well, I suppose he's doing his best like most of us, but he + PROGRAM[10:42:35]does seem to attract an UNUSUAL amount of bad publicity, + PROGRAM[10:42:51]wouldnt you say--can it all be bad luck? + JUDGE02[10:43:20]I asked you if you knew anything about sculpture. + PROGRAM[10:43:21]OK, but what happens now--does it all drift on, with + PROGRAM[10:43:36]everyone waiting to see how much his friends have said about + PROGRAM[10:43:47]him under threat of lots and lots of jail-or will something + PROGRAM[10:44:01]dramatic actually happen? + JUDGE02[10:44:19]Do you know what sculpture is? + PROGRAM[10:44:20]Well, youre more a fan of his than I am I guess---though I + PROGRAM[10:44:34]cant SWEAR what Id have done in that locked hotel room, I + PROGRAM[10:44:51]must say. + JUDGE02[10:45:26]Have you ever been to the Salmagundi Club? + PROGRAM[10:45:29]Never. to go back to the original discussion Time to get + PROGRAM[10:45:43]off this one I think and onto something more down to earth! + JUDGE02[10:46:20]What is more down to earth than art? + PROGRAM[10:46:21]I don't know what -- to be honest. - + PROGRAM[10:46:30]I suppose it depends on where you're coming from, but as the + PROGRAM[10:46:46]song goes in My Fair Lady, "Why can't a woman be more like a + PROGRAM[10:47:03]man? " + JUDGE02[10:47:52]I liked that song but I prefer "Why can't children be more like we are" + JUDGE02[10:48:10]from another play the name of which I cannot remember. + PROGRAM[10:48:12]What, if anything, do you enjoy about being a man? + JUDGE02[10:49:01]I would enjoy all aspects of life no matter what my gender. + PROGRAM[10:49:02]Do you think of yourself as being attractive? + + This program insists on always speaking about the same story around +Bill Clinton. You see, even a program with a rather narrow mind can +behave so much like a human being that it can win this prize. It is +quite common to let these programs talk to each other via network +connections. But during the competition itself, the program and its +computer have to be present at the place the competition is held. We +all would love to see a `gawk' program win in such an event. Maybe it +is up to you to accomplish this? + + Some other ideas for useful networked applications: + * Read the file `doc/awkforai.txt' in the `gawk' distribution. It + was written by Ronald P. Loui (Associate Professor of Computer + Science, at Washington University in St. Louis, +" i " | " \ + "" config[i] " |
To run it, do this:
\ Details of HTTP come from:
JK 14.9.1997
" + @} else if (MENU[2] == "AboutELIZA") @{ + Document = "This is an implementation of the famous ELIZA\ + program by Joseph Weizenbaum. It is written in GAWK and\ +/bin/sh: expad: command not found + @} else if (MENU[2] == "StartELIZA") @{ + gsub(/\+/, " ", GETARG["YouSay"]) + # Here we also have to substitute coded special characters + Document = "" + @} +@} +@c endfile +@end smallexample + +Now we are down to the heart of ELIZA, so you can see how it works. +Initially the user does not say anything; then ELIZA resets its money +counter and asks the user to tell what comes to mind open heartedly. +The subsequent answers are converted to uppercase and stored for +later comparison. ELIZA presents the bill when being confronted with +a sentence that contains the phrase ``shut up.'' Otherwise, it looks for +keywords in the sentence, conjugates the rest of the sentence, remembers +the keyword for later use, and finally selects an answer from the set of +possible answers: + +@smallexample +@c file eg/network/eliza.awk +function ElizaSays(YouSay) @{ + if (YouSay == "") @{ + cost = 0 + answer = "HI, IM ELIZA, TELL ME YOUR PROBLEM" + @} else @{ + q = toupper(YouSay) + gsub("'", "", q) + if(q == qold) @{ + answer = "PLEASE DONT REPEAT YOURSELF !" + @} else @{ + if (index(q, "SHUT UP") > 0) @{ + answer = "WELL, PLEASE PAY YOUR BILL. ITS EXACTLY ... $"\ + int(100*rand()+30+cost/100) + @} else @{ + qold = q + w = "-" # no keyword recognized yet + for (i in k) @{ # search for keywords + if (index(q, i) > 0) @{ + w = i + break + @} + @} + if (w == "-") @{ # no keyword, take old subject + w = wold + subj = subjold + @} else @{ # find subject + subj = substr(q, index(q, w) + length(w)+1) + wold = w + subjold = subj # remember keyword and subject + @} + for (i in conj) + gsub(i, conj[i], q) # conjugation + # from all answers to this keyword, select one randomly + answer = r[indices[int(split(k[w], indices) * rand()) + 1]] + # insert subject into answer + gsub("_", subj, answer) + @} + @} + @} + cost += length(answer) # for later payment : 1 cent per character + return answer +@} +@c endfile +@end smallexample + +In the long but simple function @code{SetUpEliza}, you can see tables +for conjugation, keywords, and answers.@footnote{The version shown +here is abbreviated. The full version comes with the @command{gawk} +distribution.} The associative array @code{k} +contains indices into the array of answers @code{r}. To choose an +answer, ELIZA just picks an index randomly: + +@example +@c file eg/network/eliza.awk +function SetUpEliza() @{ + srand() + wold = "-" + subjold = " " + + # table for conjugation + conj[" ARE " ] = " AM " + conj["WERE " ] = "WAS " + conj[" YOU " ] = " I " + conj["YOUR " ] = "MY " + conj[" IVE " ] =\ + conj[" I HAVE " ] = " YOU HAVE " + conj[" YOUVE " ] =\ + conj[" YOU HAVE "] = " I HAVE " + conj[" IM " ] =\ + conj[" I AM " ] = " YOU ARE " + conj[" YOURE " ] =\ + conj[" YOU ARE " ] = " I AM " + + # table of all answers + r[1] = "DONT YOU BELIEVE THAT I CAN _" + r[2] = "PERHAPS YOU WOULD LIKE TO BE ABLE TO _ ?" +@c endfile + @dots{} +@end example +@ignore +@c file eg/network/eliza.awk + r[3] = "YOU WANT ME TO BE ABLE TO _ ?" + r[4] = "PERHAPS YOU DONT WANT TO _ " + r[5] = "DO YOU WANT TO BE ABLE TO _ ?" + r[6] = "WHAT MAKES YOU THINK I AM _ ?" + r[7] = "DOES IT PLEASE YOU TO BELIEVE I AM _ ?" + r[8] = "PERHAPS YOU WOULD LIKE TO BE _ ?" + r[9] = "DO YOU SOMETIMES WISH YOU WERE _ ?" + r[10] = "DONT YOU REALLY _ ?" + r[11] = "WHY DONT YOU _ ?" + r[12] = "DO YOU WISH TO BE ABLE TO _ ?" + r[13] = "DOES THAT TROUBLE YOU ?" + r[14] = "TELL ME MORE ABOUT SUCH FEELINGS" + r[15] = "DO YOU OFTEN FEEL _ ?" + r[16] = "DO YOU ENJOY FEELING _ ?" + r[17] = "DO YOU REALLY BELIEVE I DONT _ ?" + r[18] = "PERHAPS IN GOOD TIME I WILL _ " + r[19] = "DO YOU WANT ME TO _ ?" + r[20] = "DO YOU THINK YOU SHOULD BE ABLE TO _ ?" + r[21] = "WHY CANT YOU _ ?" + r[22] = "WHY ARE YOU INTERESTED IN WHETHER OR NOT I AM _ ?" + r[23] = "WOULD YOU PREFER IF I WERE NOT _ ?" + r[24] = "PERHAPS IN YOUR FANTASIES I AM _ " + r[25] = "HOW DO YOU KNOW YOU CANT _ ?" + r[26] = "HAVE YOU TRIED ?" + r[27] = "PERHAPS YOU CAN NOW _ " + r[28] = "DID YOU COME TO ME BECAUSE YOU ARE _ ?" + r[29] = "HOW LONG HAVE YOU BEEN _ ?" + r[30] = "DO YOU BELIEVE ITS NORMAL TO BE _ ?" + r[31] = "DO YOU ENJOY BEING _ ?" + r[32] = "WE WERE DISCUSSING YOU -- NOT ME" + r[33] = "Oh, I _" + r[34] = "YOU'RE NOT REALLY TALKING ABOUT ME, ARE YOU ?" + r[35] = "WHAT WOULD IT MEAN TO YOU, IF YOU GOT _ ?" + r[36] = "WHY DO YOU WANT _ ?" + r[37] = "SUPPOSE YOU SOON GOT _" + r[38] = "WHAT IF YOU NEVER GOT _ ?" + r[39] = "I SOMETIMES ALSO WANT _" + r[40] = "WHY DO YOU ASK ?" + r[41] = "DOES THAT QUESTION INTEREST YOU ?" + r[42] = "WHAT ANSWER WOULD PLEASE YOU THE MOST ?" + r[43] = "WHAT DO YOU THINK ?" + r[44] = "ARE SUCH QUESTIONS IN YOUR MIND OFTEN ?" + r[45] = "WHAT IS IT THAT YOU REALLY WANT TO KNOW ?" + r[46] = "HAVE YOU ASKED ANYONE ELSE ?" + r[47] = "HAVE YOU ASKED SUCH QUESTIONS BEFORE ?" + r[48] = "WHAT ELSE COMES TO MIND WHEN YOU ASK THAT ?" + r[49] = "NAMES DON'T INTEREST ME" + r[50] = "I DONT CARE ABOUT NAMES -- PLEASE GO ON" + r[51] = "IS THAT THE REAL REASON ?" + r[52] = "DONT ANY OTHER REASONS COME TO MIND ?" + r[53] = "DOES THAT REASON EXPLAIN ANYTHING ELSE ?" + r[54] = "WHAT OTHER REASONS MIGHT THERE BE ?" + r[55] = "PLEASE DON'T APOLOGIZE !" + r[56] = "APOLOGIES ARE NOT NECESSARY" + r[57] = "WHAT FEELINGS DO YOU HAVE WHEN YOU APOLOGIZE ?" + r[58] = "DON'T BE SO DEFENSIVE" + r[59] = "WHAT DOES THAT DREAM SUGGEST TO YOU ?" + r[60] = "DO YOU DREAM OFTEN ?" + r[61] = "WHAT PERSONS APPEAR IN YOUR DREAMS ?" + r[62] = "ARE YOU DISTURBED BY YOUR DREAMS ?" + r[63] = "HOW DO YOU DO ... PLEASE STATE YOUR PROBLEM" + r[64] = "YOU DON'T SEEM QUITE CERTAIN" + r[65] = "WHY THE UNCERTAIN TONE ?" + r[66] = "CAN'T YOU BE MORE POSITIVE ?" + r[67] = "YOU AREN'T SURE ?" + r[68] = "DON'T YOU KNOW ?" + r[69] = "WHY NO _ ?" + r[70] = "DON'T SAY NO, IT'S ALWAYS SO NEGATIVE" + r[71] = "WHY NOT ?" + r[72] = "ARE YOU SURE ?" + r[73] = "WHY NO ?" + r[74] = "WHY ARE YOU CONCERNED ABOUT MY _ ?" + r[75] = "WHAT ABOUT YOUR OWN _ ?" + r[76] = "CAN'T YOU THINK ABOUT A SPECIFIC EXAMPLE ?" + r[77] = "WHEN ?" + r[78] = "WHAT ARE YOU THINKING OF ?" + r[79] = "REALLY, ALWAYS ?" + r[80] = "DO YOU REALLY THINK SO ?" + r[81] = "BUT YOU ARE NOT SURE YOU _ " + r[82] = "DO YOU DOUBT YOU _ ?" + r[83] = "IN WHAT WAY ?" + r[84] = "WHAT RESEMBLANCE DO YOU SEE ?" + r[85] = "WHAT DOES THE SIMILARITY SUGGEST TO YOU ?" + r[86] = "WHAT OTHER CONNECTION DO YOU SEE ?" + r[87] = "COULD THERE REALLY BE SOME CONNECTIONS ?" + r[88] = "HOW ?" + r[89] = "YOU SEEM QUITE POSITIVE" + r[90] = "ARE YOU SURE ?" + r[91] = "I SEE" + r[92] = "I UNDERSTAND" + r[93] = "WHY DO YOU BRING UP THE TOPIC OF FRIENDS ?" + r[94] = "DO YOUR FRIENDS WORRY YOU ?" + r[95] = "DO YOUR FRIENDS PICK ON YOU ?" + r[96] = "ARE YOU SURE YOU HAVE ANY FRIENDS ?" + r[97] = "DO YOU IMPOSE ON YOUR FRIENDS ?" + r[98] = "PERHAPS YOUR LOVE FOR FRIENDS WORRIES YOU" + r[99] = "DO COMPUTERS WORRY YOU ?" + r[100] = "ARE YOU TALKING ABOUT ME IN PARTICULAR ?" + r[101] = "ARE YOU FRIGHTENED BY MACHINES ?" + r[102] = "WHY DO YOU MENTION COMPUTERS ?" + r[103] = "WHAT DO YOU THINK MACHINES HAVE TO DO WITH YOUR PROBLEMS ?" + r[104] = "DON'T YOU THINK COMPUTERS CAN HELP PEOPLE ?" + r[105] = "WHAT IS IT ABOUT MACHINES THAT WORRIES YOU ?" + r[106] = "SAY, DO YOU HAVE ANY PSYCHOLOGICAL PROBLEMS ?" + r[107] = "WHAT DOES THAT SUGGEST TO YOU ?" + r[108] = "I SEE" + r[109] = "IM NOT SURE I UNDERSTAND YOU FULLY" + r[110] = "COME COME ELUCIDATE YOUR THOUGHTS" + r[111] = "CAN YOU ELABORATE ON THAT ?" + r[112] = "THAT IS QUITE INTERESTING" + r[113] = "WHY DO YOU HAVE PROBLEMS WITH MONEY ?" + r[114] = "DO YOU THINK MONEY IS EVERYTHING ?" + r[115] = "ARE YOU SURE THAT MONEY IS THE PROBLEM ?" + r[116] = "I THINK WE WANT TO TALK ABOUT YOU, NOT ABOUT ME" + r[117] = "WHAT'S ABOUT ME ?" + r[118] = "WHY DO YOU ALWAYS BRING UP MY NAME ?" +@c endfile +@end ignore + +@example +@c file eg/network/eliza.awk + # table for looking up answers that + # fit to a certain keyword + k["CAN YOU"] = "1 2 3" + k["CAN I"] = "4 5" + k["YOU ARE"] =\ + k["YOURE"] = "6 7 8 9" +@c endfile + @dots{} +@end example +@ignore +@c file eg/network/eliza.awk + k["I DONT"] = "10 11 12 13" + k["I FEEL"] = "14 15 16" + k["WHY DONT YOU"] = "17 18 19" + k["WHY CANT I"] = "20 21" + k["ARE YOU"] = "22 23 24" + k["I CANT"] = "25 26 27" + k["I AM"] =\ + k["IM "] = "28 29 30 31" + k["YOU "] = "32 33 34" + k["I WANT"] = "35 36 37 38 39" + k["WHAT"] =\ + k["HOW"] =\ + k["WHO"] =\ + k["WHERE"] =\ + k["WHEN"] =\ + k["WHY"] = "40 41 42 43 44 45 46 47 48" + k["NAME"] = "49 50" + k["CAUSE"] = "51 52 53 54" + k["SORRY"] = "55 56 57 58" + k["DREAM"] = "59 60 61 62" + k["HELLO"] =\ + k["HI "] = "63" + k["MAYBE"] = "64 65 66 67 68" + k[" NO "] = "69 70 71 72 73" + k["YOUR"] = "74 75" + k["ALWAYS"] = "76 77 78 79" + k["THINK"] = "80 81 82" + k["LIKE"] = "83 84 85 86 87 88 89" + k["YES"] = "90 91 92" + k["FRIEND"] = "93 94 95 96 97 98" + k["COMPUTER"] = "99 100 101 102 103 104 105" + k["-"] = "106 107 108 109 110 111 112" + k["MONEY"] = "113 114 115" + k["ELIZA"] = "116 117 118" +@c endfile +@end ignore +@example +@c file eg/network/eliza.awk +@} +@c endfile +@end example + +@cindex Humphrys, Mark +@cindex ELIZA program +@cindex Yahoo! +Some interesting remarks and details (including the original source code +of ELIZA) are found on Mark Humphrys' home page. Yahoo! also has a +page with a collection of ELIZA-like programs. Many of them are written +in Java, some of them disclosing the Java source code, and a few even +explain how to modify the Java source code. + +@node Caveats, Challenges, Simple Server, Using Networking +@section Network Programming Caveats + +By now it should be clear +that debugging a networked application is more +complicated than debugging a single-process single-hosted application. +The behavior of a networked application sometimes looks non-causal because +it is not reproducible in a strong sense. Whether a network application +works or not sometimes depends on the following: + +@itemize @bullet +@item +How crowded the underlying network is. + +@item +If the party at the other end is running or not. + +@item +The state of the party at the other end. +@end itemize + +@cindex network +The most difficult problems for a beginner arise from the hidden states of the +underlying network. After closing a TCP connection, it's often necessary to wait +a short while before reopening the connection. Even more difficult is the +establishment of a connection that previously ended with a ``broken pipe.'' +Those connections have to ``time out'' for a minute or so +before they can reopen. +Check this with the command @samp{netstat -a}, which +provides a list of still ``active'' connections. + +@node Challenges, , Caveats, Using Networking +@section Where To Go From Here + +@cindex Loebner, Hugh +@cindex Contest +Now, you have learned enough to build your own application. You could, +for example, take part in the +Loebner Contest +to win $100,000. The Loebner Prize is the first formal instantiation of +a Turing Test. Hugh Loebner agreed with The Cambridge Center for Behavioral +Studies to underwrite a contest designed to implement the Turing Test. +Dr.@: Loebner pledged a Grand Prize of $100,000 for the first computer whose +responses were indistinguishable from a human's. Each year an annual prize +of $2000 and a bronze medal is awarded to the @emph{most} human computer. +The winner of the annual contest is the best entry relative to other entries +that year, irrespective of how good it is in an absolute sense. Here is +an example of a conversation with the winning program of 1997: + +@smallexample +(c)1997 Cambridge Center For Behavioral Studies all rights reserved [CONVERSE] +[Intelligent Research Ltd.] Start at: [1997/04/29 08:59:40] +PROGRAM[10:39:20]Hi, my name is Catherine, what's yours? +JUDGE02[10:39:36]My name is Nathan. +PROGRAM[10:39:37]Well, it's nice to meet you, Nathan. +PROGRAM[10:39:45]Did you see that story on CNN last night about the lesbian +PROGRAM[10:40:03]couple who came out at a White House party on Sunday? +JUDGE02[10:40:45]No. I'm sorry I missed that. How did the Prez take it? +PROGRAM[10:40:47]Ellen Degeneres was one of them - she was kissing her lover +PROGRAM[10:41:08]in front of Bill Clinton. Do you think he was very +PROGRAM[10:41:21]embarrassed? +JUDGE02[10:41:37]You tell me. I didn't see it. +PROGRAM[10:41:38]Are you still a Friend of Bill Clinton? +JUDGE02[10:42:22]Yes. I would like to talk about something else. Do you know anything about sculpture. +PROGRAM[10:42:24]Well, I suppose he's doing his best like most of us, but he +PROGRAM[10:42:35]does seem to attract an UNUSUAL amount of bad publicity, +PROGRAM[10:42:51]wouldnt you say--can it all be bad luck? +JUDGE02[10:43:20]I asked you if you knew anything about sculpture. +PROGRAM[10:43:21]OK, but what happens now--does it all drift on, with +PROGRAM[10:43:36]everyone waiting to see how much his friends have said about +PROGRAM[10:43:47]him under threat of lots and lots of jail-or will something +PROGRAM[10:44:01]dramatic actually happen? +JUDGE02[10:44:19]Do you know what sculpture is? +PROGRAM[10:44:20]Well, youre more a fan of his than I am I guess---though I +PROGRAM[10:44:34]cant SWEAR what Id have done in that locked hotel room, I +PROGRAM[10:44:51]must say. +JUDGE02[10:45:26]Have you ever been to the Salmagundi Club? +PROGRAM[10:45:29]Never. to go back to the original discussion Time to get +PROGRAM[10:45:43]off this one I think and onto something more down to earth! +JUDGE02[10:46:20]What is more down to earth than art? +PROGRAM[10:46:21]I don't know what -- to be honest. - +PROGRAM[10:46:30]I suppose it depends on where you're coming from, but as the +PROGRAM[10:46:46]song goes in My Fair Lady, "Why can't a woman be more like a +PROGRAM[10:47:03]man? " +JUDGE02[10:47:52]I liked that song but I prefer "Why can't children be more like we are" +JUDGE02[10:48:10]from another play the name of which I cannot remember. +PROGRAM[10:48:12]What, if anything, do you enjoy about being a man? +JUDGE02[10:49:01]I would enjoy all aspects of life no matter what my gender. +PROGRAM[10:49:02]Do you think of yourself as being attractive? +@end smallexample + +@cindex Clinton, Bill +This program insists on always speaking about the same story around Bill +Clinton. You see, even a program with a rather narrow mind can behave so +much like a human being that it can win this prize. It is quite common to +let these programs talk to each other via network connections. But during the +competition itself, the program and its computer have to be present at the +place the competition is held. We all would love to see a @command{gawk} +program win in such an event. Maybe it is up to you to accomplish this? + +Some other ideas for useful networked applications: +@itemize @bullet +@item +Read the file @file{doc/awkforai.txt} in the @command{gawk} distribution. +It was written by Ronald P.@: Loui (Associate Professor of +Computer Science, at Washington University in St. Louis, +@email{loui@@ai.wustl.edu}) and summarizes why +he teaches @command{gawk} to students of Artificial Intelligence. Here are +some passages from the text: + +@cindex AI +@cindex PROLOG +@cindex Loui, Ronald P. +@cindex agent +@quotation +The GAWK manual can +be consumed in a single lab session and the language can be mastered by +the next morning by the average student. GAWK's automatic +initialization, implicit coercion, I/O support and lack of pointers +forgive many of the mistakes that young programmers are likely to make. +Those who have seen C but not mastered it are happy to see that GAWK +retains some of the same sensibilities while adding what must be +regarded as spoonsful of syntactic sugar.@* +@dots{}@* +@cindex robot +There are further simple answers. Probably the best is the fact that +increasingly, undergraduate AI programming is involving the Web. Oren +Etzioni (University of Washington, Seattle) has for a while been arguing +that the ``softbot'' is replacing the mechanical engineers' robot as the +most glamorous AI testbed. If the artifact whose behavior needs to be +controlled in an intelligent way is the software agent, then a language +that is well-suited to controlling the software environment is the +appropriate language. That would imply a scripting language. If the +robot is KAREL, then the right language is ``turn left; turn right.'' If +the robot is Netscape, then the right language is something that can +generate @samp{netscape -remote 'openURL(http://cs.wustl.edu/~loui)'} with +elan.@* +@dots{}@* +AI programming requires high-level thinking. There have always been a few +gifted programmers who can write high-level programs in assembly language. +Most however need the ambient abstraction to have a higher floor.@* +@dots{}@* +Second, inference is merely the expansion of notation. No matter whether +the logic that underlies an AI program is fuzzy, probabilistic, deontic, +defeasible, or deductive, the logic merely defines how strings can be +transformed into other strings. A language that provides the best +support for string processing in the end provides the best support for +logic, for the exploration of various logics, and for most forms of +symbolic processing that AI might choose to call ``reasoning'' instead of +``logic.'' The implication is that PROLOG, which saves the AI programmer +from having to write a unifier, saves perhaps two dozen lines of GAWK +code at the expense of strongly biasing the logic and representational +expressiveness of any approach. +@end quotation + +Now that @command{gawk} itself can connect to the Internet, it should be obvious +that it is suitable for writing intelligent web agents. + +@item +@command{awk} is strong at pattern recognition and string processing. +So, it is well suited to the classic problem of language translation. +A first try could be a program that knows the 100 most frequent English +words and their counterparts in German or French. The service could be +implemented by regularly reading email with the program above, replacing +each word by its translation and sending the translation back via SMTP. +Users would send English email to their translation service and get +back a translated email message in return. As soon as this works, +more effort can be spent on a real translation program. + +@item +Another dialogue-oriented application (on the verge +of ridicule) is the email ``support service.'' Troubled customers write an +email to an automatic @command{gawk} service that reads the email. It looks +for keywords in the mail and assembles a reply email accordingly. By carefully +investigating the email header, and repeating these keywords through the +reply email, it is rather simple to give the customer a feeling that +someone cares. Ideally, such a service would search a database of previous +cases for solutions. If none exists, the database could, for example, consist +of all the newsgroups, mailing lists and FAQs on the Internet. +@end itemize + +@node Some Applications and Techniques, Links, Using Networking, Top +@comment node-name, next, previous, up + +@chapter Some Applications and Techniques +In this @value{CHAPTER}, we look at a number of self-contained +scripts, with an emphasis on concise networking. Along the way, we +work towards creating building blocks that encapsulate often needed +functions of the networking world, show new techniques that +broaden the scope of problems that can be solved with @command{gawk}, and +explore leading edge technology that may shape the future of networking. + +We often refer to the site-independent core of the server that +we built in +@ref{Simple Server, ,A Simple Web Server}. +When building new and non-trivial servers, we +always copy this building block and append new instances of the two +functions @code{SetUpServer} and @code{HandleGET}. + +This makes a lot of sense, since +this scheme of event-driven +execution provides @command{gawk} with an interface to the most widely +accepted standard for GUIs: the web browser. Now, @command{gawk} can even rival +Tcl/Tk. + +@cindex Tcl/Tk +@cindex JavaScript +Tcl and @command{gawk} have much in common. Both are simple scripting languages +that allow us to quickly solve problems with short programs. But Tcl has Tk +on top of it and @command{gawk} had nothing comparable up to now. While Tcl +needs a large and ever changing library (Tk, which was bound to the X Window +System until recently), @command{gawk} needs just the networking interface +and some kind of browser on the client's side. Besides better portability, +the most important advantage of this approach (embracing well-established +standards such HTTP and HTML) is that @emph{we do not need to change the +language}. We let others do the work of fighting over protocols and standards. +We can use HTML, JavaScript, VRML, or whatever else comes along to do our work. + +@menu +* PANIC:: An Emergency Web Server. +* GETURL:: Retrieving Web Pages. +* REMCONF:: Remote Configuration Of Embedded Systems. +* URLCHK:: Look For Changed Web Pages. +* WEBGRAB:: Extract Links From A Page. +* STATIST:: Graphing A Statistical Distribution. +* MAZE:: Walking Through A Maze In Virtual Reality. +* MOBAGWHO:: A Simple Mobile Agent. +* STOXPRED:: Stock Market Prediction As A Service. +* PROTBASE:: Searching Through A Protein Database. +@end menu + +@node PANIC, GETURL, Some Applications and Techniques, Some Applications and Techniques +@section PANIC: an Emergency Web Server +@cindex PANIC program +At first glance, the @code{"Hello, world"} example in +@ref{Primitive Service, ,A Primitive Web Service}, +seems useless. By adding just a few lines, we can turn it into something useful. + +The PANIC program tells everyone who connects that the local +site is not working. When a web server breaks down, it makes a difference +if customers get a strange ``network unreachable'' message, or a short message +telling them that the server has a problem. In such an emergency, +the hard disk and everything on it (including the regular web service) may +be unavailable. Rebooting the web server off a diskette makes sense in this +setting. + +To use the PANIC program as an emergency web server, all you need are the +@command{gawk} executable and the program below on a diskette. By default, +it connects to port 8080. A different value may be supplied on the +command line: + +@example +@c file eg/network/panic.awk +BEGIN @{ + RS = ORS = "\r\n" + if (MyPort == 0) MyPort = 8080 + HttpService = "/inet/tcp/" MyPort "/0/0" + Hello = "" i " | " \ + "" config[i] " |