window.octopv_fileVersion="plugin101-1003250"; 
window.octopv_group = ""; // global group used when group is not defined in the octolink.
window.octopvDebugDiv = "octopv_logDiv"; // see comment to octopv_log2 function	
window.octopvDebugTopPost = false;	
window.octopv_appletDisplayName = 'Octoshape Grid Delivery Enhancement';
window.octopv_abortAutoLaunch=false;
window.octopv_jsInitMillis=(new Date().getTime());

/* #################################################################################### 
							PATHS TO FILES USED (and variants)
								
   #################################################################################### 
   If necessary override some or all of the following 10 variables in a separate js file.
   for instance (can be done either before or after including this file):
	window.octofbp2_swf=		'http://www.mydomain.com/octoshape/launchers/';
	window.octoinit_jar=		'http://www.mydomain.com/octoshape/launchers/';
	window.octolauncher_jar=	'http://www.mydomain.com/octoshape/launchers/';
	window.AC_OETags_js=		'http://www.mydomain.com/octoshape/launchers/';
	window.octoeula_swf=		'http://www.mydomain.com/octoshape/installers/';
	window.octosetup_cab=		'http://www.mydomain.com/octoshape/installers/';
	window.octosetup_jar=		'http://www.mydomain.com/octoshape/installers/';
	window.octosetup_mac_jar=	'http://www.mydomain.com/octoshape/installers/';
	window.octoshapeVariantEula='MYVAR';
	window.octoshapeVariant=	'MYVAR'; 
 */

function octopv_ConstructPaths(){
	this.allFiles=new Array();
	
	this.get=function(fileName){
		var id = fileName.replace('.','_');
		id = id.replace('-','_');
		var p = this[id+'_path'];
		if(typeof(window[id])=='string'){
			p = window[id];
		}
		if((p.charAt(p.length-1)!='/') && p.length>0){
			octopv_log.log('inserting / at the end of: '+id+', now it is '+p);
			p = p+'/';
		}
		var f = this[id+'_file'];
		var octoVar='';
		var octoVarEula='';
		if(typeof (window.octoshapeVariant) == 'string'){
			octoVar=window.octoshapeVariant;
		}
		if(typeof (window.octoshapeVariantEula) == 'string'){
			octoVarEula=window.octoshapeVariantEula;
		}
		f = f.replace('_OCTOVAR_',octoVar);
		f = f.replace('_OCTOVAREULA_',octoVarEula);
		return p+f;
	}
	this.getVariant=function(){
		if(typeof (window.octoshapeVariant) == 'string'){
			return window.octoshapeVariant;
		}else{
			return "";
		}
	};
	this.add=function(file,path){
		var id = file.replace('.','_');
		id = id.replace('-','_');
		id = id.replace('_OCTOVAREULA_','');
		id = id.replace('_OCTOVAR_','');
		this[id+'_file']=file;
		this[id+'_path']=path;
		this.allFiles.push(id);
	}
}

window.octopv_paths=new octopv_ConstructPaths();
octopv_paths.add('octofbp2.swf',			'http://www.octoshape.com/plugin/util/');
octopv_paths.add('octoinit.jar',			'http://www.octoshape.com/plugin/util/');
octopv_paths.add('octolauncher.jar',		'http://www.octoshape.com/plugin/util/');
octopv_paths.add('AC_OETags.js',			'http://www.octoshape.com/javascripts/');
octopv_paths.add('octoeula_OCTOVAREULA_.swf','http://www.octoshape.com/plugin/autoinstall/');
octopv_paths.add('octosetup_OCTOVAR_.cab',	'http://www.octoshape.com/files/');
octopv_paths.add('octosetup_OCTOVAR_.jar',	'http://www.octoshape.com/files/');
octopv_paths.add('octosetup_OCTOVAR_-mac.jar','http://www.octoshape.com/files/');
octopv_paths.add('octostat.swf',			'http://www.octoshape.com/plugin/util/');

function octopv_setVariant(installer, eula){
	window.octoshapeVariantEula=eula;
	window.octoshapeVariant=installer;
}

function octopv_disableFlashEula(){
	window.octopve_disableEula=true;
}

function octopv_disableCabInstall(){
	window.octopvCAB_topobject.disable=true;
}


/* #################################################################################### 
						         STATUS CODES 
                      the single object for status error codes
   #################################################################################### */

/** Status codes layout (the closer to 0, the more certain the answer is.):
		       0: Octoshape is installed and running.
	-100 to -199: User said no to octoshape.
				  -100 to -109: User rejected the EULA, either we should not use Octoshape or 
  								  we should tell the user not to reject. 
				  -110 to -119: User cancelled a security alert, either we should not use Octoshape 
				  				  or we should tell the user not to cancel. 
	-200 to -299: We are pretty sure octoshape is installed and that the user just needs to 
					refresh the page or re-start the browser to make everything work.
	-300 to -399: We are pretty sure that octo is or has been installed, but is now in some error 
				  state. User should do manual re-install.
	-400 to -499: We are pretty sure octo is not installed. User should do manual install.
	-500 to -599: We think octo is installed, but not running. If octoshape is installed, user should 
				  manually launch octoshape and then refresh page, if no octoshape then manual install.
	-600 to -699: We have no idea if octo is installed or not. Ask user for advice.
	-900 to -999: There was a web integration error. This should not happen. What should the user 
				  do? (manuel install?)   */
function octopv_ConstructErrorCodes(){
	this.CODE_USER_DECLINED = 			-1;
	this.CODE_USER_SHOULD_REFRESH = 	-2;
	this.CODE_USER_SHOULD_REINSTALL = 	-3;
	this.CODE_USER_SHOULD_INSTALL = 	-4;
	this.CODE_USER_SHOULD_LAUNCH = 		-5;
	this.CODE_UNKNOWN_STATUS = 			-6;
	this.CODE_ERROR = 					-9;
	
	this.FLASH_EULA_REJECT = 		-100;
	this.INSTALL_APPLET_EULA_REJECT=-101;	

	this.LAUNCH_APPLET_SECURITY=	-110;
	this.INSTALL_APPLET_SECURITY= 	-111;

	this.LAUNCH_APPLET_AFTER_INSTALL=-200;
	this.BP_AFTER_INSTALL=			-201;
	// -299 is used is asosa.

	this.PLUGIN_ANSWER_BP_SUB=		-300; 
	this.PLUGIN_ANSWER_APP_SUB=		-310; 

	this.NO_BROWSER_PLUGIN=			-490;
	this.LAUNCH_APPLET_NO_PLUGIN=	-491;
	this.PLUGIN_ANSWER_BP_NOT_FOUND=-492;
	
	this.FLASH_BP_NOT_LAUNCHED=     -500;	
	this.CAB_AFTER_INSTALL=			-501;
	this.BROWSER_PLUGIN_NO_METHOD=	-502;
	
	this.LAUNCH_APPLET_TIMEOUT=		-600;	
	this.PRELOAD_APPLET_TIMEOUT=	-601;	
	this.JS_ABORTED=				-602;
	this.JSHTTP_CONNECT=			-603;
	this.JSHTTP_CONNECT_TIMEOUT=	-604;
	this.JSHTTP_CONNECT_EX=			-605;
	this.JSHTTP_NOT_XML=			-606;
	this.JSHTTP_XML=				-607;
	this.JSHTTP_TIMEOUT=			-608;
	this.FLASH_BP_TIMEOUT=			-609;
	this.FLASH_BP_UNKNOWN=			-610;
	this.FLASH_BP_NO_CALLBACK=		-611;
	this.BP_IMPOSSIBLE=				-612;
	this.TEST_APPLET_ERROR=			-613;
	
	this.LAUNCH_APPLET_IMPOSSIBLE=	-620;
	this.LAUNCH_APPLET_NO_COOKIE=	-621;
	this.FLASH_BP_IMPOSSIBLE= 		-622;
	this.JSHTTP_IMPOSSIBLE= 		-623;
	this.TEST_APPLET_IMPOSSIBLE=	-624;
	this.JAVA_NOT_ENABLED=			-625;
	this.CAB_IMPOSSIBLE=			-626;
	this.CAB_IMPOSSIBLE_VISTA=		-627;

	this.INSTALL_APPLET_OLD_MAC=	-628;
	this.INSTALL_APPLET_VISTA_OLD_JAVA=-629;

	this.LAUNCH_APPLET_REPLY=		-630;
	this.LAUNCH_APPLET_WRITE=		-631;
	this.INSTALL_APPLET_JS=			-632;
	this.INSTALL_APPLET_NO_FILE= 	-633;		
	this.INSTALL_APPLET_EXECUTION= 	-634;
	this.INSTALL_APPLET_UNKNOWN= 	-635;
	this.CAB_READY_STATE=			-636; // Ready state not defined
	this.PROTOCAL_LAUNCH_AFTER=		-637; 
	this.PROTOCAL_LAUNCH_ERROR=		-638; 
	this.LAUNCH_APPLET_JAVASCRIPT=	-639;

	this.JS=						-900;
	this.JSHTTP_UNKNOWN=			-901;
	this.LAUNCH_APPLET_UNKNOWN = 	-902;
	this.LAUNCH_APPLET_NOT_READY=	-903;
	this.PRELOAD_APPLET_INSERT=		-905;
	this.WRAP_ERROR=				-906;

	this.PRELOAD_APPLET_OK=			-910;	// only used for internal workings
	this.FLASH_EULA_ACCEPT= 		-911;	// only used for internal workings
	this.INSTALL_APPLET_OK= 		-912;	// only used for internal workings
	this.TEST_APPLET_OK=			-913;	// only used for internal workings

	this.NOT_SET= 		-999;	// Do not change. it is used from silver-osa
	
	this.getCode=function(err){
		if(err==0) return 0;
		if(err<=-700) return this.CODE_ERROR;
		if(err<=-600) return this.CODE_UNKNOWN_STATUS;
		if(err<=-500) return this.CODE_USER_SHOULD_LAUNCH;
		if(err<=-400) return this.CODE_USER_SHOULD_INSTALL;
		if(err<=-300) return this.CODE_USER_SHOULD_REINSTALL;
		if(err<=-200) return this.CODE_USER_SHOULD_REFRESH;
		if(err<=-100) return this.CODE_USER_DECLINED;
		return this.CODE_ERROR;
	}
	
	this.print=function(err){
		var e = " ("+err+")";
		switch(err){
		case 0: 							return "Success";
		
		case this.JS:						return "JavaScript error"+e;
		case this.JS_ABORTED:				return "JavaScript Aborted"+e;
		case this.WRAP_ERROR:				return "Plugin launch attempt wrap init"+e;

		
		case this.JSHTTP_CONNECT: return "JavaScript-HTTP error on connect (Plugin not running)"+e;
		case this.JSHTTP_CONNECT_TIMEOUT: 	return "JavaScript-HTTP connect time-out reached"+e;
		case this.JSHTTP_CONNECT_EX:		return "JavaScript-HTTP exception while connecting"+e;
		case this.JSHTTP_NOT_XML: 	return "JavaScript-HTTP plugin did not reply with xml doc"+e;
		case this.JSHTTP_XML: return "JavaScript-HTTP plugin replied with incorrect base node tag"+e;
		case this.JSHTTP_TIMEOUT: 			return "JavaScript-HTTP master time-out reached"+e;
		case this.JSHTTP_UNKNOWN: 			return "JavaScript-HTTP unknown error"+e;
		case this.JSHTTP_IMPOSSIBLE:		return "JavaScript-HTTP can not be used"+e;
		case this.TEST_APPLET_ERROR:		return "Test applet error"+e;
		case this.FLASH_BP_IMPOSSIBLE:		return "Flash-bp can not be used"+e;
		case this.FLASH_BP_TIMEOUT:			return "Flash-bp time-out reached"+e;
		case this.FLASH_BP_NOT_LAUNCHED:return "Flash-bp could not reach plug-in, but it is installed"+e;
		case this.FLASH_BP_UNKNOWN:			return "Flash-bp could not reach plug-in"+e;
		case this.FLASH_BP_NO_CALLBACK:		return "Flash-bp had no callback function"+e;		
		case this.BP_IMPOSSIBLE:			return "Browser plugin could not be used"+e;

		case this.INSTALL_APPLET_OLD_MAC:	return "No applet install since to old mac os"+e;
		case this.INSTALL_APPLET_VISTA_OLD_JAVA:return "No applet install since Vista + old java"+e;
		case this.PRELOAD_APPLET_INSERT:return "Preload applet could not be inserted to the page"+e;
		case this.TEST_APPLET_IMPOSSIBLE:	return "Test applet could not be used"+e;
		case this.PRELOAD_APPLET_TIMEOUT:	return "Preload applet timeout"+e;
		case this.TEST_APPLET_OK:			return "Test applet success"+e;
		case this.FLASH_EULA_ACCEPT:		return "Flash EULA accepted"+e;
		case this.LAUNCH_APPLET_TIMEOUT: 	return "Launch applet timeout reached"+e;
		case this.LAUNCH_APPLET_REPLY: 		return "Launch applet reply error"+e;
		case this.LAUNCH_APPLET_SECURITY:	return "Launch applet not trusted by user"+e;
		case this.LAUNCH_APPLET_WRITE: 		return "Launch applet disk write error"+e;
		case this.LAUNCH_APPLET_IMPOSSIBLE:	return "Launch applet can not be used"+e;
		case this.LAUNCH_APPLET_NO_COOKIE:	return "Launch applet had no cookie"+e;
		case this.LAUNCH_APPLET_NOT_READY:	return "Launch applet is not ready"+e;
		case this.LAUNCH_APPLET_UNKNOWN: 	return "Launch applet unknown error"+e;
		case this.LAUNCH_APPLET_JAVASCRIPT:	return "Launch applet javascript error"+e;
		case this.NO_BROWSER_PLUGIN:		return "Could not find browser plug-in"+e;
		case this.BROWSER_PLUGIN_NO_METHOD:return "Browser plugin is missing a method definition"+e;
		case this.LAUNCH_APPLET_NO_PLUGIN:	return "Launch applet did not find plugin"+e;
		case this.PLUGIN_ANSWER_BP_NOT_FOUND:return "Browser plugin could not find octo-plugin"+e;
		case this.JAVA_NOT_ENABLED:			return "Java disabled in browser"+e;
		case this.LAUNCH_APPLET_AFTER_INSTALL:return "Launch applet did not work after applet install"+e;
		case this.BP_AFTER_INSTALL:	return "Browser plugin did not work after applet install"+e;
		case this.CAB_IMPOSSIBLE:			return "Cab install can not be done"+e;
		case this.CAB_IMPOSSIBLE_VISTA:		return "Cab install can not be done on Vista"+e;
		case this.CAB_AFTER_INSTALL:		return "Cab has run"+e;
		case this.CAB_READY_STATE:			return "Cab ready state not defined"+e;
		case this.PROTOCAL_LAUNCH_AFTER:	return "Protocol launch has run"+e; 
		case this.PROTOCAL_LAUNCH_ERROR:	return "Protocol launch error"+e; 
		
		case this.FLASH_EULA_REJECT:		return "Flash EULA rejected"+e;
		case this.INSTALL_APPLET_JS:		return "Install applet JavaScript error"+e;
		case this.INSTALL_APPLET_UNKNOWN:	return "Install applet unknown error"+e;
		case this.INSTALL_APPLET_EXECUTION:	return "Install applet execution error"+e;
		case this.INSTALL_APPLET_NO_FILE:	return "Install applet no file error"+e;
		case this.INSTALL_APPLET_SECURITY:	return "Install applet not trusted by user"+e;
		case this.INSTALL_APPLET_EULA_REJECT:return "Install applet EULA rejected"+e;
		case this.NOT_SET:					return "JS value is not set."+e;
		}
		if((this.PLUGIN_ANSWER_BP_SUB-10) < err && err < this.PLUGIN_ANSWER_BP_SUB){
						return "Plugin error (BP): "+(((-this.PLUGIN_ANSWER_BP_SUB) + err)+'/'+e);
		}
		if((this.PLUGIN_ANSWER_APP_SUB-10) < err && err < this.PLUGIN_ANSWER_APP_SUB){
						return "Plugin error (APP): "+(((-this.PLUGIN_ANSWER_APP_SUB) + err)+'/'+e);
		}
		
		return "unknown"+e;
	};
	/** True iff the error code is from the an instance of the browser plugin,
		that is, we are installed but in some error state. */
	this.isBrowserPluginError = function(err){
		return ((this.PLUGIN_ANSWER_BP_SUB+10) < err && err < this.PLUGIN_ANSWER_BP_SUB);
	};
}

window.octoErrors = new octopv_ConstructErrorCodes();


/* #################################################################################### 
						GENERAL PLUGIN INTERFACE FUNCTIONS
                      functions integrated with auto-install
   #################################################################################### */

/**  */
function octoAbortAutoLaunch(){
	octopv_log.log('Aborting auto-launch');
	window.octopv_abortAutoLaunch=true;
	// should only be necesarry if we are currently running applet launch ...
	octopv_pluginLauncherApplet.resetAll(); 
};

/**  */
function octoManualLaunch(){
	octopv_log.log('Doing protocol launch');
	octopv_launchByProtocol();
};

/** 
	Starts up octoshape and reports the status to functionInt(status)
 */
function octoGetPluginStatus(functionInt, tryAutoInstall, messageFunction){
	var obj = new octopv_ConstructPluginLaunch(1, functionInt,null,messageFunction);
	obj.setUseInstall(tryAutoInstall);
	obj.start();
};

/** Starts up octoshape and reports the full ip address + port to functionIntString(status, url)
	on success status is 0
	on error status is <0 and the url may be undefined or null.	*/
function octoGetConnectUrl(functionIntString, tryAutoInstall, messageFunction){
	var obj = new octopv_ConstructPluginLaunch(2, functionIntString,null,messageFunction);
	obj.setUseInstall(tryAutoInstall);
	obj.start();
};

/*doc <!--
<function id="octoGetPlayLink" group="ajavascript functions"> 
	<description>
		Call this function every time you wish to play a link. 
		It will start up the Octoshape plugin-in and report the converted play link to the supplied 
		reply function.
		<BR /><BR />
		Do not call this function from the head section of an html document.
	</description>			
	<param id="octolink" description="The unique OctoLink you got from Octoshape" />
	<param id="replyFunctionIntString" 	>
		This must be a JavaScript function taking 2 arguments, a status (number) and the play link 
		(string). On a successfull launch (/and install) of the plug-in, the status is 0 and the 
		string is the converted play link. On error status is less than 0 and the string is null or 
		undefined. 
	</param>
	
	<param id="player_width" 	
		description="The width in pixels you want the embedded media player to have" />
	<param id="player_height">
		The height in pixels you want the viewing area of the embedded media player to have. 
		The actual player (including the controls below) is an additional 46 pixels high.
	</param>
	<param id="tryAutoInstall" optional="true" >
		If true we will attempt to perform an auto-install if the plug-in if it is not there already.
	</param>
	<param id="messageFunction" optional="true" >
		A function taking a string argument. It will be called during the auto-install with various
		messages, for instance 'Initializing installation', 'Running installer' etc.
	</param>
</function> 
 --> **/
function octoGetPlayLink(octolink, functionIntString, tryAutoInstall, messageFunction){
	var obj = new octopv_ConstructPluginLaunch(3, functionIntString, octolink,messageFunction);
	obj.setUseInstall(tryAutoInstall);
	obj.start();
};

/** Starts up octoshape and reports the option to functionIntString(status, resultSting)
	on success status is 0	
	on error status is <0 and the string can be null */
function octoGetStringOption(option,functionIntString, tryAutoInstall, messageFunction){
	var obj = new octopv_ConstructPluginLaunch(4, functionIntString, option, messageFunction);
	obj.setUseInstall(tryAutoInstall);
	obj.start();
};

/** Starts up octoshape and reports the sua veriosn to functionIntString(status, verisionString)
	on success status is 0
	on error status is <0 and the version may be undefined or null. */
function octoGetSuaVersion(functionIntString, tryAutoInstall, messageFunction){
	var obj = new octopv_ConstructPluginLaunch(5, functionIntString,null,messageFunction);
	obj.setUseInstall(tryAutoInstall);
	obj.start();
};

window.octopv_disableLaunches=new Object();

window.octopv_LAUNCH_START_UP=			1;
window.octopv_LAUNCH_GET_CONNECT_URL=	2;
window.octopv_LAUNCH_CONVERT_LINK=		3;
window.octopv_LAUNCH_GET_STRING=		4;
window.octopv_LAUNCH_GET_SUA_VERSION=	5;

/* PRIVATE function  
	There are 4 different possible argument sets of the first 3 arguments: 
	(1,functionInt,null): 			startup up octoshape and return status.
	(2,functionIntString,null):		Starts up octoshape and reports the connect url
	(3,functionIntString,octolink):	Starts up octoshape and reports the converted link
	(4,functionIntString,option):	Starts up octoshape and reports the option
	(5,functionIntString,option):	Starts up octoshape and reports the sua version
	Plus all functions will be called with a statistic reportString as last argument.
	NB: If the status argument to the reply function is negative(indicates an error state), 
		any subsequent argments may be undefined (except for the reportString)!
	
	tryAutoInstall:	may be undefined or boolean
	messageFunction: may be undefined or null or a function taking a string.
*/
function octopv_ConstructPluginLaunch(replyKind, replyFunction1, arg, messageFunction){
	this.isFinished=false;
	this._doAutoInstall = false;

	// the number of parameters to the reply function.
	this._replyFunctionParameterNum = replyKind==octopv_LAUNCH_START_UP?1:2;
	this._kind = replyKind;
	this._arg = arg;
	this.stat=null;
	var top=this;
	
	this.setUseInstall=function(useIt){
		this._doAutoInstall = (typeof(useIt)=='boolean' && useIt);
	};
	
	// TODO set from osa
	this.setUseLaunchStat=function(playerId, instanceId, statTimeout){
		this.stat = new octopv_ConstructLaunchStatistics(playerId, instanceId, replyKind+"", 
				this._doAutoInstall, statTimeout); 
	};
	
	/* **********************    Message function helpers    ********************* */
	/*  Some helper wrappers for the callers message funstion 
		(which is an optional argument). */
	function messageLaunch(){
		if(typeof(messageFunction)=='function'){
			messageFunction("Launching Octoshape");
		}
	}
	function messageInstall(){
		if(typeof(messageFunction)=='function'){
			messageFunction("Installing Octoshape");
		}
	}
	function messageEnd(success){
		if(typeof(messageFunction)=='function'){
			if(success){
				messageFunction("Octoshape launch success");
			}else{
				messageFunction("Octoshape launch failed");
			}
		}
	}

	/* **********************    The result function     ********************* */

	function logApart(str, tag){
		if(str == null){
			var str2="";
			var i = 10;
			for(;i>0;i--){
				str2+="**********";
			}
			octopv_log.log(' '+str2+' ',tag);
		}else{
			var s = '';
			var len = ((90-str.length)-1)/2;
			while(len>0){
				s += '.';
				len--;
			}
			var ex = str.length%2==0?'':'.';
			octopv_log.log(' *****'+s+str+s+ex+'***** ',tag);
		}
	}
	
	/* We report a 'super' attempt for the entire pluginLaunch function.
	   To ensure that we close this attempt again we make a wrapper for the 
	   callers replyFunction1 */
	function replyFunction(theIntState, theStringReply){
		if(octopv_abortAutoLaunch) return;
		if(top.stat!=null){
			octopv_log.log('calling close on this.stat ... ');
			top.stat.close(theIntState);
		}else{
			octopv_log.log('NB: stat was null!'+typeof(top.stat));
		}
		messageEnd(theIntState==0);
		octopv_log.log('String reply: '+theStringReply);
		var str = 'Final status: '+octoErrors.print(theIntState);
		logApart(str,'replyFunction');
		logApart(null,'replyFunction');
		/* Note to self: no we can not just use replyFunction1.apply(this,arguments)
			since we do not want to change the value og 'this' inside the callers 
			reply-function.  */
		// last argument to replyfunction is for backwards compatible (old stat report)
		if(this._replyFunctionParameterNum==1){
			replyFunction1(theIntState, "");	
		}else{
			replyFunction1(theIntState, theStringReply,"");	
		}
		this.isFinished=true;
	}
	
	/* ************************       Run obj wrapper      *********************** */
	function ConstructWrap(parent, myId){
		/* PRIVATE functions and properties  */
		this.content=parent;
		this._runId=myId;
		this.running=false;
		this.exitState=octoErrors.WRAP_ERROR; 
		this._hasRun=false;
		this._statAttId="";
		this._logTag = 'wrap-'+this._runId;
		
		this.isClosed=function(){
			var isRunOnce = typeof(this.content.runonce)=='boolean' && this.content.runonce;
			var hasExit = this.exitState!=octoErrors.WRAP_ERROR;
			return (isRunOnce && this._hasRun && hasExit);
		};

		this.start=function(onError){
			if(this.running){
				octopv_log.log('ERROR: calling start on running run-obj',this._logTag);
				return;	
			}
			if(this.isClosed()){
				octopv_log.log('calling start on closed run-obj',this._logTag);
				onError(this.exitState);
				return;	
			}
			this.running=true;
			if(top.stat!=null){
				this._statAttId=top.stat.beginAttempt(this._runId);
			}
			var me = this;
			logApart('OPENING '+this._runId,this._logTag);
			this.content.start(function(err){
				if(me._close(err,onError)){
					onError(err);
				}
			}, function(str){
				if(me._close(0,replyFunction)){
					replyFunction(0,str);
				}
			});
		};
		
		this._close=function(state, func){
			if(!this.running){
				octopv_log.log('ERROR: calling close on not running run-obj',this._logTag);
				return false;
			}
			if(typeof(func)!='function'){
				octopv_log.log('ERROR: reply function('+state+') is '+typeof(func),this._logTag);
				return false;
			}
			var str='CLOSING '+this._runId+': '+octoErrors.print(state);
			logApart(str,this._logTag);
			this._hasRun=true;
			this.exitState=state;
			this.running=false;
			if(top.stat!=null){
				top.stat.endAttempt(state,this._statAttId);
			}
			return true;
		};
	}
	
	/* Applet intall helper */
	function runInstallByApplet(eula, tApp, pApp, iApp){
		//--- The auto-install procedure
		//- Two procedures are started to run in parallel, and we wait for both to complete 
		// before moving on.
		//- The first one:
		//- if AppletTest returns that we have applet support
			//- then if #PreloadInstallApplet.canAnswer 
				//- then preload applet is run to download the install applet.
		//- The second runs the falsh eula. 
		//- (the result is that we download the install applet while the user contemplates the eula).
		//- When both have finished with positive results, we run the actual install applet
		function onFinish(errApp){
			//-	if the install was successful but did not return the port
			if(errApp==octoErrors.INSTALL_APPLET_OK){
				var nlApp_1 = new octopv_ConstructAppletLaunch(top._kind, top._arg);
				var nlApp = new ConstructWrap(nlApp_1,"applaunch");
				if(nlApp.content.canAnswer()==0){
					//-	if #AppletLaunch.canAnswer
					//-	we try the applet launcher
					nlApp.start(function(errLApp){
						//-	if that fails we return that we think we are installed,
						// but could not get port.
						replyFunction(octoErrors.LAUNCH_APPLET_AFTER_INSTALL);
					});
				}else{ //- else (AppletLaunch failed)
					var nlBp = new ConstructWrap(new octopv_ConstructBP(top._kind,top._arg),"bp");
					//-	we try the BrowserPlugin
					nlBp.start(function(errBp2){
						//-	if that fails we return that we think we are installed, 
						// but could not get port.
						replyFunction(octoErrors.BP_AFTER_INSTALL);
					});
				}
			}else{ //- else (install applet was not successful)
				//- we return the install applet error (might be no to the eula etc.)
				replyFunction(errApp);
			}
		};
		function afterEulaAndPreload(){
			octopv_log.log('after eula called ... ');
			if(eula.isClosed() && tApp.isClosed() && !pApp.running){ 
				if(pApp.exitState == octoErrors.PRELOAD_APPLET_OK){
					// we must try the install applet.
					messageInstall();
					iApp.start(function(err4){
						onFinish(err4);
					}); 
				}else{
					if(pApp.isClosed()){
						onFinish(pApp.exitState);
					}else{
						onFinish(tApp.exitState);
					}
				}
			}
		}
		tApp.start(function(errTest){
			octopv_log.log('test ok?: '+octoErrors.print(errTest),'super-app-install');
			if(errTest==octoErrors.TEST_APPLET_OK){
				pApp.start(function(errLoad){
					octopv_log.log('load ok?: '+octoErrors.print(errLoad),'super-app-install');
					afterEulaAndPreload();
				});
			}else{
				afterEulaAndPreload();
			}
		});
		eula.start(function(err1){
			if(err1==octoErrors.FLASH_EULA_ACCEPT){
				afterEulaAndPreload();
			}else{ 
				onFinish(err1);
			}
		});
	}

	/* *******************       Filling Launch and install attempts      ****************** */
	
	//--- The auto-launch procedure
	this.start=function(){
		var str = 'Auto-Launch ('+replyKind+') called. Auto-install: '+this._doAutoInstall;
		logApart(null,'start');
		logApart(str,'start');
		messageLaunch();
		window.octopv_abortAutoLaunch=false;
		if(this.stat!=null) this.stat.open();
		
		// We only make one AppletTest and use it everywhere, since running it a second time 
		// will not actually insert the applet again, but just return the previous answer. 
		// timeout 8 secs
		var appletTest = new ConstructWrap(new octopv_ConstructAppletTest(8000),"apptest");

		// Likewise we only have one eula.
		var eula = new ConstructWrap(new octopv_ConstructShowEula(),"feula");
		
		var arr=new Array();
		var jshttp=new ConstructWrap(new octopv_ConstructJsHttp(6498,8247,2000,this._kind),"jshttp"); 
		if(jshttp.content.canAnswer()==0){	//-	if JsHttp is possible
			//-	we try JsHttp port 6498 and 8247
			arr.push(jshttp);
			arr.push(new ConstructWrap(new octopv_ConstructBP(this._kind,this._arg),"bp"));
		}else{	//-	else
			arr.push(new ConstructWrap(new octopv_ConstructBP(this._kind,this._arg),"bp"));
			arr.push(new ConstructWrap(new octopv_ConstructPortFlash(6498, 8247,this._kind),"fbp"));
		}
		octopv_runAllRunObjects2(0,arr,function(bpErr){
			messageLaunch();
			appletTest.start(function(errTapp){
				//-	if #AppletTest.canAnswer we run AppletTest 
				//- (to see if user has applet support) and if that was a success 
				if(errTapp==octoErrors.TEST_APPLET_OK){
					//-	if #AppletLaunch.canAnswer we run the AppletLaunch 
					var lApp = new ConstructWrap(new octopv_ConstructAppletLaunch(top._kind,top._arg),"applaunch");
					messageLaunch();
					lApp.start(function(errLapp){
						//-	if we should not do auto-install
						if(!top._doAutoInstall){
							//-	if AppletLaunch was run 
							if(lApp.content.canAnswer()==0){							
								//-	we return the AppletLaunch error
								replyFunction(errLapp);
							}else{ // - else (AppletLaunch could not run)
								//-	we return the BrowserPlugin error
								replyFunction(bpErr);
							}
						}else{	//- else (should do auto-install)
							//- This probably means that octoshape is not installed,
							//- But 1: If we are on windows and has IE, this might mean that a yellow
							//-		bar is showing, so we do not trust the negative answer completely.
							//- But 2: We should be able to trust the 'no octo' answer in FX, but 
							//-		super-tester-1 had an issue in FX where this did not work 
							//-		(after an install, without browser re-start).
							//-	So we run the applet install procedure in all cases 
							//-	we start the applet install procedure
							var preload = new octopv_ConstructPreloadInstallApplet(appletTest.content, 20000);
							var install = new octopv_ConstructInstallApplet(top._kind);
							messageInstall();
							runInstallByApplet(eula, appletTest, new ConstructWrap(preload,"appload"),
									new ConstructWrap(install,"appinstall"));
						}
						
					});
				}else{ //- else (AppletTest failed) 
					//- if we should not do auto-install
					if(!top._doAutoInstall){
						//- we return the browser plugin error code 
						replyFunction(bpErr);
					}else{ //- else (we should do auto-install)
						var cab = new ConstructWrap(new octopv_ConstructCabInstall(3000,eula),"cabinstall");
						messageInstall();
						cab.start(function(errCab){
							//- if #CabInstall.canAnswer 
							//- we try the CabInstall (with flash eula) and 
							//- if there were no errors (does not mean that it was successful) 
							if(errCab==octoErrors.CAB_AFTER_INSTALL){
								messageLaunch();
								//- if we can do JsHttp 
								if(window.XDomainRequest){ 
									//- we try JsHttp with port 6498 and 8247 and then the BrowserPlugin
									var jshttp_2 = new octopv_ConstructJsHttp(6498, 8247,2000, top._kind);
									var jshttp2 = new ConstructWrap(jshttp_2, "jshttp"); 
									var bp_2 = new octopv_ConstructBP(top._kind,top._arg);
									var bp2 = new ConstructWrap(bp_2,"bp");
									octopv_runAllRunObjects(jshttp2,bp2,replyFunction);
								}else{ //- else (no JsHttp)
									//- we try PortFlash with port 6498 and 8247 and then the BrowserPlugin
									var fbp_2 = new octopv_ConstructPortFlash(6498, 8247,top._kind);
									var fbp2 = new ConstructWrap(fbp_2, "fbp");
									var bp_2 = new octopv_ConstructBP(top._kind,top._arg);
									var bp2 = new ConstructWrap(bp_2,"bp");
									octopv_runAllRunObjects(fbp2,bp2,replyFunction);
								}
							}else{ //- else (CabInstall failed) 
								//- we report that 
								replyFunction(bpErr);
							}
						});
					}
				}
			});
		});
	}
	window["octopv_autolaunch"+octopv_getJsUniqueId()] = this;
}

function octopv_runAllRunObjects(){
	var endFunction = arguments[arguments.length-1];
	var arr=new Array(arguments.length-1);
	for(var i=0;i<arr.length;i++){
		arr[i] = arguments[i];
	}
	octopv_runAllRunObjects2(0,arr, endFunction);
};

function octopv_runAllRunObjects2(i,arr, endFunction){
	var toRun = arr[i];
	toRun.start(function(err){
		var i2=i+1;
		if(i2<arr.length){
			octopv_runAllRunObjects2(i+1,arr,endFunction);
		}else{
			endFunction(err);
		}
	});
};

/* #################################################################################### 
					WRAPPER OF GENERAL PLUGIN INTERFACE FUNCTIONS
                      			for use by osas 
   #################################################################################### */

function octoGetConnectUrlOsa(swfname, tryAutoInstall, statTimeout, playerId, instanceId){
	var asosa=null;
   	if (navigator.appName.indexOf("Microsoft") != -1) {
   		asosa=window[swfname];
   	}else{
   		asosa=document[swfname];
	}
   	if(typeof(asosa)=='undefined'){
		octopv_log.log('ERROR!: could not get a hold of asosa swf: '+swfname);
   	}
	var obj = new octopv_ConstructPluginLaunch(2, function(intStatus, stringReply){
		asosa.octopvAS_jsreply(intStatus,stringReply);
	},null,
	function(message){
		if(typeof(message)=="string"){
			try{
				asosa.octopvAS_jsmessage(message);
			}catch(ex){
				octopv_log.log('Could not call message function on asosa: '+ex);
			}
		}
	});
	obj.setUseInstall(tryAutoInstall);
	if(typeof(statTimeout)=='number' && typeof(playerId)=='string'){
		octopv_log.log('Using launch stat ('+playerId+') since it was set from osa.');
		obj.setUseLaunchStat(playerId, instanceId, statTimeout); 
	}else if(document.domain=='www.octoshape.com'){
		octopv_log.log('Using launch stat since we are on www.octoshape.com.');
		obj.setUseLaunchStat("octoshape", null, 30000); 
	}
	obj.start();
};

// silver-osa:
window.octopv_osaPullCount = 0;
function octopv_ConstructOsaPullObject(){
	octopv_osaPullCount++;
	this.name = "octopv_osaPullObject"+octopv_osaPullCount;
	this.status = octoErrors.NOT_SET; // -999
	this.url = "";
	this.message = "";
	this.statustype = "url";

	// set from outside.
	this.tryAutoInstall = false; 	// public
	this.updatelink = null;			// public
	this.okSuaVersion=null;			// public
	
	this.setMessage=function(m){
		if(typeof(m)=="string"){
			this.message=m;
		}
	};
	this.setResult = function(s,u){
		this.status=s;
		if(s==0){
			this.url=u;
		}
	}
	
	// public
	this.start=function(){
		var me=this;
		octoGetConnectUrl(function(intStatus, stringReply){
			if(intStatus==0 && me.updatelink!=null && me.okSuaVersion!=null){
				me.doSuaUpdate(intStatus, stringReply);
			}else{
				me.setResult(intStatus, stringReply); 
			}},
			me.tryAutoInstall,
			function(message){ me.setMessage(message);},
			function(versionInt,attId,ranId,jsId,cookieId, millis,name,result){}
		);
	};
	
	this.doSuaUpdate=function(intStatus, stringReply){
		var me=this;
		octopv_forceSuaUpdateIfNeeded(me.updatelink, me.okSuaVersion, function(suaResult){
			if(suaResult == 0){
				// the current sua version was ok
				me.setResult(intStatus, stringReply); 
			}else if(suaResult == 1){
				// we have updated the sua, and are now ready again.
				me.okSuaVersion=null;
				me.updatelink=null;
				me.start();				
			}else{
				// If octoshape not installed or there was some error with the browser plugin
				var logStr = 'We failed at sua update after success at get url.';
				octopv_log.log(logStr+'Sua result: '+octoErrors.print(suaResult));
				me.statustype='sua';
				me.setResult(suaResult, ""); 
			}
		});
	};
};

function octoGetConnectUrlOsaPullBegin(tryAutoInstall, updatelink, okSuaVersion){
	var pullObject = new octopv_ConstructOsaPullObject();
	window[pullObject.name] = pullObject;
	pullObject.tryAutoInstall=tryAutoInstall;
	var updateLinkOk = (typeof(updatelink)=='string' && updatelink!="");
	var okSuaVersionOk = (typeof(okSuaVersion)=='string' && okSuaVersion!="");
	if(updateLinkOk && okSuaVersionOk){
		octopv_log.log('Yes sua update. '+updatelink+'/'+okSuaVersion);
		pullObject.updatelink=updatelink;
		pullObject.okSuaVersion=okSuaVersion;
	}else{
		octopv_log.log('No sua update. '+updatelink+'/'+okSuaVersion);
	}
	pullObject.start();
	return pullObject.name;
};

// kind must be one of 'status', 'url', 'message', or 'statustype' (kan be 'sua' or 'url').
function octoGetConnectUrlOsaPull(name, kind){
	var obj = window[name];
	return obj[kind];
}

function octoCleanOsaPull(name){
	if(typeof(window[name])!='undefined'){
		delete window[name];
		octopv_log.log('have deleted '+name+'. type now: '+(typeof(window[name])));
	}
}

/* #################################################################################### 
                                 USER PREFERENCES
                             variables and functions
   #################################################################################### */

function octopv_ConstructPreferencePluginLaunch(){
	this.cookieCanUse=function(id){
		return octopv_hasCookie("octoweb"+id+"=true");
	};

	// TODO should also be called by windows applet install when 
	// installer tells us that we are preaproved.
	this.cookieSetCanUse=function(id){
		octopv_log.log('Setting cookie for: '+id+' ');
		var date = new Date();
		date.setTime(date.getTime()+(31*24*60*60*1000)); // one month expiry
		document.cookie = "octoweb"+id+"=true; expires="+date.toGMTString()+"; path=/";
	};
}
window.octopv_prefsPluginLaunch=new octopv_ConstructPreferencePluginLaunch();

/* #################################################################################### 
                                    STATISTICS 
                             variables and functions
   #################################################################################### */

function octopv_ConstructDirectStat(){
	this._logTag="octostat";
	this._obj=null;
	this._listeners=new Array();
	
	//<-1: some error state
	// -1: nothing done
	//  0: ready 
	//  1: inserted and waiting for reply
	this._state=-1;
	
	this.ready=function(reply){
		switch(this._state){
		case -1: 
			this._listeners.push(reply);
			this._insert();
			return; 
		case 1: 
			this._listeners.push(reply);	
			return; 
		default: 
			reply(this._state); 			
			return; 
		}
	};	

	var arr = this._listeners;
	this._callListeners=function(){
	this._listeners=new Array();
	for(var i=0; i<arr.length; i++){
			arr[i](this._state);
		}
	};	

	this.openSession=function(strXmlString,keepAlive){
		try{
			var statId = this._obj.openSessionStr(strXmlString,keepAlive);
			return statId;
		}catch(ex){
			octopv_log.log("Exception while calling open: "+ex,this._logTag);
			return null;
		}
	};
	
	
	this.finishedSession=function(strXmlString){
		try{
			this._obj.finishedSessionStr(strXmlString);
		}catch(ex){
			octopv_log.log("Exception while calling finished: "+ex,this._logTag);
		}
	};	
	
	
	this.updateSession=function(statIdString, strXmlString){
		try{
			this._obj.updateSessionStr(statIdString, strXmlString);
		}catch(ex){
			octopv_log.log("Exception while calling update: "+ex,this._logTag);
		}
	};	
	
	this.closeSession=function(statIdString, strXmlString){
		try{
			this._obj.closeSessionStr(statIdString, strXmlString);
		}catch(ex){
			octopv_log.log("Exception while calling close: "+ex,this._logTag);
		}
	};

	this._initTimoutReached=function(){
		if(this._state==1){
			this._state = -2; 
			octopv_log.log('Timeout has been reached and we had no answer from flash',this._logTag);
			this._callListeners();
		}else{
			octopv_log.log('(Timeout has been reached, but we already replied)',this._logTag);
		}
	}

	this._initFromFlash=function(swfname){
		octopv_log.log('init-function called',this._logTag);
		var oldState = this._state;
		this._state = 0; 
    	if (navigator.appName.indexOf("Microsoft") != -1) {
    		this._obj=window[swfname];
    	}else{
    		this._obj=document[swfname];
 		}
    	if(oldState==-2){
			octopv_log.log("Init called after timeout was reached.",this._logTag);
    	}else{
			this._callListeners();
    	}
	}
	
	this._insert=function(){
		this._state = 1; 
		var myId="octopv_directStatId";
		var jslog=octopv_log.isShowing();
		var debug=false;
		
		var timeoutfunctionName=myId+'timeout';
		var initfunctionName=myId+'init';
		var flashName=myId+'name';
		var path = octopv_paths.get('octostat.swf');
		var flashVars = 'init='+initfunctionName+'&debug='+debug+'&jslog='+jslog;
		
	  	var html  = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
	   	html += ' id="'+flashName+'" ';
	    if(debug){
		   	html += ' width="800" height="200"';
	    }else{
		   	html += ' width="0" height="0"';
	    }
	    html += ' codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">';
	    html += ' <param name="movie" value="'+path+'" />';
	    html += ' <param name="FlashVars" value="'+flashVars+'" />';
	    html += ' <param name="wmode" value="transparent" />';
	    html += ' <param name="AllowScriptAccess" value="always" />';
	    html += ' <embed src="'+path+'"';
	    if(debug){
		    html += ' width="800" height="200"';
	    }else{
		    html += ' width="1" height="1"';
	    }
	    html += ' name="'+flashName+'"';
	    html += ' AllowScriptAccess="always"';
	    html += ' FlashVars="'+flashVars+'"';
	    html += ' play="true" loop="false" wmode="transparent"';
	    html += ' type="application/x-shockwave-flash" ';
	    html += ' pluginspage="http://www.adobe.com/go/getflashplayer">';
	    html += ' </embed></object>';
	    
		octopv_log.log('Inserts flash helper from '+path,this._logTag);
		
		window[initfunctionName]=function(swfname){
			octopv_directStatObject._initFromFlash(swfname);
		};
		var w = debug?800:-1;
		var h = debug?200:-1;
		if(octopv_writeInNewDiv(html,w,h)){
			// We set a timeout here just in case there is something wrong with the swf,
			//  and it does not get initialized. It should never happen though.
			window[timeoutfunctionName]=function flashStat_timeout2(){
				octopv_directStatObject._initTimoutReached();
			};
			setTimeout("window."+timeoutfunctionName+"();",4500);
	    }else{
			octopv_log.log('Could not write to div',this._logTag);
			this._state = -3; 
			this._callListeners();
	    }
	};
}
window.octopv_directStatObject=new octopv_ConstructDirectStat();

function octopv_ConstructLaunchStatistics(playerId, instanceId, replyKind, useInstall, timeout){
	this._logTag="octostat";
	this._enabled=true;
	this._statTimeout=timeout;
	this._playerId=playerId;
	this._instanceId=instanceId;
	this._statId=null;
	this._begin=0;
	this._end=0;
	this._result=-9999;
	this._attempts = new Array();
	this._reply = replyKind;
	this._install=useInstall;
	
	this._cookieid = octopv_getCookie("octowebstatid");
	if(this._cookieid==null||this._cookieid==""){
		this._cookieid=octopv_randomString(20);
	}
	var date = new Date();
	date.setTime(date.getTime()+(365*24*60*60*1000)); // one year expiry
	document.cookie = "octowebstatid="+this._cookieid+"; expires="+date.toGMTString()+"; path=/";

	this._toXml=function(){
		var xml = '<autolaunch ';
		xml+='reply="'+this._reply+'" ';
		if(this._install){
			var vari = octopv_paths.getVariant();
			if(vari==null || vari==""){
				vari='octoshape';
			}
			xml+='install="'+vari+'" ';
		}
		if(this._playerId){
			xml+='playerid="'+this._playerId+'" ';
		}
		if(this._instanceId){
			xml+='instanceid="'+this._instanceId+'" ';
		}
		xml+='version="0" ';
		xml+='jsid="'+window.octopv_randomId+'" ';
		xml+='cookieid="'+this._cookieid+'" ';
		xml+='useragent="'+navigator.userAgent+'" ';
		xml+='jsversion="'+octopv_fileVersion+'" ';
		if(octopv_log.isShowing()){
			xml+='debug="true" ';
		}
		//xml+='="'++'" ';
		xml+='begin="'+this._begin+'" ';
		if(this._end>0){
			xml+='end="'+this._end+'" result="'+this._result+'" ';
		}
		xml+=' >';
		var ai=0;
		for (;ai<this._attempts.length;ai++){
			xml+=this._attempts[ai].toXml();
		}
		xml += '</autolaunch>';
		return xml;
	};

	/* Public function*/
	this.open=function(){
		if(this._end>0){
			octopv_log.log("ERROR: opening closed stat session: "+this._statId,this._logTag);
			return;
		}
		if(this._begin>0){
			octopv_log.log("ERROR: opening opened stat session: "+this._statId,this._logTag);
			return;
		}
		this._begin=new Date().getTime();
		if(this._enabled){
			var me = this;
			octopv_directStatObject.ready(function(status){
				if(status==0){
					octopv_log.log('Stat is ready, now to call open session.',me._logTag);
					var xml = me._toXml();
					if(me._end>0){
						octopv_directStatObject.finishedSession(xml);
					}else{
						me._statId=octopv_directStatObject.openSession(xml,me._statTimeout);
						if(me._statId==-1){
							octopv_log.log('Stat open returned -1. Disabling stat.',me._logTag);
							me._enabled=false;
						}
					}
				}else{
					octopv_log.log('Stat error: '+status,me._logTag);
					me._enabled=false;
				}
			});
		}
	};
	
	/* Public function */
	this.beginAttempt=function(name){
		if(this._end>0){
			octopv_log.log("ERROR: begin attempt on closed stat session: "+this._statId,this._logTag);
			return "";
		}else{
			var att = new ConstructAttempt(name, this._logTag);
			var newLen = this._attempts.push(att);
			this._updateStat();
			return (newLen-1);
		}
	};
	
	/* Public function*/
	this.endAttempt=function(intResult, attId){
		if(this._end>0){
			octopv_log.log("ERROR: end attempt on closed stat session: "+this._statId,this._logTag);
		}else{
			var att = this._attempts[attId];
			if(typeof(att)=='object' && typeof(att.end)=='function'){
				att.end(intResult);
				this._updateStat();
			}
		}
	};
	
	/* Public function*/
	this.close=function(intResult){
		if(this._end>0){
			octopv_log.log("ERROR: Closing already closed stat session: "+this._statId,this._logTag);
		}else{
			this._end=new Date().getTime();
			this._result=intResult;
			this._updateStat();
		}
	};
	
	this._updateStat=function(){
		if(this._enabled && this._statId!=null){
			if(this._end>0){
				octopv_directStatObject.closeSession(this._statId, this._toXml());
			}else{
				octopv_directStatObject.updateSession(this._statId, this._toXml());
			}
		}else{
			var logStr = "Not updating since enabled:"+this._enabled+". ";
			octopv_log.log(logStr+"Is open:"+this._statId,this._logTag);
		}
	};
	
	function ConstructAttempt(name1,logTag){
		this._logTag=logTag;
		this._name = name1;
		this._begin = new Date().getTime();
		this._end = 0;
		this._result = -1; 

		this.end=function(intResult){
			if(this._end>0){
				octopv_log.log("ERROR: end attempt on already ended att ",this._logTag);
			}else{
				this._end=new Date().getTime();
				this._result=intResult;
			}
		}
		
		this.toXml=function(){
			var xml = '<attempt name="'+this._name+'" begin="'+this._begin+'" ';
			if(this._end>0){
				xml+='end="'+this._end+'" result="'+this._result+'" ';
			}
			xml+=' /> ';
			return xml;
		};
	}
}

/* #################################################################################### 
                                 BROWSER PLUGIN 
                             variables and functions
   #################################################################################### */

function octopv_ConstructBP(replyKind, strArg){
	this._replyKind=replyKind;
	this._strArg=strArg;
	this.canAnswer=function(){
		if(window.octopv_bp.canHave()){
			return 0;
		}else{
			return window.octoErrors.BP_IMPOSSIBLE;
		}
	};
	var me=this;
	this.start=function(onError, onSuccses){
		window.octopv_bp.makePluginReady(function(result){
			if(result==0){
				octopv_prefsPluginLaunch.cookieSetCanUse("BrowserPlugin");
				switch(me._replyKind){
				case octopv_LAUNCH_START_UP: onSuccses(0); break;
				case octopv_LAUNCH_GET_CONNECT_URL: 
					var xml = window.octopv_bp.plugin.getString('xmlbound');
					onSuccses(xml); 
					break;
				case octopv_LAUNCH_CONVERT_LINK: 	
					var playlink = window.octopv_bp.plugin.getLink(me._strArg,false);
					octopv_log.log('Got play link from browser plugin: '+playlink+'.');
					onSuccses(playlink); 
					break;
				case octopv_LAUNCH_GET_STRING: 
					onSuccses(window.octopv_bp.plugin.getString(me._strArg)); 
					break;
				case octopv_LAUNCH_GET_SUA_VERSION:
					var xml = window.octopv_bp.plugin.getString('suaversion');
					onSuccses(xml); 
					break;
				}
			}else{
				if(result == octoErrors.NO_BROWSER_PLUGIN){
					var browserNotIE=navigator.userAgent.toLowerCase().indexOf("msie") == -1;
					var hasCookie=octopv_prefsPluginLaunch.cookieCanUse("BrowserPlugin");
					var logStr='We trust this answer? cookie:'+hasCookie+' / non-ie:'+browserNotIE;
					octopv_log.log('Not found ('+result+'). '+logStr);
					onError(result);
				}else{
					onError(result);
				}
			}
		});
	};	
}

function octopv_ConstructBrowserPlugin(){
	this.plugin = null;
	this._replyFunction = function(){};
	
	this._setPlugin = function BPsetPlugin(plug){
		this.plugin=plug;
		this._readyRepeat();
	};

	this._convertPluginError=function(error){
		if(error==-1) return octoErrors.PLUGIN_ANSWER_BP_NOT_FOUND;
		return -((-octoErrors.PLUGIN_ANSWER_BP_SUB)+(-error));
	};
	
	this._readyRepeat=function BPReadyRepeat(){
		try {
			var result = this.plugin.getStatus(true);
			switch (result){
		 		case 1:
					// we call our self again in 2000 milli-seconds
					setTimeout("window.octopv_bp._readyRepeat();",1000);
					return;
				case 2:
					// octoshape is already started up, so we reply to any listener
					this._replyFunction(0); 
					return;
		 		default:
					this._replyFunction(this._convertPluginError(result)); 
		 			return;
			}
		}catch (exception) {
			octopv_log.log('window.octopv_bp._readyRepeat exception '+exception);
			this._replyFunction(this._convertPluginError(-6)); 
		}
	}

	this._check=function BPCheck(octoobject){
		if (octoobject==null || typeof(octoobject) == "undefined"){
			octopv_log.log('Octoobject('+octoobject+'): is typeof undefined');
			return octoErrors.NO_BROWSER_PLUGIN;
		}
		if (typeof(octoobject.getStatus) == "undefined") {
			octopv_log.log('Octoobject('+octoobject+'): has no getStatus method');
			return octoErrors.BROWSER_PLUGIN_NO_METHOD;	
		}
		return 0;
	}

	this._mimeType=function BPMimetype() {
		var octomime = "application/x-octoshapeplugin"+octopv_group+"-client";
		octopv_log.log("Trying to get browser plugin by mime type: "+octomime);
						
		if (navigator && navigator.mimeTypes && navigator.mimeTypes.length > 0) {
			var mimetype = navigator.mimeTypes[octomime];

			if (!mimetype && (navigator.plugins)) {
				octopv_log.log("Refreshing plugins");
				navigator.plugins.refresh(false);
				mimetype = navigator.mimeTypes[octomime];
			}

			if (!mimetype) {
				octomime = octomime.toLowerCase();
				mimetype = navigator.mimeTypes[octomime];
			}
			
			if (mimetype) {
				var name = 'octoshapeclientobject';
				var octoshape = document.getElementById(name);
				if (!octoshape) {
					octopv_log.log("We have no "+name+" object");
					var html = "";
					if(octopv_isOSX()){
						html = '<embed id="'+name+'" type="'+octomime+'" hidden="true"></embed>';
					}else{
						var style = 'height:0px; width:1px; visibility:hidden;';
						html = '<object id="'+name+'" type="'+octomime+'" style="'+style+'" />';
						
					}
					octopv_writeInNewDiv(html);
					octoshape = document.getElementById(name);
				}
				octopv_log.log("Have inserted html mime type object, now checking object. ");
				if (this._check(octoshape)==0) {
					octopv_log.log("Client loaded using mimeTypes:" + octomime);
					this._setPlugin(octoshape);
					return true;
				}else{
					octopv_log.log("Mime type "+octomime+" not known. Inserted object:"+octoshape);
					octopv_log.log("We try to wait 1 second ... ");
					
					octopv_setTimeoutFunction(1000, function(){
						octopv_log.log("After waiting 1 second for browser plugin");
						var octoDims = document.getElementById('octoshapeclientobject');
						if (octoDims==null || typeof(octoDims) == "undefined"){
							window.octopv_bp._replyFunction(octoErrors.NO_BROWSER_PLUGIN);
						}
						if (typeof(octoDims.getStatus) == "undefined") {
							window.octopv_bp._replyFunction(octoErrors.BROWSER_PLUGIN_NO_METHOD);
						}
						octopv_log.log("Browser plugin ok after wait");
						window.octopv_bp._setPlugin(octoDims);
					});
					return true;
				}
			} 
		}
		return false;
	};
	
	/**	We start up octoshape and 
	 *	replyFunction is a function taking and int reply/error code + the octoshape plugin instance 
	 *		where the second argumet may be undefined if the first is non-zero. **/
	this._getBp=function BPGet(){
		// Do not call this from the head section of a document.
		var errorCode = octoErrors.NO_BROWSER_PLUGIN;
		try {
			if (window.ActiveXObject) {
				try {
					var octoshape = new ActiveXObject("octoshapeplugin"+octopv_group+".client");
					errorCode = this._check(octoshape);
					if(errorCode==0){ 
						octopv_log.log("Client loaded using ActiveXObject");
						this._setPlugin(octoshape)
						return; 
					}
				} catch(exception) {}
			}
		
			if (window.GeckoActiveXObject) {
				try {
					var octoshape = new GeckoActiveXObject("octoshapeplugin"+octopv_group+".client");
					errorCode = this._check(octoshape);
					if(errorCode==0){ 
						octopv_log.log("Client loaded using GeckoActiveXObject");
						this._setPlugin(octoshape)
						return;
					}
				} catch(exception) {}
			}
			
			// Crashes opera
			if (false && navigator && navigator.plugins && navigator.plugins.length > 0) {
				var octoshape = navigator.plugins["application/x-octoshapeplugin"+octopv_group+".client"];
				errorCode = this._check(octoshape);
				if(errorCode==0){ 
					octopv_log.log("Client loaded using navigator.plugins");
					this._setPlugin(octoshape)
					return;
				}
			}
		
			if(navigator && navigator.mimeTypes && navigator.mimeTypes.length > 0) {
				if(this._mimeType()) return;
			}
		} catch (exception) {
			if(this._mimeType()) return;
		}
		
		octopv_log.log("Client loading failed all together.");
		this._replyFunction(errorCode);
	};
	
	this.canHave=function(){
		var text = navigator.userAgent.toLowerCase();
		if (text.indexOf("windows") >= 0 || text.indexOf("mac os x") >= 0 ) {
			return (text.indexOf("opera") == -1);
		} 
		return false;
	};

	// if replyfunction is called with 0, then use the plugin property.
	// NB: replyFunction is set on bp object so 'this' inside it is bp object.
	this.makePluginReady=function(replyFunction){
		this._replyFunction = replyFunction;
		if(this._check(this.plugin)==0){
			this._readyRepeat();
		}else{
			this._getBp();
		}
	};
}

window.octopv_bp = new octopv_ConstructBrowserPlugin();

/* #################################################################################### 
                                 APPLET PRELOADER                                        
                             
   #################################################################################### */

window.octopv_preloadAppletCount=0;
window.octopv_preloadAppletReplies=new Object();
function octopv_initAppletInited(callbackId, major,minor,micro,osVersion){
	octopv_log.log("got applet reply for "+callbackId);
	if(arguments.length>=4){
		octopv_log.log('System info: java version 1.'+major+'.'+minor+'_'+micro);
	}
	octopv_preloadAppletReplies[callbackId](major,minor,micro,osVersion);
}

/**	This can be used for testing to see if java works and for preloading jar archive files.
	arguments:
	- replyFunction takes an int that is either:
		0: 										applet loaded
		octoErrors.PRELOAD_APPLET_INSERT: 	web error
		octoErrors.PRELOAD_APPLET_TIMEOUT:	timeout reached before we got reply.
	- timeoutMillis are the milli seconds we wait for the applet to load.
	- archive1 and archive2 are both optional (they are the archives that will be preloaded). */
function octopv_preloadApplet(replyFunction, timeoutMillis, archive1){
	var answered=false;
	var name = 'func'+window.octopv_preloadAppletCount;
	var reply = 'window.octopv_preloadAppletReplies.'+name+'();';
	window.octopv_preloadAppletReplies[name]=function(major,minor,micro,osVersion){
		if(answered){
			octopv_log.log("got applet reply from "+name+" but we have already answered!");
		}else{
			octopv_log.log("got applet reply from "+name);
			answered=true;
			replyFunction(0,major,minor,micro,osVersion);
		}
	};
	var div = 'octopv_preloadApplet'+window.octopv_preloadAppletCount;
	window.octopv_preloadAppletCount++;
	var html='';
	var initcode='octoshape.applets.init.OctoTestApplet.class';
	var initjar = octopv_paths.get('octoinit.jar');
	if(navigator.userAgent.toLowerCase().indexOf("msie") != -1){
		// browser is IE:
		octopv_log.log("generating test applet ie tag");
		html += '<OBJECT ';
		html += 'NAME="'+name+'" ';
		html += 'ID="'+name+'" ';
	  	html += 'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ';
		html += 'width="1" height="1"> ';
		html += '<PARAM NAME="code" value="'+initcode+'" /> ';
		if(typeof(archive1)=='string'){
			html += '<PARAM NAME="archive" VALUE="'+initjar+','+archive1+'">';
		}else{
			html += '<PARAM NAME="archive" VALUE="'+initjar+'" />';
		}
	  	html += '<PARAM NAME="mayscript" VALUE="true" />';
	  	html += '<PARAM NAME="callbackstring" VALUE="'+name+'" />';
		html += '</OBJECT> ';
	}else{
		// not IE:
		octopv_log.log("generating test applet non-ie tag");
		html += '<applet code="'+initcode+'" '; 
		html += 'width="1" height="1" ';
		if(typeof(archive1)=='string'){
			html+='archive="'+initjar+','+archive1+'" ';
		}else{
			html+='archive="'+initjar+'" ';
		}
        html += 'scriptable="true" ';
        html += 'mayscript="true" ';
		html += 'callbackstring="'+name+'" ';
		html += '>';
		// mac os safari needs params in this way
		html += '<PARAM name="callbackstring" value="'+name+'">';	
		html += '</applet>';
	}
	var timeoutName=name+'timeout'; 
	var timeout = 'window.octopv_preloadAppletReplies.'+timeoutName+'();';
	window.octopv_preloadAppletReplies[timeoutName]=function(){
		if(answered){
			octopv_log.log("(Reached timeout for "+name+" but we have already answered)");
		}else{
			octopv_log.log("Reached timeout for "+name);
			answered=true;
			replyFunction(octoErrors.PRELOAD_APPLET_TIMEOUT);
		}
	};
	octopv_log.log("Writing test applet tag to page.");
	if(octopv_writeToDiv(div, html, true)){
		if(answered){
			octopv_log.log("Not setting timeout since we already have answered");
		}else{
			octopv_log.log("Setting timeout to "+timeoutMillis);
			setTimeout(timeout,timeoutMillis);
		}
	}else{
		replyFunction(octoErrors.PRELOAD_APPLET_INSERT); 
	}
}

function octopv_ConstructAppletTest(timeoutMillis){
	this.major=-1;
	this.minor=-1;
	this.micro=-1;
	this.runonce=true;
	this.osVersion="";
	this._timeoutMillis=timeoutMillis;
	
	//-- AppletTest.canAnswer if we are on windows or mac os x and have java enabled (in browser)
	this.canAnswer=function(){
		if(octopv_isWindows() || octopv_isOSX()){
			if(!navigator.javaEnabled()){
				if(octopv_isWindows() && octopv_isFirefox()){
					octopv_log.log("Java disabled, but user-conf is win+fx, so we try anyway.");
				 	return 0;
				}else{
					octopv_log.log("Applet launch impossible. java disabled:"+navigator.javaEnabled());
				 	return octoErrors.JAVA_NOT_ENABLED; 
				}
			}
			return 0;
		}else{
			// not windows and not mac os x.
			octopv_log.log("Can not do applet launch or install since OS is not windows or mac os x");
			return octoErrors.TEST_APPLET_IMPOSSIBLE;
		}
	};
	var me=this;
	this.start=function(onFinish){
		var can = this.canAnswer();
		if(can!=0){
			onFinish(can);
			return;
		}
		octopv_preloadApplet(function(ok,major,minor,micro,osVersion){
			if(ok==0){
				me.major=major;
				me.minor=minor;
				me.micro=micro;
				me.osVersion=osVersion;
				onFinish(octoErrors.TEST_APPLET_OK);
			}else{
				onFinish(ok);
			}
		},this._timeoutMillis);
	};
}

function octopv_ConstructPreloadInstallApplet(appTest,timeoutMillis){
	this._appTest=appTest;
	this._timeoutMillis=timeoutMillis;
	this.runonce=true;
	
	this.canAnswer=function preloadInstallAppletCan(){
		//--- PreloadInstallApplet.canAnswer 
		//- if #AppletTest.canAnswer 
		//- and AppletTest have completed
		var appTestCan = this._appTest.canAnswer();
		if(appTestCan!=0){
			return appTestCan;
		}
		var userAgent = navigator.userAgent.toLowerCase();
		//- if on mac os x  
		if(octopv_isOSX()){
			// the user.agent detection of os version is not perfect for mac, 
			// so we might have some pre-10.4 users to deny auto-install here.
			function hasVersion(str){ return (appTest.osVersion.indexOf(str) != -1); }
			//- if AppletTest reported 10.3 or lower os version 
			if(hasVersion("10.0")||hasVersion("10.1")||hasVersion("10.2")||hasVersion("10.3")){
				//- we can not use applet install 
				return octoErrors.INSTALL_APPLET_OLD_MAC; 
			}
		//- else if IE and Vista
		}else if(octopv_isIE() && octopv_isVista()){
			//- if java version strictly higher than 1.6.0_07 
			//- (that and earlier java versions does not use vistas broker process) 
			if(this._appTest.major < 6 || (this._appTest.major==6 && 
					this._appTest.minor==0 && this._appTest.micro < 8)){
				// we are on vista and have ie and have a too old java version!
				//- we can not do applet install
				octopv_log.log("no applet install since: vista + ie + java<=1.6.0_07: "+
						major+"/"+minor+"/"+micro);
				return octoErrors.INSTALL_APPLET_VISTA_OLD_JAVA; 
			}
		}
		//- else all is well for applet install proceed
		return 0;
	};
	var me=this;
	this.start=function(onFinish){
		var can=this.canAnswer();
		if(can!=0){
			onFinish(can);
			return;
		}
		octopv_preloadApplet(function(ok){
			var exit = ok==0?octoErrors.PRELOAD_APPLET_OK:ok;
			onFinish(exit);
		},this._timeoutMillis,octopv_AppletInstallObject.installjar()); 
	};
}

/* #################################################################################### 
                                 APPLET LAUNCHER                                        
                             variables and functions
   #################################################################################### */

//function 

/* -10: timeout reached.
 -4: applet reply error
 -3: applet not trusted by user
 -2: there was some error in initializing the applet (writing to disk)
 -1: we can not do applet install
	0: init finished answer from applet
	1: not written to page
  2: applet written to page
  3: applet init answer, still waiting for finish */ 
function octopv_ConstuctLauncherApplet(){
	this.status=1;
	this.name = 'octopv_pluginLauncherAppletApplet';
	this._readyFunction=null;
	this._readyFunctionNew=false;
	
	/* PUBLIC function for starting up both applet and octoshape
	 functIntBool is a function taking an int status and a bool 
	 		if the status is an error status, 
				then if bool is true the error is from the octoshape plugin
				else the error is from the applet.
		TODO make timeout for no answer */ 
	this.start=function launcherAppletStart(functIntBool){
		if(this.status<0){
			// the applet was alreday on the page, and in some error mode 
			// (the applet in in error, not the plugin).
			// there is no reason to try and insert it again. 
			functIntBool(this.status,false);
		}else if(this.status==0){
			// applet is inserted and ready to answer
			// now we need to wait for plugin startup ... 
			this._readyFunction=functIntBool;
			this._readyFunctionNew=true;
			this._startupPlugin();
		}else{
			// applet is beeing inserted at this moment
			// we set the readyFunction and wait for it the call to appletReady
			this._readyFunction=functIntBool;
			this._readyFunctionNew=true;
			
			if(this.status==1){	
				if(!this._insert()){
					this.status=octoErrors.LAUNCH_APPLET_JAVASCRIPT;
					this._readyFunctionNew=false;
					functIntBool(this.status,false);
				}
			}
		}
	};
	
	this._startupPlugin=function LauncherAppletLoop(){
		octopv_log.log('Looping for plugin startup.');
		this._loopCount=0;
		this._loopForPlugin();
	};

	this._loopCount=0;
	this._loopForPlugin=function(){
		this._loopCount++;
		var os = this.getStatus(this._loopCount==1);
		if(os==0 ||os==1){
			setTimeout("window.octopv_pluginLauncherApplet._loopForPlugin();",1000);
		}else{
			if(this._readyFunction!=null && this._readyFunctionNew){
				this._readyFunctionNew=false;
				this._readyFunction(os,true);
			}
		}
	};
	
	this.resetAll=function(){
		this._readyFunctionNew=false;
	};

	this._appletReady=function launcherAppletReady(reply){
		var init = octopv_convertToNumber(reply, octoErrors.LAUNCH_APPLET_REPLY);
		octopv_log.log('Launcher applet inited with '+init+'. Status is '+this.status);
		if(init>0){
			this.status=3; 
		}else{
			if(init==0){
				this.status=0;
			}else if(init==-2){
				this.status=octoErrors.LAUNCH_APPLET_WRITE;
			}else if(init==-3){
				this.status=octoErrors.LAUNCH_APPLET_SECURITY;
			}else{
				this.status=octoErrors.LAUNCH_APPLET_UNKNOWN; 
			}
			/* This function is actually called from the applet start() function,
			but we dont want to continue till after that function has returned. 
			So we postpone replying half a second .*/
			setTimeout("octopv_pluginLauncherApplet._startupPlugin();",500);
		}
	};
	
	this._insert=function launcherAppletInsert(){
		try{
			this.status=2;
			var html='';
			var mainClass = 'octoshape.applets.OctoPluginLauncherApplet.class';
			var jarFile = octopv_paths.get("octolauncher.jar");
			var initJarFile = octopv_paths.get("octoinit.jar");
			if(navigator.userAgent.toLowerCase().indexOf("msie") != -1){
				// browser is IE:
				html += '<OBJECT ';
				html += 'NAME="'+this.name+'" ';
				html += 'ID="'+this.name+'" ';
			  	html += 'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ';
				html += 'width="1" height="1"> ';
				html += '<PARAM NAME="code" value="'+mainClass+'" /> ';
				html += '<PARAM NAME="archive" VALUE="'+initJarFile+','+jarFile+'" />';
			  	html += '<PARAM NAME="mayscript" VALUE="true" />';
			  	html += '<PARAM NAME="scriptable" VALUE="true" />';
			  	html += '<PARAM NAME="callbackstring" VALUE="launcher" />';
			  	html += '<PARAM NAME="initfunction" VALUE="octopv_pluginLauncherAppletInited" />';
			  	html += '<PARAM NAME="NAME" VALUE="'+octopv_appletDisplayName+'">';
			  	html += octopv_log.appletDebugParams(true);
				html += '</OBJECT> ';
			}else{
				// not IE:
				html += '<embed code="'+mainClass+'" '; 
				html += 'width="1" height="1" type="application/x-java-applet;version=1.1" ';
				html += 'pluginspage="http://java.sun.com/javase/downloads/" ';
		        html += 'id="'+this.name+'" ';
				html += 'NAME="'+octopv_appletDisplayName+'" ';
				html += 'archive="'+initJarFile+','+jarFile+'" ';
		        html += 'scriptable="true" ';
		        html += 'mayscript="true" ';
				html += 'callbackstring="launcher" ';
			  	html += 'initfunction="octopv_pluginLauncherAppletInited" ';
			  	html += octopv_log.appletDebugParams(false);
				html += '/>';
			}
			if(!octopv_writeToDiv('octopv_pluginLauncherAppletDiv', html, true)){
				return false;
			}
			return true;
		
		}catch(ex){ 
			octopv_log.log('JavaScript error: '+ex.message);
			return false;
		}
	}
		
	this.getPlayLink=function launcherAppletGetPlayLink(octolink){
		if(this.status!=0) return "";
		return document[this.name].getLink(octolink, false);
	};

	this.getStringOption=function(option){
		if(this.status!=0) return "";
		return document[this.name].getString(option);
	};

	this.getStatus=function launcherAppletGetStatus(startup){
		try{
			if(this.status<0){
				return status;
			} 
			if(this.status>0){
				return octoErrors.LAUNCH_APPLET_NOT_READY;
			}
			var reply = document[this.name].getStatus(startup);
			octopv_log.log('stat: '+this.status+'. Reply from getStatus('+typeof(reply)+'): '+reply);
			return reply;
		}catch(ex){ 
			octopv_log.log('JavaScript error: '+ex.message);
			return octoErrors.JS;
		}
	};
}
var octopv_pluginLauncherApplet=new octopv_ConstuctLauncherApplet();

/* called from applet. called with 
   <0: error happend
	0: finished init
   >0: still running init  */
function octopv_pluginLauncherAppletInited(reply){
	octopv_pluginLauncherApplet._appletReady(reply);
}

function octopv_ConstructAppletLaunch(replyKind, strArg){
	this._replyKind=replyKind;
	this._strArg=strArg;
	
	this.canAnswer=function(){
		if(octopv_isOSX()){
			octopv_log.log('can not use applet launch since we are on mac os.','app-launch.can');
			return octoErrors.LAUNCH_APPLET_IMPOSSIBLE;
		}
		if(octopv_prefsPluginLaunch.cookieCanUse("Applet")){
			return 0;
		}else{
			octopv_log.log('can not use applet launch since there is no cookie','app-launch.can');
			return octoErrors.LAUNCH_APPLET_NO_COOKIE;
		}
	};
	
	var me=this;
	this.start=function(onError, onSuccess){
		var can = this.canAnswer();
		if(can!=0){
			onError(can);
			return;
		}
		octopv_pluginLauncherApplet.start(function(status, fromPlugin){
			/* For some odd reason the getStatus replies from jni has 2 as success. 
				(both applet and browser plugin uses the same code) */
			var pluginStatus = status==2?0:status;	
			var appletStatus = status-1000;	// we set -1000 to distinguish it from plugin errors.
			var statStatus = fromPlugin?pluginStatus:appletStatus;
			var debugString = 'pluginStatus '+pluginStatus+' ';
			debugString += 'appletStatus: '+appletStatus+' statStatus:'+statStatus;
			octopv_log.log('fromPlugin('+fromPlugin+'): '+debugString);
		
			if(fromPlugin){
				// The applet was initialized ok and the reply is from jni. 
				// If the status is an error reply, it is not going to be different from the
				// browser plugin reply.
				if(pluginStatus==0){
					// Applet replied that octoshape is up and running
					octopv_prefsPluginLaunch.cookieSetCanUse("Applet");
					switch(me._replyKind){
					case octopv_LAUNCH_START_UP: 
						onSuccess(); 
						break;
					case octopv_LAUNCH_GET_CONNECT_URL: 
						var xml = octopv_pluginLauncherApplet.getStringOption('xmlbound');
						onSuccess(xml); 
						break;
					case octopv_LAUNCH_CONVERT_LINK: 
						onSuccess(octopv_pluginLauncherApplet.getPlayLink(me._strArg)); 
						break;
					case octopv_LAUNCH_GET_STRING: 
						onSuccess(octopv_pluginLauncherApplet.getStringOption(me._strArg)); 
						break;
					case octopv_LAUNCH_GET_SUA_VERSION: 
						var xml = octopv_pluginLauncherApplet.getStringOption('suaversion');
						onSuccess(xml); 
						break;
					}
				}else{
					// Applet replied that octoshape is in some error state (or not installed).
					var err = octoErrors.PLUGIN_ANSWER_APP_SUB-pluginStatus;
					if(pluginStatus==-1){
						// this is most likely because we are not installed.
						err = octoErrors.LAUNCH_APPLET_NO_PLUGIN; 
					}
					var logStr = '('+typeof(pluginStatus)+') '+pluginStatus+' ('+err+') ';
					octopv_log.log('Replying with error'+logStr);
					onError(err);
				}
			}else{
				// we got error reply from applet launcher
				onError(status);
			}
		});
	};
}

/* #################################################################################### 
                         JAVASCRIPT HTTP-REQUEST PORT TEST                                        
                              variables and functions
   #################################################################################### */

/** Testing if octoshape is running by http request from JavaScript. 
May return false negative, but not false positive.<b> 
Primary function returns true if this method can be used, otherwise false.
If it returns true the reply function will be called at some time, otherwise it will not be called.

For test to be performed we need:
 	- IE 8
 	- a sua > 090512
 And it still may falsely return false (if octoshape is bound on some secondary port).
  ipport is the ip addres + port to connect to.
  timeout is in millis. (2000 should be ok)
  replyFunction must take 1 int argument (the status) + 1 string argument (the plugin version).
	 0: succes.
	 some error-code on error (<0) */
function octopv_ConstructJsHttp(port1a, port2a, timeout, replyKind){ 
	this._portArr=new Array();
	this._portCount=-1;
	this._timeout=timeout;
	this._replyKind=replyKind;

	if(typeof(port1a)!='undefined'){
		this._portArr.push(port1a);
	}

	if(typeof(port2a)!='undefined'){
		this._portArr.push(port2a);
	}
	
	this.canAnswer = function(){
		if(window.XDomainRequest){
			switch(this._replyKind){
				case octopv_LAUNCH_START_UP:  		return 0;
				case octopv_LAUNCH_GET_CONNECT_URL: return 0;
				case octopv_LAUNCH_GET_SUA_VERSION:	return 0;
			}
		}
		return octoErrors.JSHTTP_IMPOSSIBLE;
	};

	this.start=function(onError,onSuccess){
		if (this.canAnswer(this._replyKind)!=0){
			onError(octoErrors.JSHTTP_IMPOSSIBLE); 
			return;
		}
		this._run(octoErrors.JSHTTP_IMPOSSIBLE, onError,onSuccess);
	}
	
	this.reset=function(){
		this._portCount=-1;
	}
	
	this._run=function(err, onError, onSuccess){
		this._portCount++;
		if(this._portCount>=this._portArr.length){
			onError(err);
		}else{
			var ipport = '127.0.0.1:'+(this._portArr[this._portCount]);
			var me = this;
			this._tryPort(ipport, this._replyKind, function(err){
				me._run(err, onError,onSuccess);
			},onSuccess);
		}
	};
	
	this._tryPort=function jshttpTryPort(ipport, replyKind, onError, onSuccess){
		octopv_log.log('Trying ip+port: '+ipport);
		var finished=false;
		try{
			// we need a single run object since we always reach the javascript timeout.
			//var replyOnce = octopv_toSingleRunFunction(this, replyFunction);
			octopv_log.log('Making XDomainRequest object ... ');
			var xdr=new XDomainRequest(); 
			if(!xdr){
				octopv_log.log('Could not make object.');
				onError(octoErrors.JSHTTP_IMPOSSIBLE); 
				return;
			}
			xdr.onload=function(){
				octopv_log.log('onload called');
				var reply = octoErrors.JSHTTP_UNKNOWN;
				var version = "";
				try {
					var xmlDoc=new ActiveXObject('Microsoft.XMLDOM');
					xmlDoc.async='false';
					var text = xdr.responseText;
					xmlDoc.loadXML(text);
					if(xmlDoc.documentElement.tagName=='octoshapesua'){
						reply = 0;
						version = xmlDoc.documentElement.getAttribute('version');
					}else{
						reply = octoErrors.JSHTTP_XML;
					}
					octopv_log.log('version: '+version);
					octopv_log.log('reply was: '+text);
				}catch(e){
					octopv_log.log('Err '+e.name+': '+e.message, arguments.callee);
					reply = octoErrors.JSHTTP_NOT_XML;
				}
				finished=true;
				
				switch(replyKind){
				case octopv_LAUNCH_START_UP: 
					onSuccess();
					break;
				case octopv_LAUNCH_GET_CONNECT_URL: 
					onSuccess(ipport);
					break;
				case octopv_LAUNCH_GET_SUA_VERSION:	
					onSuccess(version);
					break;
				default:
					octopv_log.log('ERROR: (jshttp) unknown reply kind was: '+replyKind2);
				}
			};
			xdr.onerror = function(){
				octopv_log.log('onerror called: '+typeof(onError));
				finished=true;
				onError(octoErrors.JSHTTP_CONNECT);
			};
	        xdr.ontimeout = function(){
				octopv_log.log('ontimeout called');
				finished=true;
				onError(octoErrors.JSHTTP_CONNECT_TIMEOUT);
			};
	  		xdr.timeout = this._timeout;
	  		var req = 'http://'+ipport+'/octoshapeprobe.xml';
	  		// we use post to make sure that the answer is not cached.
	  		xdr.open('POST', req);
			
			octopv_setTimeoutFunction(this._timeout+1500, function(){
				if(finished){
					octopv_log.log('We reached javascript timeout, but have already answered.');
				}else{
					finished=true;
					onError(octoErrors.JSHTTP_TIMEOUT);
				}
			});
	  		var randomStr = 'random'+(Math.floor(Math.random()*100000));
			octopv_log.log('Sending request: '+req+' post: '+randomStr);
			xdr.send(randomStr);
		}catch(ex){
			octopv_log.log('Caught exception: '+ex);
			finished=true;
			onError(octoErrors.JSHTTP_CONNECT_EX);
		}
	}
}

/* #################################################################################### 
                                FLASH PORT TEST                                        
                            variables and functions
   #################################################################################### */

//	window.octopv_flashOctoIsRunningTester.initDone=false;
window.octopv_counter=0;
function octopv_getJsUniqueId(){
	window.octopv_counter++;
	return ('id'+window.octopv_counter);
};

function octopv_ConstructPortFlash(port1,port2, replyKind){
	this._replyKind=replyKind;
	this._port1=port1;
	this._port2=port2;

	//-- PortFlash.canAnswer if the user has flash version with ActionScript 3 support 
	this.canAnswer=function(){
		if(typeof(window.octopv_disableLaunches["FlashGetPort"])=='boolean' && 
		window.octopv_disableLaunches["FlashGetPort"]) return octoErrors.FLASH_BP_IMPOSSIBLE;
		if(octopv_flashOk()){
			switch(this._replyKind){
				case octopv_LAUNCH_START_UP:  		return 0;
				case octopv_LAUNCH_GET_CONNECT_URL: return 0;
			}
		}
		return octoErrors.FLASH_BP_IMPOSSIBLE;
	};
	var me=this;
	this.start=function(onError, onSuccess){
		var can = this.canAnswer();
		if(can!=0){
			onError(can);
			return;
		}
		octopv_FlashBP(function(portReply){
			octopv_log.log('reply from octopv_FlashBP:'+portReply,'fbp.start');
			if(portReply>0){
				if(me._replyKind==octopv_LAUNCH_START_UP){
					onSuccess();
				}else if(me._replyKind==octopv_LAUNCH_GET_CONNECT_URL){
					onSuccess('127.0.0.1:'+portReply);
				}
			}else{
				if(portReply==octoErrors.FLASH_BP_NOT_LAUNCHED){
					// can we do something special here? 
					//  add the LaunchByProtocol to the loop?
				}
				//octopv_log.log('we try to go on:'+getPropertiesString(me));
				onError(portReply);
			}
		},this._port1,this._port2); 
	};
}

// replyfunc must be a function taking 1 int argument (the port, or <0 on error).
function octopv_FlashBP(replyfunc){

	if(!octopv_flashOk()){
		replyfunc(octoErrors.FLASH_BP_IMPOSSIBLE); 
	};

	var myId=octopv_getJsUniqueId();
	
	var replyfunctionName='octopv_flashOctoIsRunningTester_reply'+myId;
	var timeoutfunctionName='octopv_flashOctoIsRunningTester_timeout'+myId;
	var initfunctionName='octopv_flashOctoIsRunningTester_init'+myId;
	var flashName='octopv_flash_bp'+myId;

	var path = octopv_paths.get('octofbp2.swf');

  	var html  = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
   	html += ' id="'+flashName+'" width="0" height="0"';
    html += ' codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">';
    html += ' <param name="movie" value="'+path+'" />';
    html += ' <param name="FlashVars" value="init='+initfunctionName+'" />';
    html += ' <param name="wmode" value="transparent" />';
    html += ' <param name="AllowScriptAccess" value="always" />';
    html += ' <embed src="'+path+'"';
    html += ' width="1" height="1" name="'+flashName+'"';
    html += ' AllowScriptAccess="always"';
    html += ' FlashVars="init='+initfunctionName+'"';
    html += ' play="true" loop="false" wmode="transparent"';
    html += ' type="application/x-shockwave-flash" ';
    html += ' pluginspage="http://www.adobe.com/go/getflashplayer">';
    html += ' </embed></object>';

	octopv_log.log('Inserts flash helper from '+path);
	
	var portsArr = new Array();
	var debugStr = '';
	for(var i=1; i<arguments.length; i++){
        portsArr.push(arguments[i]);
	}
	
	for(var i=0; i<portsArr.length; i++){
        debugStr+=(portsArr[i]+',');
	}
	octopv_log.log('Ports to check ('+portsArr.length+'): '+debugStr);
	
	window[initfunctionName]=function flashBP_init(swfname){
		octopv_log.log('init-function called');
		var dims=null;
    	if (navigator.appName.indexOf("Microsoft") != -1) {
        	dims=window[swfname];
    	}else{
	        dims=document[swfname];
 		}
		window[timeoutfunctionName]=function flashBP_timeout(){
			octopv_log.log('(Timeout has been reached, but we already replied)');
		};
		octopv_log.log('Calling flash bp: '+dims);
		window[replyfunctionName]=function flashBP_reply(intResult){
			if(intResult==-1){
				replyfunc(octoErrors.FLASH_BP_UNKNOWN);
			}else if(intResult==0){
				octopv_log.log('Installed but not launched reply from flash!');
				replyfunc(octoErrors.FLASH_BP_NOT_LAUNCHED);
			}else{
				replyfunc(intResult);
			}
		};
		
		// currently when called from silverlight osa the call to the flash function 
		// never generates a return call to the replyFunction. 
		// temp solotion is to avoid the flash tester when calling from silverlight
		
		try{
	   		dims.octopvAS_beginCheck(replyfunctionName,2000,portsArr);
    	}catch(ex){
			octopv_log.log('ex:'+ex);
			octopv_log.log('try to wait 1 second and then try again ...');
			octopv_setTimeoutFunction(1000, function(){
				try{
					octopv_log.log('After wait of 1 second.');
			   		dims.octopvAS_beginCheck(replyfunctionName,2000,portsArr);
		    	}catch(ex){
					octopv_log.log('After wait of 1 second we still got ex!:'+ex);
		    		replyfunc(octoErrors.FLASH_BP_NO_CALLBACK);
		    	}
			});
    	}
	};
    if(octopv_writeInNewDiv(html)){
		// We set a timeout here just in case there is something wrong with the swf,
		//  and it does not get initialized. It should never happen though.
		window[timeoutfunctionName]=function flashBP_timeout2(){
			octopv_log.log('Timeout has been reached and we had no answer from flash -- ');
			window[initfunctionName]=function flashBP_init2(){
				octopv_log.log('Flash answer was inited after timeout. ');
			};
			window[replyfunctionName]=function flashBP_reply2(intResult){
				octopv_log.log('Flash answer got after timeout: '+intResult);
			};
			replyfunc(octoErrors.FLASH_BP_TIMEOUT);
		};
		setTimeout("window."+timeoutfunctionName+"();",4500);
    }else{
		octopv_log.log('Could not write to div octopv_flashOctoIsRunningTesterDiv');
		replyfunc(octoErrors.FLASH_BP_IMPOSSIBLE); 
    }
}

/* #################################################################################### 
                               FORCE SUA UPDATE 
                            variables and functions
   #################################################################################### */

/**	replyFunction must be a function taking an int argument indicating:
		<0: if octoshape not installed or there was some error with the browser plugin
		 0: the current sua version was ok
		 1: we have updated the sua, and are now ready again.	*/
function octopv_forceSuaUpdateIfNeeded(updatelink, okSuaVersion, replyFunction){
	octopv_log.log("Function called. updatelink: "+updatelink+" sua:"+okSuaVersion);
	
	octoGetSuaVersion(function(intStatus, stringVersion){
		if(intStatus==0){
			var ver = stringVersion;
			var doUpdate = false;
	   		if (ver.Length == okSuaVersion.Length) {
			    	doUpdate = ver < okSuaVersion; // lexicographical javascript compare!
		    } else {
    			doUpdate = ver.Length < okSuaVersion.Length;
    		}
    		if(doUpdate){
    			octopv_log.log("Doing sua update. Current ver is "+ver+", marker is "+okSuaVersion);
    			octoGetPlayLink(updatelink, function(intStatus2,playlink){
    				if(intStatus2<0){
    					replyFunction(intStatus2);
    				}else{
    					// we have the update playlink.
						octopv_insertInvisibleIframe(playlink);
						window.octopv_forceSuaUpdateIfNeededLoopReply=replyFunction;
						setTimeout("octopv_forceSuaUpdateIfNeededLoop();",3000);
    				}
    			}, false);
    		}else{
				replyFunction(0);
    		}
		}else{
			replyFunction(intStatus);
		}
	}, false);
}

window.octopv_forceSuaUpdateIfNeededLoopReply=null;
function octopv_forceSuaUpdateIfNeededLoop(){
	octopv_log.log("calling after wait.");
	octoGetPluginStatus(function(intStatus){
		if(intStatus<0){
			octopv_forceSuaUpdateIfNeededLoopReply(intStatus);
		}else{
			octopv_forceSuaUpdateIfNeededLoopReply(1);
		}
	}, false);
}

/* #################################################################################### 
                               SIMPLE LAUNCH 
                            variables and functions
   #################################################################################### */

/**
if callback is a function then it must be a function taking no argument. 
It will be called after a delay, where we might be started up. 
*/
function octopv_launchByProtocol(callback,timeout){
	try{
		var name = "octopv_launchByProtocolFrame";
		var e = document.getElementById(name);
		if(e==null){
			e = document.createElement("iframe");
			e.id=name;
			e.name=name;
			e.width=0;
			e.height=0;
			e.style.display = "none";
			e.src="OCTOSHAPE:";
			document.body.insertBefore(e,document.body.firstChild);
		}else{
			e.src="OCTOSHAPE:";
		}
		if(typeof(callback)=='function'){
			var to = (typeof(timeout)=='number')?timeout:3000;
			octopv_log.log("After launch by protocol we wait for "+to+" milli-secs before returning");
			octopv_setTimeoutFunction(to, function(){
				callback(octoErrors.PROTOCAL_LAUNCH_AFTER);
			});
		}
	}catch(ex){
		octopv_log.log("Exception "+ex);
		if(typeof(callback)=='function'){
			callback(octoErrors.PROTOCAL_LAUNCH_ERROR);
		}
	}
}


/* #################################################################################### 
                               INSTALL APPLET FUNCTIONS

   #################################################################################### */

/** This JavaScript file contains functions to install octoshape on windows by a signed applet.
It requires 2 files to be present:
	- octoinit.jar
	- octoinstall.jar **/
function ConstructAppletInstall(){
	this.installCompleted=null;
	this.installCompletedNew=false;
	this.progress=function(str){};
	this.waitFinishedCount=0;
	this.installcode='octoshape.applets.OctoInstallApplet.class';
	if(octopv_isOSX()){
		this.installcode='octoshape.applets.OctoInstallAppletMac.class';
	}
	this.installjar=function(){
		if(octopv_isOSX()){
			return octopv_paths.get('octosetup-mac.jar');
		}else{
			return octopv_paths.get('octosetup.jar');
		}
	}

	this.appletCallback=function AppletCallback(result){
		octopv_log.log("applet finished install (1): "+result);
		var r=octoErrors.INSTALL_APPLET_JS;
		try{
			r = parseInt(result);
			if(r>=0){
				octopv_prefsPluginLaunch.cookieSetCanUse("Applet");
			}else{
				switch(r){
					case -5: r=octoErrors.INSTALL_APPLET_EXECUTION; 	break;
					case -4: r=octoErrors.INSTALL_APPLET_NO_FILE;		break;
					case -3: r=octoErrors.INSTALL_APPLET_SECURITY;	break;
					case -2: r=octoErrors.INSTALL_APPLET_EULA_REJECT;	break;
					default: r=octoErrors.INSTALL_APPLET_UNKNOWN;		break;
				}
			}
			octopv_log.log("applet install result converted to: "+r);
		}catch(ex){ 
			octopv_log.log('JavaScript error (result was '+result+': '+ex.message);
		}
		if(this.installCompleted!=null && this.installCompletedNew){
			this.installCompletedNew=false;
			octopv_log.log("calling install completed: "+result);
			this.installCompleted(r);
		}else{
			var logStr = "Got reply from applet, but could not call onComplete. ";
			octopv_log.log(logStr+"Type: "+typeof(this.installCompleted)+" New:"+this.installCompletedNew);
		}
	};

	/** if indiv is null, we write directly
	 * 	onComplete must be a function taking an int (or not defined):
		* 		  - 4: installation error ... disk?
		* 		  - 3: user denied applet security
		* 		  - 2: eula not accepted
		* 		  (- 1: could not do applet install)
		* 		    >0: all is well and finished with the install and this is the port to bind to
		*/
	this.doInstall=function AppletDoInstall(indiv, onComplete, progressFunction){
		if(typeof(onComplete)=='function'){
			this.installCompleted=onComplete;
			this.installCompletedNew=true;
		}
		
		if(typeof(progressFunction) == 'function'){
			this.progress=progressFunction;
		}else if(typeof(progressFunction) == 'string'){
			this.progress = function(str){
				octopv_writeToDiv(progressFunction +": "+ str);
			};
		}else{
			this.progress=function(str){};
		}
		
		var html='';
		var initJarFile = octopv_paths.get("octoinit.jar");
		if(navigator.userAgent.toLowerCase().indexOf("msie") != -1){
			// browser is IE:
			html += '<OBJECT NAME="octopv_applet"';
		  	html += 'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ';
			html += 'width="1" height="1"> ';
			html += '<PARAM NAME="code" value="'+this.installcode+'"> ';
			html += '<PARAM NAME="archive" VALUE="'+initJarFile+','+this.installjar()+'">';
		  	html += '<PARAM NAME="mayscript" VALUE="true">';
		  	html += '<PARAM NAME="NAME" VALUE="'+octopv_appletDisplayName+'">';
		  	if(arguments.length == 4){
				html += '<PARAM name="'+param1+'" VALUE="'+value1+'"/>';
			}
		  	html += octopv_log.appletDebugParams(true);
			html += '</OBJECT> ';
		}else{
			// not IE:
			html += '<embed code="'+this.installcode+'" '; 
			html += 'NAME="'+octopv_appletDisplayName+'" ';
			html += 'width="1" height="1" type="application/x-java-applet;version=1.1" ';
			html += 'pluginspage="http://java.sun.com/javase/downloads/" ';
			html += 'archive="'+initJarFile+','+this.installjar()+'" ';
	        html += 'scriptable="true" ';
	        html += 'mayscript="true" ';
			html += 'callbackstring="install" ';
		  	html += octopv_log.appletDebugParams(false);
			html += '/>';
		}
		octopv_log.log("inserting install-jar from: "+this.installjar());
		octopv_writeToDiv(indiv, html);
	}
}
var octopv_AppletInstallObject = new ConstructAppletInstall();

/*** Applet callback functions */
/** called by install applet */
function octopv_appletProgress(message){
	octopv_log.log("applet install progress: "+message+"", arguments.callee);
	octopv_AppletInstallObject.progress(message);
}

/** called by install applet. 0: ok, <0 not ok. result might be a string */
function octopv_installAppletFinishedInstall(result){
	octopv_AppletInstallObject.appletCallback(result);
};

function octopv_ConstructInstallApplet(replyKind){
	this._replyKind=replyKind;
	this.canAnswer=function(){
		return 0;
	};
	var me=this;
	this.start=function(onError,onSucces){
		var div3="octopv_appletDiv3";
		octopv_createNewDiv(div3);
		octopv_AppletInstallObject.doInstall(div3, function(result){
			octopv_log.log('applet install answer: '+result);
			if(octopv_abortAutoLaunch){
				octopv_log.log('NB: octopv_abortAutoLaunch false after running applet install.');
			}
			if(result<0){
				onError(result);
			}else{
				octopv_prefsPluginLaunch.cookieSetCanUse("Applet");
				if(octopv_LAUNCH_START_UP==me._replyKind){
					onSucces();
				}else if(octopv_LAUNCH_GET_CONNECT_URL==me._replyKind && result>0){
					onSucces('127.0.0.1:'+result);
				}else{
					onError(octoErrors.INSTALL_APPLET_OK);
				}
			}
		}, function(str){
			octopv_log.log('Installing: '+str,'app-install');
		});
	};
}

/* #################################################################################### 
                                 FLASH EULA FUNCTIONS

   #################################################################################### */

var octopve_callbackFunc = null;
var octopve_disableEula = false;

/** callback */
function octopve_spawnEula(callback) {
	var containerid="octopv_topEulaDiv";

	//if user does not have flash, we return true to let call callback(true)
	if(!octopv_flashOk()){
		callback(true);
		return;
	};
	
	if(octopve_disableEula){
		callback(true);
		return;
	}
	
	octopve_callbackFunc = callback;

	var container = document.getElementById(containerid);
	if(container==null){
		container=document.createElement("div");
		container.id=containerid;
		container.style.position='absolute';
		container.style.zIndex='9999';
		container.style.width='100%';
		container.style.height='100%';
		container.style.top='0px';
		container.style.left='0px';
		document.body.insertBefore(container,document.body.firstChild);
	}
	if(container == null){
		// TODO wait 1 sec and try again before returning?
		callback(true);
		return;
	}
	var path = octopv_paths.get("octoeula.swf");

  	var html  = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
    html += ' id="octopveula" width="100%" height="100%"';
    html += ' codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">';
    html += ' <param name="movie" value="'+path+'" />';
    html += ' <param name="wmode" value="transparent" />';
    html += ' <param name="AllowScriptAccess" value="always" />';
    html += ' <param name="FlashVars" value="containerId='+containerid+'" />';

    html += ' <embed src="'+path+'"';
    html += ' width="100%" height="100%" name="octopveula"';
    html += ' AllowScriptAccess="always"';
    html += ' play="true" loop="false" wmode="transparent"';
    html += ' type="application/x-shockwave-flash" FlashVars="containerId='+containerid+'"';
    html += ' pluginspage="http://www.adobe.com/go/getflashplayer">';
    html += ' </embed></object>';

	octopv_log.log('Showing eula from:' +path);
    container.innerHTML = html;
}


function octopv_ConstructShowEula(){
	this.runonce = true;
	this.canAnswer=function(){
		return true;
	};
	var me=this;
	this.start=function(onFinish){
		octopve_spawnEula(function(proceed){
			octopv_log.log('Eula reply: '+proceed,'eula-obj');
			if(proceed){
				onFinish(octoErrors.FLASH_EULA_ACCEPT);
			}else{
				onFinish(octoErrors.FLASH_EULA_REJECT);
			}
		});
	};
}

/* #################################################################################### 
                                 CAB INSTALLER

   #################################################################################### */

var octopvCAB_topobject = new Object();
octopvCAB_topobject.onComplete=null;
octopvCAB_topobject.timeout=0;
octopvCAB_topobject.disable=false;

function octopv_doCabInstall(indiv, timeout, onComplete){
	octopvCAB_topobject.onComplete = onComplete;
	octopvCAB_topobject.timeout=timeout;
	var file = octopv_paths.get('octosetup.cab');
	var html = '<OBJECT onreadystatechange="javascript:octopv_cabReadychange();"';
	html += ' CODEBASE="'+file+'#version=1.0.0.0"';
	html += ' id="OctoshapeCabInstaller" CLASSID="CLSID:7D4733C0-C43B-4A81-AF43-F9B20D1F8348"';
	html += ' width="0" height="0" >';
	html += '</OBJECT>';
	octopv_log.log("Inserting cab file from "+file);
	octopv_writeToDiv(indiv, html);
}

function octopv_cabReadychange(dontWait){
	try{
		var state = document.all["OctoshapeCabInstaller"].readyState;
		octopv_log.log("Ready state changed to "+state);
		if(state==4){
			if(octopvCAB_topobject.onComplete!=null){
				setTimeout("octopvCAB_topobject.onComplete(0);",octopvCAB_topobject.timeout);
			}
		}
	}catch(ex){
		if(typeof dontWait == 'boolean' && !dontWait){
			octopv_log.log("Ready state not defined: "+ex);
			// If we do not report complete back here then we might end up in an 
			// error state where we never report back.
			if(octopvCAB_topobject.onComplete!=null){
				octopvCAB_topobject.onComplete(octoErrors.CAB_READY_STATE);
			}
		}else{
			octopv_log.log("Ready state not defined: "+ex+" trying to wait a little ... ");
			setTimeout("octopv_cabReadychange(true);",500);
		}
	}
}

function octopv_ConstructCabInstall(timeout, eula){
	this._timeout=timeout;
	this._eula=eula;
	this.canAnswer=function cabInstallCan(){
		if(octopvCAB_topobject.disable){
			octopv_log.log("Can not do cab install since it it disabled.");
			return octoErrors.CAB_IMPOSSIBLE;
		}
		if(!octopv_isWindows()){
			// not windows.
			octopv_log.log("Can not do cab install since OS is not windows.");
			return octoErrors.CAB_IMPOSSIBLE;
		}
		if(!octopv_isIE()){
			// not explorer.
			octopv_log.log("Can not do cab install since browser is not ie.");
			return octoErrors.CAB_IMPOSSIBLE;
		}
		// Temporarily disabled for all vista users.
		if(octopv_isVista()){
			// we have vista 
			octopv_log.log("Can not do cab install since we are on vista. ");
			//return 0;
			return octoErrors.CAB_IMPOSSIBLE_VISTA; 
		}
		return 0;
	};
	var me=this;
	this.start=function(onFinish){
		var can = this.canAnswer();
		if(can!=0){
			onFinish(can);
			return;
		}
		var divCab="octopv_topCabDiv";
		octopv_createNewDiv2(divCab);
		this._eula.start(function(err1){
			if(err1==octoErrors.FLASH_EULA_ACCEPT){
				octopv_doCabInstall(divCab, me._timeout, function(err){
					// cab complete.
					// but we do not know if: there was a success, a fail, 
					//or vista is showing a yellow bar to the user.
					if(err==0){
						octopv_log.log('Cab finished, but was it successful?.');
						onFinish(octoErrors.CAB_AFTER_INSTALL);
					}else{
						onFinish(err);
					}
				});
			}else{
				onFinish(err1);
			}
		});
	};
}

/* #################################################################################### 
                               UTILITY FUNCTIONS

   #################################################################################### */
   

function octopv_fileVersionAsNumber(){
	var ver = octopv_fileVersion.substring(6,9);
	return parseInt(ver);
}

/** Helper to set a function to be called after timeout. */
function octopv_setTimeoutFunction(millis, func){
	octopv_setTimeoutFunctionObject.count++;
	var name = "name"+octopv_setTimeoutFunctionObject.count;
	window.octopv_setTimeoutFunctionObject[name] = function(){
		func();
	};
	setTimeout("octopv_setTimeoutFunctionObject."+name+"();",millis);
}
window.octopv_setTimeoutFunctionObject = new Object();
window.octopv_setTimeoutFunctionObject.count=0;

/** This wrapper will ensure that the argument function only will be called 1 time.
	The returned object has a function .callme, that calls the function 
	(and returns true if the function was called). */
function octopv_toSingleRunFunction(thisReference, func){
	var obj = new Object();
	obj.done = false;
	obj.func = func;
	obj.thisref=thisReference;
	obj.callme=function(){
		if(this.done){
   			octopv_log.log("Stopping multiple calls to "+obj.thisref);
			return false;
		}
		this.done=true;
		this.func.apply(this.thisref,arguments);
		return true;
	};
	return obj;
};

function octopv_getCookie(name){
	var cs = document.cookie.split(';');
	for(var i=0;i < cs.length;i++) {
		var c = cs[i];
		// trimming c
		while (c.charAt(0)==' '){
			c = c.substring(1,c.length);
		}
		if (c.indexOf(name) == 0) {
			// we need to split the key from the value
			var kv = c.split('=');
			if(kv.length >= 1&&kv[0]==name){
				if(kv.length==2){
					return kv[1];
				}else{
					return"";
				}
			}
		}
	}
	return null;
}

function octopv_hasCookie(name){
	var cs = document.cookie.split(';');
	for(var i=0;i < cs.length;i++) {
		var c = cs[i];
		while (c.charAt(0)==' '){
			c = c.substring(1,c.length);
		}
		if (c.indexOf(name) == 0) {
			return true;
		}
	}
	return false;
}

function octopv_portFromXmlBoundString(xmlBoundReply){
	if((typeof (xmlBoundReply)=='undefined') || xmlBoundReply==null || xmlBoundReply==""){
		return -1;
	}
	try{
		var p = xmlBoundReply.substring(xmlBoundReply.indexOf(":",0)+1,xmlBoundReply.length);
		var port = parseInt(p); 
		return port;
	}catch(e){
		return -1;
	}
}

function octopv_insertInvisibleIframe(source){
	var iframe = document.createElement("iframe");
	iframe.setAttribute("width", 0);
	iframe.setAttribute("height", 0);
	iframe.setAttribute("src", source);
	iframe.style.display = "none";
	document.body.insertBefore(iframe,document.body.firstChild);
}

function octopv_includeJSFile(path){
	var script = document.createElement("script");
	script.setAttribute("language", "JavaScript");
	script.setAttribute("type", "text/javascript");
	script.setAttribute("src", path);
	try{
		var head = document.getElementsByTagName("head")[0];
		head.insertBefore(script,head.lastChild);
	}catch(e){
		octopv_log.postponedError="ERROR inserting js in head: "+e.name+"; "+e.message;
	}
}


window.octopvpv_loopArray = new Object();

/** name is a string id for the loop
	theFunction is a int function taking 1 int argument, 
		the argument is the count of times the loop has run (the first time it gives 1)
		the return value must be number of millis to loop next (0 or negative when loop no more). 
		NB: the function will be assigned to a special (global) object when run, 
			so it should only reference global functions and variables.  */
function octopv_loopUntil(name, theFunction){
	octopvpv_loopArray[name]=theFunction;
	octopvpv_loopArray[name+"Count"]=0;
	octopvpv_loopUntilDo(name);
}

/** private */
function octopvpv_loopUntilDo(name){
	octopvpv_loopArray[name+"Count"]++;
	var time = octopvpv_loopArray[name](octopvpv_loopArray[name+"Count"]);
	if(time>0){
		setTimeout("octopvpv_loopUntilDo('"+name+"');",time);
	}
}

function octopv_convertToNumber(reply, def){
	var intReply=def;
	if(typeof reply == 'number'){
		intReply=reply;
	}else{
		var parsed=parseInt(reply);
		if(!isNaN(parsed)){
			intReply=parsed;
		}
	}
	return intReply;
}

/** Insets a new div at the top of the page an adds the html into it.
 * returns true on success. 
 * (width and height are used for debugging) */
function octopv_writeInNewDiv(html, width, height){
	try{
		var oDiv = document.createElement("div");
		var id = octopv_getJsUniqueId();
		oDiv.id=id;
		if(octopv_isFirefox() || octopv_isSafari()){
			oDiv.style.height = "0px"; 
		}
		if((typeof(width)=='number') && (typeof(height)=='number') && width>=0 && height>=0){
			oDiv.style.height = height+"px"; 
			oDiv.style.width = width+"px"; 
		}
		document.body.insertBefore(oDiv,document.body.firstChild);
		return octopv_writeToDiv(id, html);
	}catch(ex){
		return false;
	}
};

function octopv_createNewDiv2(idName){
	var elem = document.getElementById(idName);
	if(elem==null){
		var oDiv = document.createElement("div");
		oDiv.id=idName;
		document.body.insertBefore(oDiv,document.body.firstChild);
		return true;
	}else{
		return false;
	}
}

function octopv_createNewDiv(idName){
	try{
		var elem = document.getElementById(idName);
		if(elem==null){
			var oDiv = document.createElement("div");
			oDiv.id=idName;
			oDiv.style.height = "0px"; 
			oDiv.style.width = "1px"; 
			document.body.insertBefore(oDiv,document.body.firstChild);
			return true;
		}else{
			return false;
		}
	}catch(ex){ 
		octopv_log.log('JavaScript error: '+ex.message);
		return false;
	}
}

function octopv_writeToDiv(indiv, html, create, noStyle){
	try{
		if( typeof(create)=='boolean' &&  create) {
			if(typeof(noStyle)=='boolean' && noStyle){
				octopv_createNewDiv2(indiv);
			}else{
				octopv_createNewDiv(indiv);
			}
		}
	 	var div = null;
	 	if(indiv!=null){
	 		div = document.getElementById(indiv);
	 		if(div==null){
	 			octopv_log.log("div "+indiv+" does not exist.");
	 			return false;
	 		}
	 	}
	 	if(indiv==null){
	 		document.write(html);
	 	}else{
	 		div.innerHTML=html;
	 	}
	 	octopv_log.log("inserted HTML into div "+indiv);
	 	return true;
	}catch(ex){ 
		octopv_log.log('JavaScript error for div '+indiv+': '+ex.message);
		return false;
	}
}

function octopv_writeToIdLessDiv(html){
	var oDiv = document.createElement("div");
	oDiv.style.height = "0px";
	oDiv.style.width = "1px";
	oDiv.innerHTML=html;
	document.body.insertBefore(oDiv,document.body.firstChild);
 	octopv_log.log("inserted HTML into nameless div ");
 	return true;
}

function octopv_activexdisabled(){
	var text = navigator.userAgent.toLowerCase();
	if (text.indexOf("msie") >= 0){ 
		try{
			var test = new ActiveXObject("Scripting.Dictionary");
		}catch(e){
			return true;
		}
	}
	return false;
}

function octopv_isOSX(){
	return navigator.userAgent.toLowerCase().indexOf("mac os x") != -1;
}

function octopv_isOSX106(){
	var str = navigator.userAgent.toLowerCase();
	return str.indexOf("mac os x 10_6") != -1 || str.indexOf("mac os x 10.6") != -1;
}

function octopv_isWindows(){
	return navigator.userAgent.toLowerCase().indexOf("windows") != -1;
}

function octopv_isSafari(){
	return navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1;
}

function octopv_isFirefox(){
	return navigator.userAgent.toLowerCase().indexOf("firefox") != -1;
}

function octopv_isFirefox3(){
	return navigator.userAgent.toLowerCase().indexOf("firefox/3") != -1;
}

function octopv_isIE(){
	return navigator.userAgent.toLowerCase().indexOf("msie") != -1;
}

function octopv_isVista(){
	return navigator.userAgent.toLowerCase().indexOf("windows nt 6.0") != -1;
}

function octopv_isXP(){
	var str = navigator.userAgent.toLowerCase();
	return (str.indexOf("windows nt 5.1") != -1 || str.indexOf("windows nt 5.2") != -1);
}

// returns true iff there is a plugin registered for the mime type mimeID and
//  the name of this plugin contains pluginName (case oblivious).
function octopv_mime_plugin_is(mimeID, pluginName){
	if(navigator && navigator.mimeTypes && navigator.mimeTypes.length){
		var mime =  navigator.mimeTypes[mimeID];
		if(mime){
			var text  = mime.enabledPlugin.name.toLowerCase();
			return (text.indexOf(pluginName.toLowerCase()) >=0);
		}
	}
	return false;
}

// returns true if there is a plug-in installed that can handle the video/x-ms-asf mime-type
function octopv_has_mime(mimeID){
	if(navigator && navigator.mimeTypes && navigator.mimeTypes.length){
		var mime =  navigator.mimeTypes[mimeID];
		if(mime && mime.enabledPlugin){
			return true;
		}
	}
	return false;
}

function octopv_QueryStringMap(){
	this.map = new Object();
	this.size = 0;
	var qs = window.location.search;
	if(qs.length>1){
		qs = qs.substring(1);
		var arr = qs.split('&');
		var i=0;
		for(;i<arr.length;i++){
			var v = arr[i]; 
			if(v.length>0){
				this.size++;
				if(v.indexOf("=")== -1){
					this.map[v] = "";
				}else{
					var a = v.split('=',2);
					this.map[a[0]] = a[1];
				}
			}
		}
	}
	
	this.get=function(name,defaultValue){
		if(typeof(this.map[name])=='undefined'){
			return defaultValue;
		}else{
			return this.map[name];
		}
	}
}

function octopv_randomString(numChars){
	var num = Math.pow(36,numChars);
	return (Math.floor(Math.random()*num)).toString(36);
}

/** Returns false if the adobe JavaScript file AC_OETags.js has not been included
or ActioScript 3 is not available  */
function octopv_flashOk(){
	try{
		if(window.DetectFlashVer && window.DetectFlashVer(9,0,0)){
			return true;
		}else if(window.DetectFlashVer){
			octopv_log.log('User has no flash or only old flash.');
			return false;
		}else{
			octopv_log.log('We had no AC_OETags.js - assuming user has flash 9');
			return true;
		}
	}catch(ex){
		octopv_log.log('Cought exception while testing for flash:'+ex.message);
		return false;
	}
};

function octopv_logInitFromQueryString(){
	octopv_log.log('onload window event');
	octopv_log.log(null);
}

/* About the variable octopvDebugDiv:
	if this is set (to a divID name) we display debug in the div, if the div exists.
	if it does not exist, but the html querystring contains octoshapejsdebug=true then 
		we append the div to the html page (end of body)
	if it does not exist and there is no querystring setting, the debug will be saved, 
		but not shown (maybe later a debug div will be there) 
	To avoid any debug info what so ever to be saved at all, set octopvDebugDiv=false */
function octopv_ConstructDebug(){
	this._arr=new Array();
	this._qsmap = new octopv_QueryStringMap();
	var qsvalue = this._qsmap.get('octoshapejsdebug','false');
	this._debugFromQueryString = (qsvalue=='true'); 
	this._extraSettings = new Object();
	
	/** call with 'arguments.callee' to get current function name. */
	this.init=function(){
		if(this._debugFromQueryString){
			if(typeof (window.addEventListener) != 'undefined'){
				window.addEventListener("load", octopv_logInitFromQueryString, false);
			}else if (typeof (document.addEventListener) != 'undefined'){
				document.addEventListener("load", octopv_logInitFromQueryString, false);
			}else if(typeof (window.attachEvent) != 'undefined'){
				window.attachEvent("onload", octopv_logInitFromQueryString, false);
			}else{
				var alertStr = 'Octoshape js debug could not set eventlistener\n';
				alert(alertStr+'Your query-string has octoshapejsdebug=true set');
			}
		}
	}
	
	this.addTopSetting=function(name,value){
		this._extraSettings[name] = value;
	}
	
	/** call with 'arguments.callee' to get current function name. */
	this._getFunctionName=function(func, anonymous){
		var funcStr = func.toString();
		var a1 = funcStr.toLowerCase().indexOf('function');
		var b1 = funcStr.indexOf("(");
		var a=a1==0?8:0;
		var b=b1>0?b1:funcStr.length;
		funcStr = funcStr.substring(a,b);
		funcStr = funcStr.replace(/ /, "");
		if(funcStr.length==0){
			if(typeof(anonymous)=='undefined'){
				funcStr="anonymous";
			}else{
				funcStr=anonymous;
			}
		}else{
			var a2 = funcStr.lastIndexOf('_');
			if(a2>0){
				funcStr = funcStr.substring(a2+1);
			}
		}
		return funcStr;
	};
	
	this.postponedError=null;
	this.log=function(str, debugName){
		if(this.postponedError!=null){
			this._log(this.postponedError,"postponed");
			this.postponedError=null;
		}
		this._log(str,debugName);
	};

	this.isEnabled=function(){
		return (typeof(octopvDebugDiv) != 'boolean' || octopvDebugDiv);
	}

	this.isShowing=function(){
		return (this._getDiv()!=null);
	}

	// return null on no div found
	this._getDiv=function(){
		if(!this.isEnabled()) return false;
		var	div = document.getElementById(octopvDebugDiv);
		if(div)return div;
		// If div does not exist 
		if((!div) && this._debugFromQueryString){
			// Div does not exist, but we should add it according to the qs settings
			var oDiv = document.createElement("div");
			oDiv.id=octopvDebugDiv;
			oDiv.style.backgroundColor = "white";
			document.body.appendChild(oDiv);
			return oDiv;
		} 
		return null;
	}

	this.appletDebugParams=function(paramParams){
		if(this.isShowing()){
			if(paramParams){
				return '<param name="display" value="debug_console_div"/>';
			}else{
				return 'display="debug_console_div" ';
			}
		}else{
			 return '';
		}
	}

	this._hasProperty=function(obj, element){
		for (var i in obj){ 
			if(obj[i].toLowerCase() == element.toLowerCase()){
				return true;
			}
		}
		return false;
	}

	this.logObjectProperty=function(objectName, obj, prop){
		this.log("Object "+objectName+" has property "+prop+": "+this._hasProperty(obj, prop), 
				"JS-Object");
	}

	this.logObject=function(message, obj){
		var result = "[";
		var delim = "";
		for (var i in obj){ 
			result += (delim + i);
			delim = ",";
		}
		result+="]";
		this.log(message+": "+result, "JS-Object");
	};

	/* returns true if we are in debug mode.  */
	this._log = function(str, debugName){
		if(!this.isEnabled()) return false;
		try{
			var name = null;
			if(typeof(debugName)=='string'){
				name = debugName;
			}
			if(name==null){
				var func = arguments.callee.caller.caller;
				if(typeof(func)=='function'){
					name = this._getFunctionName(func,null);
				}
			}
			if(name==null){
				name = 'unknown';
			}
			var millis = (new Date().getTime()) - window.octopv_jsInitMillis;
			if(str!=null){
				str = str.replace(/</g, "&lt;");
				str = str.replace(/>/g, "&gt;");
				this._arr.push('<TR><TD ALIGN="right">'+millis+'<TD>'+name+'<TD>|<TD>'+str+'</TR>');
			}
			var	div = this._getDiv();
			if(div){
				var font = 'font-family:monospace; font-size:9pt; ';
				var color = 'background-color:white; color:black; ';
				var theString = '<div STYLE="'+color+font+'"><table>';
				theString+=("<TR STYLE=\"background-color:#B0B0B0; font-weight: bold;\">");
				theString+=("<TD colspan=4>OCTOSHAPE JAVASCRIPT DEBUG OUTPUT</TR>");
				theString+=("<TR STYLE=\"background-color:#D8D8D8;\"><TD><TD>SETTINGS<TD>|<TD></TR>");
				
				theString+=("<TR ><TD><TD>js-version<TD>|<TD>"+ window.octopv_fileVersion +"</TR>");
				theString+=("<TR ><TD><TD>user-agent<TD>|<TD>"+ navigator.userAgent +" </TR>");
				theString+=("<TR ><TD><TD>variant<TD>|<TD>"+ window.octoshapeVariant +" </TR>");
				theString+=("<TR ><TD><TD>EULA variant<TD>|<TD>"+window.octoshapeVariantEula+" </TR>");
				
				for (var e in this._extraSettings){ 
					theString+=("<TR ><TD><TD>"+e+"<TD>|<TD>"+ this._extraSettings[e] +"</TR>");
				}
				
				var arr = octopv_paths.allFiles;
				for(var i2=0;i2<arr.length;i2++){
					var file = arr[i2];
					var path = octopv_paths.get(file);
					var linkStyle = 'color:blue;text-decoration:underline;cursor:pointer;';
					var linkOnclick = 'javascript:window.open(\''+path+'\'); return false; ';
					var link = '<span STYLE="'+linkStyle+'" onclick="'+linkOnclick+'">get</span>';
					theString+=("<TR ><TD><TD>"+file+"<TD>|<TD> "+ link + " " +path +"</TR>");
				}
				theString+=("<TR STYLE=\"background-color:#D8D8D8;\"><TD><TD>LOGS<TD>|"); 
				theString+=("<TD> size: "+this._arr.length+"</TR>"); 
				
				for(var i=0;i<this._arr.length;i++){
					theString+=this._arr[i];
				}
				theString+="</table></div>";
				div.innerHTML = theString;
				return true;
			}
		}catch (exception) {}
		return false;
	};
}
window.octopv_log = new octopv_ConstructDebug();
window.octopv_log.init();
// for old compatibility reasons. (applet call this)
function octopv_debug(str1,str2){
	octopv_log.log(str1,str2);
}
window.octopv_randomId=octopv_randomString(10);
// This adobe JavaScript file is included to be able to test if the user has Flash Player installed.
if(!window.DetectFlashVer) octopv_includeJSFile(octopv_paths.get("AC_OETags.js"));
function octopv_fileInitFunction(){  return octopv_fileVersion;  };