String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g,""); };
var kProtocol_clsid = "clsid:";

if (!RealNetworks)
    var RealNetworks = {};

RealNetworks.RPBrowserEmbeddedObjectUtils = {};

function ClsidToParamNameAndMimeTypeObject(sClsid, sParamName, sMimeType)
{
    this.sClsid = sClsid;
    this.sParamName = sParamName;
    this.sMimeType = sMimeType;
}

// RPBrowserEmbeddedObjectUtils Member variables -----------------------------------------------------------

RealNetworks.RPBrowserEmbeddedObjectUtils.kClsidsToParamNameAndMimeType =
    [
        new ClsidToParamNameAndMimeTypeObject("D27CDB6E-AE6D-11cf-96B8-444553540000", "movie",      "application/x-shockwave-flash"),   // Flash
        new ClsidToParamNameAndMimeTypeObject("CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA", "src",        "audio/x-pn-realaudio-plugin"),     // RealPlayer
        new ClsidToParamNameAndMimeTypeObject("02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "src",        "video/quicktime"),                 // QuickTime
        new ClsidToParamNameAndMimeTypeObject("6BF52A52-394A-11d3-B153-00C04F79FAA6", "url",        "application/x-mplayer2"),          // WindowsMedia
        new ClsidToParamNameAndMimeTypeObject("22D6F312-B0F6-11D0-94AB-0080C74C7E95", "filename",   "application/x-mplayer2"),          // WindowsMedia
        new ClsidToParamNameAndMimeTypeObject("05589FA1-C356-11CE-BF01-00AA0055595A", "filename",   "application/x-mplayer2")           // WindowsMedia
    ];

RealNetworks.RPBrowserEmbeddedObjectUtils.kRecordableMediaMimeTypes =
    [
        "video/x-flv",                     // Flash
        "video/flv",
        "video/flash",
        "audio/mpeg",
        "audio/x-pn-realaudio-plugin",     // RealPlayer
        "application/vnd.rn-realav",
        "video/quicktime",                 // QuickTime
        "application/x-mplayer2",          // WindowsMedia
        "application/asx",
        "video/x-ms-asf",
        "video/x-ms-asf-plugin",
        "video/x-ms-wm",
        "audio/x-ms-wma",
        "audio/x-ms-wax",
        "video/x-ms-wmv",
        "video/x-ms-wvx"
    ];

RealNetworks.RPBrowserEmbeddedObjectUtils.kMoveNetworksMimeType =
    [
        "application/x-vnd.moveplayer.qm", // MoveNetworks
        "application/x-vnd.moveplay2.qm",
        "application/x-vnd.movenetworks.qm"
    ];

RealNetworks.RPBrowserEmbeddedObjectUtils.kKnownPluginMimeType =
    [
        "application/x-shockwave-flash",   // Flash
    ];
RealNetworks.RPBrowserEmbeddedObjectUtils.kKnownPluginMimeType = RealNetworks.RPBrowserEmbeddedObjectUtils.kKnownPluginMimeType.concat(RealNetworks.RPBrowserEmbeddedObjectUtils.kMoveNetworksMimeType);
RealNetworks.RPBrowserEmbeddedObjectUtils.kKnownPluginMimeType = RealNetworks.RPBrowserEmbeddedObjectUtils.kKnownPluginMimeType.concat(RealNetworks.RPBrowserEmbeddedObjectUtils.kRecordableMediaMimeTypes);

// RPBrowserEmbeddedObjectUtils Functions -------------------------------------------------------
RealNetworks.RPBrowserEmbeddedObjectUtils.IsMoveNetworksElement = function(oElem)
{
    var isMoveNetworks = false;
    if (oElem && oElem.type)
    {
        var type = oElem.type.toLowerCase();
        for (var x = 0; !isMoveNetworks && x < RealNetworks.RPBrowserEmbeddedObjectUtils.kMoveNetworksMimeType.length; x++)
        {
            isMoveNetworks = (type == RealNetworks.RPBrowserEmbeddedObjectUtils.kMoveNetworksMimeType[x]);
        }
    }
    return isMoveNetworks;
};

RealNetworks.RPBrowserEmbeddedObjectUtils.IsKnownPluginMimeType = function(sMimeType)
{
    if (!sMimeType || sMimeType.length <=0)
    {
        return false;
    }
    
    for (var x = 0; x < RealNetworks.RPBrowserEmbeddedObjectUtils.kKnownPluginMimeType.length; ++x)
    {
        if (RealNetworks.RPBrowserEmbeddedObjectUtils.kKnownPluginMimeType[x].toLowerCase() == sMimeType.toLowerCase())
        {
            return true;
        }
    }
    return false;
};

RealNetworks.RPBrowserEmbeddedObjectUtils.IsRecordableMediaMimeType = function(sMimeType)
{
    if (!sMimeType || sMimeType.length <=0)
    {
        return false;
    }
    
    for (var x = 0; x < RealNetworks.RPBrowserEmbeddedObjectUtils.kRecordableMediaMimeTypes.length; ++x)
    {
        if (RealNetworks.RPBrowserEmbeddedObjectUtils.kRecordableMediaMimeTypes[x].toLowerCase() == sMimeType.toLowerCase())
        {
            return true;
        }
    }
    return false;
};

RealNetworks.RPBrowserEmbeddedObjectUtils.GetFieldFromClsid = function(sClsid, sFieldName)
{
    if (!sClsid || sClsid.length <=0 || !sFieldName || sFieldName.length <= 0)
    {
        return null;
    }

    sClsid.trim();
    sClsid = sClsid.toLowerCase();

    // Removing the clsid protocol
    if (sClsid.substr(0,kProtocol_clsid.length) == kProtocol_clsid.toLowerCase())
    {
        sClsid = sClsid.substr(kProtocol_clsid.length, sClsid.length);
    }

    // returning the field name value if we find the Clsid
    for (var x = 0; x < RealNetworks.RPBrowserEmbeddedObjectUtils.kClsidsToParamNameAndMimeType.length; ++x)
    {
        if (sClsid == RealNetworks.RPBrowserEmbeddedObjectUtils.kClsidsToParamNameAndMimeType[x].sClsid.toLowerCase())
        {
            return RealNetworks.RPBrowserEmbeddedObjectUtils.kClsidsToParamNameAndMimeType[x][sFieldName];
        }
    }

    return null;
};

RealNetworks.RPBrowserEmbeddedObjectUtils.GetParamNameContainingUrl = function(sClsid)
{
    return RealNetworks.RPBrowserEmbeddedObjectUtils.GetFieldFromClsid(sClsid, "sParamName");
};

RealNetworks.RPBrowserEmbeddedObjectUtils.GetClsidFromMimeType = function(sTheMimetype)
{
    for (var x = 0; x < RealNetworks.RPBrowserEmbeddedObjectUtils.kClsidsToParamNameAndMimeType.length; ++x)
    {
        if (sTheMimetype == RealNetworks.RPBrowserEmbeddedObjectUtils.kClsidsToParamNameAndMimeType[x].sMimeType.toLowerCase())
        {
            return RealNetworks.RPBrowserEmbeddedObjectUtils.kClsidsToParamNameAndMimeType[x].sClsid;
        }
    }
    return "";
};

RealNetworks.RPBrowserEmbeddedObjectUtils.GetMimeTypeFromClsid = function(sClsid)
{
    return RealNetworks.RPBrowserEmbeddedObjectUtils.GetFieldFromClsid(sClsid, "sMimeType");
};

// Extra Utilities
RealNetworks.RPBrowserEmbeddedObjectUtils.GetExtensionFromUrl = function(sUrl)
{
    if (!sUrl || sUrl.length <= 0)
    {
        return false;
    }
    
    var sExtension = "";

    // Trimming the query string
    var sUrlWithoutQueryString = sUrl;
    var iIndexOfQuery = sUrl.indexOf("?");
    if (iIndexOfQuery > -1)
    {
        sUrlWithoutQueryString = sUrl.substr(0, iIndexOfQuery);
    }
    
    // Finding the extension of the file
    var iLastIndexOfDivider = sUrlWithoutQueryString.lastIndexOf("/");
    if (iLastIndexOfDivider > -1)
    {
        var sFilename = sUrlWithoutQueryString.substr(iLastIndexOfDivider+1, sUrlWithoutQueryString.length);
        var iLastIndexOfPeriod = sFilename.lastIndexOf(".");
        if (iLastIndexOfPeriod > -1)
        {
            sExtension = sFilename.substr(iLastIndexOfPeriod+1, sFilename.length).toLowerCase();
            sExtension.trim();
        }
    }
    return sExtension;
};

RealNetworks.RPBrowserEmbeddedObjectUtils.IsFlashClsid = function(sClsid)
{
    return sClsid == "D27CDB6E-AE6D-11cf-96B8-444553540000";
};

RealNetworks.RPBrowserEmbeddedObjectUtils.IsFLVUrl = function(sUrl)
{
    var sExtension = RealNetworks.RPBrowserEmbeddedObjectUtils.GetExtensionFromUrl(sUrl);
    return (sExtension == "flv");
};

RealNetworks.RPBrowserEmbeddedObjectUtils.IsFlashUrl = function(sUrl)
{
    var sExtension = RealNetworks.RPBrowserEmbeddedObjectUtils.GetExtensionFromUrl(sUrl);
    return (sExtension == "flv") || (sExtension == "swf");
};

RealNetworks.RPBrowserEmbeddedObjectUtils.IsFlashMimeType = function(sMimeType)
{
    return (sMimeType == "application/x-shockwave-flash") || (sMimeType == "video/x-flv") || (sMimeType == "video/flv") || (sMimeType == "video/flash");
};

RealNetworks.RPBrowserEmbeddedObjectUtils.IsFLVMimeType = function(sMimeType)
{
    return (sMimeType == "video/x-flv") || (sMimeType == "video/flv");
};

RealNetworks.RPBrowserEmbeddedObjectUtils.IsKnownPlugin = function(oElem)
{
    var bRecordable = false;
    if (oElem instanceof HTMLEmbedElement)
    {
        // Embeds can have only have a src but no type.
        if (!oElem.type)
        {
            if (oElem.src)
            {
                bRecordable = true;
            }
        }
        else
        {
            bRecordable = RealNetworks.RPBrowserEmbeddedObjectUtils.IsKnownPluginMimeType(oElem.type);
        }
    }
    else if (oElem instanceof HTMLObjectElement)
    {
        var sMimeType = oElem.type;
        bRecordable = (sMimeType && RealNetworks.RPBrowserEmbeddedObjectUtils.IsKnownPluginMimeType(sMimeType));
    }
    return bRecordable;
};

// General Utilities -------------------------------------------------------------------------------
RealNetworks.Utils = {};
RealNetworks.Utils.GetValueInBounds = function(value, min, max)
{
    var retval = value;
    if (value < min)
        retval = min;
    else if (value > max)
        retval = max;
    return retval;
};

/////////////////////////////////////////////////////
// RealNetworks.Utils.IsVisible
// Determines whether the given offsets is visible
// Param:
//      offset = [top, bottom, left, right]
// Returns true if offset is visible, and false otherwise
/////////////////////////////////////////////////////
RealNetworks.Utils.IsVisible = function(offset)
{
    return (offset[0] != offset[1]) && (offset[2] != offset[3]);
}

/////////////////////////////////////////////////////
// RealNetworks.Utils.GetFrameElementInParentDocumentIfFrame
// Given an HTMLDocument object, it will determine if it's inside a frame,
// and will return the corresponding frame element if it is.
//
// Param:
//      oDoc = HTMLDocument
// Returns a Frame Element or null if it cannot determine/doesn't exists
/////////////////////////////////////////////////////
RealNetworks.Utils.GetFrameElementInParentDocumentIfFrame = function(oDoc)
{
    var oFrameElement = null;
    if (oDoc && oDoc.defaultView && oDoc.defaultView.parent && oDoc.defaultView.parent.frames && oDoc.defaultView.parent.frames.length > 0)
    {
        for (var x = 0; x < oDoc.defaultView.parent.frames.length; x++)
        {
            if (oDoc.defaultView.parent.frames[x] && oDoc.defaultView.parent.frames[x] === oDoc.defaultView)
            {
                oFrameElement = oDoc.defaultView.parent.frames[x].frameElement;
                break;
            }
        }
    }
    return oFrameElement;
};

/////////////////////////////////////////////////////
// RealNetworks.Utils.FindElementRectOffsetToMainParentDocument
// Given an HTML element, it will determine visible rectangular offset of oElem in
// respect to the main parent document (going through frames).
//
// Param:
//      oElem = Any HTML element, can even be the document itself
//      bFactorScrolling = true, if we should take into account the scrolling offset
// Returns an integer array representing the offset as [top, bottom, left, right] of
// the visible dimensions of the element
/////////////////////////////////////////////////////
RealNetworks.Utils.FindElementRectOffsetToMainParentDocument = function(oElem, bFactorScrolling)
{
    var offset = RealNetworks.Utils.FindElementRectOffsetToParentDoc(oElem, bFactorScrolling);
    var bIsVisible = RealNetworks.Utils.IsVisible(offset);
    
    if (bIsVisible)
    {    
        // Now calculate offset for frames
        var oFrameElement = RealNetworks.Utils.GetFrameElementInParentDocumentIfFrame(oElem.ownerDocument);
        while (bIsVisible && oFrameElement && oFrameElement.ownerDocument)
        {
            var parentOffset = RealNetworks.Utils.FindElementRectOffsetToParentDoc(oFrameElement, bFactorScrolling);
            bIsVisible = RealNetworks.Utils.IsVisible(parentOffset);
            
            if (bIsVisible)
            {
                offset[0] = offset[0] + parentOffset[0];
                offset[1] = offset[1] + parentOffset[0];
                offset[2] = offset[2] + parentOffset[2];
                offset[3] = offset[3] + parentOffset[2];
                oFrameElement = RealNetworks.Utils.GetFrameElementInParentDocumentIfFrame(oFrameElement.ownerDocument);
            }
        }
    }

    if (!bIsVisible)
    {
        offset = [0,0,0,0];
    }
    
    return offset;
};

/////////////////////////////////////////////////////
// RealNetworks.Utils.FindElementRectOffsetToParentDoc
// Given an HTML element it will determine visible rectangular offset
// of oElem in respect to its parent document.
//
// Param:
//      oElem = Any HTML element, can even be the document itself
//      bFactorScrolling = true, if we should take into account the scrolling offset
// Returns an integer array representing the offset as [top, bottom, left, right] of
// the visible dimensions of the element
/////////////////////////////////////////////////////
RealNetworks.Utils.FindElementRectOffsetToParentDoc = function(oElem, bFactorScrolling)
{
    var offset = [0,0,0,0]; // [top, bottom, left, right]
    var doc = oElem.ownerDocument;
    var boxObject = doc.getBoxObjectFor(oElem);
    
    var xOffset = 0;
    var yOffset = 0;
    var windowWidth = 999999999;
    var windowHeight = windowWidth;
    
    if (doc && bFactorScrolling)
    {
        var win = doc.defaultView;
        xOffset = win.pageXOffset;
        yOffset = win.pageYOffset;
        windowWidth = win.innerWidth;
        windowHeight = win.innerHeight;
    }
    
    offset[0] = offset[0] + RealNetworks.Utils.GetValueInBounds(boxObject.y - yOffset, 0, windowHeight);
    offset[1] = offset[1] + RealNetworks.Utils.GetValueInBounds(oElem.offsetHeight + boxObject.y - yOffset, 0, windowHeight);
    offset[2] = offset[2] + RealNetworks.Utils.GetValueInBounds(boxObject.x - xOffset, 0, windowWidth);
    offset[3] = offset[3] + RealNetworks.Utils.GetValueInBounds(oElem.offsetWidth + boxObject.x - xOffset, 0, windowWidth);
    
    return offset;
};

/////////////////////////////////////////////////////
// RealNetworks.Utils.FindAssociatedTabFromChannel
// Given an nsIHttpChannel interface, it will return that tab that this
// channel was created by.
//
// Param:
//      oiHttp = object that implements nsIHttpChannel and was QI-ed to it
// Returns the associated tab object, or null if it cannot determine
/////////////////////////////////////////////////////
RealNetworks.Utils.FindAssociatedTabFromChannel = function(oiHttp)
{
    var oNotificationCallbacks = null;
        
    if (oiHttp)
    {
        oNotificationCallbacks = oiHttp.notificationCallbacks;
        if (!oNotificationCallbacks && oiHttp.loadGroup)
            oNotificationCallbacks = oiHttp.loadGroup.notificationCallbacks;
    }
    
    if (oNotificationCallbacks)
    {
        try
        {
            var oiWebNavigation = null;
            var oiDocShell = null;
            
            try
            {
                oiWebNavigation = oNotificationCallbacks.getInterface(Components.interfaces.nsIWebNavigation);
            }
            catch(e) {}
            
            try
            {
                oiDocShell = oNotificationCallbacks.getInterface(Components.interfaces.nsIDocShell);
                var oiDocShellTreeItem = oiDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeItem);
                if (oiDocShellTreeItem)
                {
                    oiDocShell = oiDocShellTreeItem.sameTypeRootTreeItem.QueryInterface(Components.interfaces.nsIDocShell);
                }
            }
            catch(e) {}
            
            // Associate the channel to the tab
            var aoTabs = window.getBrowser().mTabContainer.childNodes;
            var oTab = null;
            var x = 0;
            
            // Discover via nsIWebNavigation
            for (x = 0; x < aoTabs.length && !oTab; x++)
            {
                var oiTabWebNavigation = window.getBrowser().getBrowserForTab(aoTabs[x]).webNavigation;
                if ((oiTabWebNavigation === oiWebNavigation) ||
                    (oiDocShell && oiDocShell.contentViewer && (oiTabWebNavigation === oiDocShell)))
                {
                    oTab = aoTabs[x];
                    break;
                }
            }
            
            return oTab;
        }
        catch (e)
        {
            RealNetworks.Debug.fPrint("findAssociatedTabFromChannel Error:\n"+e);
        }
    }
    
    return null;
};

/////////////////////////////////////////////////////
// RealNetworks.Utils.GetAllBrowsers
// Gets all the browser
//
// Returns an array of Browser objects.
/////////////////////////////////////////////////////
RealNetworks.Utils.GetAllBrowsers = function()
{
    try
    {
        var browserArray = new Array();
        
        var oBrowser = getBrowser();
        var oDocumentBrowser = null;
        var oTab = oBrowser.tabContainer.firstChild;
        while (oTab)
        {
            var oTabBrowser = oBrowser.getBrowserForTab(oTab);
            if (oTabBrowser)
            {
                browserArray.push(oTabBrowser);
            }
            oTab = oTab.nextSibling;
        }
        return browserArray;
    }
    catch(e)
    {
        RealNetworks.Debug.fPrint("GetBrowserForDocument Error:\n"+e);
    }
    return null;
};

/////////////////////////////////////////////////////
// RealNetworks.Utils.GetBrowserForDocument
// Given an HTMLDocument, it will find the associated browser object
//
// Param:
//      oDoc = HTMLDocument
// Returns the associated Browser object, or null if it cannot determine
/////////////////////////////////////////////////////
RealNetworks.Utils.GetBrowserForDocument = function(oDoc)
{
    try
    {
        var oBrowser = getBrowser();
        
        var oDocAncestor = oDoc;
        while (oDocAncestor && oDocAncestor.defaultView && oDocAncestor.defaultView.parent && oDocAncestor.defaultView.parent.document && !(oDocAncestor.defaultView.parent.document === oDocAncestor))
        {
            oDocAncestor = oDocAncestor.defaultView.parent.document;
        }
        
        var oDocumentBrowser = null;
        var oTab = oBrowser.tabContainer.firstChild;
        while (oTab)
        {
            var oTabBrowser = oBrowser.getBrowserForTab(oTab);
            if (oTabBrowser && oTabBrowser.contentDocument === oDocAncestor)
            {
                oDocumentBrowser = oTabBrowser;
                break;
            }
            oTab = oTab.nextSibling;
        }
        return oDocumentBrowser;
    }
    catch(e)
    {
        RealNetworks.Debug.fPrint("GetBrowserForDocument Error:\n"+e);
    }
    return null;
};

/////////////////////////////////////////////////////
// RealNetworks.Utils.FindParamElementWithFollowingId
// HTML Object element and a param name, it will traverse the param list of the
// HTML Object element and return the param element with the given name
//
// Param:
//      oObjectElement = HTMLObjectElement
//      sParamName = string.  the name of the param element for this object element
// Returns the associated Browser object, or null if it cannot determine
/////////////////////////////////////////////////////
RealNetworks.Utils.FindParamElementWithFollowingId = function(oObjectElement, sParamName)
{
    try
    {
        var aoParamList = oObjectElement.getElementsByTagName("param");
        sParamName = sParamName.toLowerCase();
        if (aoParamList && aoParamList.length > 0)
        {
            for (var x = 0; x < aoParamList.length; ++x)
            {
                if (aoParamList[x].name.toLowerCase() == sParamName)
                {
                    return aoParamList[x];
                }
            }
        }
    }
    catch (e)
    {
        RealNetworks.Debug.fPrint("FindParamElementWithFollowingId:\n"+e);
    }
    return null;
};

RealNetworks.Utils.GetElementFlashVars = function(oElem)
{
    var sFlashVars = "";
    if (oElem instanceof HTMLEmbedElement)
    {
        sFlashVars = oElem.getAttribute("FlashVars");
    }
    else if (oElem instanceof HTMLObjectElement)
    {
        var oParamElement = RealNetworks.Utils.FindParamElementWithFollowingId(oElem, "FlashVars");
        if (oParamElement)
        {
            sFlashVars = oParamElement.value;
        }
    }
    return sFlashVars;
};

/////////////////////////////////////////////////////
// RealNetworks.Utils.GetElementUrl
// Returns the url associated with an HTMLEmbedElement or HTMLObjectElement
//
// Param:
//      oElem = an HTMLEmbedElement or HTMLObjectElement
//      bDoNotModifyURL = set to true if you don't want any url modifications
// Returns the associated url for the HTMLEmbedElement/HTMLObjectElement
/////////////////////////////////////////////////////
RealNetworks.Utils.GetElementUrl = function(oElem, bDoNotModifyURL)
{
    var sRetUrl = "";
    var sFlashVars = "";
    
    // First try to get the URL directory from the control.
    if (oElem && oElem.wrappedJSObject)
    {
        try
        {
            // This is Flash
            if (oElem.wrappedJSObject.TGetProperty)
            {
                sFlashVars = RealNetworks.Utils.GetElementFlashVars(oElem);
                sRetUrl = oElem.wrappedJSObject.TGetProperty("_root", 15);
            }
        }
        catch(e) {}
        
        if (!sRetUrl)
        {
            // This is RealPlayer
            try
            {
                if (oElem.wrappedJSObject.GetSource)
                {
                    sRetUrl = oElem.wrappedJSObject.GetSource();
                }
            }
            catch(e) {}
        }
        
        if (!sRetUrl)
        {
            // This is PlayerX
            try
            {
                if (oElem.wrappedJSObject.CurrentURL)
                {
                    sRetUrl = oElem.wrappedJSObject.CurrentURL;
                }
            }
            catch(e) {}
        }
        
        if (!sRetUrl)
        {
            // This is Quicktime
            try
            {
                if (oElem.wrappedJSObject.GetURL)
                {
                    sRetUrl = oElem.wrappedJSObject.GetURL();
                }
            }
            catch(e) {}
        }
        
        if (!sRetUrl)
        {
            // This is windows media player
            try
            {
                if (oElem.wrappedJSObject.URL)
                    sRetUrl = oElem.wrappedJSObject.URL;
            }
            catch(e) {}
        }
    }

    // If unable to get the URL directly from the control itself, try to get it from the document
    if (!sRetUrl)
    {
        // TODO: convert from relative to absolute path
        if (oElem instanceof HTMLEmbedElement)
        {
            sRetUrl = oElem.src;
        }
        else if (oElem instanceof HTMLObjectElement)
        {
            var classid = oElem.getAttribute("classid");
            if (!classid || classid.length == 0)
            {
                classid = RealNetworks.RPBrowserEmbeddedObjectUtils.GetClsidFromMimeType(oElem.type);
            }

            if (classid && classid.length > 0)
            {
                var sParamNameUrl = RealNetworks.RPBrowserEmbeddedObjectUtils.GetParamNameContainingUrl(classid);
                if (sParamNameUrl && sParamNameUrl.length > 0)
                {
                    var oParamElement = RealNetworks.Utils.FindParamElementWithFollowingId(oElem, sParamNameUrl);
                    if (oParamElement)
                    {
                        sRetUrl = oParamElement.value;
                    }
                }
            }
            
            if (!sRetUrl && oElem.data)
            {
                sRetUrl = oElem.data;
            }
        }
    }

    if (!bDoNotModifyURL && sRetUrl && sFlashVars)
    {
        if (sRetUrl.indexOf("?") != -1)
        {
            sRetUrl += "&" + sFlashVars;
        }
        else
        {
            sRetUrl += "?" + sFlashVars;
        }
    }
    
    if (sRetUrl && oElem && oElem.ownerDocument && oElem.ownerDocument instanceof HTMLDocument)
        sRetUrl = RealNetworks.Utils.ResolveUrl(oElem.ownerDocument.URL, sRetUrl);
    
    RealNetworks.Debug.fPrint("GetElementUrl:\n"+sRetUrl);
    
    return sRetUrl;
};


RealNetworks.Utils.TrimString = function(str)
{
    return str ? str.replace(/^\s+/g,"").replace(/\s+$/g,"") : str;
};

RealNetworks.Utils.GetContentTypeFromResponseHeader = function(uri, responseHeader)
{
    var contentType = "";
    if (uri && responseHeader)
    {
        var sContentTypeString = "content-type:";
        var indexContentType = responseHeader.toLowerCase().indexOf(sContentTypeString);
        if (indexContentType != -1)
        {
            var endIndex = -1;
            var startIndex = indexContentType+sContentTypeString.length;
            var indexEndOfContentTypeSemiColon = responseHeader.indexOf(";", startIndex);
            var indexEndOfContentTypeNewLine = responseHeader.indexOf("\n", startIndex);
            if (indexEndOfContentTypeSemiColon != -1 && indexEndOfContentTypeNewLine != -1)
            {
                if (indexEndOfContentTypeSemiColon < indexEndOfContentTypeNewLine)
                    endIndex = indexEndOfContentTypeSemiColon;
                else
                    endIndex = indexEndOfContentTypeNewLine;
            }
            else if (indexEndOfContentTypeSemiColon != -1)
                endIndex = indexEndOfContentTypeSemiColon;
            else if (indexEndOfContentTypeNewLine != -1)
                endIndex = indexEndOfContentTypeNewLine;
            else
                endIndex = responseHeader.length;
            
            if (endIndex > startIndex)
                contentType = RealNetworks.Utils.TrimString(responseHeader.substring(startIndex, endIndex));
        }
    }
    return contentType;
};

RealNetworks.Utils.GetStandardURLInstance = function(url)
{
    var standardUrl = Components.classes['@mozilla.org/network/standard-url;1'].createInstance(Components.interfaces.nsIStandardURL);
    if (standardUrl)
    {
        standardUrl.init(Components.interfaces.nsIStandardURL.URLTYPE_STANDARD, 80, url, null, null);
        try
        {
            standardUrl = standardUrl.QueryInterface(Components.interfaces.nsIURI);
        }
        catch(e)
        {
            standardUrl = null;
        }
    }
    return standardUrl;
};

RealNetworks.Utils.ResolveUrl = function(parentFullPathUrl, possibleChildUrl)
{
    var retUrl = possibleChildUrl;
    try
    {
        if (parentFullPathUrl && possibleChildUrl)
        {
            var standardUrl = RealNetworks.Utils.GetStandardURLInstance(parentFullPathUrl);
            if (standardUrl)
            {
                var resolvedUrl = standardUrl.resolve(retUrl);
                if (resolvedUrl)
                    retUrl = resolvedUrl;
            }
        }
    }
    catch(e){}
    return retUrl;
};

RealNetworks.Utils.IsRTMP = function(oElem)
{
    if (oElem.wrappedJSObject.__RP_Connection_Callback_Url && oElem.wrappedJSObject.__RP_TotalBytes_Callback_Bytes && oElem.wrappedJSObject.__RP_TotalBytes_Callback_Bytes == "0" && oElem.wrappedJSObject.__RP_Connection_Callback_Url.length > 0)
    {
        var index = oElem.wrappedJSObject.__RP_Connection_Callback_Url.indexOf("rtmp://");
        return (index != -1);
    }
    return false;
};
