/** * PLUGIN FRAMEWORK, Version 0.5 * For details, see the Knallgrau web site: http://www.knallgrau.code/prototype/plugins_js * Copyright (c) 2006 Matthias Platzer <matthias@knallgrau.at> * This code is freely distributable under the terms of an MIT-style license. *  *********************************************************************************** *  Copyright (c) 2006 Matthias Platzer <matthias@knallgrau.at> *   *  Permission is hereby granted, free of charge, to any person obtaining a copy  *  of this software and associated documentation files (the "Software"), to deal  *  in the Software without restriction, including without limitation the rights  *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  *  copies of the Software, and to permit persons to whom the Software is  *  furnished to do so, subject to the following conditions: *   *  The above copyright notice and this permission notice shall be included in  *  all copies or substantial portions of the Software. *   *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE *  SOFTWARE. * *********************************************************************************** * *  inspired by Prototype JavaScript framework * *  Provides the following functions *    // name accepts:  *    // Acrobat, QuickTime, DivX, Director,  *    // 'Windows Media', Flash, Java, RealPlayer, VLC *    Plugin.isInstalled(String name)  *    Plugin.getVersion(String name) *    Plugin.getPluginsForMimeType(String mimeType)  // returns Array of Plugin Names *    Plugin.getPluginsForFileSuffix(String suffix)  // returns Array of Plugin Names *    Plugin.embed(pluginName, options, target) *    Plugin.getInfo(String name)  *      // Result Object contains informations about the plugin *      Boolean isInstalled *      String  version *      String  description *      Array   progID        to be used with new ActiveXObject() *      String  classID       for ActiveX *      String  pluginsPage   URL to download the plugin *      Array   acceptedMimeTypes  provides MimeType info for IE * * CHANGELOG: * 17.12.2005: Version 0.1 *   initial version * 18.12.2005: Version 0.2 *   added mimetypes for divx & co. *   added VLC support (detection for IE is missing) *   renamed getPluginsForMimeType, getPluginsForFileSuffix -> returns Array, instead of String *   dropped support vor Adobe SVG (IE) *   tested and debugged RealPlayer -> still reports a strange version number *   fixed bugs where script did break on unknown name attribute *   added experimental Plugin.embed * 20.12.2005: Version 0.3 *   added docs *   added license *   rewrote Plugin.embed -> now it's easier to add new formats *   downloadURL became pluginsPage *   added mimeType, activeXType and codeBase to Plugin.PLUGINS *   Plugin.embed accepts strings as target (id) *   Added Plugin.embed support for Flash, RealPlayer and VLC * 23.03.2006: Version 0.4 *   Fixed a few warnings reported by firefox in javascript strict mode (reported by Olav Roth) * 13.04.2006: Version 0.5 *   Improved support for Windows Media Plugin *   - use WM6.4 ClassID instead of WM7 (this fixes a lot of bad behaviour, like missing controls) *   - detect installed ActiveX support for Mozilla (Firefox) *   - added support for forceObjectTag as a sideeffect *   Fixed a bug with embeding VLC (src needs to be present in the embed tag) *   Updated DivX support to final Version 1.0 *  * you may remove the comments section, but please leave the copyright/*--------------------------------------------------------------------------*/var PluginFactory = function() {  // Returns if plugin with identifier name is installed  // @see Plugin.getInfo  this.isInstalled = function(name) {    return Plugin.getInfo(name).isInstalled;  }  // Returns version number of plugin if available  // @see Plugin.getInfo  this.getVersion = function(name) {    return Plugin.getInfo(name).version;  }  // Returns an Array of plugin identifier names,   // that can handle this mimeType.  this.getPluginsForMimeType = function(mimeType) {    var result = [];    if (supportsNavigatorPlugins()) {      // navigator.mimeTypes      for (var i=0; i<navigator.mimeTypes.length; i++) {        if (navigator.mimeTypes[i].type.indexOf(mimeType) == 0 && navigator.mimeTypes[i].enabledPlugin) {          var pluginName = (findPluginName(navigator.mimeTypes[i].enabledPlugin.name) || navigator.mimeTypes[i].enabledPlugin.name);          if (!Array.contains(result, pluginName)) result.push(pluginName);        }      }    } else {      // Code for IE using ActiveX      for (var pluginName in Plugin.PLUGINS) {        var mimeTypes = Plugin.PLUGINS[pluginName].acceptedMimeTypes;        if (!mimeTypes) continue;        for (var j=0; j<mimeTypes.length; j++) {          if (mimeTypes[j].type.indexOf(mimeType) == 0 && Plugin.isInstalled(pluginName)) {            if (!Array.contains(result, pluginName)) result.push(pluginName);          }        }      }        }    return result;  }  // Returns an Array of plugin identifier names,   // that can handle a file with this suffix.  this.getPluginsForFileSuffix = function(suffix) {    var result = [];    if (supportsNavigatorPlugins()) {      // navigator.mimeTypes      for (var i=0; i<navigator.mimeTypes.length; i++) {        if ((","+navigator.mimeTypes[i].suffixes+",").indexOf(","+suffix+",") != -1 && navigator.mimeTypes[i].enabledPlugin) {          var pluginName = (findPluginName(navigator.mimeTypes[i].enabledPlugin.name) || navigator.mimeTypes[i].enabledPlugin.name);          if (!Array.contains(result, pluginName)) result.push(pluginName);        }      }    } else {      // Code for IE using ActiveX      for (var pluginName in Plugin.PLUGINS) {        var mimeTypes = Plugin.PLUGINS[pluginName].acceptedMimeTypes;        if (!mimeTypes) continue;        for (var j=0; j<mimeTypes.length; j++) {          if ((","+mimeTypes[j].suffixes+",").indexOf(","+suffix+",") != -1 && Plugin.isInstalled(pluginName)) {            if (!Array.contains(result, pluginName)) result.push(pluginName);          }        }      }        }    return result;  }  // Returns general information about a plugin.  // accepts: Acrobat, QuickTime, DivX, Director, 'Windows Media',   //          Flash, Java, RealPlayer, VLC  this.getInfo = function(name) {    var info = Plugin.PLUGINS[name];    var isInstalled = false;    var version = null;    if (supportsNavigatorPlugins()) {      // navigator.plugins      var plugin = findNavigatorPluginByName((name == "RealPlayer") ? "RealPlayer Version Plugin" : name);      if (plugin) {        isInstalled = true;        version = getVersionFromPlugin(plugin);      }    } else {      // Code for IE using ActiveX      isInstalled = hasActiveXObject(Plugin.PLUGINS[name] && Plugin.PLUGINS[name].progID);      if (isInstalled) {        if (Plugin.PLUGINS[name].getActiveXVersionInfo) {          version = Plugin.PLUGINS[name].getActiveXVersionInfo();        } else {          // assume that the progID contains the version number          // this is not always correct          var progID = getProgIdForActiveXObject(Plugin.PLUGINS[name].progID);          version = getVersionFromPlugin(progID);        }      } else {        version = getActiveXPluginByClassId(Plugin.PLUGINS[name] && Plugin.PLUGINS[name].classID);        if (version) version = version.replace(/,/g, ".");        isInstalled = (version!=undefined);      }    }    var result = {};    for (var i in info) {      result[i] = info[i];    }    result["isInstalled"] = isInstalled;    result["version"] = version;    result["name"] = name;    return result;  }/** * writes an embed or object tag to document.write or target. * @param plugin   name of the plugin to be used * @param options  options for embed respectivly object tag. *   .src,.width,.height,.type,.activeXType will get a special treatment *   all other properties of options will be added to the  *   embed tag as attributes resp. to the object tag as param(eters). *   option names should be lower case! * @param target   optional (id of) container element for the embed/object tag */  this.embed = function(plugin, options, target) {    options = options || {};    var embedOptions = Object.extend({}, options);    var src = embedOptions.src;    delete embedOptions.src;    var id = embedOptions.id;    delete embedOptions.id;    var name = embedOptions.name || id;    delete embedOptions.name;    var width = embedOptions.width;    delete embedOptions.width;    var height = embedOptions.height;    delete embedOptions.height;    var type = embedOptions.type || (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].mimeType) || "";    delete embedOptions.type;    var activeXType = embedOptions.activeXType || (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].activeXType) || type;    delete embedOptions.activeXType;    var forceEmbedTag = (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].forceEmbedTag === true) ? true : false;    var forceObjectTag = (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].forceObjectdTag === true) ? true : false;    var embedOptions = Object.extend(((Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].standardEmbedAttributes) || {}), embedOptions);    switch (plugin) {      case "QuickTime":        // get space for controlls        if (embedOptions.controller == "true" && (height+"").indexOf("%") == -1) {          height += 16;        }        if (!options.activeXType) {          activeXType = null;        }        break;      case "DivX":        // get space for controlls        if ((height+"").indexOf("%") == -1) {          if (embedOptions.mode == "mini") height += 20;          else if (embedOptions.mode == "large") height += 65;          else if (embedOptions.mode == "full") height += 90;        }        break;      case "Windows Media":        // check if ActiveX for Firefox is installed        // http://help.yahoo.com/help/us/launch/videos/videos-07.html        if (!supportsNavigatorPlugins() || window.GeckoActiveXObject) {           forceObjectTag = true;        }        // get space for controlls        if ((window.ActiveXObject || window.GeckoActiveXObject || window.opera) &&            (height+"").indexOf("%") == -1) {          height += 45;        }        break;      case "Flash":        // flash wants the src to be named "movie" if passed as object param        if (!supportsNavigatorPlugins()) {          embedOptions.movie = src;          src = null;        }        break;      case "VLC":        // VLC wants the src to be named "target"        // update: that's actualy wrong, even it's documented like that!        if (supportsNavigatorPlugins()) {          embedOptions.target = src;        }        break;      case "RealPlayer":        break;              default:         // do nothing        break;    }    // prepare html code    var html = "";    if ((supportsNavigatorPlugins() && ! forceObjectTag) || forceEmbedTag) {      // Netscape Plugin embed Tag      html += '<embed' + getAttributeHtml("src", src)  + getAttributeHtml("id", id) + getAttributeHtml("name", name) + getAttributeHtml("width", width) + getAttributeHtml("height", height) + getAttributeHtml("pluginspage", Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].pluginsPage) + getAttributeHtml("type", type);      for (var i in embedOptions) {        html += ' '+i+'="'+embedOptions[i]+'"';      }      html += '></embed>\n';    } else {      // ActiveX object tag      html += '<object classid="clsid:'+(Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].classID)+'"';      html += getAttributeHtml("id", id) + getAttributeHtml("name", name) + getAttributeHtml("width", width) + getAttributeHtml("height", height) + getAttributeHtml("codebase", (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].codeBase)) + getAttributeHtml("type", activeXType) + '>\n';      html += (src) ? '  <param name="src" value="'+src+'">\n' : '';      for (var i in embedOptions) {        html += '  <param name="'+i+'" value="'+embedOptions[i]+'" />';      }      html += '</object>\n';    }    if (target) {      if (typeof target == "string") target = document.getElementById(target);      target.innerHTML = html;    } else {      document.write(html);    }  }  var getAttributeHtml = function(name, value) {    return (value) ? (" " + name + "=\"" + value + "\"") : "";  }  // Info about known plugins  this.PLUGINS = {    "Acrobat": {      description: "Adobe Acrobat Plugin",      progID: ["PDF.PdfCtrl.7", "PDF.PdfCtrl.6", "PDF.PdfCtrl.5", "PDF.PdfCtrl.4", "PDF.PdfCtrl.3", "AcroPDF.PDF.1"],      classID: "CA8A9780-280D-11CF-A24D-444553540000",      pluginsPage: "http://www.adobe.com/products/acrobat/readstep2.html",      acceptedMimeTypes: [        { type: "application/pdf", suffixes: "pdf" },        { type: "application/vnd.fdf", suffixes: "fdf" },        { type: "application/vnd.adobe.xfdf", suffixes: "xfdf" },        { type: "application/vnd.adobe.xdp+xml", suffixes: "xdp" },        { type: "application/vnd.adobe.xfd+xml", suffixes: "xfd" }      ]    },    "QuickTime": {      description: "QuickTime Plug-in",      progID: ["QuickTimeCheckObject.QuickTimeCheck.1", "QuickTime.QuickTime"],      classID: "02BF25D5-8C17-4B23-BC80-D3488ABDDC6B",      pluginsPage: "http://www.apple.com/quicktime/download/",      codeBase: "http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0",      mimeType: "video/quicktime",      standardEmbedAttributes: {        autoplay: "false"      },      // embedInfo: http://www.apple.com/quicktime/tutorials/embed.html       //            http://developer.apple.com/quicktime/compatibility.html      getActiveXVersionInfo: function() {         var progID = getProgIdForActiveXObject(Plugin.PLUGINS["QuickTime"].progID);         var obj = new ActiveXObject(progID);        var version = (obj && obj.QuickTimeVersion) ? obj.QuickTimeVersion.toString(16) : "";        return version.substring(0,1) + '.' + version.substring(1,2) + '.' + version.substring(2,3);      },      acceptedMimeTypes: [        { type: "image/tiff", suffixes: "tif,tiff" },        { type: "image/x-tiff", suffixes: "tif,tiff" },        { type: "video/x-m4v", suffixes: "m4v" },        { type: "image/x-macpaint", suffixes: "pntg,pnt,mac" },        { type: "image/pict", suffixes: "pict,pic,pct" },        { type: "image/x-pict", suffixes: "pict,pic,pct" },        { type: "image/x-quicktime", suffixes: "qtif,qti" },        { type: "image/x-sgi", suffixes: "sgi,rgb" },        { type: "image/x-targa", suffixes: "targa,tga" },        { type: "audio/3gpp", suffixes: "3gp,3gpp" },        { type: "video/3gpp2", suffixes: "3g2,3gp2" },        { type: "audio/3gpp2", suffixes: "3g2,3gp2" },        { type: "video/sd-video", suffixes: "sdv" },        { type: "application/x-mpeg", suffixes: "amc" },        { type: "video/mp4", suffixes: "mp4" },        { type: "audio/mp4", suffixes: "mp4" },        { type: "audio/x-m4a", suffixes: "m4a" },        { type: "audio/x-m4p", suffixes: "m4p" },        { type: "audio/x-m4b", suffixes: "m4b" },        { type: "video/mpeg", suffixes: "mpeg,mpg,m1s,m1v,m1a,m75,m15,mp2,mpm,mpv,mpa" },        { type: "audio/mpeg", suffixes: "mpeg,mpg,m1s,m1a,mp2,mpm,mpa,m2a" },        { type: "audio/x-mpeg", suffixes: "mpeg,mpg,m1s,m1a,mp2,mpm,mpa,m2a" },        { type: "video/3gpp", suffixes: "3gp,3gpp" },        { type: "audio/x-gsm", suffixes: "gsm" },        { type: "audio/AMR", suffixes: "AMR" },        { type: "audio/aac", suffixes: "aac,adts" },        { type: "audio/x-aac", suffixes: "aac,adts" },        { type: "audio/x-caf", suffixes: "caf" },        { type: "video/x-mpeg", suffixes: "mpeg,mpg,m1s,m1v,m1a,m75,m15,mp2,mpm,mpv,mpa" },        { type: "audio/aiff", suffixes: "aiff,aif,aifc,cdda" },        { type: "audio/x-aiff", suffixes: "aiff,aif,aifc,cdda" },        { type: "audio/basic", suffixes: "au,snd,ulw" },        { type: "audio/mid", suffixes: "mid,midi,smf,kar" },        { type: "audio/x-midi", suffixes: "mid,midi,smf,kar" },        { type: "audio/midi", suffixes: "mid,midi,smf,kar" },        { type: "audio/vnd.qcelp", suffixes: "qcp" },        { type: "application/sdp", suffixes: "sdp" },        { type: "application/x-sdp", suffixes: "sdp" },        { type: "application/x-rtsp", suffixes: "rtsp,rts" },        { type: "video/quicktime", suffixes: "mov,qt,mqv" },        { type: "video/flc", suffixes: "flc,fli,cel" },        { type: "audio/x-wav", suffixes: "wav,bwf" },        { type: "audio/wav", suffixes: "wav,bwf" }      ]    },    "DivX": {      description: "DivX Browser Plugin",      progID: ["npdivx.DivXBrowserPlugin.1", "npdivx.DivXBrowserPlugin"],      classID: "67DABFBF-D0AB-41fa-9C46-CC0F21721616",      codeBase: "http://go.divx.com/plugin/DivXBrowserPlugin.cab",      pluginsPage: "http://go.divx.com/plugin/download/",      mimeType: "video/divx",      standardEmbedAttributes: {        mode: "mini",        minversion: "1.0.0"      },      // embedInfo: Beta1: http://labs.divx.com/archives/000072.html      //            SDK&Doc: http://download.divx.com/labs/Webmaster_SDK.zip      getActiveXVersionInfo2: function() {        var progID = getProgIdForActiveXObject(Plugin.PLUGINS["DivX"].progID);         return "1.0.0"; // that's the only currently available      },      acceptedMimeTypes: [        { type: "video/divx", suffixes: "dvx,divx" }      ]    },    "Director": {      description: "Macromedia Director",      progID: ["SWCtl.SWCtl.11","SWCtl.SWCtl.10","SWCtl.SWCtl.9","SWCtl.SWCtl.8","SWCtl.SWCtl.7","SWCtl.SWCtl.6","SWCtl.SWCtl.5","SWCtl.SWCtl.4"],      classID: "166B1BCA-3F9C-11CF-8075-444553540000",      pluginsPage: "http://www.macromedia.com/shockwave/download/",      codeBase: "http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0",      mimeType: "application/x-director"    },             "Flash": {      description: "Macromedia Shockwave Flash",      progID: ["ShockwaveFlash.ShockwaveFlash.9", "ShockwaveFlash.ShockwaveFlash.8.5", "ShockwaveFlash.ShockwaveFlash.8", "ShockwaveFlash.ShockwaveFlash.7", "ShockwaveFlash.ShockwaveFlash.6", "ShockwaveFlash.ShockwaveFlash.5", "ShockwaveFlash.ShockwaveFlash.4"],      classID: "D27CDB6E-AE6D-11CF-96B8-444553540000",      pluginsPage: "http://www.macromedia.com/go/getflashplayer",      codeBase: "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0",      mimeType: "application/x-shockwave-flash",      standardEmbedAttributes: {        quality: "high"      },      // embedInfo: http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_4150      //            http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_12701      acceptedMimeTypes: [        { type: "application/x-shockwave-flash", suffixes: "swf" },        { type: "application/futuresplash", suffixes: "spl" }      ]    },     "VLC": {      description: "VLC multimedia plugin",      progID: [],      classID: "",      pluginsPage: "http://www.videolan.org/doc/play-howto/en/ch02.html#id287569",      codeBase: "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0",      mimeType: "application/x-vlc-plugin",      standardEmbedAttributes: {        quality: "high",        autoplay: "no"      },      // embedInfo: http://www.videolan.org/doc/vlc-user-guide/en/ch07.html      //            http://www.videolan.org/doc/play-howto/en/ch04.html#id293251      acceptedMimeTypes: [        { type: "audio/mpeg", suffixes: "mp2,mp3,mpga,mpega" },        { type: "audio/x-mpeg", suffixes: "mp2,mp3,mpga,mpega" },        { type: "video/mpeg", suffixes: "mpg,mpeg,mpe" },        { type: "video/x-mpeg", suffixes: "mpg,mpeg,mpe" },        { type: "video/mpeg-system", suffixes: "mpg,mpeg,vob" },        { type: "video/x-mpeg-system", suffixes: "mpg,mpeg,vob" },        { type: "video/mpeg4", suffixes: "mp4,mpg4" },        { type: "audio/mpeg4", suffixes: "mp4,mpg4" },        { type: "application/mpeg4-iod", suffixes: "mp4,mpg4" },        { type: "application/mpeg4-muxcodetable", suffixes: "mp4,mpg4" },        { type: "video/x-msvideo", suffixes: "avi" },        { type: "video/quicktime", suffixes: "mov,qt" },        { type: "application/x-ogg", suffixes: "ogg" },        { type: "application/x-vlc-plugin", suffixes: "*" },        { type: "video/x-ms-asf-plugin", suffixes: "asf,asx,*" },        { type: "video/x-ms-asf", suffixes: "asf,asx,*" },        { type: "application/x-mplayer2", suffixes: "dvx,divx,ivx,xvid,ivf,*" },        { type: "video/x-ms-wmv", suffixes: "wmv,*" },        { type: "application/x-google-vlc-plugin", suffixes: "*" }            ]    },    "Windows Media": {      description: "Windows Media Player Plug-in Dynamic Link Library",      progID: ["WMPlayer.OCX", "MediaPlayer.MediaPlayer.1"],      classID: "22D6f312-B0F6-11D0-94AB-0080C74C7E95", // WMP6 -> semms to work a lot better, don't know why      // classID: "6BF52A52-394A-11D3-B153-00C04F79FAA6", // WMP7+ -> doesn't work for me      pluginsPage: "http://www.microsoft.com/windows/windowsmedia/",      codeBase: "http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,0,02,902",      mimeType: "application/x-mplayer2",      activeXType: "application/x-oleobject",      standardEmbedAttributes: {        autoplay: "false"      },      // embedInfo: http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/samples/internet/imedia/netshow/crossbrowserembed/default.asp      getActiveXVersionInfo: function() {         var progID = getProgIdForActiveXObject(Plugin.PLUGINS["Windows Media"].progID);         var obj = new ActiveXObject(progID);        return (obj && obj.versionInfo) ? obj.versionInfo : "";      },      acceptedMimeTypes: [        { type: "application/asx", suffixes: "*" },        { type: "video/x-msvideo", suffixes: "avi" },        { type: "video/x-ms-asf-plugin", suffixes: "*" },        { type: "application/x-mplayer2", suffixes: "dvx,divx,ivx,xvid,ivf,*" },        { type: "video/x-ms-asf", suffixes: "asf,asx,*" },        { type: "video/x-ms-wm", suffixes: "wm,*" },        { type: "audio/x-ms-wma", suffixes: "wma,*" },        { type: "audio/x-ms-wax", suffixes: "wax,*" },        { type: "video/x-ms-wmv", suffixes: "wmv,*" },        { type: "video/x-ms-wvx", suffixes: "wvx,*" }      ]    },    "Java": {      description: "Java Virtual Machine",      progID: [],      classID: "08B0E5C0-4FCB-11CF-AAA5-00401C608500",      pluginsPage: "http://www.java.com/de/download/manual.jsp",      acceptedMimeTypes: [        { type: "application/x-java-applet", suffixes: "" },        { type: "application/x-java-bean", suffixes: "" },        { type: "application/x-java-vm", suffixes: " " }      ]    },              "RealPlayer": {      description: "RealPlayer Version Plugin",      progID: ["RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)", "RealVideo.RealVideo(tm) ActiveX Control (32-bit)", "rmocx.RealPlayer G2 Control"],      classID: "CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA",      mimeType: "audio/x-pn-realaudio-plugin",      pluginsPage: "http://www.real.com/freeplayer/?rppr=rnwk",      forceEmbedTag: true,      standardEmbedAttributes: {        controls: "ControlPanel",        nojava: "true",        autostart: "false"      },      // embedInfo: http://service.real.com/help/library/guides/realone/ProductionGuide/HTML/realpgd.htm?page=htmfiles/embed.htm      // couldn't find any info about the object tag!      getActiveXVersionInfo: function() {         var progID = getProgIdForActiveXObject(Plugin.PLUGINS["RealPlayer"].progID);         var obj = new ActiveXObject(progID);        var version = (obj) ? obj.GetVersionInfo() : "";        return version;      },      acceptedMimeTypes: [        { type: "audio/x-pn-realaudio-plugin", suffixes: "rpm" },        { type: "application/vnd.rn-realplayer-javascript", suffixes: "rpj" }      ]    }  }  var supportsNavigatorPlugins = function() {    return (navigator.plugins && (navigator.plugins.length > 0));  }  var supportsActiveX = function() {    return ((typeof 'ActiveXObject' != 'undefined') && (navigator.userAgent.indexOf('Win') != -1));  }  var findNavigatorPluginByName = function(name) {    if (supportsNavigatorPlugins()) {      for(var i=0;i<navigator.plugins.length;++i) {        var plugin = navigator.plugins[i];        if (plugin.name.indexOf(name) != -1) {          return plugin;        }      }    }    return null;  }  var findPluginName = function(str) {    for (var pluginName in Plugin.PLUGINS) {      if (str.indexOf(pluginName) != -1) {        return pluginName;      }    }    return null;  }  var getIEClientCaps = function() {    var clientcaps = document.getElementById("__Plugin_ClientCaps");    if (!clientcaps) {      var clientcaps = document.createElement("DIV");      clientcaps.id = "__Plugin_ClientCaps";      if (clientcaps.addBehavior) {        clientcaps.addBehavior("#default#clientCaps");        document.body.appendChild(clientcaps);      }      clientcaps = document.getElementById("__Plugin_ClientCaps");    }    return clientcaps;      }  var getActiveXPluginByClassId = function(classID) {    if (!classID) return null;    if (!classID.match(/{[^}]+}/)) classID = "{" + classID + "}";    var clientcaps = getIEClientCaps();    try {      var result = clientcaps.getComponentVersion(classID, "ComponentID")      return result || null;    } catch (err) { }    return null;  }  var hasActiveXObject = function(progID) {    progID = getProgIdForActiveXObject(progID);    return (progID != null);  }  var getProgIdForActiveXObject = function(progID) {    if (!progID) return null;    for (var i=0; i<progID.length; i++) {      try {        var obj = new ActiveXObject(progID[i]);        return progID[i] || null;      }      catch(e) { }    }    return null;  }  // accepts plugin or string  var getVersionFromPlugin = function(plugin) {    if (!plugin.name) plugin = { name: plugin, description: name };    var matches = /[\d][\d\.]*/.exec(plugin.name);    if (matches && plugin.name.indexOf("Java") == -1) return matches[0];    matches = /[\d\.]+/.exec(plugin.description);    return matches ? matches[0] : "";  }  };// helper functions// for usage without prototype.jsif (!Object.extend) {  Object.extend = function(destination, source) {    for (property in source) {      destination[property] = source[property];    }    return destination;  }}// Array functionsArray.contains = function(arr, el) {  return Array.indexOf(arr, el) != -1;}Array.indexOf = function(arr, el) {  for (var i=0; i<arr.length; i++) {    if (arr[i] == el) return i;  }  return -1;}String.encode =String.prototype.encode = function() {  var str = this;  str = str.replace("&", "&amp;");  str = str.replace("<", "&lt;");  str = str.replace(">", "&gt;");  str = str.replace("\"", "&quot;");  str = str.replace("\n", "");  return str;}if (!window.Plugin) {  var Plugin = new Object();}Object.extend(Plugin, (new PluginFactory()));