var _t = ''; _t += ''; _t += '
| '; writeString += ' | ';
if (navigator.appName.indexOf('WebTV') != -1) {
document.write('');
} else {
writeString += ' ';
writeString += ' ';
writeString += '
';
writeString += ' ';
writeString += '';
document.write(writeString);
}
document.write('');
/* Begin: MSN search header (FSCOM-4763) */
/////////////////////////////////////////////////////////////////////////////////
//
// File: base.js
// Defines:
// Dependencies:
// Description: this is the base framework module. This must be the first JS
// file; all other framework files depend on the prototypes defined
// within.
//
// Copyright (c) 2006 by Microsoft Corporation. All rights reserved.
//
/////////////////////////////////////////////////////////////////////////////////
Function.prototype.addMethod = function(name,func)
{
// if the function doesn't already exist
if ( !this.prototype[name] )
{
// add it now
this.prototype[name] = func;
}
// return this to allow chaining
return this;
};
Function.addMethod("as", function(ns,isSingleton)
{
// split the namespace string on the periods
var chain = (ns ? ns.split('.') : []);
// if the array is empty, then nothing to do
if ( chain.length > 0 )
{
// the root is the window object
var base = window;
// start with the first stop with the second-to-last portion
// in the namespace chain
for(var ndx = 0; ndx < chain.length - 1; ++ndx)
{
// the token should not be empty -- skip it if it is
var token = chain[ndx];
if ( token )
{
// if the namespace object for this token doesn't
// already exist, then we need to create it now
if ( !base[token] )
{
// make it an empty object
base[token] = {};
}
// walk down the chain
base = base[token];
}
}
// the last namespace in the chain is a new instance
// of this object
base[chain.last()] = (isSingleton ? new this() : this);
}
return this;
});
Function.addMethod("ns",function(ns)
{
// just define this function as the namespace, but as a singleton
// (just a shortcut for readability purposes)
this.as(ns,1);
});
String.addMethod("trim",function()
{
// trim off all leading and trailing spaces
return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/,"$1");
});
String.addMethod("collapse", function()
{
// trim off all leading and trailing spaces, and collapse all instances
// of whitespace to a single space character
return this.replace(/\s+/g,' ').trim();
});
String.addMethod("wrap", function(delim)
{
// return the text wrapped in the delimeter
var close, delims = {"(":")", "{":"}", "[":"]", "<":">", "«":"»", "‹":"›", "“":"”", "‘":"’"};
if ( delims[delim] )
{
close = delims[delim];
}
else
{
var m = (/^<(\w+)(\s+\w+\s*=\s*"[^"]*")*\s*>$/).exec( delim );
if ( m )
{
close = "" + m[1] + ">";
}
}
return delim + this + (close ? close : delim);
});
String.addMethod("format",function()
{
// use this string as the format
var fmt = this;
// walk through each argument passed in
for(var ndx=0; ndx < arguments.length; ++ndx)
{
// replace {0} with argument[0], {1} with argument[1], etc.
fmt = fmt.replace( new RegExp('\\{' + ndx + '\\}',"g"), arguments[ndx] );
}
// return the formatted string
return fmt;
});
String.addMethod("encodeHtml",function()
{
var returnString = this.replace(/\>/g, ">").replace(/\").replace(/</g, "<").replace(/&/g, "&").replace(/'/g, "'").replace(/"/g, '"');
return returnString;
});
String.addMethod("encodeURIComponent",function() {
return (typeof encodeURIComponent != "undefined" ? encodeURIComponent(this) : escape(this));
});
String.addMethod("decodeURIComponent",function() {
return (typeof decodeURIComponent != "undefined" ? decodeURIComponent(this) : unescape(this));
});
Array.addMethod("last",function()
{
// return the last element in the array,
// or "undefined" if the array is empty
return (this.length > 0 ? this[this.length-1] : void(0));
});
Array.addMethod("remove",function(obj)
{
// walk backwards because we might be removing items
for(var ndx=this.length-1; ndx >= 0; --ndx)
{
// if this element is the same as the argument...
if ( this[ndx] === obj )
{
// splice it out now
this.splice(ndx, 1);
}
}
return this;
});
Array.addMethod("contains", function(obj)
{
// walk all the items in the array
for(var ndx=0; ndx < this.length; ++ndx)
{
// check to see if this item is the exact same (no conversion)
// as the object passed to us
if ( this[ndx] === obj )
{
// we can bail as soon as we find it
return 1;
}
}
// if we get here, we didn't find it
return 0;
});
// these methods are typically already defined on more-recent browsers
// but we'll try to add them in case this is an older browser that doesn't
// support them (since we use them).
// examples are IE 5.0 or earlier, IE for the Mac, etc.
Array.addMethod("push",function(obj)
{
// add the object to the end of the array
this[this.length] = obj;
// return the new array length
return this.length;
});
Array.addMethod("shift",function()
{
// splice returns an array of the deleted items, so delete one item
// from the head, and return the one element in the returned array
return this.splice(0,1)[0];
});
Array.addMethod("splice",function(start,delCount)
{
// we might be adding new elements -- calculate how many were passed in (if any)
var delta;
var addCount = arguments.length - 2;
// verify some values based on the length of the array
// can't start past the end of the array
if ( start > this.length )
{
start = this.length;
}
// can't delete more items than we have
if ( start + delCount > this.length )
{
delCount = this.length - start;
}
// create the array of deleted items (if any)
var deleted = [];
for(var ndx = 0; ndx < delCount; ++ndx)
{
deleted.push(this[start+ndx]);
}
if ( addCount > delCount )
{
// have to push out elements to make room for added items
delta = addCount - delCount;
for(ndx = this.length + delta - 1; ndx >= start + delta; --ndx)
{
this[ndx] = this[ndx - delta];
}
// don't have to adjust the length when adding -- gets done
// automatically by adding items beyond the old length
}
else if ( addCount < delCount )
{
// pushing in elements because more deleted than added
delta = delCount - addCount;
for(ndx = start + addCount; ndx < this.length - delta; ++ndx)
{
this[ndx] = this[ndx + delta];
}
// delete the excess items starting where we left off
for(; ndx < this.length - 1; ++ndx)
{
delete this[ndx];
}
// adjust the length
this.length -= delta;
}
// if we're adding items, add them now
for(ndx = 0; ndx < addCount; ++ndx )
{
this[start+ndx] = arguments[2+ndx];
}
return deleted;
});
/////////////////////////////////////////////////////////////////////////////////
//
// File: dom.js
// Defines: Msn.DOM
// Dependencies: base.js
// Description: implements framework DOM functionality. Common DOM-walking
// methods and event hooking.
//
// Copyright (c) 2006 by Microsoft Corporation. All rights reserved.
//
/////////////////////////////////////////////////////////////////////////////////
(function()
{
// shortcut
var dom = this;
Function.addMethod("hook",function(element,eventName)
{
if ( element )
{
var isSafari = checkSafari();
if ( !isSafari && element.addEventListener )
{
// if the browser supports the w3c model, use it
element.addEventListener( eventName, this, false );
}
else if ( !isSafari && element.attachEvent )
{
// if the browser supports the IE model, use it
element.attachEvent( 'on' + eventName, this );
}
else
{
// normally we'd just assign to "on"+eventName, but let's try
// to fake it by setting up an array of event handlers as a property
// on the element. Then we'll set the real event handler to a function
// that walks that array, calling each of the handlers. If any of the handlers
// returns false, we stop walking and return false. Otherwise we'll return true.
//
// see if there's already an event handler for this event
var handlers = element["x"+eventName];
if ( handlers && handlers.constructor == Array )
{
// yes -- add this new function to the list if it isn't already
if ( handlers.contains(this) )
{
// already there -- null the handler variable so we do nothing
handlers = null;
}
else
{
// add it
handlers.push(this);
}
}
else
{
// no -- create a new array with this function as the only item
handlers = element["x"+eventName] = [this];
}
if ( handlers )
{
// set the real handler to be a custom function
element['on' + eventName] = function(ev)
{
var returnValue = true;
// the event object
ev = dom.Event(ev);
// walk the array
for(var ndx=0; ndx < handlers.length; ++ndx)
{
// call the handler
var handlerReturn = handlers[ndx](ev);
if ( typeof handlerReturn != "undefined" && !handlerReturn )
{
// return false to cancel the event and stop calling handlers
returnValue = false;
}
}
// everything was fine and dandy
return returnValue;
};
// the above closure will leak memory under IE.
// null out the element reference and the leak won't happen.
element = null;
}
}
}
return this;
});
Function.addMethod("unhook",function(element,eventName)
{
if ( element )
{
var isSafari = checkSafari();
if ( !isSafari && element.removeEventListener )
{
// if the browser supports the w3c model, use it
element.removeEventListener( eventName, this, false );
}
else if ( !isSafari && element.detachEvent )
{
// if the browser supports the IE model, use it
element.detachEvent( 'on' + eventName, this );
}
else
{
// see if we've set up an array of handlers on a property of this element
var arr = element["x"+eventName];
if ( arr && arr.constructor == Array )
{
// remove this function from the array
arr.remove( this );
}
else
{
// just set the handler to be null, just in case
element["on"+eventName] = null;
}
}
}
return this;
});
// call this method in your handlers in order to cancel an event
// and prevent bubbling
dom.CancelEvent = function( ev )
{
// if no event is passed, pull the event from the window object
ev = dom.Event(ev);
if ( ev )
{
// this cancels the bubble in order to prevent the
// event from bubbling up the dom chain
// (eg: OOB script won't log link click)
ev.cancelBubble = true;
if ( ev.stopPropagation )
{
ev.stopPropagation();
}
// this sets the return value to false and stops the
// default action from occurring
// (eg: clicks on links won't navigate)
ev.returnValue = false;
if ( ev.preventDefault )
{
ev.preventDefault();
}
}
// return false in case we want to use in an onclick property
return false;
};
// this function is pretty easily coded, but once it's crunched, it
// will actually save a few bytes for every time it's used.
dom.Event = function(ev)
{
return (ev ? ev : window.event);
};
// this function is a shortcut for getting the browser-independent
// source element from the event
dom.Target = function(ev)
{
// typically this is done in the calling code, but just in case...
ev = dom.Event(ev);
// get the browser-independent target property
var target = (ev.target ? ev.target : ev.srcElement);
// some browsers (like Safari) might give us the actual text element
// that was clicked. But we want to return an element, so if the
// target isn't an element...
if( target && target.nodeType != 1 )
{
// get the first parent element from the tree
target = dom.ParentElem( target );
}
return target;
};
// browser-neutral innerText method.
// if the browser supports the innerText property, return it;
// otherwise calculate the inner text by walking the dom nodes.
dom.InnerText = function( el )
{
var text = '';
//for each child of the node
for (var ndx=0 ; ndx < el.childNodes.length; ndx++)
{
var child = el.childNodes[ndx];
if (child.nodeType == 1)
{
// recurse child element nodes, adding their text to the string we're building
text += dom.InnerText(child);
}
else if (child.nodeType == 3)
{
// just add the value of the text nodes to the string we're building
text += child.data;
}
}
return text;
};
// given an element, returns the next sibling element in the dom,
// or null if there is none
// if tagName is specified, it will keep looking until it finds an element of that tag name
dom.NextElem = function( element, tagName )
{
var nextElement = element.nextSibling;
while( nextElement && (nextElement.nodeType != 1 || (tagName && nextElement.nodeName != tagName)) )
{
nextElement = nextElement.nextSibling;
}
return nextElement;
};
// given an element, returns the previous sibling element in the dom,
// or null if there is none
// if tagName is specified, it will keep looking until it finds an element of that tag name
dom.PrevElem = function( element, tagName )
{
var prevElement = element.previousSibling;
while( prevElement && (prevElement.nodeType != 1 || (tagName && prevElement.nodeName != tagName)) )
{
prevElement = prevElement.previousSibling;
}
return prevElement;
};
// get the fist element up the dom tree from element.
// if tagName is specified, it will keep looking until it finds an element of that tag name
dom.ParentElem = function( element, tagName )
{
var parentNode = element.parentNode;
while( parentNode && (parentNode.nodeType != 1 || (tagName && parentNode.nodeName != tagName)) )
{
parentNode = parentNode.parentNode;
}
return parentNode;
};
// get the first child element under node parentNode.
// if optional parameter, tagName, is specified, keep looking
// until we find the first child with that tag name
// if immediate is non-zero, only the immediate children are checked
dom.ChildElem = function( parentNode, tagName, immediate )
{
var element = null, childNode;
// check all our child elements
for(var ndx=0; !element && ndx < parentNode.childNodes.length; ++ndx)
{
childNode = parentNode.childNodes[ndx];
if ( childNode.nodeType == 1 )
{
// child is an element. if we are not looking for a particular tag name,
// or if we are and they match, then we are done
if ( !tagName || childNode.nodeName == tagName )
{
// save this element and pop out of the recursion
element = childNode;
}
}
}
if ( !immediate )
{
// now recurse each of the children if we haven't found anything yet
for(ndx=0; !element && ndx < parentNode.childNodes.length; ++ndx)
{
// check to make sure it's an element
childNode = parentNode.childNodes[ndx];
if ( childNode.nodeType == 1 )
{
// it is -- recurse it
element = dom.ChildElem( childNode, tagName );
}
}
}
return element;
};
// for each immediate child of the parent node
// (optionally only those with the supplied tag name),
// call the function provided, passing in the node as the parameter
dom.ForEach = function( func, parent, tagName )
{
for(var ndx = 0; ndx < parent.childNodes.length; ++ndx)
{
var child = parent.childNodes[ndx];
if ( child.nodeType == 1 && (!tagName || child.nodeName == tagName) )
{
if ( func( child ) )
{
break;
}
}
}
};
// returns the number of child elements for the given node
// if nodeName is supplied, it will only count those child nodes with the given name
// returns the new className for the element
dom.ChildCount = function( element, nodeName )
{
var count = 0;
var ndx,child;
for(ndx=0; ndx < element.childNodes.length; ++ndx)
{
child = element.childNodes[ndx];
count += (child.nodeType == 1 && (!nodeName || child.nodeName == nodeName) ? 1 : 0);
}
return count;
}
// add the specified class name to the element's list of classes
// if it isn't already there
dom.AddClass = function( element, className )
{
// get the current classes
var originalValue = element.className;
if ( originalValue )
{
// split on spaces (after collapsing all the whitespace)
var originalClasses = originalValue.collapse().split(' ');
var newClasses = className.collapse().split(' ');
for( var ndx = 0; ndx < newClasses.length; ++ndx )
{
var newClass = newClasses[ndx];
// if the array doesn't contain the given class name...
if ( !originalClasses.contains( newClass ) )
{
// add it to the end
element.className += ' ' + newClass;
}
}
}
else
{
// nothing there now -- just set the new one
element.className = className;
}
return element.className;
};
// if the element has a class name in its class list, remove it.
// returns the new className for the element
dom.DelClass = function( element, className )
{
// get the current classes
var originalValue = element.className;
// if it's blank, there's nothing to do
if ( originalValue )
{
// collapse all the whitespace, split on the space, and remove
// the given class name from the array (if it exists)
var classes = originalValue.collapse().split(' ');
var oldClasses = className.collapse().split(' ');
for(var ndx = 0; ndx < oldClasses.length; ++ndx)
{
classes.remove( oldClasses[ndx] );
}
// caluclate the new value, separated with a space
var newValue = classes.join(' ');
// if the newvalue is different from the original value...
if ( newValue != originalValue )
{
// change it
element.className = newValue;
}
}
return element.className;
};
// returns true if the element has the given className in its list
dom.HasClass = function( element, className )
{
return element.className.collapse().split(' ').contains( className );
};
// call this function whenever you update the DOM.
// This function expects some other code to add an Impl function
// to it for a site-specific implementation of accessibility notification.
// This method is mainly provided as a stub that is always present, but can
// use multiple implmentations for specific sites in the future, while allowing
// other code to remain unchanged.
dom.Updated = function()
{
// if some other code has implemented accessibility feature for the DOM...
if (dom.Access && typeof dom.Access.Updated == 'function')
{
// let's call into it
dom.Access.Updated();
}
};
function checkSafari()
{
return (navigator.userAgent.indexOf("Safari") >= 0);
}
}).ns("Msn.DOM");
/////////////////////////////////////////////////////////////////////////////////
//
// File: bind.js
// Defines: Msn.Bind
// Dependencies: base.js
// Description: framework implementation of binding.
// "bind" method can bind to an element reference, an array of
// element references, the results of getElementsByTagName, or
// a string representing a CSS selector.
//
// Copyright (c) 2006 by Microsoft Corporation. All rights reserved.
//
/////////////////////////////////////////////////////////////////////////////////
(function()
{
// shortcut
var bind = this;
// this is the binding array -- every time we create a binding, we also
// add a reference to it here. The unload event is hooked to loop through
// this array and call the dispose method (if it exists) on each binding.
var allBindings = [];
// bind an object of type, typ, to the DOM element(s) specified by
// the selector, sel.
Function.addMethod("bind",function( sel, args )
{
var elements;
switch(typeof sel)
{
case 'object':
// could be an element or an array of elements.
// if this is an element, we'll have the nodeType property and it will be 1.
// if this is the document object, we'll have a nodeType property of 9.
// if we are an element, create an array with the element as the one item.
// if we have a length property, then assume we are some sort of array
// otherwise just return null becasue we don't know what it is
elements = (sel.nodeType == 1 || sel.nodeType == 9) ? [sel] : (sel.length ? sel : null);
break;
case 'string':
// a string should be a css selector that we can
// evaluate to return an array of elements
elements = bind.Select( sel );
break;
}
if ( elements )
{
// walk each element...
for(var ndx = 0; ndx < elements.length; ++ndx)
{
var element = elements[ndx];
// create a new binding object, passing in the element we are binding to,
// and the parameters object and add the binding to our reference array
// so we can dispose of it during the unload event
var binding = new this( element, args );
if ( element.bindings )
{
element.bindings.push( binding );
}
else
{
element.bindings = [ binding ];
}
allBindings.push( binding );
}
}
return this;
});
// unbind any existing bindings from the given element, el.
// if r is true, all child elements of el are recursively unbound.
bind.Unbind = function( element, recurse )
{
var ndx;
// if there are any bindings on this element
if ( element.bindings && element.bindings.length )
{
// walk the array backwards because we might decide we
for(ndx=0; ndx < element.bindings.length; ++ndx)
{
var binding = element.bindings[ndx];
// if there is a dispose method on the binding, call it
if ( binding && typeof binding.dispose == 'function' )
{
binding.dispose();
}
// remove from the global bindings array
allBindings.remove( binding );
}
// clear the array
element.bindings = null;
}
// if we want to recursively unbind...
if( recurse )
{
// for each child node of this element...
for(ndx=0; ndx < element.childNodes.length; ++ndx)
{
var child = element.childNodes[ndx];
// if the child is an element...
if ( child.nodeType == 1 )
{
// recurse.
bind.Unbind( child, recurse );
}
}
}
};
/////////////////////////////////////////////////////////////////////////////
//
// this method takes a css-style selector and returns an array of elements
// within the DOM that satisfy that criteria.
// The selector should follow this pattern:
// selector: simpsel [ combinator? simpsel ]*
// combinator: [ '>' | '+' | |