Welcome to "The WebWasher Tutorial!"
Welcome! The WebWasher is a LambdaCore MOO object that makes web pages FOR other MOO objects. It is an HTML "proxy". It began being developed in 1997 by Larry "Wingnut" Wendlandt and Jon "Stucky" Maul... and is still being tweaked as of Feb 2001. It has a parent called "Generic Query" that retrieves a piece of DATA from an object, or its parent. Once retrieved, the WebWasher wraps the data in HTML elements (tags). Which data is queried... is dependent upon a LIST of data names that are stored in a property called .hassembly. For any data named in .hassembly, a verb (program) with a corresponding name, is attempted to be executed on the object being queried or on the WebWasher itself. For example, if the word "name" appears in the .hassembly list, a verb called :hname is searched-for, and executed if possible. First, the Generic Query object (parent of the WebWasher) tries to find a verb called ":hname" on the browsed object (i.e. target object). If :hname is found on the object or its parent, the verb is executed and must return a string, number, or list. The Generic Query returns the data to the WebWasher, where some processing is done to add HTML tags on each side of the data. (The data is "wrapped" in HTML.)
In the case where the :hname verb was NOT found on the target object or its parent, the WebWasher runs its own verb called :hname. The WebWasher's :hname verb KNOWS that :hname could not be found on the object, so it tells the Generic Query to go look for a verb called :name on the object or its parent. Since :name is a common verb on LamdaCore MOO objects, data can be found... or an error condition is announced. Once the WebWasher's :hname has good name data from the target object (via Generic Query), it can wrap HTML around the name data.
Generally speaking, the Generic Query refuses to quit looking for a piece of data until it has exhausted all possibilities. Using our name data as an example... first, the WebWasher/Generic Query (heretofore "WW/GQ") goes looking for a VERB on the target object named :hname. If that fails, it goes looking for a PROPERTY on the target object called .hname. If that fails, WW/GQ goes looking for a VERB named :hname on the PARENT of the target object. If that fails, WW/GQ goes looking for a PROPERTY called .hname on the parent of the target object. And if THAT fails, WW/GQ runs a verb called :hname that is located on itself. Quite an extensive query, one must admit. All of this is triggered by the existence of the word "name" in the objects' or WebWasher's' .hassembly property.
This illustrates some of the versatility of the WebWasher system. If the object you are "webbing-up" has a verb or property named "hname", or its parent has a verb or property named "hname"... and if any one of them returns a string, number, or list... then you can "intervene" in the HTML markup of that "section" of your object. (In this case, the object's name as seen on the web)... (its "hname"). Here's a quick example. Let's say that some target object (#1234) had a name that was "The Golden Fish". If you had programmer's permissions on your MOO, you could type...
;#1234:name()
...hit enter, and the MOO would respond with...
"The Golden Fish"
The :name verb on your object... probably just goes and reads a PROPERTY on your object called .name. You could test this by typing...
;#1234.name
...hit enter, and the MOO would respond with...
"The Golden Fish"
The code in the :name verb would probably be...
return this.name;
Verbs like this are called "wrapper verbs". They "wrap" an object's property (.name) with a verb (:name). This has little to do with the "wrapping" of HTML around data that is done in the WW/GQ :hname verb. I am simply stating that simple verbs like :name, that just return the contents of a property like .name... are common and often called "wrapper verbs". Wrapper verbs are reasonably unimportant to our discussions except for one point. The WW/GQ looks for VERBS first, then properties. If your object contains a verb named :hname AND a property named .hname, the verb will be queried first... and ONLY IF that verb does not return a string, number, or list... will the WW/GQ go looking for the property named .hname. Wrapper verbs are searched-for... before property contents.
1st: Look for verb on the object.
2nd: Look for property on the object.
3rd: Look for verb on the PARENT of the object.
4th: Look for property on the PARENT of the object.
5th: Look for verb on the WebWasher itself.
Back to our example, your object has "The Golden Fish" in its .name property. If you were to LOOK at your object from within the MOO, its name would show-up as "The Golden Fish". The WebWasher, by default, honors your wish to have "The Golden Fish" as the name of your object, and when you browse your object from the web, it will be called "The Golden Fish". But what if... you wanted to call your object "The Webby Fish" when it was viewed from the web??? Well, its easy. Add a property to your object called .hname and fill it with "The Webby Fish". For programmers... it'd be...
@prop #1234.hname "The Webby Fish" (hit enter)
If you wanted to change it later, you could do...
;#1234.hname = "The Webby Frog" (hit enter)
When it was time for the WW/GQ to markup the NAME section of your object's webpage, it would find the .hname property you set, and it would use that instead of using the object's real name. The same could be done by adding the :hname VERB to the object...
@verb #1234:hname rx (hit enter)
@prog #1234:hname (hit enter)
enter (hit enter) (type the word 'enter' then hit enter)
return "The Golden Frog"; (hit enter)
. (hit enter) (type a period, then hit enter)
That should do it. When the WW/GQ sees that you've made a verb called :hname on your object, and that it nicely returns a string of text... then the WW/GQ will use THAT data and not continue searching for name data. The WW/GQ will be satisfied with your well-built "intervention". To illustrate further...
1st: Look for verb on the object. (PERFORMED & SATISFIED!!!)
2nd: Look for property on the object. (NOT PERFORMED)
3rd: Look for verb on the PARENT of the object. (NOT PERFORMED)
4th: Look for property on the PARENT of the object. (NOT PERFORMED)
5th: Look for verb on the WebWasher itself. (NOT PERFORMED)
Since 1st search step was satisfied, the WW/GQ will NOT search further, and steps 2 through 5 will not be taken.
So, we've now highlighted 4 methods of intervening with the HTML markup of the NAME section of your object's webpage. Verb on the object, property on the object, verb on the object's parent, and property on the object's parent. Powerful, but the fun is just beginning.
DABBLES:
"Dabble" is a term I use to describe two other points of intervention. For every entry in an object's .hassembly list... ('name' is one such entry)... there is something called a NOSE DABBLE and a TAIL DABBLE. Our NAME data (.hname) has a nose dabble called .hname_prefix and a tail dabble called .hname_suffix. The WebWasher, by default, has these two properties on itself, and your object, by default, probably doesn't. And although "name_prefix" and "name_suffix" does NOT show up in your object's, or the WebWasher's .hassembly list... the WebWasher still goes looking for them. (I call it a feature.) When the WebWasher puts HTML tags around (wraps) your object's name or hname, it wants to give you a chance to have some say about WHAT tags will be wrapped around your object's name. If you were to go look at the WebWasher's .hname_prefix...
;(webwasher#).hname_prefix (hit enter)
...the MOO would likely return...
"<font size=6 color=red>"
These are the HTML commands that tell the browser to display the NAME (or hname) of your object... in big red letters. And following the proper rules of HTML usage in "turning-off" things when you're done using them...
;(webwasher#).hname_suffix (hit enter)
...the MOO would likely return...
"</font>"
Via the default WebWasher dabble properties, the WebWasher is telling itself what to wrap the name data with. And guess what. You can add nose dabbles (prefix) and tail dabbles (suffix) to your object by adding verbs or properties to your object. Just like before, the WW/GQ goes looking for a verb called :hname_prefix first, then it looks for a property called .hname_prefix, then it checks the object's parent for a verb called :hname_prefix, then it checks for a property on the parent called .hname_prefix, and lastly it looks for a property on itself called .hname_prefix, which it will always find if all else fails. The WW/GQ does the exact same procedure when its time to look for "hname_suffix" as well. Now we are up to 6 methods of intervention, and we are still dealing with your object's web-based NAME section. Wild, huh?
ANY HTML can be put into the _prefix and _suffix dabbles for a given data section. Let's say you wanted a little flag graphic just to the left of the name of your object. (On the object's webpage.) With your programmer's permissions...
@prop #1234.hname_prefix "" (hit enter)
(that MAKES the property called .hname_prefix on your object and sets it to empty)
;#1234.hname_prefix = "<IMG src=http://www.images.com/flag.gif><font size=6 color=red>" (hit enter)
Since an IMG tags does not require a closing tag... you do not need to add the .hname_suffix property to your object. But you might have noticed that I needed to add the BIG RED FONT command AFTER the IMG tag. Remember that once you add a .hname_prefix to your object, the .hname_prefix on the WebWasher is no longer used. So, if I hadn't put it in there, the fonts for your object's name would not be big and red. Since the WebWasher's .hname_suffix contains
"</font>"... it still "closes" the big red font command we put in your object's .hname_prefix. Again, the IMG tag does not need to be closed within .hname_suffix. This is a rare exception. Generally, if you add a NOSE DABBLE like .hname_prefix to your object, you should also add a TAIL DABBLE like .hname_suffix to the object as well, so you can "undo" everything you did within your intervened .hname_prefix.
Its getting complicated, isn't it? That's all right. The worst part is over now. You're getting close to becoming an expert in the WebWasher system. Take a break, eat a sandwich, and let this soak-in. The word "name" is found in the WebWasher's .hassembly list... which is used for your object as well. (unless you make a copy of the WebWasher's .hassembly on your object.) The WebWasher grabs the word "name" from there, adds a "h" to the front of it (makes it "hname" meaning hypertext name), and then goes searching. It searches your object for :hname, and then for .hname. Then it searches your object's parent for :hname, and then for .hname. Lastly, it runs its own :hname verb which harvests your object's .name property. Once its got that, it goes and does the same search for hname_prefix, and uses THAT if found... to place on the "nose" of the name (just before it). Then it goes searching for hname_suffix, and uses THAT if found... to place on the "tail" of the name (just after it). Easy, huh? ANY HTML can be put in a dabble. Often, a font setting is put into a nose dabble, and a /font, a period, and "<br><br>" is put into a tail dabble. This is often NOT the case with dabbles used on each side of a picture. (hpicture_prefix & hpicture_suffix) There would be little reason to adjust the font setting on a picture. :)
You may have noticed that for the hname query, the order of events was...
1st: Look for verb on the object.
2nd: Look for property on the object.
3rd: Look for verb on the PARENT of the object.
4th: Look for property on the PARENT of the object.
5th: Look for verb on the WebWasher itself.
...and for the dabbles hname_prefix and hname_suffix, the order of events is...
1st: Look for verb on the object.
2nd: Look for property on the object.
3rd: Look for verb on the PARENT of the object.
4th: Look for property on the PARENT of the object.
5th: Look for verb on the WebWasher itself.
6th: Look for property on the WebWasher itself.
In all truth, the WebWasher ALWAYS can do up to 6 events in order to search for a given property. In the case of hname, I personally know a verb exists on the WebWasher called :hname, so I know a data search for hname will not get past event 5. But there is NOT a verb on the WebWasher called :hname_prefix (or :hname_suffix). There IS a property called .hname_prefix (and .hname_suffix) on the WebWasher, and thus, I know the search will be satisfied at the 6th event.
There are really only 4 "sections" needed to make a webpage for a MOO object. They are the same 4 used when you LOOK at an object in the MOO. "The Big 4" are name, description, contents, and exits. The exits section is only active on rooms, so its really "The Big 3". Contents is only active on container objects, so its really "The Big 2". But for a webpage of an object, one feels highly compelled to have a picture of the object, so we have to go back to "The Big 3" for web markup. The truth is, there are lots of "sections" that we could add for the web "LOOK" and the WebWasher has options for quite a few. A webby object could have a background song (midi) and a sound effect (wave). It could have the object's location displayed on the webpage, and we could include even things as weird as a RealAudio stream, a VRML picture, or we could display the time-of-day according to the server. We could do ALL of it, or any combination we want to. This is where the magic of the .hassembly list of "sections" that need to be marked-up. (Each "section" is ONE piece of data wrapped in HTML with the assistance of its nose and tail dabbles.)
Below, shows the contents of the .hassembly found on RiverMOO's WebWasher...
{"head", "name", "location", "picture", "description", "contents", "exits", "webhits", "foot"}
For now, or forever, you can ignore "head" and "foot". The only concern is that you leave "head" as the first member of .hassembly, and leave "foot" as the last member. What's inbetween is your business. Yep, that's right. You can change or re-arrange the "sections" of .hassembly... by putting a .hassembly property on your object... and then messing around with its contents. I did that on my object #3631 at RiverMOO. (http://rivermoo.com:8889/3631). First, i made a property on #3631 called .hassembly...
@prop #3631.hassembly (enter)
Then, I made it look like the one on the WebWasher...
;#3631.hassembly = #4901.hassembly (enter)
The WebWasher's number can often be found by typing... @audit Wingy (enter)
I make sure that the property copy happened correctly by typing...
;#3631.hassembly (enter)
and comparing that to...
;#4901.hassembly (enter)
So now, #3631.hassembly looks like...
{"head", "name", "location", "picture", "description", "contents", "exits", "webhits", "foot"}
Then you can do something fun like...
;#3631.hassembly = {"head", "midi", "sample", "name", "location", "picture", "description", "contents", "exits", "webhits", "foot"} (enter)
Notice that we inserted the sections named "midi" and "sample" in front of "name". Everything is still ok with this, because I have verbs on the WebWasher called :hmidi and :hsample. I also have properties called .hmidi_prefix, .hmidi_suffix, .hsample_prefix, and .hsample_suffix... so the dabbles are taken care of. But let's say you really wanted to get wild, and add a section of your own. Maybe you want to display the OWNER of the object on the object's webpage. Here's what you need to do.
First, you might want to put the word "owner" somewhere in the .hassembly sequence. Where you put it amongst the other sections determines where on your webpage the data will be displayed. Once "owner" shows up in your object's .hassembly, the WebWasher will go out looking for "howner" data. (Remember it adds the "h" to the name?)
Next, you'll need a verb or property on your object... that is named :howner or .howner respectively. In this case, a verb might do the trick the best. The owner of a LambdaCore MOO object... is held in a property called .owner as an object number. So, the verb code for your #1234:howner verb might look like this...
@verb #1234:howner
@prog #1234:howner
stuff = "The owner of this object is " + $string_utils:nn(this.owner) + ".<br>";
return stuff;
Compile that puppy, and you're on your way! You don't need to put .howner_prefix and .howner_suffix dabbles on your object. You can send all the text and HTML "stuff" to the WebWasher via the "stuff" variable that's getting returned. To explain a bit about the verb code above... we are making one big string of text... some of it is plain old text, and some of it is HTML text. $string_utils:nn() is a LambdaCore MOO helper verb that takes an object number and converts it to an object NAME & NUMBER. (Remember that .owner contains only an object number, so we'd rather have a NAME as the object's owner. Your name.) The last section includes a period for ending the sentence, and a <br> which stands for BReak. Its much the same as a "carriage return" or "enter". Sometimes you'll want ONE <br> at the end of your data, and sometimes you'll want two or more. Experiment to see what looks good.
Your :howner verb, or any WebWasher-ready "section" has only two rules in order to make it work. Its name, minus the preceding "h" must be found in your object's .hassembly list. (i.e. "owner" must be in .hassembly somewhere)... and your verb MUST return a string, number, or list. For best results, make it return a string. (Numbers have been tested and work ok... but list-type returns have not been tested.) The rest of the design of your custom "h"-verb is up to you. It could return nothing or it could return an entire webpage in a string. The WebWasher cares not, and will try to include any string you return... right in the same place within the webpage as it is listed within .hassembly.
Speaking of .hassembly, did you know that once you put one on your object, than you can have fun just re-arranging the order of the words in there? Each change will affect the "look" of your object's web markup. Remember to keep "head" at the beginning of .hassembly, and "foot" at the end. You can remove the picture from the object's webpage by simply removing the word "picture" from the .hassembly list. I think you can also do this by adding an .hpicture property to your object and setting it to an empty string. ("") Older versions of the WebWasher might require .hpicture to be set to " " (quotes with a space in the middle) in order to turn off the picture. The same sort of stuff goes for "midi" and "sample". In the case of RiverMOO, midi and sample are not included in the WebWasher's .hassembly by default. Even if it were, you could turn it off on YOUR object by either adding a .hassembly property to your object and then removing the word "midi" from it, or by adding a property called .hmidi and setting it to an empty string. You could even add a verb called :hmidi and have it return ""... and that would turn off the midi music on your object's webpage.
Let's say you login to a MOO somewhere, and you make a "thing". Then you go view the thing from the web, and it starts playing midi background music. Let's say that this MOO was smart and used the WebWasher system as its webbing proxy. Now, there's a few assumptions that you can probably make. Somewhere... (either on your object, on your object's parent, or on the WebWasher itself) is a property called .hassembly that has the word "midi" in it. You can also assume that somewhere (either on your object, on your object's parent, or on the WebWasher itself) is a property called .hmidi which has the address to a midi song in it. Most likely, in both cases, they reside on the WebWasher. Now, let's say you don't like the song, and want to pick your own song for your object. First off, you need to add a property called .hmidi to your object.
@prop #1234.hmidi (enter)
Then you need to go find the address of a cool midi song... and put that address into the newly-made .hmidi property...
;#1234.hmidi = "http://www.coolsongs.com/rockin.mid" (enter)
And that's it. When you web-browse your object, it should now be playing the song in YOUR .hmidi property, and no longer the song found in the WebWasher's .hmidi property. The WebWasher will be able to see that you have set a .hmidi property... and will use IT instead of its own. Cool, huh?
The same exact procedure happens with .hpicture. The WebWasher often puts up a picture FOR you. It is usually just the name of the MOO or something otherwise generic. You, simply need to add a property called .hpicture, and set it so that it contains the address to a picture. Careful. Some WebWashed moos have added a .hpicture property to their object #1, so you may not need to, or be able to... ADD a property named .hpicture to your object... because it already exists via being inherited from a parent or grandparent. In this case, you only need to SET the contents of your .hpicture property so that it contains the address to a picture you like.
Ok, if you've held-on THIS long, and still understand, than I will call you an expert on the WebWasher system. From here on out, we're just going to show some pictures with examples, and review and reiterate what's already been said. Congratulations! You've made it through the worst part of the tutorial! Well done!
Here is the "look" or "layout" of an average WebWashed MOO object. I will use this demo "washed" object throughout the rest of the tutorial. Study it carefully. I think you can see its "sections". Ignoring "head" and "foot", one "section" corresponds directly to one of the words found in this object's, or the WebWasher's .hassembly list. The .hassembly for this webpage... looks like this...
{"head", "midi", "sample", "name", "location", "picture", "description", "contents", "exits", "webhits", "foot"}
The two dual-buttons in the upper left corner are for the midi and sample sections. These buttons are provided by Netscape's Media plugin. If you viewed this webpage with Internet Explorer, the buttons would look somewhat different. Each button "panel" (there are two panels on this webpage) is called a "console". The left 2-button console is for midi, (thus it is also called MIDCON) and it is used to play the midi song that is found in your object's .hmidi property. It could also be used to play the song that your :hmidi VERB returned the address for. Want a randomly different song to play each time someone browses this webpage? Then put a list of song URLs in your :hmidi verb, and write a bit of code that returns a different URL each time the verb is RUNned. Easy huh? Here's a worthless diagram that pertains to midcon and the hmidi section.
Oh, you already forgot about DABBLES, huh? Yep, the hmidi section (midcon) has a dabble on each side of it. Putting a...
"<img src=http://www.images.com/tiny_musical_note_icon.gif>"
into your newly-added property called .hmidi_prefix... might be pretty. But what isn't pretty is all the adjustments Netscape allowed for its midi playing console. And guess what... Wingy and Stucky had to honor those adjustments and put all those properties onto the WebWasher. Here is a list of the properties for Netscape's media player, all of which you can add to your object and play around with...
HMIDI ADJUSTABLES |
||
|---|---|---|
| Property Name | Allowed Return Values | Default Return Value |
.hmidi |
Full URL of a midi song (.mid) |
Varies MOO to MOO |
.hmidi_prefix |
anything |
empty |
.hmidi_suffix |
anything |
empty |
.auto-start |
"true" or "false" |
"true" |
.midi_volume |
0 - 100 |
100 |
.midi_play_type |
"loop" or "play" |
"play" |
.midi_controls |
"console" or "smallconsole" |
"smallconsole" |
.midcon_height |
0 - ??? |
14 |
.midcon_width |
0 - ??? |
49 |
.midcon_align |
??? |
"bottom" |
NOTE: Just because I put periods in front of those DATA names doesn't mean they need to be PROPERTIES that you make and set on your object. They also could be VERB names, as in :hmidi, :hmidi_prefix, :midcon_height, etc. Remember that the WebWasher looks for properly-named verbs on your object JUST BEFORE it checks for properly-named properties.
Yessiree Bob, here's hsample, worse-known as the sample console or SAMCON. Its the second dual-button console in the upper left corner of the page. It resides, by default, just to the right of MIDCON. It follows all the same rules as MIDCON, and has all the same general properties. To have a unique sample (wave file) on your object, you need to make and set a property called .hsample. (And, of course, you could make a verb called :hsample instead. That's real handy for having a random sound effect happen when folks view your object's webpage.
There's one small weirdness I noticed as I was writing this section. There is only one "auto-start" property on the WebWasher, and thusly, only one can be put on your object. That means both MIDI and SAMPLE trigger from this auto-start setting. Look for this to change sometime soon. There is likely to be midi_autostart and sample_autostart properties added, so that the autostarting can be controlled separately for both kinds of audio.
You're starting to get the hang of this stuff, aren't you? Are you about ready to make your own "section"? Maybe put an .hassembly list on your own object, and put "flash" in there? Then write a verb called :hflash that retrieves the .hflash data and then produces the correct HTML to embed a Macromedia Flash presentation somewhere on your webpage? Maybe your "hverb" will go look for the presence of .hflash_prefix and .hflash_suffix? MAYBE???? :) Take a look at some of the verbs on the WebWasher... they should help in your design.
HSAMPLE ADJUSTABLES |
||
|---|---|---|
| Property Name | Allowed Return Values | Default Return Value |
.hsample |
Full URL of a sample file (.wav) |
Varies MOO to MOO |
.hsample_prefix |
anything |
empty |
.hsample_suffix |
anything |
empty |
.auto-start |
"true" or "false" |
"true" |
.sample_volume |
0 - 100 |
100 |
.sample_play_type |
"loop" or "play" |
"play" |
.sample_controls |
"console" or "smallconsole" |
"smallconsole" |
.samcon_height |
0 - ??? |
14 |
.samcon_width |
0 - ??? |
49 |
.samcon_align |
??? |
"bottom" |
Here's a real simple section... or is it? What's in a name? Well, somewhere along the LambdaCore history, someone decided MOO objects could have a TITLE instead of a NAME. That's one problem. Another is that many moos do not have a wrapper verb for the classic .name property. Some MOOS DO use a :name wrapper verb, but plaster it full of ANSI colors. Colors are a problem within hdescription, hcontents, and hexits too. ANSI colors need to be converted to HTML FONT or STYLE commands in order to make the proper transition to web. Its ugly, and the WebWasher's trusty :hname verb has taken some of the brunt. The WebWasher's :hname MIGHT NOT conform to the order of events listed far above. It might go look for :hname, then .hname, and then get .name and might not look beyond that. Take a look at the free-to-view WebWasher :hname verb on the moo you are working-on... for full detail.
HNAME ADJUSTABLES |
||
|---|---|---|
| Property Name | Allowed Return Values | Default Return Value |
.hname |
anything |
Name of object |
.hname_prefix |
anything |
Often "<FONT size=6 color=red>" |
.hname_suffix |
anything |
Often "</FONT>" |
Here's hlocation. It has a few odd characteristics. First, hlocation is a LINK... a clickable... and so, its color is controlled by the BODY command's LINK, ALINK, and VLINK attributes. For the HTML4-compliant WebWasher (not yet built)... the colors are controlled by the A:LINK, A:ALINK, and A:VLINK attributes of a STYLE element. The current WebWasher has a property called .hbackground that you can copy to your object and adjust colors with. We will talk about that far below.
Besides the basic .hlocation, .hlocation_prefix, and .hlocation_suffix properties, there is
a curious property called .hlocation_link. This contains a URL (http address) to a webpage or some other media. When we're dealing with MOO objects, most objects are in some kind of container. If the object owner hasn't set a special .hlocation property or written an :hlocation verb, then the WebWasher's :hlocation verb grabs the object's .location property, and wraps html around it and uses that on your webpage. It also makes the location's link... target the true MOO object that contains YOUR object. How does it do that? Well, the WebWasher KNOWS what the MOO's BASE URL is, and simply makes a link to MOO BASE URL + THE CONTAINING OBJECT'S NUMBER. And, it puts the NAME of the containing object in the text of the location. It works quite automatically. But, of course, you CAN override the NAME of the hlocation via setting an .hlocation property or making a :hlocation verb on your object. You can also override the hlocation link via setting a .hlocation_link property or a :hlocation_link verb. You don't have to do both either.
Some early experimentation happened with hlocation on SnowMOO, where the WebWasher system was initially designed. I should say here that the design of the WebWasher system is based around a similar but primitive system designed at SnowMOO by Sam Epstein (aka rocker). Anyhoo, .hlocation and .hlocation_link was set as writeable by anyone, and a small utility verb was written so that anyone could adjust these settings on anyone's objects. This meant that when you viewed your object's webpage, its "Location:" could be set to say ANYWHERE and its link could go ANYPLACE. In affect, this meant that your object, according to its webpage's location, could be placed anywhere on the planet. An example might be where, when you created a thing, it might reside in "the library"... and a click might take the user to the webpage for the MOO's library object. Someone who is logged-in to the moo... could maybe move the object (set its .hlocation) to Cairo Egypt... and then set its .hlocation_link to maybe the Cairo Tourism Bureau homepage address. You, as an object owner, would know that your object is still safe and sound in the moo, but according to your object's webpage, the object is in Cairo, at the Tourism Bureau. Naturally, we had a owner-locked setting for disallowing other people from dragging your object all over the web. The concept was fun and was in use at the time SnowMOO evaporated.
The WebWasher also likes to know (has a property containing...) the web address (URL) to the MOO's main homepage. And it has a property that contains the MOO's name. Why? Because IF the .location of your object is set to #-1, which is often called "nowhere" or "limbo", then the WebWasher's :hlocation verb sets your object's location display to be the name of the moo, and sets the link to target the MOO's main webpage. This might be an opportunity for you to make a .hlocation_link property on your object, and set it to "http://www.limbo.com/" if one existed.
HLOCATION ADJUSTABLES |
||
|---|---|---|
| Property Name | Allowed Return Values | Default Return Value |
.hlocation |
anything |
Container object name (.location) or MOO name |
.hlocation_prefix |
anything |
Often "<FONT size=5 color=blue> Location: " |
.hlocation_suffix |
anything |
Often "</FONT>" |
.hlocation_link |
any URL |
Container object URL or MOO homepage URL |
According to painters and photographers, a picture is worth a thousand words. According to writers and speakers, nothing paints a picture like words. With a WebWashed MOO object, you have the abilities to use both, either, or neither.
HPICTURE is one of the more complicated segments of the WebWasher. Not because :hpicture is some sort of complicated verb, but because the browser companies have placed quite a bit of weirdness in their picture handling. One of the larger weirdnesses is ISMAPS or IMAGE MAPS. This is where one portion of a picture can have a link to some URL, and another portion of the SAME picture, can have a link to another URL, ad infinitum. This can be quite a chunk of hassle for a meager hverb like :hpicture, and so... we left it out. So, if you plan on doing IMAGE MAP (nowadays called AREA MAP) processing, you will need to write your own :hpicture verb and put it on your object. If you do, contact Wingy as he might want to steal your code for implementation on the WebWasher. The non-dabble attributes of the hpicture section (listed in blue on the table below) are changing fairly quickly amongst the HTML specs, so we included the ones that placed us somewhere around the HTML 2.2 specification. All the "big dog" browser makers still honor these attributes as of Feb 2001, and that's good enough for us. We will be looking at hpicture in the future, making sure we include the best and most logical attributes. For now, it might be best to wander to the browser companies and W3C and see what's being put into the "blue" attributes, especially .hpicture_align. (Its the ALIGN="???" part of an IMG element.) Also, .hpicture_width and .hpicture_height, last I checked, were honoring both PIXEL settings, and PERCENT settings. I've found PERCENT settings very useful, because a resize of a browser window that's displaying a WebWashed object... is very proportionate. (In short, a resized WW object looks pretty damned good!)
Another area of concern is with .hpicture_link. The browser companies have made it so that a picture that is also a clickable link... has a border around it. I'm pretty sure you can get rid of it, but I can't remember how right now. If I remember right, .hpicture_border set to 0 (default) does not do the trick. Experiment around a bit, and go visit HTML help areas on the web to give you some insight. Suggestions of ways to modify the hpicture section are certainly welcome and appreciated.
Lastly, .hpicture_alt is a place to make a textual description of the picture that you chose for your object's webpage. In my opinion, as well as many others'... setting a good description in .hpicture_alt is important because it is often read-to blind people who browse the web. A voice synthesizer program reads .hpicture_alt. (ALT="???" in the IMG element.) There is also a new attribute being tested for pictures called "long description" and is made to be ALT 2... the legend continues. Keep in mind that the contents of .hpicture_alt are just appended into the IMG tag as the ALT="???" attribute. Although rarely tested, you MAY be able to "extend" the contents of .hpicture_alt. Consider this...
;#124.hpicture_alt = "\"A beautiful snow-adorned alpine lodge-like rubber chicken.\" longdescription=\"This is an elevated view of the front of an alpine lodge. There are pine trees all around the snow-adorned lodge, and there are large beautiful snow-capped mountains in the distance. It is late evening or early morning, and the warm lights and log-cabin design of the large three-story lodge invites you inside for a cup of hot cocoa./""
Pretty nice describing if I say so myself. You'll have to play around with the escaped quotes (\") a bit, and experiment. Extending the contents of a property like this HAS BEEN DONE before, it just takes some fiddle-pahdiddling and an adventurous frame of mind. The WebWasher system (and HTML) is based upon strings and text, which is a format that IS, and will always be... very versatile.
HPICTURE ADJUSTABLES |
||
|---|---|---|
| Property Name | Allowed Return Values | Default Return Value |
.hpicture |
anything |
Often, a URL to a MOO logo picture |
.hpicture_prefix |
anything |
empty |
.hpicture_suffix |
anything |
empty |
.hpicture_link |
any URL |
empty |
.hpicture_alt |
any text |
empty |
.hpicture_centered |
0 or 1 |
Varies MOO to MOO |
.hpicture_width |
0 - 800? |
Varies MOO to MOO |
.hpicture_height |
0 - 600? |
Varies MOO to MOO |
.hpicture_border |
0 - 6? |
0 |
.hpicture_align |
"top", "bottom", "right", "left", "center", absbottom, abstop, (see HTML spec) |
"center" |
You're getting the hang of this just fine, and I don't see that I need to talk too much about the very simple hdescription section.
One of the more fun things I like to do with .hdescription and its dabbles... is to modify the description that is shown to the web viewers. Something like this can be fun...
@prop #1234.hdescription_suffix "" (hit enter)
;#1234.hdescription_suffix = " Although this MOO object happily resides in the MOO database, it somehow senses you are viewing it from the World Wide Web, and it pokes out a funny looking MOO object arm and waves at you in a happy, webby fashion. <BR><BR>" (hit enter)
HDESCRIPTION ADJUSTABLES |
||
|---|---|---|
| Property Name | Allowed Return Values | Default Return Value |
.hdescription |
any text |
Object's .hdescription, :hdescription or .description (text) |
.hdescription_prefix |
anything |
empty |
.hdescription_suffix |
anything |
Often "<BR><BR>" |
Here's HCONTENTS! It waves at you webishly.
The hcontents of a MOO object are not displayed if your object is not a "container" or if your object has no contents. (.contents) I, personally, have hid the contents from web viewers, (via removing "contents" from .hassembly) but I have never tried to completely override hcontents via a :hcontents verb, or fiddling with a .hcontents property. The contents of a MOO object is often a LIST type property, and it seems it would be pretty easy to screw-up by modifying hcontents data. Of course, the dabbles are a nice place to fiddle with things, as you well know.
NOTE: There is a common class of MOO ROOM that has a property on it called .ctype. Ctype, if I remember right, has 4 settings allowed... 0, 1, 2, or 3. I can't guarantee that changing your object's .ctype will in any way affect hcontents, but it might. Experiment by playing with .ctype settings and LOOKing at your room both in-MOO and via web between different settings.
HCONTENTS ADJUSTABLES |
||
|---|---|---|
| Property Name | Allowed Return Values | Default Return Value |
.hcontents |
a LIST of object numbers |
Clickable names of this object's contents |
.hcontents_prefix |
anything |
Often "<FONT size=5 color=green> Contents: " |
.hcontents_suffix |
anything |
Often "</FONT><BR><BR>" |
Here's HEXITS! (room-class objects only)
The hexits of a MOO object are not displayed if your object is not a "room" or if your room has no exits. (.exits) I have hid the exits from web viewers, (via removing "exits" from .hassembly) but I have never tried to completely override hexits via a :hexits verb, or fiddling with a .hexits property. The exits of a MOO room is often a LIST type property, and it seems it would be pretty easy to screw-up by modifying hexits data. Of course, the dabbles are a nice place to fiddle with things, as you well know.
HEXITS ADJUSTABLES |
||
|---|---|---|
| Property Name | Allowed Return Values | Default Return Value |
.hexits |
Names & links to webpages |
Names & links to targets of exits on this object |
.hexits_prefix |
anything |
Often "<FONT size=5 color=blue> Exits: " |
.hexits_suffix |
anything |
Often "</FONT><BR><BR>" |
Hey, look at this. We're down to the last section of a classic WebWasher markup! Hurray! This is an easy one too, but this one makes extensive use of dabbles from the get-go.
The only other thing to know about hwebhits is that an object's .webhits property must be writeable, and thus requires a bit of wizard dust to create it. Its created at the time the WebWasher is installed on a MOO. Often, web daemons send out player-class objects to gather the webpage for a browsed MOO object... and although the player-class "web-session" object is running around with programmer-level permissions, it is not allowed to write to a property on another person's object. This is why HWEBHITS is turned-off on some WebWashed MOOs.
HWEBHITS ADJUSTABLES |
||
|---|---|---|
| Property Name | Allowed Return Values | Default Return Value |
.hwebhits |
any number |
Current webhits count for this object |
.hwebhits_prefix |
anything |
Often "<FONT color=cyan> Webhits: " |
.hwebhits_suffix |
anything |
Often "</FONT>" |
There is an odd "dabble-able" property that is active in the HHEAD ("head") section that we must talk about. It is the HBACKGROUND property/verb. It is one of the more important and powerful h-sections, and so, I figured I'd better tell you about it. Once you create an .hbackground property on your object, you can set it to the COMPLETE contents of a classic HTML BODY command. Here's a few examples...
;#1234.hbackground = "<BODY BGCOLOR=black TEXT=#ffff00 LINK=RGB(0,255,0) ALINK=GREEN VLINK=lightgreen>" (hit enter)
In the above example, the background color to your object's webpage will be black (BGCOLOR) with yellow text (#ffff00 means full red, full green, no blue... = yellow) and links will be green (255 is the same as hex FF and its in the green "slot") with activated links (ALINKS - links you TAB to... with your browser) being green, and VLINKs (links you've been-to already) being light green. See what I said about POWERFUL!? Here's another...
;#1234.hbackground = "<BODY BACKGROUND=http://www.images.com/coolbackdrop.jpg TEXT=#ffff00 LINK=#00ff00 ALINK=#00ff00 VLINK=#66ee66>" (hit enter)
The above example is essentially the same as the previous one except for one obvious difference. This HTML BODY command uses a picture as a background for your webpage. There are numerous examples of BODY commands floating around the net. Choose VIEW SOURCE in your browser when viewing nearly any web page, and you'll probably find a BODY element amongst the debris. In the future, colors, backdrops, and font styles will all be handled by the STYLE element and/or by entries in a "cascading style sheet". The WebWasher will be using "styles" in the HTML 4.x version... coming soon.
There are other sections available on the WebWasher. One, for player-class objects, is HIDLE. HIDLE marks-up the player login status and idle time. Often, such a markup looks like this...
Wingy is logged into the MOO, but has been idle for 15 minutes.
Or if a player-class object is browsed, and that player is NOT logged into the MOO, it might say...
Wingy is asleep.
There are other sections too, not currently activated by .hassembly, but still available for you to use. There's one called HVRML for embeding a .wrl file (virtual reality)... and there's hrealaudio, for embedding .rpm files (realaudio plugin module). Stucky's most-excellent HTIME is close at hand on many WebWashers, and if not, just ask. It displays the current time, and it has fine dabbles as well. HOBJECT is under construction, which will be a very powerful future module, handling numerous file types and replacing the EMBED command. Got a file type you want to try to include in your web markup? Write an hverb, and then give it to Wingy to put on the WebWasher if its a good one. The WebWasher is certainly open to "community development"!
You can see now... that the WebWasher is made-up of "segments" or "modules". This is called "modular design". In designing the WebWasher, the vision was to build a damned good "FRAME for a bedroom dresser" and make the drawers interchangeable with each other. The drawers must be easy to modify, easy to insert and remove, and use VERY LITTLE OBJECT MEMORY OVERHEAD! In the building of this "super dresser frame", there were many people who were instrumental. Sam Epstein (rocker) and Kayla Block (Irradiate) were quite tolerant as I bitched and moaned and tore-through their moos. I questioned everything, and often spouted my yap well before I had the knowledge to go spouting. Yet both of these people kept gently kicking me in the "modular" direction... and I appreciate that. Many things were learned from both these people. I stole lots of petting and tech tips from Irradiate, and I stole lots of code and concepts from rocker. Rads and rockfish are both excellent MOO coders.
Speaking of excellent MOO coders, Jason Mills (sunray) has helped stucky and I build the WebWasher in SO MANY WAYS, its ridiculous. Sunray essentially wrote the meat and potatoes of the "frame" of the WebWasher... by writing some VERY TIGHT data gathering verbs found on the Generic Query. I also stole many other programming techniques from Sunray, each one ripping a healthy chunk of ticks (run time) off of the query-heavy WebWasher system. Jason is also the author of SunNet, a cross-MOO chat and RMI system... where MANY collaborative conversations took place regarding the WebWasher. Thanks Jason!
Speaking of collaborators, let's give a hi-5 to an excellent design collaborator named Jon Maul (stucky/somms). Although Jon did not write all that much code for the WebWasher, he maintained a fantastic testbed called "The Generic Webby Pueblo Room". All of stucky's and wingy's rooms were children of "the poo room", and every time a new development happened on the WebWasher, stucky would immediately implement it, update help-files, make announcements, and torture test the new feature. Besides all that, stucky is my friend, he's friendly and smart, and has a highly-creative mind. He came up with TONS of ideas for WebWasher advancement, and nearly all of those ideas have been implemented. Thanks stuckster! Excellent work!
There's many other people to thank, all of which I've forgotten their names. The WebWasher is really just a "fleshing-out" of a section of the SenseMedia WOODS server system. It has some features derived from some gracious early-peeks at the SenseMedia VOODO server system as well. Lastly, the WebWasher has a few nice characteristics that are my fine ideas. Thanks Wingy! :))) I apologize to the many I've left out.... thanks to all of you.
Now, we need to wrap this all up into a tight little ball somehow. The WebWasher has 3 "sisters" that can mark-up different types of markup. They are The VRML Varnisher, The Pueblo Painter, and the TTY Twister. All of them child to the Generic Query. They each operate on the same modular principles seen in the WebWasher. Speaking of modules, all of the main modules used in the WebWasher... hmidi, hsample, hname, hlocation, hpicture, hdescription, hcontents, hexits, and hwebhits... are written fairly kludgefully. The modules are subject to becoming outdated as HTML specifications change, and they are written by me, which means the code is not that wonderfully tight. I invite EVERYONE to work on improving the efficiency of any module verb on the WebWasher. I ask that you try to maintain original functionality, targeting speed increases if possible. I once clocked some fairly-gaudy WebWasher-created pages at 1400 ticks, which is not bad considering the pile of data queries that the WebWasher performs. PLEASE feel free to help us clip ticks off the WebWasher.
To see some WebWashed object webpages, visit http://www.winternet.com/~wingnut/html/shuttle.htm and choose links near the top that refer to OnceUpon, StrangeBrew, Rupert, and RiverMoo. OnceUpon and StrangeBrew are both using the WebWasher to web-up their entire MOO, and RiverMOO and Rupert both have local implementations. Many of the WebWasher-made webpages don't use audio, because the world just isn't ready for it yet, or the MOO's admin chose not to turn that on. Keep in mind that THAT doesn't mean YOU can't turn it on for your objects. hmidi and hsample are active on all implementations of the WebWasher, so burn a copy of .hassembly from the WebWasher onto your object, put the words "midi" and "sample" in there somewhere, and you're going to hear sound (if your sound system is configured correctly). I keep the default .hmidi and .hsample properties on the WebWasher up-to-date with working URL's. This tutorial was written in late February 2001, and it will be modified often until I get the mistakes out of it, and the omissions into it.
Enjoy using the WebWasher and don't forget to help Wingy and stucky improve it. The HTML 4.x WebWasher modules are currently in light development, so we're not leaving. The WebWasher, VRML Varnisher, POO Painter, and TTY Twister are copyrighted but can be freely installed on any MOO that does not charge fees in any way. Wingy will even install it for you. Very few wizard-grade modifications are needed to install the WebWasher or any of the sister objects. It works well with most web daemons, including WOODS, Shelob, Changeling, and E-Web. Get one for your MOO just by visiting Wingy's Homepage and dropping him a piece of email. An alphabetical list of WebWasher properties is dynamically generated at this address and here's the section-categorized master list of properties in use for the WebWasher...
HMIDI ADJUSTABLES |
||
|---|---|---|
| Property Name | Allowed Return Values | Default Return Value |
.hmidi |
Full URL of a midi song (.mid) |
Varies MOO to MOO |
.hmidi_prefix |
anything |
empty |
.hmidi_suffix |
anything |
empty |
.auto-start |
"true" or "false" |
"true" |
.midi_volume |
0 - 100 |
100 |
.midi_play_type |
"loop" or "play" |
"play" |
.midi_controls |
"console" or "smallconsole" |
"smallconsole" |
.midcon_height |
0 - ??? |
14 |
.midcon_width |
0 - ??? |
49 |
.midcon_align |
??? |
"bottom" |
HSAMPLE ADJUSTABLES |
| Property Name | Allowed Return Values | Default Return Value |
.hsample |
Full URL of a sample file (.wav) |
Varies MOO to MOO |
.hsample_prefix |
anything |
empty |
.hsample_suffix |
anything |
empty |
.auto-start |
"true" or "false" |
"true" |
.sample_volume |
0 - 100 |
100 |
.sample_play_type |
"loop" or "play" |
"play" |
.sample_controls |
"console" or "smallconsole" |
"smallconsole" |
.samcon_height |
0 - ??? |
14 |
.samcon_width |
0 - ??? |
49 |
.samcon_align |
??? |
"bottom" |
HNAME ADJUSTABLES |
| Property Name | Allowed Return Values | Default Return Value |
.hname |
anything |
Name of object |
.hname_prefix |
anything |
Often "<FONT size=6 color=red>" |
.hname_suffix |
anything |
Often "</FONT>" |
HLOCATION ADJUSTABLES |
| Property Name | Allowed Return Values | Default Return Value |
.hlocation |
anything |
Container object name (.location) or MOO name |
.hlocation_prefix |
anything |
Often "<FONT size=5 color=blue> Location: " |
.hlocation_suffix |
anything |
Often "</FONT>" |
.hlocation_link |
any URL |
Container object URL or MOO homepage URL |
HPICTURE ADJUSTABLES |
| Property Name | Allowed Return Values | Default Return Value |
.hpicture |
anything |
Often, a URL to a MOO logo picture |
.hpicture_prefix |
anything |
empty |
.hpicture_suffix |
anything |
empty |
.hpicture_link |
any URL |
empty |
.hpicture_alt |
any text |
empty |
.hpicture_centered |
0 or 1 |
Varies MOO to MOO |
.hpicture_width |
0 - 800? |
Varies MOO to MOO |
.hpicture_height |
0 - 600? |
Varies MOO to MOO |
.hpicture_border |
0 - 6? |
0 |
.hpicture_align |
"top", "bottom", "right", "left", "center", absbottom, abstop, (see HTML spec) |
"center" |
HDESCRIPTION ADJUSTABLES |
| Property Name | Allowed Return Values | Default Return Value |
.hdescription |
any text |
Object's .hdescription, :hdescription or .description (text) |
.hdescription_prefix |
anything |
empty |
.hdescription_suffix |
anything |
Often "<BR><BR>" |
HCONTENTS ADJUSTABLES |
| Property Name | Allowed Return Values | Default Return Value |
.hcontents |
a LIST of object numbers |
Clickable names of this object's contents |
.hcontents_prefix |
anything |
Often "<FONT size=5 color=green> Contents: " |
.hcontents_suffix |
anything |
Often "</FONT><BR><BR>" |
HEXITS ADJUSTABLES |
| Property Name | Allowed Return Values | Default Return Value |
.hexits |
Names & links to webpages |
Names & links to targets of exits on this object |
.hexits_prefix |
anything |
Often "<FONT size=5 color=blue> Exits: " |
.hexits_suffix |
anything |
Often "</FONT><BR><BR>" |
HWEBHITS ADJUSTABLES |
| Property Name | Allowed Return Values | Default Return Value |
.hwebhits |
any number |
Current webhits count for this object |
.hwebhits_prefix |
anything |
Often "<FONT color=cyan> Webhits: " |
.hwebhits_suffix |
anything |
Often "</FONT>" |