Contents Index Topic Contents | ||
Previous Topic: Scripting with Elements and Collections Next Topic: Cross-Frame Scripting and Security |
Understanding the Event Model
An event is a notification that occurs in response to an action, such as a change in state or as a result of the user clicking the mouse or pressing a key while viewing the document. An event handler is code, typically a function or routine written in a scripting language, that receives control when the corresponding event occurs. The following topics describe events and event handlers and explain how to use them in your documents.
Returning Values and Canceling Default Actions
The Life Cycle of an Event
An event has a life cycle that begins with the action or condition that initiates the event and ends with the final response to the event by an event handler or Internet Explorer. The life cycle of a typical event has these steps:
- The user action or condition associated with the event occurs.
- The event object is instantly updated to reflect the conditions of the event.
- The event fires. This is the actual notification in response to the event.
- The event handler associated with the source element is called. The event handler carries out its actions and returns.
- The event bubbles up to the next element in the hierarchy, and the event handler for that element is called. This step repeats until the event bubbles up to the window object or a handler cancels bubbling.
- The final default action (if any) is taken, but only if this action has not been canceled by a handler.
For events that bubble, if there is no event handler bound to the source element, the event handler for the next element up the hierarchy is called.
When an event handler carries out its actions, it uses the event object to retrieve information about the event, such as the position of the mouse, the state of the keyboard keys, the element in which the event occurred, and so on.
The following example defines an event handler, named "wasClicked", for the onclick event and associates it with the BODY element. When the user clicks the mouse button anywhere in this document, the event fires and the event handler displays the message "I was clicked", followed by the tag name of the element in which the event occurred.
<HTML> <BODY onclick="wasClicked()"> <H1>Welcome!</H1> <P>This is a very <B>short</B> document. <SCRIPT LANGUAGE="JavaScript"> function wasClicked() { alert("I was clicked " + window.event.srcElement.tagName); } </SCRIPT> </BODY> </HTML>The srcElement property of the event object specifies the element object in which the event occurred. This is useful for deciding what action the event handler should take in response to the event.
Attaching another event handler, "wasAlsoClicked", to the P element demonstrates the parent-child relationship of document elements.
<HTML> <BODY onclick="wasClicked()"> <H1>Welcome!</H1> <P onclick="wasAlsoClicked()">This is a very <B>short</B> document. <SCRIPT LANGUAGE="JavaScript"> function wasClicked() { alert("I was clicked " + window.event.srcElement.tagName); } function wasAlsoClicked() { alert("You clicked me " + window.event.srcElement.tagName); } </SCRIPT> </BODY> </HTML>As in the previous example, if the user clicks in the heading "Welcome!", the message "I was clicked H1" appears. But if the user clicks the word "short", two messages appear: "You clicked me B" followed by "I was clicked B". In the first instance, the click in "Welcome!" fires the onclick event, setting the H1 element as the source element of the event. There is no event handler for this element, so the event bubbles up to its parent element in the hierarchy, BODY, and its event handler, wasClicked, is called.
In the second case, when the user clicks in the word "short", the onclick event fires again. This time the B element is set as the source element. Since there is no event handler for B, the event bubbles up to the P element and its event handler, wasAlsoClicked, is called. But that's not the end of the event. After wasAlsoClicked returns, the event continues to bubble up the hierarchy to the next parent element, BODY, causing wasClicked to be called.
In some cases, you might not want the event to bubble up in the hierarchy. You can stop bubbling by setting the cancelBubble property of the event object to true in any event handler. After the handler returns, the event stops bubbling and comes to an immediate end. Note that this cancellation affects only the current event, not subsequent events. Subsequent events will bubble unless you explicitly cancel them.
Consider the following document. It defines two event handlers, setBodyStyle and setParaStyle, that are called when the user clicks in the document or in the paragraph, respectively. To ensure that only the style for the paragraph changes when the user clicks in the paragraph, the setParaStyle handler uses cancelBubble to prevent the event from bubbling up to BODY.
<HTML> <BODY onclick="setBodyStyle()"> <H1>Welcome!</H1> <P onclick="setParaStyle()">This is a very <B>short</B> document. <SCRIPT LANGUAGE="JavaScript"> function setBodyStyle() { // Set all headings to green var coll = document.all.tags("H1"); for (i=0; i<coll.length; i++) coll.item(i).style.color = "green"; } function setParaStyle() { // Underline the paragraph var el = window.event.srcElement; while ((el != null) && (el.tagName != "P")) { el = el.parentElement; } if (el != null) el.style.textDecoration = "underline"; window.event.cancelBubble = true; } </SCRIPT> </BODY> </HTML>Notice that the above example does not automatically assume that the source element is P. Because the user might have clicked in the B element, the event handler must check the element before applying the style. In this case, the handler uses the parentElement property to move up the element hierarchy until the P element is found.
Attaching an Event Handler
You must associate an event handler to a specific event and specific element or object in order for the handler to be called when the event fires. You can associate an event handler by using any one of the following, essentially equivalent, methods.
Declare an event handler function and assign a call to that function in the appropriate inline event attribute of an HTML tag. For example, the following defines the JScript function named "flip" and associates it to the IMG element as the event handler for the onmouseover event.
<SCRIPT LANGUAGE="JavaScript"> function flip() { // Carry out some work } </SCRIPT> . . . <IMG SRC="sample.gif" onmouseover="flip()">This example shows an event handler function being bound; however, any expression can be used here to be evaluated each time the event fires. Note that since this is an expression, the parentheses following the function name are required.
Declare event handling code and use the FOR= and EVENT= attributes of the SCRIPT tag to associate the code with the event. The following example also defines JScript code and associates it as the onmouseover event handler for the IMG element having the identifier "MyImage".
<SCRIPT FOR=MyImage EVENT=onmouseover LANGUAGE="JavaScript"> // Carry out some work </SCRIPT> . . . <IMG ID=MyImage SRC="sample.gif">Declare an event handler function in VBScript and associate it with an event by giving it a name having this form: id_event. The following example defines a VBScript function that handles the IMG element as its onmouseover event handler.
<SCRIPT LANGUAGE="VBScript"> Function MyImage_onmouseover ' Carry out some work End Function </SCRIPT> . . . <IMG ID=MyImage SRC="sample.gif">As a general rule, you should always define and associate your event handlers as early in the document as possible. Depending on the method you use, the handler can begin handling events either while the document is loading or immediately after loading, as shown in the following list.
JScript event handler When set using an inline event attribute, associates when the element is created. FOR= and EVENT= event handling code Associates when the document is fully loaded. VBScript event handler Associates when the document and all contained objects and applications have been loaded. Some events can occur while the document is loading. If you need to handle events at this time, you can use JScript and an inline event attribute to associate the handler when the element is created.
You can associate the same event handler with more than one element in the document. This is useful if you want the same action to occur whenever the given event occurs in any of the elements. Typically, event handlers are written to handle only one type of event, but it is possible to create event handlers that can handle more than one.
You don't have to limit yourself to one event handler for each type of event. If the action you want to occur for a given event in one element is different than for the same event in another element, you can define two event handlers and associate each to its appropriate element. In general, you can define any number of event handlers for the same type of event and associate each with one or more elements in the document.
If you use a combination of handling methods in a document, you can also define more than one event handler for the same event in the same element. For example, you can declare both a JScript and a VBScript event handler and associate them both with the same event and element. If you associate more than one event handler in this way and the handlers are in different languages, all handlers will receive the event, but the order in which they receive the event is not specified.
If you associate two event handlers of the same language to the same event and element, only one handler receives the event. In most cases, this will be the first handler that you bound to the element. But any handler associated using the FOR= and EVENT= attributes always takes precedence over a handler associated using an inline event attribute.
When you associate with an inline attribute, you typically assign to the attribute a call to the event handler function, causing that function to be called when the event fires. But assigning a call to an event handler is not a requirement. You can instead assign any valid script code; this code is executed when the event fires. For example, the following BUTTON element displays the message "Hello World!" when you click it.
<BUTTON onclick="alert('Hello World!')" LANGUAGE="JavaScript">Click Me</BUTTON>This method is convenient as long as the code is relatively short and uncomplicated. If you use an inline attribute in this way, you should also use the LANGUAGE= attribute to specify the scripting language for the code. If you don't specify the language, either the default language or the most recent language specified is assumed.
Attaching with Event Properties
The inline event attributes of an element are also available as properties. This means you can use the properties to dynamically change the event handling for an element at any time. For example, you can associate a handler to an element that didn't previously have one, or change the existing handler for an element to some other handler. Adding or changing event handlers is a useful way to make sure that the actions taken on an event reflect the current content of the element.
The following JScript example use the event property to associate the event handler, named setHeadStyle, to the H1 element. It assigns a call to the function to the onclick property of the element.
<H1 id=MyHeading>Welcome!</H1> . . . <SCRIPT LANGUAGE="JavaScript"> function setHeadStyle() { window.event.srcElement.style.color = "green"; } document.all.MyHeading.onclick="setHeadStyle()"; </SCRIPT>An alternate way to associate the event handler is to assign the function pointer (rather than a function call) to the property as in the following example. VBScript does not support function pointers.
document.all.MyHeading.onclick=setHeadStyle;Handling Custom Events or Events with Parameters
Using the FOR= and EVENT= attributes to associate events gives you access to custom events fired by embedded objects and to any parameters that an event generates. Unlike standard events that can be bound using attributes or properties, in the case of custom objects these are not available.
You use the FOR= attribute to specify which element or object to handle, assigning it an identifier or the name of an object, application, or control. If there is more than one element or object having the same identifier or name, only the first one is bound to the handler. Names take precedence over identifiers. If you don't specify this attribute, the handler is bound to the window by default. Note that JScript is case sensitive, so you must type the identifier or name exactly as it appears in the corresponding element or object.
You use the EVENT= attribute to specify which event to associate to, assigning it an event name. If the event generates parameters (few predefined events do), you can also specify a list of comma-separated parameter names enclosed in parentheses immediately after the event name. The parameters are untyped. Because JScript is case sensitive, make sure you always spell event names in lowercase letters. Also, if you give a parameter list, VBScript requires that all parameters defined for the event be listed, even if they are not used.
The following JScript example associates the event handling code with the onerror event for the window. This event fires when an error while loading the document is detected. The event generates parameters, so a parameter list is given, and the "lineno" parameter is used in the code.
<SCRIPT FOR=window EVENT="onerror(message, url, lineno)" LANGUAGE="JavaScript"> alert("An error has occurred on line " + lineno); </SCRIPT>The following JScript example associates the event handling code with a custom event, named "ondatechange", that the embedded object fires.
<OBJECT ID=myDateObject ... ></OBJECT> <SCRIPT FOR=myDateObject EVENT="ondatechange()" LANGUAGE="JavaScript"> // Carries out an action when the date changes </SCRIPT>An alternate way to handle custom events and to receive event parameters is to associate VBScript handlers. In this case, you use VBScript's id_event format for the event handler name and provide a parameter list if appropriate. The following VBScript example handles the onerror event and receives its parameters.
<SCRIPT LANGUAGE="VBScript"> Function window_onerror(message, url, lineno) alert "An error has occurred on line " & lineno End Function </SCRIPT>Similarly, the following VBScript example handles the custom event, ondatechange, fired by the embedded object.
<OBJECT ID=myDateObject ... ></OBJECT> <SCRIPT LANGUAGE="VBScript"> Function myDateObject_ondatechange() // Carries out an action when the date changes End Function </SCRIPT>More About Event Bubbling
Event bubbling ensures that the event handlers for all elements in which an event occurs have an opportunity to respond to the event. Consider the following example.
<P onclick="doPara()"> Jump to a <B>sample</B> document. </P>The user might reasonably expect that clicking the word "sample" will cause the same action, a call to the event handler named "doPara", as clicking any other word in the P element. But if events did not bubble up from the source element, clicking "sample" would cause no action because there is no event handler bound to the B element. Because events do bubble up through the element hierarchy, every event handler on the element's parent hierarchy has a chance to respond, and in this case "doPara" is called when the user clicks "sample".
Unless you keep event bubbling in mind, you might initially be baffled by some results. For example, consider a document that uses onmouseover and onmouseout events to show and hide a collection of paragraphs, but also uses the events inside the list to highlight paragraphs in the collection.
<DIV onmouseover="showPara()" onmouseout="hidePara()"> My Menu <P STYLE="display:none" onmouseover="highlight()" onmouseout="unhighlight()">Item 1 <P STYLE="display:none" onmouseover="highlight()" onmouseout="unhighlight()">Item 2 </DIV>In the example above, suppose the user moves the mouse over the words "My Menu", then over the words "Item 1", and finally over the words "Item 2". Here's what happens:
- The mouse cursor moves over "My Menu".
- The onmouseover event fires for the DIV element, and "showPara" is called.
- The mouse cursor moves from "My Menu".
- The onmouseout event fires for the DIV element, and "hidePara" is called.
- The mouse cursor moves over "Item 1".
- The onmouseover event fires for the P element, and "highlight" is called.
- The onmouseover event bubbles up to the DIV element, and "showPara" is called with P as the source element.
- The mouse cursor moves from "Item 1".
- The onmouseout event fires for the P element, and "unhighlight" is called.
- The onmouseout event bubbles up to the DIV element, and "hidePara" is called with P as the source element.
- The mouse cursor moves over "Item 2".
- The onmouseover event fires for the P element, and "unhighlight" is called.
- The onmouseover event bubbles up to the DIV element, and "showPara" is called with the second P as the source element.
As you can see, whenever the user moves the mouse over and from a paragraph in the collection, the event handlers for DIV are called. If the handlers were written without taking this into account, the paragraphs might be hidden when they should not be.
In general, whenever you use nested event handlers in this way, you need to carefully consider whether the event handler should carry out an action each time it is called. One way to control the action is to use the cancelBubble property. In the previous example, the "highlight" and "unhighlight" event handlers could set cancelBubble to true to prevent the event from bubbling up to the DIV element. Another way is to check the source element for the event, the srcElement property of the event object, and pick an action that is appropriate to that element.
Returning Values and Canceling Default Actions
Event handlers can return values to the event either by using the return value mechanism defined for the language, such as the return statement for JScript, or by using the returnValue property of the event object.
Return values are useful for controlling the default actions associated with events. For example, clicking the A element causes the browser to load the document specified by the href attribute. You can cancel default actions such as these by returning false from your event handlers.
Not all scripting languages support return values. For these languages, you must use the returnValue property to set a return value. If a language supports return values, you can use either the language-defined method of returning a value or returnValue. If you use both methods, the property always takes precedence.
After all event bubbling is complete, any default action associated with the event is canceled if returnValue is false or, if this property is not set, the return value of the last function is false. Note that some events do not have default actions associated with them and might use the returnValue (or function return value) in other ways.
Canceling a default action is not the same as canceling event bubbling. You can cancel the default action and still allow the event to bubble up through the hierarchy.
Event Handler Scoping
Depending upon whether a script is written inside a FORM container or elsewhere in the document, different scoping rules are applied for executing event handlers and the elements that are available on the window object. The different scenarios are listed below.
When events are fired, a special object referencethe me pointer in VBScript and this in JScriptis set to the current element firing the event.
1) Event handler for a button outside a form
This is the basic case. You can use any of the handling mechanisms described earlier. The only rule is that you cannot access elements within a form block directly on the window object. Instead, you can access them from the document object or the particular form's elements collection.
2) Event handler not inside the FORM block for a button inside a form
If the button has a unique identifier to the entire document, the event handler can be written anywhere within the document. If the event handler is written outside the form block, the same rules apply for accessing elements on the window object as described in 1) above.
3) Event handler inside the FORM block for a button inside the form
If the button's identifier is not unique to the document, the event handler must be written within the form. When writing event handlers behind the form, using either inline attributes or the FOR= and EVENT= attributes (but not the VBScript id_event method) changes the scoping rules of the window object. Events defined this way can access elements behind the form directly from the window object. They can also access elements that are outside the form directly as long as they do not conflict with any of the form's element names.
When using the VBScriptid_event method of handling, only elements that are not within the form's scope can be accessed as properties of the window.
If there is no unique identifier within the form, the first element with the matching identifier is bound to the event handler when using the FOR= and EVENT= attributes of the SCRIPT element or the VBScript id_event mechanism of defining events.
4) Event handler inside the FORM block for a button outside the form
The event handler executes only if the VBScript id_event method of handling is used. Otherwise this code will not execute.
You can write an event handler for multiple elements. This can be done only when the elements are not within the same scope, where scope is defined as being inside the form or not inside the form. For example, if writing an event handler for id=genericButton in the document's scope, and adding a genericButton to the document and another within a form, the same click event is fired in both cases. The me pointer will point to the actual source of the event. These elements do not have to be of the same type for this to work.
If multiple elements have the same identifier and are within the same scope, only the first one fires the event.
Event Object
The event object, on the window object, is accessible to all event handlers and is the language-independent, preferred way for handlers to get and modify information about the event. For example, the following VBScript and JScript examples both use the object to display the tag name of the element in which the event occurred.
<SCRIPT LANGUAGE="VBScript"> Function document_onclick alert window.event.srcElement.tagName End Function </SCRIPT> <SCRIPT LANGUAGE="JavaScript"> function doClick() { alert(window.event.srcElement.tagName); } </SCRIPT>Note In VBScript, you must use the window keyword with event to avoid a conflict with the VBScript event keyword.
The srcElement property is one of the most important properties on event. Many event handlers use this property to determine an action to take based on the source of the event. For example, the following JScript event handler carries out an action whenever the user clicks any of the H1 elements in the document.
<SCRIPT FOR=document EVENT="onclick()" LANGUAGE="JavaScript"> if ("H1" == event.srcElement.tagName) { // user clicked on a H1 } </SCRIPT>Another important property is cancelBubble, which controls event bubbling for the given event and, if set to true, prevents the event from bubbling up the element hierarchy.
The returnValue property gives an event handler a language-independent way to return a value to the event. For many events, setting the return value to false cancels the default action for that event.
Some properties of the event object have meaning only for certain events. For example, the keyCode property is an integer specifying a standard numeric Unicode keycode for keyboard key events. For other events, this property is set to zero. Other examples are the toElement and fromElement properties, which represent the element that the mouse is going to and coming from for the onmouseover and onmouseout events. For other events, these properties are null.
When a mouse event occurs, such as onclick, the x and y properties specify the horizontal and vertical position of the mouse. If none of the elements containing the source element are positioned, the position of the mouse is relative to the BODY element. If a positioned element contains the source element, the position of the mouse is relative to that element. In addition to mouse position, the button property indicates which mouse buttons are pressed at the time of the event. It is 0 if no buttons are pressed, 1 for the left button, 2 for the right, and 3 for both.
The altKey, ctrlKey, and shiftKey properties are useful for all events. These specify whether the ALT, CTRL, and SHIFT keys were down or up at the time of the event. The property is true if the key was down. The following VBScript example cancels the default action for the A element if the SHIFT key is down when the event occurs.
<SCRIPT FOR=document EVENT="onclick()" LANGUAGE="VBScript"> If (("A" = window.event.srcElement.tagName) and (window.event.shift)) Then event.returnValue = false End If </SCRIPT>The clientX and clientY properties are integers specifying the coordinates relative to the size of the client area, not including window decorations. The offsetX and offsetY properties are integers specifying container relative positions. These match the offsetTop and offsetLeft properties of the element. Use the offsetParent property to find the container that defines this positioning. The screenX and screenY properties are integers specifying the coordinates relative to the physical screen.
Note that properties such as returnValue and keyCode are read/write properties. This means an event handler can assign a new value to the property, overwriting the original value. The property retains this new value as the event bubbles up the element hierarchy. This makes it easy for an event handler bound at a low level in the hierarchy to modify events that are also handled at a higher level.
The event object gives you detailed information about where in the document an event occurs, so it is easy to write an event handler that can adapt its action based on the source of the event. If you associate the event handler on an element or object that contains all the elements in which the event might occur, event bubbling will ensure that the handler is called whenever the event occurs. This means you don't need to associate the event handler to each element.
Keyboard Events
Keyboard events occur when the user presses or releases a keyboard key. The onkeydown and onkeyup events fire when a key changes state, either being pressed (down) or released (up). These events fire for all keys on the keyboard, including shift state keys such as SHIFT, CTRL, and ALT.
The onkeypress event fires when the user's keyboard input is translated to a character. These occur, for example, when the user presses letter or number keys, or a combination of shift keys and letters and numbers.
When a keyboard event occurs, the keyCode property of the event object contains the Unicode keycode of the corresponding key. The altKey, ctrlKey, and shiftKey properties specify the state of the ALT, CTRL, and SHIFT keys.
You can change which key is associated with the event by either changing the value of the keyCode property or returning an integer value. You can cancel the event by returning zero or false.
The onhelp event is a special keyboard event that occurs when the user presses the help key (F1).
Mouse Events
Mouse events occur when the user moves the mouse or clicks the left button. The onmousemove event fires when the user moves the mouse, and onmouseover and onmouseout fire when the mouse moves in and out of an element. The onmousedown and onmouseup events fire when the left mouse button changes state, either being pressed (down) or released (up). The onclick and ondblclick events fire when the user single-clicks and double-clicks the button.
When a mouse event occurs, the button property of the event object identifies which mouse button (if any) is down. The x and y properties specify the location of the mouse at the time of the event. For the onmouseover and onmouseout events, the toElement and fromElement properties specify the elements the mouse is moving to and from.
Mouse Clicks
The onclick event fires when the user presses and releases the button. The ondblclick event occurs when the elapsed time between two consecutive onclick events is within a system-defined range.
Mouse click events are interspersed with onmousedown and onmouseup events. For example, the onclick event follows an onmouseup event. The ondblclick event occurs at the end of this sequence:
onmousedown onmouseup onclick onmouseup ondblclick An onclick event can also occur when the user presses the ENTER key on a focusable element, such as a BUTTON element. In this case, the event fires without a preceding onmouseup event.
You can cancel a mouse click by returning false or setting the returnValue property to false.
Note For mice that have one button, the button is considered the left mouse button.
Moving Between Elements
The onmouseover and onmouseout events fire whenever the mouse cursor moves from one element to another. Consider the following document fragment.
<H1>Move from here</H1> <P id=myP><B><I>To here</I></B></P>In the above example, as the mouse moves from the H1 element to the words "To here", it crosses over the boundaries of the P, B, and I elements. However, the event sequence is simplified to the following: onmouseout on the H1 (which bubbles up the hierarchy), and onmouseover on the I element (again bubbling up the hierarchy).
The fromElement and toElement properties on the event object return the element object the mouse is coming from and going to. Through event bubbling, it is possible to determine each boundary that has been crossed by the mouse move.
When moving between elements, the onmouseout event fires first to indicate that the mouse has left the original element. Next the onmousemove event fires, indicating that the mouse has moved. Finally, onmouseover fires to indicate that the mouse has entered the new element.
Focus and Selection Events
The focus and selection events give you detailed information about what actions the user is taking in the document.
The focus events occur on elements such as BUTTON and various types of INPUT that can receive the input focus. For these elements, the onfocus event fires when an element receives the focus, and the onblur event fires when an element loses the focus. An element receives the input focus when the user clicks it with the mouse or navigates to it using the keyboard. These events are useful for knowing when to prepare an element to receive input from the user.
Note that the focus events fire whether moving the input focus between elements in the document or between frames in the window or even applications on the desktop. For example, if a control in the document has the focus and the user switches to another application, the onblur event fires for that control. When the user switches back to the document, the onfocus event fires. It is not possible to cancel the loss of focus.
The selection events occur when the user selects a portion of the document by using the mouse or keyboard. The onselectstart event fires when a selection is first initiated, for example, when the user clicks a character or object in the document. The onselect event fires when the user changes the selection, for example, by moving the mouse over a portion of the document while holding down the mouse button. The default action for the onselectstart event is to move the selection to the given character or object and highlight that selection. You can cancel this default action by returning false.
The ondragstart event fires when the user first begins to drag the selection. The user can drag a selection by holding down the mouse button on the current selection and moving the mouse. The default action for this event is to prepare the selection to be copied to another element. You can cancel this default action by returning false.
Load and Readystate Events
There are three events that signify the current state of the document: onreadystatechange, onload, and onunload.
The onreadystatechange event fires when the document changes from initializing to interactive, and from interactive to loaded. A document is interactive as soon as the user can interact with it by scrolling or clicking on anchors or elements. A document is loaded when all the content has been downloaded.
The onload event fires after the document is loaded and all the elements on the page have been completely downloaded. The onunload event fires immediately prior to the document being unloaded (when navigating to another document).
Specifying code for the onload and onunload events can be done on the body object. However, these events actually occur on the window. Therefore, when handling the onload event using the <SCRIPT FOR= EVENT=> syntax, <SCRIPT FOR=myBody Event=onLoad> will fail. Instead, you must use <SCRIPT FOR=window Event=onLoad>.
Other Events
There are a number of other useful events that you can use in your document. For a complete list, see the Events reference.
Top of Page
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.