/**
* PLUGIN FRAMEWORK, Version 0.4
* 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)
* 
* 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) {
//alert('getPluginsForMimeType');
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 && Plugin.PLUGINS[plugin].forceEmbedTag == 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":
// get space for controlls
if ((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"
if (supportsNavigatorPlugins()) {
embedOptions.target = src;
src = null;
}
break;

case "RealPlayer":
break; 

default: 
// do nothing
break;
}

// prepare html code
var html = "";
if (supportsNavigatorPlugins() || 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",
autoplay: "false"
},
// 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 "0.9.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
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: "6BF52A52-394A-11D3-B153-00C04F79FAA6", // WMP7+
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-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] : "";
}

};

if (!window.Plugin) {
//alert('plugin = new object');
var Plugin = new Object();
} else {
//alert('plugin already exists?');
}

// 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;
}

Object.extend(Plugin, (new PluginFactory()));

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;
}
