Articles Archive
Articles Search
Director Wiki
 

Survey says...PostNetText it!

July 17, 2000
by Alan Levine

For the next six months you should find plenty of randomness in this space, as I have the great opportunity to take a 6-month sabbatical from my gig at Maricopa. I will focus some concentrated time on development projects (my Lingo rust is showing) plus get a chance to meet colleagues on the opposite side of the globe as I visit Kiwis and Aussies (travel to New Zealand and Australia). You can check my progress at http://dommy.com/az2nzau/

If anyone is worried about Director Web, just relax, as we have set it on auto pilot, and it will continue to self-update as always. (Maybe I am not really so essential.)

For July and August of my sabbatical, my travel is just two hours north up the highway to Flagstaff, Arizona, where I will work on some Director projects with Mike Kelly and his CREATE project (Center for Research and Evaluation of Advanced Technologies in Education) at Northern Arizona University. This portion was cleverly planned to avoid the summer heat of Phoenix. Next month I will share a bit more about the highly interactive educational applications they "create" here and what I come up with in dabbling with the Shockwave Multiuser Server.

This column will review my approach to using Director's ability to send data from a Shockwave application or a Projector to a web server CGI via PostNetText.

But first a small diversion related to last month's menu randomness.

Menus part deux

My last column dealt with customizing the droplist behavior to create menus that looked like other menus on Macs or Windows. It took 4 sprites to make it happen (plus a behavior, plus an ancestor script). In that column, I wished that Director had the ability to package all of that into a single package I could insert as a single sprite, like having encapsulated mini-movies.

Recently, James Newton (author of the original behavior I hacked away at) e-mailed and let me know that this certainly was possible via a Linked Director Movie, or as the gurus refer to them, an LDM. James's example had all of the sprites and code for the menus in a Director movie that could then be linked into our main or host movie, thus shielding the developer from the intricacies of 4 sprites and code.

There is some significant Lingo going back and forth, but it is a brilliant solution. For more, see James's example files at:

http://perso.planetb.fr/newton/realmenu/

Thanks to James for sharing this code (and not spitting on me for mucking up your original behavior).

Post it? Get it?

There are two protocols for how data is sent from something like a web page form (or, in what we will do, a desktop projector or a Shockwave doo-dad) to a web server program (CGI) that does something with the information. The data is always sent in a paired format of variable name and variable value.

When the data is transmitted using the GET method, the variable names are simply appended to the URL for the server script. So if the data we are sending is something like (variable / value):

   name / alan
   eyes / brown
   iq   / 212

and it goes to a script at http://www.blah.com/cgi-bin/record_user.pl, the data string that is sent looks like:

http://www.blah.com/cgi-bin/record_user.pl?name=alan&eyes=brown&iq=212

You would see this exact URL in the address field of your web browser after it was sent from a web form where this information was entered.

The POST method still sends information as variable/value pairs, but they are encoded with extra information that describes the length of each variable/value pair. When sent from a web form, you do not see the encoded data appended to the URL, so if you sent the same data from a web form with the information above, after clicking submit you would just see in the address field:

http://www.blah.com/cgi-bin/record_user.pl

Why then would anyone ever use the GET method? Someone with more HTTP protocol knowledge than I can tell you, but I would bet it might be faster and/or more efficient to process. However, the GET method limits how much data can be sent, so typically the POST method is used where large amounts of data or text (sentences to paragraphs) are to be transmitted.

What does this have to do with Director?

When Shockwave first came out (Director 4-6 era), we were granted the ability to send data from Shockwave to a web server CGI, but only with the GET method. This meant that there was a length limit to how much text (the variable name/value pairs) could be strapped on the back of a URL (1-4k depending on the browser flavor). So if you needed to send large chunks of text, you were forced to send it in multiple calls and re-assemble on the server side. Not only that, but you had to convert normal looking text to hexadecimal equivalents (spaces, question marks, etc., translated to special codes). It was not pretty.

Fortunately, Director 7 brought the ability to send large data chunks via the POST method with the PostNetText command. In addition, you could assemble the data as a Lingo property list, and Director would convert it to the arcane string the CGI expects. So, in Lingo, we could send information like:

-- assemble cgi param names and values as prop list
cgiData = [#name:"Alan Levine", #eyes:"brown", #iq:212, #comments:"If my iq were that high, I would write better articles"]

-- web address for server
cgiURL = "http://www.blah.com/cgi-bin/record_user.pl"

-- send it!
postNetText (cgiURL, cgiData)

Not only does Director 7+ provide the POST method, it allows you to send all of the data as a familiar-looking property list, and Director does the necessary grunt work to turn it into something the CGI script can understand.

The context

The first time I devised this strategy was for a CD project that was pretty much wrapped up. We decided to tack on a user survey when a user exited the program. Yes, it was a fine case of a feature that crept in, but it would be valuable as we sent it out for testing and eventual use.

Fortunately, the program already funneled all exits to a specific movie credits.dir (the one that makes lawyers happy by displaying the Macromedia copyright badge). So it was a snap to rename this movie finalcredits.dir and write a new one named credits.dir that would be our survey, and would then exit through the finalcredits.dir movie. This way, all exits pass through the survey.

The survey needed to have some flexibility so it would not be received like a dinner time phone solicitor. Basically, the survey started with three options:

  1. No Thanks!
    User exits without doing the survey ("roll the final credits and say goodbye")
  2. Okay, but I do not want to go online.
    User completes the survey, but saves data as text file that could be printed or e-mailed later (export data with FileIO and roll the credits)
  3. Okay, do it online.
    User completes the survey and data is sent to web server CGIdirectly from Lingo(and yes, roll the credits)

As a footnote, when I built the survey, I used the Radio buttons behavior "as is" from the Director 7 Library. If you read my last column, I lobbied for pages abut the virtues of modifying these behaviors and putting them on a Jenny Craig weight-loss program. But in this case, the pre-built behavior did exactly what I needed (multiple sets of 5 buttons on a screen).

PostNetText in action

I created a mini-demo that can demonstrate a strategy for doing this kind of net operation. You can try it first as Shockwave from my site:

http://dommy.com/random/postnettext.html

and then download the Director 8 source files in PC and Mac formats. This page also contains a web form that allows you to view results that were submitted and stored on the server:

see the results!
survey sez'
view last log entries

In the original CD application, the survey was optional, so before it even started, there was an option to bypass the survey completely.

The first stage is to construct a series of questions that allows your users to submit their responses. For the demo, I have data that comes from:

  1. radio buttons (using off-the-shelf D8 Library behavior)
  2. drop-down menus (using the example I wrote about in my last column)
  3. editable fields (hopefully that it not much of a mystery!)
  4. Lingo-calculated variables (in this case date/time and theuser's computer platform)

All you are doing is providing a series of screens with this input, and then saving the responses to a property list after leaving the screen. In my first version I just stashed the information in a global variable, but in this demo I am using a behavior stashed in a sprite (channel 2 in the demo) that spans the entire question sequence.

-- script "data bin"
-- This sits in a sprite that spans the entire question
-- sequence. Returning to the first frame of it resets
-- the prop list that captures the responses

property pData, pPlatform

on beginSprite me
  if the platform contains "Windows" then
    pPlatform = "Windows"
  else
    pPlatform = "Macintosh"
  end if

  -- initialize survey data with 2 generated values
  -- a date time stamp, and the computer platform
  pData = [#taken: the long date && the time, #plat: pPlatform]
end

on putData me, dname, dvalue
  -- dname is property name (string)
  -- dvalue is associated value (string or number)

  -- called by other handlers to add/update data to our list
  pData[symbol(dname)] = dvalue
end

on getData me
  -- called by other handlers to return the property list
  return pData
end

By the end of the survey, you have a property list of name/value pairs to be sent to the CGI. The property names are exact matches for the variables expected by the CGI. Be sure that the case of the variable names matches, as UNIX servers will ignore values for a Lingo property named #myBigValue if the CGI variable is named $mybigvalue.

When you are ready to send, you provide the user the option to send the info via the web, or to skip it. On a Projector version, you could also offer the opportunity for the user to save the data as a text file that could later be e-mailed or printed and sent, even through snail mail (done via FileIO, left as an exercise for the reader). This option allows the user to avoid going online.

The processing through the web runs as follows:

(1) Initiate a net process through PostNetText, storing the network ID for later reference. The call is pretty simple: you pass it a variable that contains the URL for the CGI and the property list of data.

global gNetID
myFormData = sendAllSprites(#getData)

-- Assign a global to the net call so you can track the progress elsewhere
gNetId = postNetText( myCGI, myFormData)

-- start a Lingo timer so you can track how long since the net call was initiated
startTimer

-- go to a looping frame so you can check progress
go to frame "saveToNet"

(2) In the looping frame, you are checking the network processes. First, you test netDone(gNetID) to see if the process is complete. If it is done, you next see if netError reports a problem code. If it does, you jump to a problem report screen and provide a link to the options screen (where the user can resubmit or cancel).

If there are no network errors, you check netTextResult(gNetID), the string that was returned from the CGI script. I write mine to return "ok" if things went fine on the server side (tricky, eh?). If this all happened successfully, you can proceed to a confirmation screen.

If the network process is not complete (netDone(gNetID) = false), you first check to see if the timer has passed a certain delay time. If it has, consider it as timed out and pop an alert letting the user know she can either continue to wait or bail.

The looping frame also contains a "cancel" button so the user can stop the process at any time. The script cleans out the network processes:

global gNetId
netAbort(gNetId)
gNetId = void

and jumps back to the options frame.

That is pretty much what you need on the Lingo side.

On the server end, you need a script to take this data and do something with it. In this case, my simple perl script (included in the source download) simply takes the values of the variables it receives and writes them in tab-delimited format to a log file.

The important thing is to make sure the CGI script is set to return any response (an "ok" status) as plain text, not as HTML as most scripts do.

And that's about it -- the POST method makes it easy to shuttle a pile of content to a web server (provided you have something on the web server side to process it). The CGI in this example was pretty simple; you could call it a WebFileIO, as it just did an mWrite in Append mode (for all those fileIO geeks out there).

Look here in a few weeks as I share what I am able to wrangle out of the Shockwave Multiuser Server.

Alan Levine is an Instructional Technologist at the Maricopa Center for Learning & Instruction at the Maricopa Community Colleges. Among other random things, he tries to maintain the DirectorWeb, does side work as dommy media, and not often enough, mountainbikes in the desert.

Copyright 1997-2017, Director Online. Article content copyright by respective authors.