//----------------------------------------------------------------------------
//
//	Copyright (C) Microsoft Corporation 2005.  All Rights Reserved.
//
//	Project:	Windows Live Frameworks
//
//	File:		Gadgets.js
//
//  Description: This file can load and render gadgets
//
//----------------------------------------------------------------------------

//TO DO:
// 1) Wire up resize event when in isolation and auto-resize
// 2) Finish up modes

// Timestamp
var GadgetVersion = "0.060830.0";
//----------------------------------------------------------------------------
//
//	Singleton:	Web.Gadget
//
//	Synopsis:	Fetches binding definitions and related files
//
//----------------------------------------------------------------------------

registerNamespace("Web.Settings.GadgetHost");

// Settings (these must be declared before this script to properly override them)	

var __gh_s = Web.Settings.GadgetHost;

// Does the host support remembering the user security preference
__gh_s.rememberPreference = (__gh_s.rememberPreference!=null) ?  __gh_s.rememberPreference : true;

// Does the host support loading manifests from third-parties (this does not preclude resources from third parties)
__gh_s.supportThirdParty = (__gh_s.supportThirdParty!=null) ? __gh_s.supportThirdParty : true;

// This will force the add button to never be displayed
__gh_s.disableAddButton = (__gh_s.disableAddButton!=null) ?  __gh_s.disableAddButton : false;

__gh_s.gadgetUrl = __gh_s.gadgetUrl  ?  Web.Utility.resolveUrl(__gh_s.gadgetUrl) : "";

// TODO: This forces all third-party gadgets to load their security dialog in an iframe
// This will allow sites to load third-party gadgets from our host without requiring a proxy
// Live.com would override this to false
// __gh_s.isolateThirdParty = (__gh_s.isolateThirdParty!=null) ? __gh_s.isolateThirdParty : false;


__gh_s.frameGadget = (__gh_s.frameGadget!=null) ? __gh_s.frameGadget : true;




__gh_s.Module = function(p_objGadget)
{
	__gh_s.Module.initializeBase(this, arguments);
	this._gadget = p_objGadget;
}
//----------------------------------------------------------------------------
//
//	Base Class:	Live.Settings.GadgetHost.Module.propotype
//
//	Synopsis:	This interface contains the set of methods that 
//		must be defined on a ModuleHost.  These method will be
//		expected by gadget developers.  
//	
//	Remarks:	For more details, please see:
//				http://microsoftgadgets.com/livesdk/docs/apiref.htm#module
//
//----------------------------------------------------------------------------


__gh_s.Module.prototype = 
{
	getMode : function() {return this._gadget.getMode();},
	

	//----------------------------------------------------------------------------
	//
	//	Method:		deletePreference
	//
	//	Synopsis:	Removes a setting object that was previously set by the 
	//				setPreference method. 
	//
	//	Arguments:	strKey		- The key name of the preference to delete.
	//
	//	Returns:	nothing
	//
	//----------------------------------------------------------------------------
	deletePreference: function(strKey){this._gadget.getParams()[strKey] = null;},	
	//----------------------------------------------------------------------------
	//
	//	Method:		getId
	//
	//	Synopsis:	Returns the ID of the "div" element that contains the Gadget. 
	//
	//	Arguments:	none
	//
	//	Returns:	String representing the ID of the "div" DOM element object 
	//				that contains the Gadget.
	//
	//----------------------------------------------------------------------------
	getId: function()	{return this._gadget.getId();},	
	
	//----------------------------------------------------------------------------
	//
	//	Method:		getLink
	//
	//	Synopsis:	Returns the URL associated with the Gadget title. The URL 
	//				associated with the Gadget title is most commonly set by using 
	//				the "link" element in the Gadget manifest: 
	//					<?xml version="1.0"?>
	//					<rss version="2.0" xmlns:binding="http://www.live.com">
	//						<channel>
	//							<title>Hello World</title>
	//							<link>http://www.microsoft.com</link>
	//							...    
	//						</channel>
	//					</rss>      
	//
	//	Arguments:	none
	//
	//	Returns:	String representing URL associated with the Gadget title.
	//
	//	Note:		Inline Gadgets can also use setTitleLink to change the 
	//				Gadget title URL.
	//----------------------------------------------------------------------------
	getLink: function() {return this._gadget.getManifest().link;},
	
	
	//----------------------------------------------------------------------------
	//
	//	Method:		resize
	//
	//	Synopsis:	Resizes the Gadget based on the current context so that the 
	//				contents fit within the Gadget body. Note that this is usually 
	//				not needed when the Gadget is run with Internet Explorer. 
	//				However, for cross-browser compatibility, you should always 
	//				call this method whenever the contents of your Gadget changes 
	//				in a way that may require a resize.
	//
	//	Arguments:	none
	//
	//	Returns:	nothing
	//
	//----------------------------------------------------------------------------	
	resize : function()
	{	
		var m_this = this;
		function doResize()
		{
			if (m_this._gadget.isIsolated() && self!=top)
			{
					var elGadget = m_this._gadget.getGadgetElement();
					if (elGadget)
						elGadget.onresize = null;	// Avoid recursion
					try
					{
					    window.resizeTo(document.body.offsetWidth,document.documentElement.scrollHeight);
					}
					catch (ex)
					{}
					if (elGadget)
						elGadget.onresize= doResize;
			}
		}
		
		doResize();
	},
	
	//----------------------------------------------------------------------------
	//
	//	Method:		getPreference
	//
	//	Synopsis:	Returns a setting object previously stored via the setPreference 
	//				method. Settings are scoped to per user and per Gadget instance.
	//
	//	Arguments:	strKey		- The key name of the preference to get.
	//				objDefaultValue - The default value to return if no value is found.
	//
	//	Returns:	The setting object that was previously set using strKey. If such 
	//				a setting object does not exist, this method will return null.
	//
	//----------------------------------------------------------------------------	
	getPreference: function(strKey, objDefaultValue) {return (this._gadget.getParams()[strKey] || objDefaultValue);},	getPreferences : function() {return this._gadget.getParams()},
	//----------------------------------------------------------------------------
	//
	//	Method:		setPreference
	//
	//	Synopsis:	Sets a setting object that can be later retrieved using 
	//				the getPreference method.
	//
	//	Arguments:	strKey		- The key name of the preference to set.
	//				objSetting	- The setting object to be stored. Note that the 
	//								setting does not need to be an object, but also 
	//								be of any primitive data type or string.
	//
	//	Returns:	nothing
	//
	//----------------------------------------------------------------------------
	setPreference: function(strKey, objSetting){this._gadget.getParams()[strKey] = objSetting;},
	
	//----------------------------------------------------------------------------
	//
	//	Method:		getTitle
	//
	//	Synopsis:	Returns the title of the Gadget. The title of the Gadget is 
	//				most commoly set in the Gadget manifest. Inline Gadgets can 
	//				also use setTitleText to change the Gadget title.
	//
	//	Arguments:	none
	//
	//	Returns:	String representing the title of the Gadget.
	//
	//----------------------------------------------------------------------------	
	getTitle: function() {return this._gadget.getManifest().name;},

	//----------------------------------------------------------------------------
	//
	//	Method:		resolveUrl
	//
	//	Synopsis:	Resolves a relative URL with the location of the manifest URL 
	//				as the base location. 
	//
	//	Arguments:	strUrl		- Relative URL to be resolved.
	//
	//	Returns:	Absolute URL resolved according to the relative URL passed in 
	//				with the location of the manifest URL as the base. 
	//
	//----------------------------------------------------------------------------
	resolveUrl: function(strUrl){return Web.Utility.resolveUrl(strUrl, this._gadget.getManifest().url); },
		
	//----------------------------------------------------------------------------
	//
	//	Method:		setFooterText
	//
	//	Synopsis:	Inline Gadgets only. Sets the text used in the footer of the Gadget.
	//
	//	Arguments:	strFooter	- Text of the Footer to set.
	//
	//	Returns:	nothing
	//
	//----------------------------------------------------------------------------
	setFooterText: function(strFooter){},
	//----------------------------------------------------------------------------
	//
	//	Method:		setTitleIcon
	//
	//	Synopsis:	Inline Gadgets only. Sets the icon used in the title of the 
	//				Gadget.
	//
	//	Arguments:	objN	- An object that contains two properties: state and iconUrl. 
	//							The state can be one of {expanded, collapsed, all}. The 
	//							iconUrl should be an absolute URL that points to a valid 
	//							GIF file. If you want to use a relative URL for iconUrl, 
	//							you should use resolveUrl to convert the relative URL into 
	//							an absolute URL before passing it into this method.
	//
	//	Returns:	nothing
	//
	//	Remarks:    This method accepts a variable number of ojbects, each 
	//				containing two properties: state and iconUrl (as described
	//				above.)  For now, state can be one of {expanded, collapsed, all} 
	//				which sets the icon in the title bar for the Gadget in the 
	//				expanded, collapsed and all states, respectively. Note that 
	//				iconUrl should point to a valid .gif file.
	//
	//----------------------------------------------------------------------------	
	setTitleIcon: function(){},

	//----------------------------------------------------------------------------
	//
	//	Method:		setLink
	//
	//	Synopsis:	Inline Gadgets only. Sets the text used in the footer of the Gadget.
	//
	//	Arguments:	strUrl		- The absolute URL to set for the Gadget title.
	//
	//	Returns:	nothing
	//
	//----------------------------------------------------------------------------	
	setLink: function(strUrl){this._gadget.getManifest().link = strUrl},


	//----------------------------------------------------------------------------
	//
	//	Method:		setTitle
	//
	//	Synopsis:	Inline Gadgets only. Sets the title text of the Gadget.
	//
	//	Arguments:	strTitle	- The title text to set. 
	//
	//	Returns:	nothing
	//
	//----------------------------------------------------------------------------	
	setTitle: function(strTitleText) {if (this._gadget.hostMode=="frame") document.title = strTitleText;this._gadget.getManifest().name = strTitleText},

	//----------------------------------------------------------------------------
	//
	//	Method:		addHeaderAction
	//
	//	Synopsis:	Inline Gadgets only. Allows the adding of header actions 
	//				to the module rendering.  Action invocations will trigger
	//				a OnHeaderAction callback.  See Remarks for more details. 
	//
	//	Arguments:	enumActionType	- The type of action to add.  This must be a 
	//									value of the enum Web.Gadget.Actions.
	//				strTipText		- (optional) The text to use when the mouse hovers over the
	//									action.  This may contain addtional descriptive information
	//									and will appear in a tooltip-type UI.  This may also be 
	//									use as alt text if strAltText is not passed. 
	//				strImageUrl		- (optional, unless type is Custom) The image to 
	//									use for the header action.  This may or may not 
	//									be consumed by the gadget host.  For standard actions 
	//									(Add, Settings) null may be passed to use the 
	//									default image.  To use the altText or name instead, 
	//									pass ".".
	//				strCustomKey	- (optional) For custom actions, the additional key which 
	//									will be passed to the OnHeaderAction callback.
	//				strAltText		- (optional) The alt text for the action.  Will be set as
	//									alt text for the image passed in strImageUrl.  If 
	//									strImageUrl is passed as ".", should be used as the
	//									text of the action on the header (in place of an image.)  
	//
	//	Returns:	The DOM element associated w/ the header action added.
	//
	//	Remarks:	All header actions call into a common method named OnHeaderAction, with 
	//				the following signiture:
	//
	//						this.OnHeaderAction = function(enumActionType, strCustomKey)
	//
	//				If the gadget developer wishes to handle header actions, they must
	//				implement this method on their main binding.  The gadget host
	//				will invoke this method, passing the relevant values, whenever an
	//				action is invoked.  The gadget developer can then handle this and
	//				perform the necessary gadget-specific actions. 
	//	
	//----------------------------------------------------------------------------	
	addAction: function(enumActionType, strTipText, strImageUrl, strCustomKey, strAltText ){},

	//----------------------------------------------------------------------------
	//
	//	Method:		removeHeaderAction
	//
	//	Synopsis:	Inline Gadgets only. Removes a header action added with 
	//				addHeaderAction.
	//
	//	Arguments:	enumActionType	- The type of action to add.  This must be a 
	//									value of the enum Web.Gadget.Actions.
	//				strCustomKey	- For Custom actions, the associated custom
	//									key of the custom action to remove.
	//
	//	Returns:	The DOM element associated w/ the header action removed.
	//
	//----------------------------------------------------------------------------	
	removeAction: function(enumActionType, strCustomKey){},

	//----------------------------------------------------------------------------
	//
	//	Method:		getMode
	//
	//	Synopsis:	Gets the mode of the gadget. This will be a value of the
	//				Web.Gadget.Mode enum
	//
	//	Arguments:	none
	//
	//	Returns:	The mode of the gadget. 
	//
	//	Note:		Gadgets can be rendered in different modes.  Author mode
	//				means the gadget can be modified.  View mode means
	//				the gadget should be viewable, but not modifyable.
	//				See Web.Gadget.Mode for more details.	
	//
	//----------------------------------------------------------------------------	
	getMode : function() {return this._gadget.getMode();},		
	
	//----------------------------------------------------------------------------
	//
	//	Method:		getType
	//
	//	Synopsis:	Gets the type of gadget rendering. This will be a value of the
	//				Web.Gadget.Type enum
	//
	//	Arguments:	none
	//
	//	Returns:	The type of the gadget. 
	//
	//	Note:		Gadgets can have different types of rendering.  Internal gadgets
	//				are less restricted and can interact more w/ the page.  External
	//				gadgets render in a protected mode which is more restricted. 
	//				See Web.Gadget.External for more details.	
	//
	//----------------------------------------------------------------------------		
	getType : function() {return ((this._gadget.isIsolated()) ? Web.Gadget.Type.External : Web.Gadget.Type.Internal)},	
	
	getFooterEl : function() { return this._gadget.getFooter(); },
	
	getManifest : function(){return this._gadget.getManifest();}
	
}

__gh_s.Module.registerClass("Web.Settings.GadgetHost.Module");

Web.Gadget = new function()
{
	// Version for manifest comparison
	this.version = "1.0";

	var m_gm = this;
	// Track latest view state of a module
	var m_secureList = new Object();

	var m_gadgetUrl = Web.Utility.resolveUrl(__gh_s.gadgetUrl);
	var m_gadgetAddUrl = "http://www.live.com/?add={0}"
	var m_moduleLibUrl = "{framework.base}modLibrary.js";


	// Insecure is standard mode where the user did not confirm security (forces security if user wants to switch modes)
	this.view = m_views = Web.Enum.create("Standard","Custom","Insecure","Security","Frame","FrameSecure");
	
	// Used for module deployment in IE
	var m_intModule = 0;
	var m_arrModuleSource = [];

	// Global Events
	this.onrequestmanifest = Web.Event.create();
	this.onisolategadget = Web.Event.create();
	
	// Load and Error States
	this.ReadyState = Web.Enum.create("manifestloading","manifestcomplete","securing","gadgetsavestate","isolating","gadgetinitializing","gadgetloading","gadgetcomplete","error","gadgetcancel","rssviewer");
	this.ErrorState = Web.Enum.create("none","filemissing","parseerror","rssfeed","noplatform","noclassname","badparameters","thirdpartydisabled");
	this.Mode = Web.Enum.create("author","view");
	// Gadget Type

	this.Type = {External:0, Internal:1};
	// Manifest Type
	this.ManifestType = {Gadget:0, RSSGadget:1, RSSFeed:2, Module:3};

	function generateProxyObject(p_base,p_interfaces)
	{
		var y = new Function("this.constructor.initializeBase(this,arguments);");	// Use new Function to avoid scoping
		var args = [null,p_base];
		y.registerClass.apply(y,args);
		return y;
	}

	// Gadget Host Binding
	var GadgetHost = function(p_el, p_params, p_namespace)
	{
		GadgetHost.initializeBase(this, arguments);
		var m_objManifest = p_params.manifest;  // Gadget Manifest
		var m_url = Web.Utility.resolveUrl(m_objManifest.url);			// Gadget URL
		var m_params = p_params.params || {};	// Gadget Parameters
		
		if (!m_params.module)
		{
			if (m_params.moduleDef)
			{
				m_params.module = new m_params.moduleDef(this,m_objManifest.converted);
				m_params.moduleDef = null;
			}
			else
			{
				m_params.module = new __gh_s.Module(this); // Use default implementation
			}
		}
		
		p_params.gadgetHost = m_params.gadgetHost = m_params.module;
		var m_view = p_params.view==m_views.FrameSecure ? m_views.Security : p_params.view;				// Gadget View
		var m_cb = p_params.callback;			// Callbacks (fired for load state changes)
		var m_factory = null;					// The factory used to parse and execute the manifest
		var m_noisolation = p_params.view!=m_views.Frame && p_params.view!=m_views.FrameSecure;				// Whether the gadget has any resources requiring isolation (default is no isolated resources)
		var m_secure = (CheckSecure(m_url) && m_noisolation) || p_params.view==m_views.FrameSecure;		// Is the original manifest from a secure location
		var m_autosave = (m_view!=null);
		var m_gh = this;
		var m_mode = (m_params.mode && Web.Gadget.Mode.parse(m_params.mode)) || Web.Gadget.Mode.view;
		
		// Event object used for callbacks
		var ev = {returnValue:false,manifest: m_objManifest,params:m_params,url:m_objManifest.url,error:Web.Gadget.ErrorState.none,host:m_gh};
        
		DoCallback(m_cb,Web.Gadget.ReadyState.gadgetinitializing,ev);
	
		// Keyed array of source types
		var m_source = {"text/script":[],"text/xml":[],"text/css":[],"text/gadget":[]};
	
		var m_objCacheFeed = m_objManifest.rssFeed || {};	// Does the manifest have a feed
		m_objCacheFeed.defaults = {};
		for (var i in m_params)				// Copy parameters
			m_objCacheFeed[i] = m_params[i];
		var m_strType = "";					// The Gadget Type
		var m_gadgetLive;				// The "Live" gadget type 
		var m_elGadget;				// Reference to the bound element

		// Track for memory usage
		var m_elHref;				// The add to live button
        var m_this = this;
        
        m_params.title.innerHTML = "<h3>" + m_objManifest.name + "</h3>";
        m_params.icon.src = m_objManifest.headerIcon;
        if(!m_params.fullMode)
        {
            var removeBtn = m_params.title.parentNode.childNodes[2].childNodes[0];
            removeBtn.attachEvent("onclick",RemoveGadget);
        }
        else
        {
            if(m_params.removeBtn)
            {
                m_params.removeBtn.attachEvent("onclick",RemoveGadget);
                m_params.footer.appendChild(m_params.removeBtn);
            }
        }
        
        function RemoveGadget()
        {
            m_this.dispose();
        }
        //gadget get title , body , footer
        
		// Gadget Public Methods
		
		this.hostMode = m_params.hostmode;
		
		this.getGadgetElement = function()
		{
			return m_elGadget;
		};
		
		this.getFooter = function()
		{
		    return m_params.footer;
		}
		
		this.getTitle = function()
		{
		    return m_params.title;
		}
		
		this.getMarket = function() 
		{
			return m_params.mkt;
		}
		
		this.getLocale = function() 
		{
			return m_params.loc;
		}

		this.getLanguage = function() 
		{
			return m_params.lang;
		}
		
		this.getIsolated = function()
		{
			return (this.hostMode=="frame");
		}
		
		this.getParams = function()
		{
		    if(!m_params.params )
		    {
		        m_params.params = {};
		    }
			return m_params.params;
		}
		
		this.getView = function()
		{
			return m_view;
		}
		
		this.isIsolated = function()
		{
			return (p_params.params && p_params.params.isolated==Web.Gadget.Type.External)
		}
		
		this.getMode = function()
		{
			return m_mode;
		}

		this.getId = function()
		{
			return m_params.id;
		}
		
		this.getManifest = function()
		{
			return m_objManifest;
		}
		
		// 
		// Gadget Install Functions
		//

		function CheckSecure(m_url)
		{
			var strHost = Web.Utility.extractHost(m_url);	// The host domain of the gadget
			// Is the original manifest from a secure location
			return (strHost == "" || Web.Utility.extractHost(document.location) == strHost);
		}  // CheckSecure
		
		function CheckIsolation(p_isolation)
		{
			return (p_isolation=="" || p_isolation=="optional" || p_isolation=="shared")
		}  // CheckIsolation
	
		// Separate manifest references
		function CompileResources(p_objManifest,p_objLive)
		{
			m_secure = m_secure && CheckSecure(p_objManifest.url);
			if (__gh_s.gadgetUrl!="" && !m_secure)
				m_noisolation = Web.Utility.extractHost(p_objManifest.url)=="localhost" && m_noisolation && CheckIsolation(p_objLive.isolation)

			for (var strOption in p_objLive.defaults)
			{
				if (!m_objCacheFeed.defaults[strOption])
					m_objCacheFeed.defaults[strOption] = new String(p_objLive.defaults[strOption] || "")
				else
					m_objCacheFeed.defaults[strOption][m_strType] = p_objLive.defaults[strOption];
			} 
			
			var _r = p_objLive.references;
			for (var strReference in _r)
			{
				var objSource = m_source[strReference];
				if (objSource) objSource.addRange(_r[strReference])
			}
		}  // CompileResources

		// Walk inheritance list for resources
		function InheritResources(p_arrInherits)
		{
			if (p_arrInherits)	// TODO - Test inheritance
			{
				var iCount = p_arrInherits.length;
				for (var i=0;i<iCount;i++)
				{
					var item = p_arrInherits[i];
					var objInherit = Web.Gadget.Manifest.getType(item,"live")
					if (objInherit)
						CompileResources(item,objInherit);
				}
			}
		}   // InheritResources
		
		// Element is bound to gadget
		function BindComplete(p_objBinding)
		{
			ev.binding = p_objBinding;
			Callback(Web.Gadget.ReadyState.gadgetcomplete,ev);
			
			m_params.module.resize(); 
		}   // BindComplete
		
		// Load the Gadget
		function LoadGadgetAsBinding()
		{
			if (m_elGadget) Web.Bindings.removeBindings(m_elGadget);
			ClearChildMemory();
			p_el.innerHTML = "";
			m_elGadget = _ce("div");
			m_elGadget.className="GadgetBox";
			p_el.appendChild(m_elGadget);
			DoCallback(m_cb,Web.Gadget.ReadyState.gadgetloading,ev);
			if (m_objManifest.converted && m_params.legacyscript)
			{
				m_source["text/script"].push(m_params.legacyscript);
			}
			
			if (p_params.paramString)
				m_params.params = Object.fromJSON(p_params.paramString);
			
			//----------------------- For legacy -----------------------
			//This is for legacy support.  Gadgets that use the GetBindingParms/Serialize
			//	approach expect to see their serialized preferences in the p_args passed
			//	into the gadget on initialization.  We copy preferences here to enable
			//	that. 
			for(var prop in m_params.params)
			{
				m_objCacheFeed[prop] = m_params.params[prop];
			}
			m_objCacheFeed.onDashboard = !m_params.fullMode;
			//--------------------- End For Legacy ---------------------
			Web.Bindings.attachElementBinding(
						m_elGadget,
						m_strType,
						null,
						m_objCacheFeed,
						null,
						BindComplete,
						m_source["text/script"],
						m_source["text/css"],
						null,
						m_source["text/xml"]
					);
				
		}  // LoadGadgetAsBinding
		//
		// End Gadget Install
		//
	
/*		// Generate the Add to Live button
		function generateAddButton(strId)
		{
			// Only when not on Live.com
			// TODO: Need to update for inline modules to display button
			if (!m_querystring.host.endsWith("live.com")) || (!location.host.endsWith("live.com"));
			{
				m_elHref = _ce("A");
				m_elHref.target="_blank";
				var elAdd = _ce("img");
				m_elHref.className = "Web_Gadgets_Live";
				m_elHref.style.display = elAdd.style.display = "block";
				m_elHref.href = m_gadgetAddUrl.format(escape(m_url));
				m_elHref.title = Web.Gadget.Strings.getString("AddLiveTooltip");
				elAdd.src = Web.Gadget.Strings.getString("AddLiveImage");
				elAdd.width = "80";
				elAdd.height = "25";
				elAdd.border = "0";
				m_elHref.appendChild(elAdd);

			}	
		} // generateAddButton*/

		// Process callbacks
		function Callback(p_enumState)
		{
			// When complete add button
			if (p_enumState==Web.Gadget.ReadyState.gadgetcomplete)
			{
				// TODO: GenerateAddButton needs to be configurable 
//				if (!Web.Settings.GadgetHost.disableAddButton)
//					generateAddButton();
				if (m_elHref && p_el)
				{
					var elDiv = _ce("div");
					elDiv.style.clear = "both";
					p_el.appendChild(elDiv);
					elDiv.appendChild(m_elHref);
				}
				elButton = null; 
				if (m_gh.isIsolated() && self!=top)
				{
					m_params.module.resize();
				}					

			}
			
			if (m_cb)
				m_cb(p_enumState, ev)
		}  // Callback
			//
		// Manage Gadget Security
		//
		var SecurityManager = new function()
		{	
			// If not in secure list, default to insecure
			var m_currentView = m_view || m_secureList[m_url] || m_views.Insecure;
			if (m_currentView==m_views.Frame) m_currentView = m_secure ? m_views.Custom : m_views.Insecure;
			
			var m_sm = this;		// Reference to this object
			var m_rss = m_objManifest.manifestType === Web.Gadget.ManifestType.RSSGadget; // Gadget with feed
			var m_cancel;			// Cancel Button
			var m_ok;				// Install Button
			var m_save;				// Save Settings button
			var m_label;			// persist label
			var m_resecure;			// Switch modes link for RSS gadgets
			var m_blnApproved = false; // Has the gadget been approved
			var m_blnFramed = false; // Is the gadget framed
			var m_iframe;

			function OnResizeIFrame()
			{
			// This ensures the width stays at 100%, overriding any values set by the iframe content
				if (m_iframe.style.width != "100%")
					m_iframe.style.width = "100%";
			}
			
			
			function LoadIsolationContainer(p_view)
			{
				ClearChildMemory();
				p_el.innerHTML = "";
				var ev_isolate = {returnValue:m_gadgetUrl};
				m_gm.onisolategadget.fire(ev_isolate);
				if (ev_isolate.returnValue && ev_isolate.returnValue!=m_gadgetUrl)
					m_gadgetUrl = ev_isolate.returnValue;
				if (!m_gadgetUrl)
					throw new Error("External gadgets not supported")
				else
				{
					m_iframe = _ce("iframe");
					m_iframe.scrolling = Web.Browser.isMozilla() ? "yes" : "no";
					m_iframe.frameBorder = "0";
					m_iframe.allowTransparency = "true";
					m_iframe.style.background = "transparent";
					ev.scopeData = "m=" + escape(m_objManifest.url) + "&view=" + (p_view || m_views.Insecure) + "&host=" + escape(document.location.host) + "&mode=" + m_mode
					if (p_params.id) ev.scopeData+="&id=" + p_params.id;
					if (p_params.fullMode) ev.scopeData+="&fullMode=" + p_params.fullMode;
					if (p_params.loc) ev.scopeData+="&loc=" + escape(p_params.loc);
					if (p_params.mkt) ev.scopeData+="&mkt=" + escape(p_params.mkt);
					if (p_params.lang) ev.scopeData+="&lang=" + escape(p_params.lang);					
					if (p_params.paramString) 
					{
						ev.scopeData+="&params=" + escape(p_params.paramString);
					}
					else 
					{
						if (m_params.params)
						{
							ev.scopeData+="&params=" + escape(Object.toJSON(m_params.params));
						}
					}
					Callback(Web.Gadget.ReadyState.isolating,ev);
					m_iframe.src = m_gadgetUrl + "?b=" + escape(Web.Runtime.baseUrl) + "#" + ev.scopeData;
					p_el.appendChild(m_iframe);
					m_iframe.attachEvent("onresize", OnResizeIFrame);	// Need to expose this differently
				}
			}  // LoadIsolationContainer
			
			function DoSave()
			{
				if (m_autosave || (m_save && m_save.checked))
				{
					ev.view = m_currentView;
					DoCallback(m_cb,Web.Gadget.ReadyState.gadgetsavestate,ev);		
				}
			}  //DoSave
			
			function LoadGadgetInPlace(vType)
			{
				m_secureList[m_url] = vType;
				m_sm.initialize();
			}  // LoadGadgetInPlace

			function DisposeSecurity()
			{
				if (m_iframe)
				{
					m_iframe.detachEvent("onresize", OnResizeIFrame);
					m_iframe = null;
				}
				if (m_resecure)
					m_resecure = m_resecure.onclick = null;
				if (m_cancel) 
				{
					m_cancel = m_cancel.onclick = null;
				}
				if (m_save)
				{
					m_save = m_save.onclick = null;
				}
				if (m_ok)
				{
					m_ok = m_ok.onclick = null;
				}
				if (m_label)
				{
					m_label = m_label.onclick = null;
				}
			}  // DisposeSecurity

			function DisplayStandardUx()
			{
				if (m_rss)
				{
					DisposeModeSwitch();

					m_secureList[m_url] = m_views.Standard;
					if (!m_resecure)
					{
						m_resecure = _ce("DIV");
						m_resecure.className = "Web_Gadgets_RSSMode"
						p_el.insertAdjacentElement("beforeEnd",m_resecure);
						m_resecure.style.cursor = "hand";
					}
					if (m_currentView==m_views.Standard)
					{
						m_resecure.innerHTML = Web.Gadget.Strings.getString("CustomExperience");
						if (m_resecure.previousSibling && m_resecure.previousSibling.firstChild) 
						{
							m_resecure.previousSibling.firstChild.style.position = "static"; // Temporary hack
						}
					}						
					else
						m_resecure.innerHTML = Web.Gadget.Strings.getString("StandardExperience");

					m_resecure.onclick = ResetView;
				}
			}  // DisplayStandardUx


			function DisposeModeSwitch()
			{
				if (m_resecure)
				{
					m_resecure.removeNode(true);
					m_resecure = m_resecure.onclick  = null;
				}
			}  // DisposeModeSwitch
			
			function DoDefault()
			{
				ClearChildMemory();
				p_el.innerHTML = "";
				DoCallback(m_cb,Web.Gadget.ReadyState.rssviewer,ev);		
			}  //DoDefault
			
			function ResetView()
			{
				if (m_currentView==m_views.Custom)
				{
					m_currentView = m_views.Standard;
					DoSave();
					DoDefault();
					DisplayStandardUx();
				}
				else
				{
					if (!m_blnApproved)
					{
						m_currentView = m_views.Security;
						DoSave();
						DisplaySecurity();
					}
					else
					{
						DisplayGadget();
					}
				}
			}  // ResetView
			
			function DisplayGadget()
			{
				m_blnApproved = true;
				m_currentView = m_views.Custom;
				DoSave();									
				DisposeSecurity();
				ClearChildMemory();
				p_el.innerHTML = "";
				if (!m_blnFramed && __gh_s.frameGadget)
				{
					if (m_params.hostmode!="frame" && !m_noisolation)
						LoadIsolationContainer(m_views.Custom);		
					else
					{
						m_factory(p_el,m_objManifest,Callback,p_params);			
					}
				}
				else
				{
					if (m_params.hostmode!="frame")			
						LoadGadgetInPlace(m_views.Standard);
					else
						LoadGadgetInPlace(m_views.Custom);
				}		
				if (m_rss)
					DisplayStandardUx();

			}  // DisplayGadget

			function DisplaySecurity()
			{
				ClearChildMemory();
				var elMessage = _ce("div");
				m_cancel = _ce("input");
				if (m_resecure)
				{
					m_resecure.onclick = null;
					m_resecure.removeNode(true);
					m_resecure = null;
				}
				if (m_rss)
				{
					elMessage.innerHTML = "<P><span class='Web_Gadget_Warning'>" + Web.Gadget.Strings.getString("TrustedGadget01") + "</span><P>" + Web.Gadget.Strings.getString("TrustedGadgetRss01") + " <EM><div style='width:100%;overflow:hidden'>" + m_url.replace("<","&lt;") + "</div></EM> " + Web.Gadget.Strings.getString("TrustedGadgetRss02") + " <P class='Web_Gadget_Desc'>" + (m_objManifest.description || Web.Gadget.Strings.getString("TrustedGadgetNoDesc")) + "<P>" + Web.Gadget.Strings.getString("TrustedGadgetRss03");				
					m_cancel.value = Web.Gadget.Strings.getString("TrustedGadgetStd");				
				}
				else
				{
					elMessage.innerHTML = "<P><span class='Web_Gadget_Warning'>" + Web.Gadget.Strings.getString("TrustedGadget01") + "</span><P>" + Web.Gadget.Strings.getString("TrustedGadget02") + " <EM><div style='width:100%;overflow:hidden'>" + m_url.replace("<","&lt;") + "</div></EM>" + Web.Gadget.Strings.getString("TrustedGadget03") + " <P class='Web_Gadget_Desc'>" + (m_objManifest.description || Web.Gadget.Strings.getString("TrustedGadgetNoDesc")) + "<P>" + Web.Gadget.Strings.getString("TrustedGadget04");
					m_cancel.value = Web.Gadget.Strings.getString("TrustedGadgetRemove");
					m_cancel.style.margin = "5px 5px";				
				}
				m_cancel.onclick = function() 
				{
					if (m_rss)
					{
						m_currentView = m_views.Standard;
						DoSave();
						DoDefault();
						DisplayStandardUx();						
					}
					else
					{
						m_currentView = m_views.Insecure
						DoSave();					
						ClearChildMemory();
						p_el.innerHTML = "";
						m_sm.dispose();
						Callback(Web.Gadget.ReadyState.gadgetcancel);
					}
				}
				m_ok = _ce("input");
				m_ok.style.marginTop = "5px";
				m_ok.style.marginBottom = "5px";
				m_ok.value = Web.Gadget.Strings.getString("TrustedGadgetInstall");
				m_ok.type = m_cancel.type = "button";			
				var elSaving;
				m_ok.onclick = function()
				{
					DisplayGadget();
				}
				p_el.innerHTML = "";
				p_el.appendChild(elMessage)
				p_el.appendChild(m_ok);
				p_el.appendChild(m_cancel);
				if (__gh_s.rememberPreference)
				{
					elSaving = _ce("div");
					m_save = _ce("input");
					m_save.type = "checkbox";
					m_label = _ce("label");
					m_label.innerText = " " + Web.Gadget.Strings.getString("TrustedGadgetRemember");
					p_el.appendChild(elSaving);
					elSaving.appendChild(m_save);
					elSaving.appendChild(m_label);
					if (Web.Browser.isIE())
					{
						m_save.id = "m" + m_label.uniqueID;
						m_label.htmlFor = m_save.id;
					}
					else
					{
						m_label.onclick = function()
						{
							m_save.focus();
						}
					}

					m_save.checked = m_autosave;
				}
			}  // DisplaySecurity
			
		
			function Secure(p_bln)
			{
				m_blnFramed = p_bln;
				switch (m_currentView)
				{
					case m_views.Custom: // Custom (Gadget View)
						if (__gh_s.frameGadget && !m_noisolation)
							LoadIsolationContainer(m_currentView);
						else
							m_factory(p_el,m_objManifest,Callback,p_params);
						DisplayStandardUx();
						break;
					case m_views.Standard: // RSS View (for RSS feeds)
						if (m_rss)
						{
							DoDefault();
							DisplayStandardUx();
						}
						else
							DisplaySecurity();						
						break;
					case m_views.Insecure:  // Security
					default:
						DisplaySecurity();
						break;
				}
				
				if (m_blnFramed && self!=top)	// Frames and contained (don't resize if top window)
					m_params.module.resize();
			}  // Secure

			this.initialize = function()
			{
				// CLEANUP SECURITY
				// TODO - Make sure that you callback can override security settings
				Callback(Web.Gadget.ReadyState.securing);		

				// Cleanup memory
				
				if (m_elGadget)
					Web.Bindings.removeBindings(m_elGadget);
				m_secure = (ev.secure!=null) ? ev.secure : m_secure;

				if (m_secure && m_noisolation)
				{
					m_factory(p_el,m_objManifest,Callback,p_params);
				}
				else if (!m_secure && (m_noisolation) && (!p_params.params || (p_params.params.isolated==null || p_params.params.isolated!=Web.Gadget.Type.External)))
				{
					m_secureList[m_objManifest.url] = m_views.Standard;
					Secure(false);
				}
				else if (m_noisolation)
				{
					if (typeof(m_secureList[m_objManifest.url])=="undefined")
						m_secureList[m_objManifest.url] = p_params.view;
					if (m_secureList[m_objManifest.url]==m_views.Custom)
						m_factory(p_el,m_objManifest,Callback,p_params);
					else
						Secure(true);			
				}
				else if (m_secure && !m_noisolation)
				{
					m_view = m_secureList[m_objManifest.url] = m_views.Custom;
					LoadIsolationContainer(m_currentView);
				}
				else
				{
					Secure(false);		
				}		
			}  // SecurityManager.initialize
		

		
			this.dispose = function()
			{
				DisposeSecurity();
				DisposeModeSwitch();
			} // SecurityManager.dispose
		} // SecurityManager

		this.initialize = function(p_objScope)
		{
			GadgetHost.getBaseMethod(this, "initialize", "Web.Bindings.Base").call(this, p_objScope);
			if (m_objManifest.manifestType==Web.Gadget.ManifestType.Module)		
			{
			
				m_factory = ModuleManager.attachElementManifest;
				SecurityManager.initialize();
			}
			else
			{
				m_factory = LoadGadgetAsBinding;
				
				if (!m_objManifest)	DoErrorCallback(m_cb,Web.Gadget.ErrorState.badparameters,ev);
				m_gadgetLive = Web.Gadget.Manifest.getType(m_objManifest,"live");
				if (!m_gadgetLive) DoErrorCallback(m_cb,Web.Gadget.ErrorState.noplatform,ev);	// No Live manifest
				m_strType = m_gadgetLive.className; // This is the binding type we are instantiating
				if (!m_strType) DoErrorCallback(m_cb,Web.Gadget.ErrorState.noclassname,ev);		
			
				CompileResources(m_objManifest,m_gadgetLive);
				InheritResources(m_objManifest.inheritsFrom);		
				SecurityManager.initialize();
			}
		} // GadgetHost.initialize
		
		function ClearChildMemory()
		{
			SecurityManager.dispose();
			if (m_elHref)
			{
				m_elHref = m_elHref.onclick = null;
			}
			
		} // ClearChildMemory
		
		this.dispose = function(p_blnUnload)
		{
			GadgetHost.getBaseMethod(this, "dispose", "Web.Bindings.Base").call(this, p_blnUnload);
			if (m_elGadget)
			{
				Web.Bindings.removeBindings(m_elGadget);
			}
			p_params.gadgetHost = m_params.gadgetHost = m_params.module = null;
			ClearChildMemory();
			p_el = m_elGadget = m_factory = p_el.onresize = null;
		} // GadgetHost.dispose
	}
	GadgetHost.Params = Web.Enum.create("module");
	GadgetHost.Events = Web.Enum.create("onsavestate");
	GadgetHost.registerSealedClass(null,"Web.Bindings.Base");

	this.getViewState = function(p_strUrl)
	{
		return m_secureList[p_strUrl];
	} // Web.Gadget.getViewState

	function DoErrorCallback(p_cb,p_errorState,ev)
	{
		ev.error = p_errorState;
		DoCallback(p_cb,Web.Gadget.ReadyState.error,ev);
	} // DoErrorCallback

	function DoCallback(p_cb,p_enumState,ev)
	{
		if (p_cb)
			p_cb(p_enumState,ev);
	} // DoCallback


	this.loadManifest = function(p_url, p_params, p_cb)
	{
		// Event Object for callbacks
		var ev = {returnValue:false,manifest: null,params:p_params,url:p_url,error:Web.Gadget.ErrorState.none};
		
		var m_objManifest;		// Parsed Manifests
		var m_objRequests = {};			// Executing Requests - used to cleanup memory if page unloads
		var m_intDefinitions = 0;		// Count of definitions
		var m_objCacheFeed = {};		// Cache the XML Feed
		var m_blnRssExperience = false;
		var _rs = Web.Gadget.ReadyState;

		function OnDefinitionReceived(p_xmlResponse, context)
		{
			delete m_objRequests[context.url];
			var root = Web.Utility.getDocumentRoot(p_xmlResponse);	// Get the Root Element
			var rssInfo;			// Parsed RSS
			var gadgetInfo;		// Gadget Manifest
			var gadgetLive;		// Live Fragment of Gadget Manifest
			var blnDoc = (root!=null);

			if (!root)
			{
			    root = Web.Gadget.Manifest.extract(p_xmlResponse.responseText,p_url);
			    
				if (root)
				{
					blnDoc = true;
				}
			}//*/
			
			if (!blnDoc && (!p_xmlResponse || (p_xmlResponse.status != 200 || !root)))
			{
				DoErrorCallback(p_cb,Web.Gadget.ErrorState.filemissing,ev);
				CleanupMemory();				
				return;
			}
			switch (root.tagName)
			{
				case "rss": // Handle Compatibility
					rssInfo = Web.Rss.parse(root,true,p_url);
					rssInfo.url = p_url;
					// Display error if empty feed
					if (rssInfo.channels.length == 0 || rssInfo.channels[0].items.length == 0)
					{
						DoErrorCallback(p_cb,Web.Gadget.ErrorState.parseerror,ev);
						CleanupMemory();								
						return;
					}					
					if (!m_blnRssExperience)
					{
						m_objCacheFeed.feed = rssInfo;
						m_objCacheFeed.feedUrl = rssInfo.url;
						m_objCacheFeed.xml = p_xmlResponse;
					}
					if (!Web.Rss.isManifest(rssInfo)) // RSS Feed - Do Default
					{	
						if (Web.Rss.isRSSWithManifest(rssInfo))	// RSS Feed with manifest 
						{
							m_intDefinitions--;	
							m_blnRssExperience = true;
							Download(rssInfo.channels[0].binding.manifest);
						}
						else									// Standard RSS Feed
						{
							m_objManifest = m_objCacheFeed;
							m_objManifest.manifestType = Web.Gadget.ManifestType.RSSFeed;
							ev.manifest = m_objManifest;
							DoErrorCallback(p_cb,Web.Gadget.ErrorState.rssfeed,ev);
							CleanupMemory();				
						}
						return;						
					}
					else
					{
						gadgetInfo = Web.Rss.convertToManifest(rssInfo,p_url);
						if (m_blnRssExperience)
							gadgetInfo.manifestType = Web.Gadget.ManifestType.RSSGadget;
					}
					break;
				case "Module":	// Module
				case "gadget":	// Gadget
					ev.manifest = gadgetInfo = Web.Gadget.Manifest.parse(root,p_url,true);
					break;
				default:	// Not a manifest
					DoErrorCallback(p_cb,Web.Gadget.ErrorState.parseerror,ev);
					CleanupMemory();								
					return;

			}

			if (!gadgetInfo)
			{
				DoErrorCallback(p_cb,Web.Gadget.ErrorState.noplatform,ev);
				return;
			}

			if (!m_objCacheFeed.xml)
			{
				m_objCacheFeed.xml = p_xmlResponse;		
			}
			
			if (gadgetInfo.manifestType!=Web.Gadget.ManifestType.Module)
			{
				gadgetLive = Web.Gadget.Manifest.getType(gadgetInfo,"live");
				if (!gadgetLive)
				{					
					DoErrorCallback(p_cb,Web.Gadget.ErrorState.noplatform,ev);
					return;			
				}

				if (!m_objManifest)
				{
					m_objManifest = gadgetInfo;
					m_objManifest.rssFeed = m_objCacheFeed;
					
				}
				else
				{
					if (!m_objManifest.inheritsFrom)
						m_objManifest.inheritsFrom = [gadgetInfo];
					else
						m_objManifest.inheritsFrom.push(gadgetInfo);
				}
				if (gadgetLive && gadgetLive.references)
				{
					var objRef = gadgetLive.references["text/gadget"];
					if (objRef)
						for (var i=0;i<objRef.length;i++)
						{
							Download(objRef[i]);
						}
				}
				m_intDefinitions--;	// Decrement counter (after making sure additional requests are made)
				if (m_intDefinitions == 0)	// When no more classes - instantiate
				{
					ev.manifest = m_objManifest;
					DoCallback(p_cb,_rs.manifestcomplete,ev);
					CleanupMemory();								
				}	
			}
			else
			{
				ev.manifest = gadgetInfo;
				DoCallback(p_cb,_rs.manifestcomplete,ev);
			}
		} // OnDefinitionReceived
		
		
		function Download(p_url)
		{
			p_url = Web.Utility.resolveUrl(p_url); 
			if (!m_objRequests[p_url])	// Cache for memory usage tracking
			{
				m_intDefinitions++;
				if (!p_params) p_params = {};
				p_params.url = p_url;
				if (!__gh_s.supportThirdParty && Web.Utility.extractHost(p_url)!=document.location.host)
				{
					DoErrorCallback(p_cb,Web.Gadget.ErrorState.thirdpartydisabled,ev);
				}
				else
				{
					var r = Web.Network.createRequest(
						Web.Network.Type.XML,
						p_url,
						p_params,
						OnDefinitionReceived
					);

					m_objRequests[p_url] = r;
									
					r.execute();
				}
			}
		
		} // Download
		
		function CleanupMemory()
		{
			for (var r in m_objRequests)
			{
				try 
				{
					m_objRequests[r].abort();
				}
				catch (ex) {}
				m_objRequests[r] = null;
			}
		} // CleanupMemory
		
		function Init()  
		{
			m_gm.onrequestmanifest.fire(ev);
			if (!ev.returnValue)
			{
				DoCallback(p_cb,_rs.manifestloading,ev);
				Download(p_url);
			}
			else
			{
				objManifest = ev.manifest;
				setTimeout(DoCallback,1);
			}
			Web.Runtime.onunload.attach(CleanupMemory);
		} // Init
		Init();
	}  // Web.Gadget.loadManifest
	

	// Module Management
	
	// Used to asynchronously "write" code into the iframe
	// IE will not enforce serialized load order of scripts. 
	// This function forces a pause until each script is loaded
	// This should never be called explicitly (it is a "private" public method that needs to be available to the external window)
	
	var m_regScript = new RegExp("<script","i");
	var m_regEndScript = new RegExp("</script>","i");
	
	this.loadNext = function(el,w,id)
	{
		if (el.readyState=="complete")
		{
			var blnInScript = false;
			var strLine = m_arrModuleSource[id].dequeue();
			while (strLine!=null)
			{
				m_regScript.lastIndex = 0;
				if (!blnInScript)
				{
					strLine = strLine.replace(m_regScript,"<script onreadystatechange='parent.Web.Gadget.loadNext(this,window," + id + ")' ");
					if (m_regScript.lastIndex>0)
						blnInScript = true;
				}
				w.document.writeln(strLine);
				if (blnInScript)
				{
					if (strLine.match(m_regEndScript))
					{
						return;
					}
				}
				strLine = m_arrModuleSource[id].dequeue();
			}
			w.document.close();
		}
	}  // Web.Gadget.loadNext

	// The Module Factory
	var ModuleManager = new function()
	{
		function UpdateCode(p_strArgument, p_strSource, p_strValue)
		{
			var strExp = "__UP_" + p_strArgument + "__";
			var strReg = new RegExp(strExp, "g");
			return p_strSource.replace(strReg, p_strValue);
		} // UpdateCode

		function GenerateSettings(p_objManifest, params)
		{
			var elDiv = null;
			var strForm = new Web.StringBuilder();
			var blnSettings = false;
			strForm.append("<table>");
			for (var i in p_objManifest.UserPref)
			{

				if (params && params[i]) 
					p_objManifest.UserPref[i].defaultValue = params[i];
				blnSettings = true;
				strForm.append("<tr><td class=\"Module_Setting_Label\">");
				strForm.append("<label for=\"{0}{1}\">".format(i,m_intModule) + p_objManifest.UserPref[i] + ":</label></td><td>");
				var _pref = p_objManifest.UserPref[i];
				switch (_pref.datatype)
				{
					case "bool":
						strForm.append("<input id=\"{0}{2}\" name=\"{0}\" type=\"checkbox\" {1}>".format(i,_pref.defaultValue=="true" ? "checked" : "",m_intModule));
						break;
					case "enum":
						strForm.append("<select id=\"{0}{1}\" name=\"{0}\">".format(i,m_intModule));
						for (var j in _pref.enumList)
						{
							strForm.append("<option value=\"{0}\" {1}>{2}</option>".format(_pref.enumList[j],_pref.enumList[j]==_pref.defaultValue ? "selected" : "",j));
						}
						strForm.append("</select>");
						break;
					default:
						strForm.append("<input id=\"{0}{3}\" name=\"{0}\" value=\"{1}\" class=\"{2}\" {4}>".format(i,_pref.defaultValue,"Module_Setting" + ((_pref.required) ? "_Required" : ""),m_intModule,_pref.dataType=="hidden" ? "readonly" : ""));
				}
				strForm.append("</td></tr>");
			}
			strForm.append("</table>");
			strForm.append("<input type=\"submit\" value=\"Save\">");
			if (blnSettings)
			{
				var elSettings = _ce("a");
				elSettings.innerText = Web.Gadget.Strings.getString("Edit");
				elSettings.className = "Module_Setting_Edit";
				elSettings.href = "#";
				elDiv = _ce("div");
				elDiv.className = "Module_Setting_Container";
				elDiv.appendChild(elSettings);

				elSettings.onclick = function()
				{
					elSettings.form.style.display = elSettings.form.style.display=="" ? "none" : "";
	
					if (self!=top)
						window.resizeTo(document.body.offsetWidth,document.body.scrollHeight)
					if (elSettings.form.style.display =="") // Fix IE painting Issue
					{
					    for (var i=0;i<elSettings.form.length;i++)
					    {
					        elSettings.form[i].style.display = "none";
					        elSettings.form[i].style.display = "inline";
					    }
					}
					return false;
				}
				var elForm = _ce("form");
				elForm.className = "Module_Setting_Form";
				elForm.innerHTML = strForm;
				elDiv.style.textAlign="right";
				elDiv.appendChild(elForm);
				elForm.style.textAlign="left";
				elSettings.form = elDiv.form = elForm;
			}
			return elDiv;
		}  // GenerateSettings
		
		function HtmlEncode(s)
		{
			return s.replace(/</g,"&lt;").replace(/>/g,"&gt;")
		}  // HtmlEncode
		
		function generateContents(iframe,p_objManifest)
		{
			if (p_objManifest.Content.url)
			{
				var strUrl = p_objManifest.Content.url;
				for (var i in p_objManifest.UserPref)
				{
					strUrl = UpdateCode(i,strUrl,escape(p_objManifest.UserPref[i].defaultValue));
				}
				var inSearch = strUrl.indexOf("?")>-1;
				var url = strUrl + (inSearch ? "&" : "?") + "w=" + iframe.offsetWidth + "&h=" + iframe.offsetHeight;
				for (var i in p_objManifest.UserPref)
				{
					url+="&" +  p_objManifest.UserPref[i].urlparam + "=" + escape(p_objManifest.UserPref[i].defaultValue);
				}
				iframe.src = url;
			}
			else
			{
				var doc = iframe.contentWindow.document;
				var strHtml = p_objManifest.Content.html;
				doc.open("text/html");
				doc.writeln("<html><head><style>html,body {margin:0px;padding:0px}</style>");
				doc.writeln("<base href=\"{0}\">".format(Web.Utility.extractHost(p_objManifest.url,true)));
				doc.writeln("<script>");
				doc.writeln("var __MODULE_ID__=0;");
				doc.writeln("var __prefs = new function() {");
				for (var i in p_objManifest.UserPref)
				{
					if (p_objManifest.UserPref[i].datatype=="bool")
					{
						doc.writeln("this['" + i + "'] = " + (p_objManifest.UserPref[i].defaultValue=="true" ? "\"true\"" : null)  + ";");
					}
					else
					{
						doc.writeln("this['" + i + "'] = \"" + escape(p_objManifest.UserPref[i].defaultValue)  + "\";");
						strHtml = UpdateCode(i,strHtml,HtmlEncode(p_objManifest.UserPref[i].defaultValue));
					}
				}
				
				doc.writeln("}");
				doc.writeln("</" + "script>");
				if (Web.Browser.isIE())
				{
					m_arrModuleSource[m_intModule] = strHtml.split("\n")
					doc.writeln("<script onreadystatechange=\"parent.Web.Gadget.loadNext(this,window," + m_intModule + ")\" type='text/javascript' src='" + Web.Utility.resolveUrl(m_moduleLibUrl) + "'></" + "script>");
					m_intModule++;					
				}
				else
				{
					doc.writeln("<script type='text/javascript' src='" + m_moduleLibUrl + "'></" + "script>");
					doc.writeln(strHtml);
					doc.close();
				}
				
			}
		} // generateContents

		function ValidateSettings(p_objManifest)
		{
			var m_valid = true;
			for (var i in p_objManifest.UserPref)
			{
				m_valid = m_valid && (!p_objManifest.UserPref[i].required || p_objManifest.UserPref[i].defaultValue)
			}
			return m_valid;
		}  // ValidateSettings

		this.attachElementManifest = function(p_el, p_objManifest, p_cb, p_params)
		{
			p_el.innerHTML = "";
			var ev = {returnValue:false,manifest: p_objManifest,params:null,url:p_objManifest.url,error:Web.Gadget.ErrorState.none};
		
			if (p_objManifest.ModulePref.render_inline=="required")
			{
				p_el.innerText = Web.Gadget.Strings.getString("ModuleUnsupported");
				return;
			}
			if (p_objManifest.ModulePref.live=="disabled")
			{
				p_el.innerText = Web.Gadget.Strings.getString("ModuleDisabled");
				return;			
			}
			if (p_params.params && p_params.params.params)
				for (var i in p_params.params.params)
				{
					if (p_objManifest.UserPref[i])
						p_objManifest.UserPref[i].defaultValue = p_params.params.params[i]
				}
			var m_container = _ce("div");
			p_el.appendChild(m_container);
			var elDiv = GenerateSettings(p_objManifest, p_params.params);
			if (elDiv)
				m_container.appendChild(elDiv);

			var iframe = _ce("iframe");
			iframe.allowTransparency = "true";
			iframe.style.background = "transparent";				
			iframe.height = p_objManifest.ModulePref.height || "200px";
			if (p_params.params.hostmode=="frame" && self!=top)
			{
				window.resizeTo(document.body.offsetWidth,document.body.scrollHeight + parseInt(iframe.height))
			}			
			iframe.style.width= "90%";
			iframe.frameBorder = 0;
			iframe.style.clear = "both";
			iframe.scrolling = p_objManifest.ModulePref.scrolling=="true" ? "auto" : "no";
			var blnValidate = ValidateSettings(p_objManifest);
			if (!blnValidate)
			{
				iframe.style.display = "none";
				elDiv.form.style.display = "";
			}
			else
			{
				if (elDiv && elDiv.form)
					elDiv.form.style.display = "none";
			}

			m_container.appendChild(iframe);


			if (blnValidate)
				generateContents(iframe,p_objManifest)
				
			if (elDiv && elDiv.form)
			{
				elDiv.form.onsubmit = function()
				{
					var elForm = elDiv.form;
					var objPersist = {};
					for (var i=0;i<elForm.length;i++)
					{
						var strName = elForm[i].name;
						if (p_objManifest.UserPref[strName])
						{
							if (elForm[i].type=="select")
							
								p_objManifest.UserPref[strName].defaultValue = elForm[i][elForm[i].selectedIndex].value;
							else
							if (elForm[i].type=="checkbox")
							{
								p_objManifest.UserPref[strName].defaultValue = elForm[i].checked ? "true" : "false";
							}
							else
								p_objManifest.UserPref[strName].defaultValue = elForm[i].value;
							p_params.params[strName] = p_objManifest.UserPref[strName].defaultValue;
							if (p_params.params[strName]!= p_objManifest.UserPref[strName].initialValue && p_params && p_params.gadgetHost)
							{
								p_params.gadgetHost.setPreference(strName,p_objManifest.UserPref[strName].defaultValue)
							}
						}
					}
					
					
					if (ValidateSettings(p_objManifest))
					{
						iframe.style.display = "";
						elForm.style.display = "none";
						generateContents(iframe,p_objManifest);
					}
					return false;
				}		
			}
			DoCallback(p_cb,Web.Gadget.ReadyState.gadgetcomplete,ev);			
		}	// ModuleManager.attachElementManifest
	} // ModuleManager

	this.attachObjectManifest = function(p_el, p_objManifest, p_params, p_view, p_cb)
	{
		var blnManifest = Web.Rss.isManifest(p_objManifest);
		if (!p_params) p_params = {};
		if (blnManifest)
			p_objManifest = Web.Rss.convertToManifest(p_objManifest);
		Web.Bindings.attachElementBindingSync(p_el, GadgetHost, null,{loc:p_params.loc,mkt:p_params.mkt,lang:p_params.lang,fullMode:p_params.fullMode,id:p_params.id,paramString:p_params.paramString,manifest:p_objManifest,params:p_params, view:p_view, callback:p_cb,module:p_params.module});		
	}

	this.attachElementManifest = function (p_el, p_url, p_params, p_view, p_cb)
	{

		var m_objAttach = this;
		if (!p_params) p_params = {};
		function FinishedLoading(p_state,ev)
		{
			if (p_cb)
				p_cb(p_state,ev);
			if (p_state == Web.Gadget.ReadyState.manifestcomplete && ev.manifest)
			{
				Web.Bindings.attachElementBindingSync(p_el, GadgetHost, null,{loc:p_params.loc,mkt:p_params.mkt,lang:p_params.lang,fullMode:p_params.fullMode,id:p_params.id,paramString:p_params.paramString,manifest:ev.manifest,params:p_params, view:p_view, callback:p_cb,module:p_params.module,title:p_params.title,footer:p_params.footer});
			}
		}
		this.loadManifest(p_url,null,FinishedLoading);
	} // Web.Gadget.attachElementManifest

////
	this.Interfaces = new function()
	{
		this.IEditable = function()
		{
			this.doEdit = Function.abstractMethod;
		}
		
		this.IRefreshable = function()
		{
			this.refresh = Function.abstractMethod;
		}
		
		this.ICustom  = function()
		{
		}
		
	}//*/
}  // Web.Gadget

Web.Gadget.Interfaces.IEditable.registerInterface("Web.Gadget.Interfaces.IEditable");
Web.Gadget.Interfaces.IRefreshable.registerInterface("Web.Gadget.Interfaces.IRefreshable");
Web.Gadget.Interfaces.ICustom.registerInterface("Web.Gadget.Interfaces.ICustom");//*/

Web.Gadget.Actions = Web.Enum.create("Add","Settings");


// Simple localization class
Web.Strings = function()
{
	this.markets = {};
	this.getString = function(id,args)
	{
		var strCu = this.markets[Web.Runtime.culture] || this.markets[Web.Runtime.culture][id] || this.markets["en-US"];
		var strCu = strCu && strCu[id];
		var strUs = (this.markets["en-US"] && this.markets["en-US"][id]);
		var strString = (strCu || strUs || (id + ": Missing String"));
		if (args) // Cheaper way to determine optional arguments 2-n
		{
			strString = strString.format.apply(strString,arguments);
		}
		return strString;	
	} // Web.Strings.getString
} // Web.Strings

Web.Strings.registerClass("Web.Strings");


Web.Gadget.Binding = function(p_el, p_args, p_strNamespace)
{
	Web.Gadget.Binding.initializeBase(this,arguments);	

	function SplitHash()
	{
		var objItems = {};
		var str = document.location.hash.substring(1);
		function splitEqual(strItem)
		{
			var arrItem = strItem.split("=");
			if (arrItem[0])
				objItems[arrItem[0].toLowerCase()] = unescape(arrItem[1]);
		}
		if (str)
		{
			var arrPairs = str.split("&").forEach(splitEqual);
		}
		return objItems;
	}  //SplitHash
	
	var m_querystring = p_args;
	var m_isolated = true;			
	var elWrapper;	
	var _rs = Web.Gadget.ReadyState;

	m_querystring.m = unescape(m_querystring.m || m_querystring.manifestUrl); // legacy compat.
	function DoGadgetReadyState(p_enumState, ev)
	{
		if (p_enumState==_rs.manifestcomplete)
		{
			//document.title = ev.manifest.name;
		}
		else
			if (p_enumState==_rs.error && ev.error==Web.Gadget.ErrorState.noplatform && ev.manifest.sidebar && !ev.manifest.live )
				p_el.innerHTML = Web.Gadget.Strings.getString("VistaOnly");
	}
	
	// Memory Management
	this.dispose = function(p_blnUnload)
	{
		Web.Gadget.Binding.getBaseMethod(this,"dispose","Web.Bindings.Base").call(this,p_blnUnload)	
		if (elWrapper)
			elWrapper = null;
	}  // DisposeHost
	m_querystring.m = p_args.m;
	
    var m_title = p_args.title;
    var m_body =  p_args.body;
    var m_footer= p_args.footer;
    var m_icon  = p_args.icon ? p_args.icon : null;
    
    if(m_querystring.fullMode)
    {
        p_el.className = "Modual_Popup";
        m_title.parentNode.className = "titleBar_Popup";
        m_footer.className = "Footer_Popup";
    }
        
	if (m_querystring.m != "undefined")
	{
		elWrapper = _ce("div");
		elWrapper.style.position = "relative";
		var elChild = _ce("div");
		if(m_body)
		{
		    m_body.appendChild(elWrapper);
		}
		else
		{
		    document.body.insertAdjacentElement("beforeEnd",elWrapper)
		}
		elWrapper.appendChild(elChild);
		var m_params = 
		{
			legacyscript : p_args.legacyscript || null,
			mode : m_querystring.mode || null,
			view : m_querystring.view || null,
			hostmode : p_args.hostmode || null,
			id : p_args.id || m_querystring.id || p_el.id,
			fullMode : m_querystring.fullMode || false,
			mkt : m_querystring.mkt || null,
			loc : m_querystring.loc || null,
			lang : m_querystring.lang || null,
			params : m_querystring.params && Object.fromJSON(m_querystring.params),
			title : m_title,
			footer : m_footer,
			icon : m_icon,
			keyword : m_querystring.keyword ,
			removeBtn : m_querystring.removeBtn || null
		};
		if (p_args.module)
		{
			var fn;
			m_params.moduleDef = eval("fn=" + p_args.module);
			m_params.isolated = Web.Gadget.Type.External;
		}
		Web.Gadget.attachElementManifest(elChild,m_querystring.m,m_params,m_querystring.view,DoGadgetReadyState);
	
	}
	else
	{
		document.body.innerHTML = "Missing Manifest";
	}
}
Web.Gadget.Binding.registerClass("Web.Gadget.Binding","Web.Bindings.Base");
Web.Gadget.Binding.Params = Web.Enum.create("module","legacyscript","hostmode");

// Localized Strings
// To register additional markets strings, in subsequent script define Web.Gadgets.Strings.markets["market"] = {string list}
Web.Gadget.Strings = new function()
{
	function GadgetStrings()
	{
		GadgetStrings.initializeBase(this, arguments);
		
		this.markets["en-US"] = {
			CustomExperience:"Switch to Custom Experience",
			StandardExperience:"Switch to Standard Experience",
			TrustedGadget01:"<b>Only install Gadgets from trusted sites.</b>",
			TrustedGadget02:"This a custom Gadget from",
			TrustedGadget03: "Below is a description of the Gadget:",
			TrustedGadgetNoDesc:"No Description",
			TrustedGadget04:"This 3rd party gadget has not been reviewed by Microsoft.  It could potentially access data in another 3rd party gadget, include code that is possibly unsafe and may change behavior at any time. <b>Do you trust this site and want to install this Gadget?</b>",
			TrustedGadgetRss01:"This RSS feed loaded from",
			TrustedGadgetRss02:"wants to load a custom gadget. The Gadget presents a customized experience for this feed. Below is a description of the feed:",
			TrustedGadgetRss03:"This 3rd party gadget has not been reviewed by Microsoft.  It could potentially access data in another 3rd party gadget, include code that is possibly unsafe and may change behavior at any time. <b>Do you trust this site and want to install this Gadget?</b>",
			TrustedGadgetRemove:"Remove",
			TrustedGadgetStd:"Standard View",
			TrustedGadgetInstall:"Install Gadget",
			TrustedGadgetRemember:"Remember my preference",
			Loading:"loading...",
			Error:"Unable to retrieve data, please try again.",
			UnableToLoadFeed:"Oops, we seem to be having a problem with this feed.  Please try again later.",
			AddLiveImage:"/img/wl.gif",
			AddLiveTooltip:"Add this gadget to Live.com",
			ModuleUnsupported:"Modules that require inlining are not supported.",
			ModuleDisabled:"This gadget has been disabled by the author.",
			VistaOnly:"This gadget is only supported on the Vista Sidebar",
			Edit:"Edit"
		};  // GadgetStrings.markets
	};	 // GadgetStrings
	GadgetStrings.registerSealedClass(null,"Web.Strings");
	
	return new GadgetStrings();
} // Web.Gadget.Strings
//----------------------------------------------------------------------------
//
//	Method:		Web.Parser.getTextProperty
//
//	Synopsis:	Returns text property of a node (compatible with Opera)
//
//	Arguments:	obj					- object
//
//	Returns:	string
//
//----------------------------------------------------------------------------

registerNamespace("Web.Parser");

Web.Parser.getTextProperty = function(obj)
{
	if (obj.text == "")
		return "";
	else
		return obj.text || obj.textContent;
}  // Web.Parser.getTextProperty


registerNamespace("Web.Gadget.Manifest");

// "Private" shared function
Web.Gadget.Manifest._ParseIcons = function(objManifest, elItem,strUrl)
{
	var icons = objManifest.icons = [];
	var kCount = elItem.childNodes.length;
	var _wpgt = Web.Utility.getTextProperty;
	var wuru = Web.Utility.resolveUrl;

	for (var k=0; k < kCount; k++)
	{
		var nk = elItem.childNodes[k];
		if (nk.nodeName.toLowerCase() == "icon")
		{
			var height, width, url, tmp;

			url = _wpgt(nk);
			if (url == null || url == "")
			{
				continue;
			}

			tmp = nk.getAttribute("height");
			height = tmp != null ? parseInt(tmp, 10) : 0;

			tmp = nk.getAttribute("width");
			width = tmp != null ? parseInt(tmp, 10) : 0;

			icons.push({height:height, width:width, url:wuru(url,strUrl)});
		}
	}

	if (icons.length == 1)
	{
		objManifest.headerIcon = objManifest.listIcon = icons[0].url;
	}
	else
	{
		icons.sort(function(a, b) {return a.height - b.height;});
		
		for (var k = 0; k < icons.length; k++)
		{
			if (objManifest.listIcon == null && icons[k].height >= 16)
			{
				objManifest.listIcon = icons[k].url;
			}
			if (objManifest.headerIcon == null && icons[k].height >= 32)
			{
				objManifest.headerIcon = icons[k].url;
			}
		}
	}
}  // Web.Gadget.Manifest._ParseIcons

Web.Gadget.Manifest.parse = function(response, baseUri, isRoot)
{
	var objRoot = isRoot ? response : Web.Utility.getDocumentRoot(response);
	
	if (!objRoot)  // Google pretty formats gadgets - get the manifest
	{				
		objRoot = Web.Gadget.Manifest.extract(response.responseText,baseUri);
    }//*/
    
	var objManifest = new Object();
	objManifest.url = baseUri;
	var _wpgt = Web.Parser.getTextProperty;
	function ParseGadget()
	{
		objManifest.manifestType = Web.Gadget.ManifestType.Gadget;
		var intCount = objRoot.childNodes.length;
		for (var i = 0;i < intCount;i++)
		{
			var elItem = objRoot.childNodes[i];
			switch (elItem.tagName)
			{
				case "name":
				case "link":
				case "description":
					objManifest[elItem.tagName] = new String(_wpgt(elItem) || "");
					objManifest[elItem.tagName].resourceID = elItem.getAttribute("resourceID");
					break;
				case "docs":
				case "version":
				case "email":
				case "pubDate":
				case "lastBuildDate":
				case "copyright":				
					objManifest[elItem.tagName] = _wpgt(elItem);
					break;
				case "icons":
					Web.Gadget.Manifest._ParseIcons(objManifest,elItem);
					break;
			
				case "hosts":
					var hostCount = elItem.childNodes.length;
					for (var h=0;h<hostCount;h++)
					{
						var hostItem = elItem.childNodes[h];
						objManifest.types = new Object();
						var strPlatform = hostItem.getAttribute("name");
						if (strPlatform=="sidebar")
						{
							objManifest.sidebar = true;
						}
						else if (strPlatform=="live")
						{
							objManifest.live = true;
							var objType = objManifest.types[strPlatform.toLowerCase()] = {};
							objType = objType[hostItem.getAttribute("version") || ".1"] = {}; // Default to .1 if no version
							objType.defaults = {};
							var jCount = hostItem.childNodes.length;
							for (var j=0;j<jCount;j++)
							{
								var elTypeNode = hostItem.childNodes[j];
								var intTypeCount = elTypeNode.childNodes.length;
								var objResource = objType[elTypeNode.tagName] = new Object();
								switch (elTypeNode.tagName)
								{
									case "references":
										objType.className = elTypeNode.getAttribute("class");
										objType.isolation = (elTypeNode.getAttribute("isolation") || "").toLowerCase();								
									case "interfaces":
									case "services":
										for (var k=0;k<intTypeCount;k++)
										{
											var elAdd = elTypeNode.childNodes[k];
											if (elAdd.tagName=="add")
											{
												var strUri = elAdd.getAttribute("src");
												if (strUri)
												{
													strUri=Web.Utility.resolveUrl(strUri,Web.Utility.resolveUrl(baseUri));
													if (elTypeNode.tagName=="references")
													{
														var key = elAdd.getAttribute("type") || "text/script";
														if (!objResource[key]) objResource[key] = [];
														var val = strUri;
														if (key=="text/xml")
														{
															val = new String(strUri);
															val.name = elAdd.getAttribute("name")
														}
														objResource[key].push(val);
													}
													else
													{
														var objItem = objResource[strUri] = {};
														objItem.acl = elAdd.getAttribute("acl");
														objItem.name = elAdd.getAttribute("name");										
													}
												}
												else
												{
													if (elTypeNode.tagName=="interfaces")
													{
														var strInterface = elAdd.getAttribute("type");
														if (strInterface!=null)
														{
															var objInterface = Web.Gadget.Manifest._InterfaceMap[strInterface.toLowerCase()];
															if (objInterface)
															{
																var objItem = objResource[strUri] = {};											
																objItem.type = objInterface;
																objItem.strType = strInterface;
																objItem.title = elAdd.getAttribute("title");
																objItem.icon = elAdd.getAttribute("icon");
															}
														}
													}
												}
											}
										}
										break;
									case "defaults":
										for (var k=0;k<intTypeCount;k++)
										{
											var elParam = elTypeNode.childNodes[k];
											if (elParam.tagName=="param")
												objResource[elParam.getAttribute("name")] = elParam.getAttribute("value");
										}
										break;
								}
							}
						}
					}
					break;
			}
		}
	}  // ParseGadget */

	function ParseModule()
	{
		objManifest.manifestType = Web.Gadget.ManifestType.Module;
		objManifest.UserPref = {};
		objManifest.ModulePref = {};
		objManifest.Content = {};
		var iCount = objRoot.childNodes.length;
		for (var i=0;i<iCount;i++)
		{
			var elNode = objRoot.childNodes[i];
			switch (elNode.tagName)
			{
				case "ModulePrefs":
					var jCount = elNode.attributes.length;
					for (var j=0;j<jCount;j++)
					{	
						var elA = elNode.attributes[j];
						objManifest.ModulePref[elA.nodeName] = elA.nodeValue;
					}
					objManifest.description = objManifest.ModulePref.description;
					objManifest.name = objManifest.ModulePref.directory_title || objManifest.ModulePref.title;				
					objManifest.link = objManifest.ModulePref.title_url;
					break;
				case "UserPref":
					var strName = elNode.getAttribute("name");
					if (strName)
					{
						var strItem = objManifest.UserPref[strName] = new String(elNode.getAttribute("display_name") || strName);
						strItem.initialValue = objManifest.UserPref[strName].defaultValue = elNode.getAttribute("default_value") || "";
						strItem.required = elNode.getAttribute("required")=="true" ||  false;
						strItem.datatype = elNode.getAttribute("datatype") || "";
						strItem.urlparam = elNode.getAttribute("urlparam") || ("up_" + strName);
						if (strItem.datatype=="enum")
						{
							var objEnum = strItem.enumList = {};
							var jCount = elNode.childNodes.length;
							for (var j=0;j<jCount;j++)
							{
								var elN = elNode.childNodes[j];
								objEnum[elN.getAttribute("display_value") || elN.getAttribute("value") ] = elN.getAttribute("value") || elN.getAttribute("display_value") 
							}
						}
					}
					break;
				case "Content": 
					var strType = elNode.getAttribute("type");
					if (strType=="url")
					{
						objManifest.Content[strType] = elNode.getAttribute("href");
					}
					else
					{
						objManifest.Content[strType] = _wpgt(elNode);
					}
					break;
			}
		}		
	} // ParseModule
	switch (objRoot.tagName)
	{
		case "gadget":
			ParseGadget();
			break;
		case "Module":
			ParseModule();
			break;
	}
	
	return objManifest;
}  // Web.Gadget.Manifest.parse
Web.Gadget.Manifest._InterfaceMap = {"irefreshable":Web.Gadget.Interfaces.IRefreshable,"icustom":Web.Gadget.Interfaces.ICustom,"ieditable":Web.Gadget.Interfaces.ICustom};
///
Web.Gadget.Manifest.extract = function(p_str,p_url)
{
    var root = null;
    var s = "";
	if (p_url.startsWith("http://base.google.com"))  // Google pretty formats gadgets - get the manifest
	{				
		s = p_str.replace(/(&lt;\?xml(?:.|\n)*&lt;\/Module&gt;)/i);
		s =
			RegExp.$1
			.replace(/^<br>/gim, '')
			.replace(/&lt;/gi, '<')
			.replace(/&gt;/gi, '>')
			.replace(/&quot;/gi, '"')
			.replace(/&amp;/gi,"&");
		var xmlResponse = new DOMParser();
		xmlResponse = xmlResponse.parseFromString(s);
		root = xmlResponse.documentElement;
	}
	return root;
}//*/

Web.Gadget.Manifest.getType = function(p_manifest,p_environment)
{
	var objType = null;
	var fltVersion = -1.0;
	var _env = (p_manifest && p_manifest.types && p_manifest.types[p_environment]) || null;
	if (_env)
	{
		for (var objItem in _env)
		{

			if (parseFloat(objItem)>fltVersion && parseFloat(objItem)<=Web.Gadget.version)
			{
				objType = _env[objItem];
				fltVersion = objItem;
			}
		}
	}

	return objType;
}  // Web.Gadget.Manifest.getType

//----------------------------------------------------------------------------
//
//	Method:		Web.Rss.parse
//
//	Synopsis:	Parses an RSS 2.0 feed
//
//	Arguments:	response			- xml response
//
//	Returns:	Parsed RSS Object
//
//----------------------------------------------------------------------------


registerNamespace("Web.Rss");

Web.Rss.isManifest = function(p_objParser)
{
	return (p_objParser && p_objParser.channels && p_objParser.channels[0].binding.type!=null);
} // Web.Rss.isManifest

Web.Rss.isRSSWithManifest = function(p_objParser)
{
	return (p_objParser && p_objParser.channels && p_objParser.channels[0].binding.manifest!=null);
} // Web.Rss.isRSSWithManifest

Web.Rss.convertToManifest = function(p_objParser,p_strBaseUri)
{
	var objManifest = null;
	var objChannel = p_objParser.channels[0];

	if (objChannel) 
	{
		objManifest = {};
		objManifest.url = Web.Utility.resolveUrl(p_strBaseUri);
		objManifest.converted = true;
		var arrRes = ["title","link","description","pubDate","lastBuildDate","docs"];
		var arrDest = ["name","link","description","pubDate","lastBuildDate","docs"];
		var iCount = arrRes.length;
		for (var i=0;i<iCount;i++)
		{
			var sCh = arrRes[i];
			var s = arrDest[i];
			if (objChannel[sCh])
			{
				objManifest[s] = new String(objChannel[sCh] || "");
				objManifest[s].resourceID = objChannel[sCh].resourceID;
			}
		}
		objManifest.image = objChannel.image;
		if (objManifest.image)
			for (var strItem in objChannel.image)
				objManifest.image[strItem] = objChannel.image[strItem];
		objManifest.types = {};
		var l = objManifest.types.live = {};
		l[".1"] = {};
		l[".1"].defaults = objChannel.defaults || {};
		l[".1"].className = objChannel.binding.type;
		l[".1"].isolation = objChannel.binding.renderInline ? "optional" : "none";
		objManifest.headerIcon = objChannel.headerIcon;
		objManifest.listIcon = objChannel.listIcon;


		var objRef = objManifest.types.live[".1"].references = {};
		var iCount = objChannel.items.length;
		var wuru = Web.Utility.resolveUrl;
		for (var i = 0; i < iCount; i++)
		{
			m_strSources = objChannel.items[i].link;
			if (m_strSources)
			{
				var strPath = wuru(m_strSources,objManifest.url);
				var key;
				var val = strPath;
				if (strPath)
				{
					switch (m_strSources.type)
					{
						case "text/css":
						case "css":
							key = "text/css";
							break;
						case "text/xml":
						case "xml":
							key = "text/xml";
							val = new String(strPath);
							val.name = m_strSources.name;							
							break;
						case "inherit":	// Inheriting from another definition
							key = "text/gadget";
							break;
						default:	// Build source list - order of files does not matter
							key = "text/script";
							break;
					}	
				}
				if (!objRef[key])
					objRef[key] = [];
				objRef[key].push(val);				
			}
		}		
	}
	return objManifest;
} // Web.Rss.isRSSWithManifest

Web.Rss.parse = function(response, isRoot, p_url)
{
	function IsAdUrl(url)
	{
		var adStrings = ["//ads\.", "/adclick", "/ads/", "/c.gif"];
		var re = new RegExp(adStrings.join("|"), "im");
		return (re.exec(url) ? true : false);
	}  // IsAdUrl


	var root = isRoot ? response : Web.Utility.getDocumentRoot(response);
	var objParser;
	var _wpgt =Web.Utility.getTextProperty;
	if (root)
	{
		objParser = {};
		objParser.channels = [];
		var iCount = root.childNodes.length;
		for (var i = 0; i < iCount; i++)
		{
			var ni = root.childNodes[i];
			
			if (ni.nodeName == "channel")
			{
				var objChannel = {};
				objChannel.items = [];
				objChannel.binding = {};
				objChannel.binding.type = null;
				objParser.channels.push(objChannel);
				var channelAttribs = {};
			
				// Add attributes
				var a = ni.attributes;
				for (var j = 0; j < a.length; j++)
					channelAttribs[a[j].nodeName] = a[j].nodeValue;
				objChannel.attribs = channelAttribs;

				// Find title element of channel
				var jCount = ni.childNodes.length;
				for (var j = 0; j < jCount; j++)
				{
					var nj = ni.childNodes[j];
					switch (nj.nodeName)
					{
						case "title":
						case "link":
							objChannel[nj.nodeName] = new String(_wpgt(nj) || "");
							objChannel[nj.nodeName].resourceID = nj.getAttribute("resourceID");
							break;

						case "class":
						case "binding:type":
							objChannel.binding.type = _wpgt(nj);
							break;
						case "binding:options":
 							if (nj.getAttribute("renderInline"))
							{
								objChannel.binding.renderInline = nj.getAttribute("renderInline").toLowerCase()=="true";
							}
							break;
							
						case "binding:manifest":
							objChannel.binding.manifest = _wpgt(nj);
							break;
													
						case "image":
							objChannel.image = new Object();
							var kCount = nj.childNodes.length;
							for (var k=0;k<kCount;k++)
							{
								var nk = nj.childNodes[k];
								objChannel.image[nk.nodeName] = _wpgt(nk);
							}
							break;

						case "defaults":
							objChannel.defaults = {};
							var kCount = nj.childNodes.length;
							for (var k=0;k<kCount;k++)
							{
								var elParam = nj.childNodes[k];
								if (elParam.tagName=="param")
									objChannel.defaults[elParam.getAttribute("name")] = elParam.getAttribute("value");
							}

						case "icons":
							Web.Gadget.Manifest._ParseIcons(objChannel,nj,p_url);
							break;

						case "item":
							var objItem = {};
						
							objItem.images = [];
							// Extract info
							var kCount = nj.childNodes.length;
							for (var k = 0; k < kCount; k++)
							{
								var nk = nj.childNodes[k];
								
								switch (nk.nodeName)
								{
									case "title":
									case "description":
									case "pubDate":
									case "guid":
										objItem[nk.nodeName] = _wpgt(nk);
										break;
									
									case "feedburner:origLink":
									case "link":
										var l = objItem.link = new String(_wpgt(nk) || "");
										l.type = nk.getAttribute("binding:type") || nk.getAttribute("type");
										l.name = nk.getAttribute("binding:name") || nk.getAttribute("name");

									case "source":
										var s = objItem.source = new String(_wpgt(nk) || "");
										s.url = nk.getAttribute("url");
										break;
									case "enclosure":
										var e = objItem.enclosure = new String(nk.getAttribute("url") || "");									
										if (objItem.enclosure.length > 0)
										{										
											e.encUrl = nk.getAttribute("url");
											e.encLength = nk.getAttribute("length");
											e.encType = nk.getAttribute("type");
											var enclosureHtml = "<embed autostart=\"false\" type=\"{0}\" src=\"{1}\" />";
											var mimeBaseType = e.encType.split("/")[0];
											if ((mimeBaseType == "image" || mimeBaseType == "img") && objItem.enclosure.encUrl)
											{
												objItem.images.push(objItem.enclosure.encUrl);
												enclosureHtml = "<img src=\"{1}\" />";
											}
											e.html = enclosureHtml.format(objItem.enclosure.encType, objItem.enclosure.encUrl);
										}
										
										break;			
									default:
									{
										objItem[nk.nodeName] = new String(_wpgt(nk) || "");
										
										for (var l = 0; l < nk.childNodes.length; l++)
										{
											var nl = nk.childNodes[l];
											objItem[nk.nodeName][nl.nodeName] = _wpgt(nl);
										}
									}
									
								}
							}
							if (!objItem.title)
								title = "Default Title";
							else
								if (objItem.title.substring(0,4) == "ADV:")
									continue;

							if (!objItem.link && objItem.guid && objItem.guid.substring(0,7) == "http://")
								objItem.link = objItem.guid;

							if (objItem.description)
							{
								var element = _ce("div");
								element.innerHTML = objItem.description;
								var imgEls = element.getElementsByTagName("img");
								var zCount = imgEls.length;
								for (var z = 0; z < zCount; z++)
								{
									var url = imgEls[z].src;
									if ((!IsAdUrl(url)) && (objItem.images.indexOf(url) == -1))
									{
										objItem.images.push(url);
									}
								}
							}
							objChannel.items.push(objItem);
							break;
						default:
							objChannel[nj.nodeName] = new String(_wpgt(nj));						
					}
				}
			}
		}
	}	
	return objParser;
}  // Web.Rss.parse


//----------------------------------------------------------------------------
//
//	Method:		Web.Utility.getTextProperty
//
//	Synopsis:	Returns text property of a node (compatible with Opera)
//
//	Arguments:	obj					- object
//
//	Returns:	string
//
//----------------------------------------------------------------------------

Web.Utility.getTextProperty = function(obj)
{
	if (obj.text == "")
		return "";
	else
		return obj.text || obj.textContent;
} // Web.Utility.getTextProperty

//----------------------------------------------------------------------------
//
//	Method:		Web.Utility.getDocumentRoot
//
//	Synopsis:	Retrieves reference to root of document
//
//	Arguments:	response			- xml response
//
//	Returns:	document root if no errors, else null
//
//----------------------------------------------------------------------------
Web.Utility.getDocumentRoot = function(response)
{
	var root = null;
	if (!response)
		return null;

	if (response.responseText.length == 4)	// Firefox hack
	{
		return null;
	}

	if ((!response.responseXML || response.responseXML.xml == "") && (response.status!=404))
	{
		// Try reloading the stream as the content-type from the server may not be text/xml
		try
		{
			var doc = new ActiveXObject("Microsoft.XMLDOM");
			doc.loadXML(response.responseText);
			root = doc.documentElement;
		}
		catch (e)
		{
			root = null;
		}
	}
	else
	{
		try
		{
			root = response.responseXML.documentElement;
		}
		catch (e)
		{
			root = null;
		}
	}
		
	return root;
} // Web.Utility.getDocumentRoot
