// Programming code  copyright 2001 Soren Krohn 1.02ae=document.forms[0].elements.special.value.charAt(0);oe=document.forms[0].elements.special.value.charAt(1);aa=document.forms[0].elements.special.value.charAt(2);//self.onerror=errorHandler;//win=open("","","width=200");if (document.all){ // code necessary for PC IE	document.all("speedscale").style.pixelLeft=315;	document.all("speedscale").style.pixelTop=381;	document.all("speed").style.pixelLeft=390;	document.all("speed").style.pixelTop=394;	document.all("heightscale").style.pixelLeft=430;	document.all("heightscale").style.pixelTop=0;	document.all("worksheet").style.pixelLeft=4;	document.all("worksheet").style.pixelTop=112;	document.all("help").style.pixelLeft=10;	document.all("help").style.pixelTop=10;	document.all("calculator").style.pixelLeft=514;	document.all("calculator").style.pixelTop=190;	document.all("caltext").style.pixelLeft=523;	document.all("caltext").style.pixelTop=208;	document.all("keyshadow").style.pixelLeft=514;	document.all("keyshadow").style.pixelTop=190;	document.all("helptext").style.pixelLeft=16;	document.all("helptext").style.pixelTop=30;	document.all("powerscale").style.pixelTop=43;	document.all("popturb01").style.pixelTop=284;	document.all("popwind03").style.pixelTop=188;}function errorHandler(msg,doc,no){	var reply=prompt("Error in program, please report to SK:\r"+msg+"\rline="+no+" IE="+(no-183));	while (reply!="") prompt(reply.eval().toString());return(true);}preload("kres","bub12.gif","bub13.gif","rgh01bde.gif","rotor54s.gif","rotor60m.gif","rotor60s.gif","rotor52m.gif","rotor52s.gif");preload("kr","coord01.gif","coord02.gif");down=null;Bonus1000_54=new powerCurve(54,21,"Bonus 1000 kW, 54 m rotor diameter",(new Array("../../../kres/grecross.gif","../../../kres/greeplus.gif")),"rotor54z","../../../kres/rotor54m.gif","../../../kres/rotor54s.gif",0,0,0,0,13,55,116.1,204,317.4,444.7,583.1,715.6,822.1,906.8,963.7,991,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000);Nordex1000_54=new powerCurve(54,21,"Nordex 1000 kW, 54 m rotor diameter",(new Array("../../../kres/yelcross.gif","../../../kres/yellplus.gif")),"rotor54z","../../../kres/rotor54m.gif","../../../kres/rotor54s.gif",0,0,0,0,14,51,105,179,297,427,548,697,794,885,999,1082,1090,1086,1033,1025,1021,1011,1000,990,980,970);NEG_Micon1000_60=new powerCurve(60,19,"NEG-Micon 1000 kW 60 m rotor diameter",(new Array("../../../kres/redcross.gif","../../../kres/redplus.gif")),"rotor60z","../../../kres/rotor60m.gif","../../../kres/rotor60s.gif",0,0,0,0,33,86,150,248,385,535,670,780,864,924,964,989,1000,998,987,968,944,917,889,863,840,822);Vestas850_50=new powerCurve(52,28,"Vestas 850 kW, 52 m rotor diameter",(new Array("../../../kres/blucross.gif","../../../kres/blueplus.gif")),"rotor52z","../../../kres/rotor52m.gif","../../../kres/rotor52s.gif",0,0,0,0,25.5,67.4,125,203,304,425,554,671,759,811,836,846,849,850,850,850,850,850,850,850,850,850);theTower=new tower("rough","../../../kres/rgh00bde.gif","../../../kres/rgh01bde.gif","../../../kres/rgh02bde.gif","../../../kres/rgh03bde.gif","../../../kres/rgh04bde.gif");thePower=new power(Bonus1000_54,NEG_Micon1000_60,Nordex1000_54,Vestas850_50); // *** VESTAS REPLACED BY BONUS POWER CURVE!!!! ***speedSlider=new slider("speed","x",8,19,6,thePower,0.1,1,null,null,null,null,help_speed,0,null);speedSlider.value=7.32;heightSlider=new slider("height","y",30,20,6,theTower,0.33333333,2,0,0,13,26,help_height,27,null);heightSlider.value=60;powerSlider=new slider("power","y",29,3,330,null,3.33333333,0,null,null,null,null,help_power,0,null);powerSlider.value=240;powerSlider.activeClick=false;powerSlider.activeDrag=false;turbines=new popup("popturb01",24,4,popT,help_turb,null);locations=new popup("popwind03",24,8,popW,help_loc,null);powerCurvePaper=new paper("../kr/coord01.gif",0.1,5,23,15,"x",speedSlider,"Power Curve");windShearPaper=new paper("../kr/coord02.gif",0.05,0.5,23,15,"y",heightSlider,"Wind Shear");plotArea=new area("worksheet",movea,powerCurvePaper,"popdraw",26,23,12,77,0,0,14,371,help_plotArea,null);helpWin=new area("help",movea,new paper("../../../kres/helpwin.gif",1,1,1,1,"x",null),null,32,32,32,32,0,0,14,371,null,null);helpWin.daughterLayers[0]="helptext";cal=new area("calculator",movec,new paper("../../../kres/cal.gif",41,5,32,5,"x",null),"popcal",41,5,32,5,0,0,14,92,help_cal,null);cal.daughterLayers[0]="caltext";cal.daughterLayers[1]="keyshadow";keys=new Array(new key("c",0,0,19,19),new key("=",0,24,19,43),new key("/",0,48,19,67),new key("*",0,72,19,91),new key("7",24,0,43,19),new key("8",24,24,43,43),new key("9",24,48,43,67),new key("-",24,72,43,91),new key("4",48,0,67,19),new key("5",48,24,67,43),new key("6",48,48,67,67),new key("+",48,72,67,91),new key("1",72,0,91,19),new key("2",72,24,91,43),new key("3",72,48,91,67),new key("e",72,72,115,91),new key("0",96,0,115,43),new key(".",96,48,115,67));calc=new calculator();areas=new Array(helpWin,cal,heightSlider,plotArea,speedSlider,powerSlider);//// thanks to webmonkey.com for this Netscape css fixfunction WM_netscapeCssFix() {  /*    Source: Webmonkey Code Library    (http://www.hotwired.com/webmonkey/javascript/code_library/)    Author: Taylor    Author Email: taylor@wired.com    Author URL: http://www.taylor.org/    */  // This part was inspired by Matthew_Baird@wayfarer.com  // It gets around another unfortunate bug whereby Netscape   // fires a resize event when the scrollbars pop up. This   // checks to make sure that the window's available size   // has actually changed.  if (document.WM.WM_netscapeCssFix.initWindowWidth != window.innerWidth || document.WM.WM_netscapeCssFix.initWindowHeight != window.innerHeight) {    document.location = document.location;  }}function WM_netscapeCssFixCheckIn() {  // This function checks to make sure the version of Netscape   // in use contains the bug; if so, it records the window's   // width and height and sets all resize events to be handled   // by the WM_netscapeCssFix() function.  if ((navigator.appName == 'Netscape') && (parseInt(navigator.appVersion) == 4)) {    if (typeof document.WM == 'undefined'){      document.WM = new Object;    }    if (typeof document.WM.WM_scaleFont == 'undefined') {      document.WM.WM_netscapeCssFix = new Object;      document.WM.WM_netscapeCssFix.initWindowWidth = window.innerWidth;      document.WM.WM_netscapeCssFix.initWindowHeight = window.innerHeight;    }    window.onresize = WM_netscapeCssFix;  }}WM_netscapeCssFixCheckIn()// actual programme starts here//*********black=false; // blackboard is not activeClickif (document.layers){ 	captureEvents(Event.MOUSEDOWN); 	onMouseDown=mouseD;}if (document.all){		document.onmousedown=mouseD;}function mouseU(e){	if (document.all){		window.event.cancelBubble=true;		document.onmousemove=null;		document.onmouseup=null;	}	if (document.layers){		releaseEvents(Event.MOUSEMOVE | Event.MOUSEUP);		onMouseUp=null; 		onMouseMove=null;	}	if (down==null) return true;	if (down.dragging==true) down.stopDrag();	down=null;	return true;}function mouseD(e){	if (down!=null){ // necessary if mouse goues out of bounds		if (down.dragging==true) down.stopDrag();		down.old=-1;		down=null;	}	var x=0;	var y=0;	if (document.layers){		x=e.pageX;		y=e.pageY;	}	if (document.all){		window.event.cancelBubble=true;		x=event.clientX+document.body.scrollLeft;		y=event.clientY+document.body.scrollTop;	}	if (document.layers){ 		captureEvents(Event.MOUSEMOVE | Event.MOUSEUP); 		onMouseUp=mouseU; 		onMouseMove=mouseM;	}	down=inside(areas,x,y); // Did the user click on a drag bar, a scale or a worksheet?	if (down!=null){		if (document.all){			document.onmousemove=mouseM;			document.onmouseup=mouseU;		}		if (down.name=="height"){			theTower.baseSpeed=speedSlider.value;			theTower.baseHeight=theTower.height;			theTower.baseRoughness=theTower.roughness;		}		down.dragging ? down.startDrag(x,y) : down.move(x,y);		var tab=false;		if (document.layers&&(down.name=="worksheet"||down.name=="help"||down.name=="calculator")){			var xr=x-down.left;			var wi=down.right-down.left;			if (y<down.top+14&&((xr>wi-21&&xr<wi-6)||(xr>5&&xr<20))) tab=true;		}		if (!black&&!tab) return false; // Prevent Mac from showing contextual menu	}	return true;}function mouseM(e){	if (document.all) window.event.cancelBubble=true;	if (down==null) return true;	var x,y;	if (document.layers){		x=e.pageX;		y=e.pageY;	}	if (document.all){		if (event.button!=1) return true;		x=event.clientX+document.body.scrollLeft;		y=event.clientY+document.body.scrollTop;	}	if (down.dragging){		down.drag(x,y);		return false;	}	else if (down.activeDrag==false) return true;	down.move(x,y);	//if (down.hit==2&&!black) return false; // Prevent Mac from showing contextual menu	return(false);  // Prevent Mac from showing contextual menu	return true;}function slider(name,orientation,minOffset,maxOffset,arrowOffset,message,scaleFactor,decimals,dragTop,dragLeft,dragBottom,dragRight,help,minimum,onChange){	this.v=false; // the object is visible and active	this.activate=activate; // method to make object visbile and active	this.activeClick=true; // The object should respond to clicks	this.activeDrag=true; // The object allows dragging inside it (dragging on screen is another matter)	this.value=0; // the actual logical value of this slider	this.name=name; // arrow layer name	this.scale=name+"scale"; // scale layer name=name+"scale"	this.digital=name+"digital"; // digital layer name	this.daughterLayers=new Array(this.name,this.digital); // list of daughter layers used by move method	this.orientation=orientation; // Value "x" or "y"	this.minOffset=minOffset; // offset in pixels of the origin	this.maxOffset=maxOffset; // offset in pixels of the maximum	this.arrowOffset=arrowOffset; // offset in pixels of the arrow centre from the edge (horizontal or vertical)	this.old=-1; // old coordinate value	this.message=message; // call the process method of this object and send value as message	this.scaleFactor=scaleFactor; // Used to scale pixels to final data	this.minimum=minimum; // Permitted minimum value for data	this.decimals=decimals; // decimals in digital box	//this.hit=0; // 1 if hit in arrow, 2 if hit in scale	this.move=move; // basic method when mouse moves	this.set=set; // move slider indicator with logical input data	this.measureLayer=measureLayer; // utility to initialise top left bottom right	this.top=0;	this.left=0;	this.bottom=0;	this.right=0;	this.scaleTop=0;	this.scaleLeft=0;	this.scaleBottom=0;	this.scaleRight=0;	this.measureLayer(this.scale);	this.orientation=="x" ? this.scaleTop=this.top : this.scaleTop=this.top+this.maxOffset;	this.orientation=="x" ? this.scaleLeft=this.left+this.minOffset : this.scaleLeft=this.left;	this.orientation=="x" ? this.scaleBottom=this.bottom : this.scaleBottom=this.bottom-this.minOffset;	this.orientation=="x" ? this.scaleRight=this.right-this.maxOffset : this.scaleRight=this.right;	this.dragTop=this.top+dragTop; // user gives coordinates of draggable area relative to top left corner	this.dragLeft=this.left+dragLeft; // if undefined, them drag of object on screen is ignored	this.dragBottom=this.top+dragBottom;	this.dragRight=this.left+dragRight;	this.oldX=0; // used by drag method	this.oldY=0; // used by drag method	this.startX=0; // used by drag method	this.startY=0; // used by drag method	this.dragging=false; // the object is being dragged	this.drag=drag; // drag object on screen	this.startDrag=startDrag; // drag object on screen	this.stopDrag=stopDrag;	this.undoneLayers=new Array();	this.help=help; // help function	this.onChange=onChange; // Method to call when slider is moved}function activate(huh){	this.v=huh;	if (huh) show(this.name,this.scale,this.digital);	else hide(this.name,this.scale,this.digital);}function activateA(huh){	this.v=huh;	if (this.button!=null){		huh ? show(this.button) : hide(this.button);	}}	function area(name,move,paper,button,marginTop,marginLeft,marginBottom,marginRight,dragTop,dragLeft,dragBottom,dragRight,help,onChange){	this.v=false; // indicates whether the object is visble and active	this.activate=activateA;  // method to make object visbile and active	this.activeClick=false; // indicates when the object should respond to clicks	this.activeDrag=false; // the object disallows dragging inside scale area (dragging on screen is another matter)	this.name=name; // dummy layer name for compatibility with slider	this.scale=name; // area layer name	this.daughterLayers=new Array(); // list of names of daughter layers used for hiding and restoring layers	this.old=-1; // old independent variable coordinate	this.paper=paper; // current paper object indicating the gif path and its scales	paper.parent=this; // initialise paper object	this.button=button; // layer of button opening this area	this.move=move; // move method of this object (cursor click method)	this.openA=openA; // method to show and activate clickable area	this.measureLayer=measureLayer; // utility to initialise top left bottom right	this.top=0;	this.left=0;	this.bottom=0;	this.right=0;	this.measureLayer(this.scale);	this.scaleTop=this.top+marginTop; // Define clickable area	this.scaleLeft=this.left+marginLeft; // **********	this.scaleBottom=this.bottom-marginBottom;	this.scaleRight=this.right-marginRight;	this.dragTop=this.top+dragTop; // user gives coordinates of draggable area relative to top left corner	this.dragLeft=this.left+dragLeft; // if undefined, them drag of object on screen is ignored	this.dragBottom=this.top+dragBottom;	this.dragRight=this.left+dragRight;	this.oldX=0; // used by drag method	this.oldY=0; // used by drag method	this.startX=0; // used by drag method	this.startY=0; // used by drag method	this.dragging=false; // the object is being dragged	this.drag=drag; // drag object on screen	this.startDrag=startDrag; // drag object on screen	this.stopDrag=stopDrag;	this.undo=undo;	this.redo=redo;	this.undoCurve=undoCurve;	this.undoneLayers=new Array();	this.help=help; // help function	this.print=print;	this.onChange=onChange; // method to call with result if data changes	this.onOpen=null; // may be set if open routine is to call a method with 1 or 0}function movec(x,y){ // method of area object for calculator instance	x-=this.scaleLeft;	y-=this.scaleTop;	var k=inside(keys,x,y); // get key object	if (k!=null){		// var z=getZ("calculator");		z=390; // *** HARD CODED *** Problem in IE		moveXY("keyshadow",this.scaleLeft+k.scaleLeft,this.scaleTop+k.scaleTop);		moveZ("keyshadow",z+1);		show("keyshadow");		setTimeout("moveZ('keyshadow',"+(z-1)+")",100);		calc.hit(k.ch);	}}function key(ch,scaleTop,scaleLeft,scaleBottom,scaleRight,method){	this.ch=ch; // character	this.scaleTop=scaleTop;	this.scaleLeft=scaleLeft;	this.scaleBottom=scaleBottom;	this.scaleRight=scaleRight;	this.v=true; // dummy	this.activeClick=true; // dummy	this.dragTop=null; // dummy NaN	this.method=method;}function calculator(){	this.buf="0"; // character display buffer	this.reg1=0; // first operand register top of stack	this.reg2=0; // second operand register bottom of stack	this.opJustEntered=false;	this.pendingOp="";	this.pointEntered=false;	this.hit=hit;	if (document.layers){		document.captureEvents(Event.KEYPRESS);		document.onKeyPress=grabKey;	}	if (document.all) document.onkeypress=grabKey;}function grabKey(evnt){ // utility used by keyboard	var ch;	var unicode=0;	if (document.layers){		unicode=evnt.which;	}	if (document.all){		window.event.cancelBubble=true;		unicode=window.event.keyCode;	}	ch=String.fromCharCode(unicode).toLowerCase();	if (ch==",") ch="."; // , to .	else if (unicode==13||unicode==3) ch="e"; // CR or LF	else if (unicode==8||unicode==0) ch="c"; // backspace or Delete	calc.hit(ch);}function hit(ch){ // method of calculator when key is hit. ch is a character	var tx;	if ((ch>="0"&&ch<="9")||ch=="."){		if (this.opJustEntered){			this.reg2=this.reg1;			this.reg1=this.buf;			this.buf="0";			this.opJustEntered=false;			this.pointEntered=false;		}		if (ch=="."){			if (this.pointEntered) return;			this.pointEntered=true;		}else{			if (this.buf=="0") this.buf="";		}		this.buf+=ch;		tx=this.buf.toString().replace(/\./g,",");		writeToLayer("caltext","<FONT FACE='gillsans,frutiger,helvetica,arial,geneva'><B>"+tx+"</B></FONT>");	}else{		if (ch=="+"||ch=="-"||ch=="*"||ch=="/"||ch=="="){			if (this.pendingOp!=""&&!this.opJustEntered){				this.reg2=this.reg1;				this.reg1=this.buf;				this.buf=eval(this.reg2+this.pendingOp+this.reg1);				if (this.buf>9999999999||this.buf<-999999999) this.buf="Error";				tx=this.buf.toString().replace(/\./g,",");				tx=tx.replace(/-,/,"-0,");				if (tx.charAt(0)==",") tx="0"+tx;				tx=tx.substring(0,Math.min(10,tx.length));				writeToLayer("caltext","<FONT FACE='gillsans,frutiger,helvetica,arial,geneva'><B>"+tx+"</B></FONT>");				this.reg1=0;				this.reg2=0;			}			this.opJustEntered=true;			this.pendingOp="";			if (ch!="=") this.pendingOp=ch;			this.pointEntered=false;		}else{			if (ch=="c"){				this.reg2=0;				this.reg1=0;				this.buf="0";				this.pendingOp="";				this.opJustEntered=false;				this.pointEntered=false;				tx=this.buf.toString().replace(/\./g,",");				writeToLayer("caltext","<FONT FACE='gillsans,frutiger,helvetica,arial,geneva'><B>"+tx+"</B></FONT>");			}else{				if (ch=="e"){					if(cal.onChange!=null) cal.onChange(this.buf); // send result to requesting object				}			}		}	}}function print(){	var w=window.open("","print","height=300,width=400");	w.document.open();	var d="<center><font face='gillsans,frutiger,helvetica,arial,geneva'>x is your result, + is the result of the programme</font></center>";	var t=this.paper.head;	w.document.write("<head><title>"+t+"</title></head><body bgcolor='#ffffff'><div id='xb' style='position:absolute;z-index:1;top:10;left:10'><img src='"+this.paper.src+"'><br>"+d+"</div>");	for (var i=0;i<this.daughterLayers.length;i++){		var lname=this.daughterLayers[i];		var ypos=getY(this.daughterLayers[i])-this.top+10;		var xpos=getX(this.daughterLayers[i])-this.left+10;		var div="<div id='"+lname+"' style='position:absolute;z-index:2;top:"+ypos+";left:"+xpos+";width:5;height:5'>";		var img="";		if (document.layers) img="<img src='"+document.layers[this.daughterLayers[i]].document.images[0].src+"' width='5' height='5'>";		if (document.all) img=document.all(this.daughterLayers[i]).innerHTML;		w.document.write(div+img+"</div>");	}	w.document.write("</body>");	w.document.close();	w.focus();}function startDrag(x,y){	this.oldX=x;	this.oldY=y;	this.startX=this.left;	this.startY=this.top;	hideLayers(this.daughterLayers);}function stopDrag(){	this.dragging=false;	var dx=this.left-this.startX;	var dy=this.top-this.startY;	// update	this.scaleTop+=dy;	this.scaleLeft+=dx;	this.scaleBottom+=dy;	this.scaleRight+=dx;	this.dragTop+=dy;	this.dragLeft+=dx;	this.dragBottom+=dy;	this.dragRight+=dx;	for (var i=0;i<this.daughterLayers.length;i++){		moveX(this.daughterLayers[i],getX(this.daughterLayers[i])+dx);		moveY(this.daughterLayers[i],getY(this.daughterLayers[i])+dy);		show(this.daughterLayers[i]);	}	for (var i=0;i<this.undoneLayers.length;i++){		moveX(this.undoneLayers[i],getX(this.undoneLayers[i])+dx);		moveY(this.undoneLayers[i],getY(this.undoneLayers[i])+dy);	}}function drag(x,y){ // method of slider and area	if (x==this.oldX&&y==this.oldY) return;	var dx=x-this.oldX;	var dy=y-this.oldY;	if (this.left+dx<0) dx=-this.left; // prevent moving window offscreen	if (this.top+dy<0) dy=-this.top;	var w=Math.min(screen.availWidth,780);	if (dx>w-this.right){dx=w-this.right; if (dx<0) dx=0;}	var h=Math.min(screen.availHeight,670);	if (dy>h-this.bottom){dy=h-this.bottom; if (dy<0) dy=0;}	this.left+=dx;	this.top+=dy;	this.bottom+=dy;	this.right+=dx;	moveXY(this.scale,this.left,this.top);	this.oldX+=dx;	this.oldY+=dy;}function openA(n){ // method of area. 1=activate, 0=deactivate	var t=new Array(false,true);	//for (var i=0;i<this.paper.modalLock.length;i++) this.paper.modalLock[i].activate=t[n]; // lock or unlock other objects	this.activeClick=t[n];	this.v=t[n];	if (n==1){		show(this.scale);		showLayers(this.daughterLayers);	}else{		hide(this.scale);		hideLayers(this.daughterLayers);	}	if (this.onOpen!=null) this.onOpen(n);	restart();}function plot(x,y,i){// method of paper. x,y are coordinates relative to origin of scale, i is the number of gif	var lname="j"+this.parent.daughterLayers.length;	var a=thePower.pcurves[thePower.turbineNo].color;	var img=new Array("<IMG SRC='"+a[0]+"' width='5' height='5'>","<IMG SRC='"+a[1]+"' width='5' height='5'>");	var top=this.parent.bottom-this.offsetY-y-3;	var left=x+this.parent.left+this.offsetX-3;	createLayer(lname,left,top,11,5,5);	writeToLayer(lname,img[i]);	show(lname);	this.parent.daughterLayers[this.parent.daughterLayers.length]=lname;	if (this.parent.onChange!=null) this.parent.onChange();}function paper(src,scaleX,scaleY,offsetX,offsetY,orientation,message,head){	this.src=src; // src is graph paper gif path	this.scaleX=scaleX;	this.scaleY=scaleY;	this.offsetX=offsetX;	this.offsetY=offsetY;	this.orientation=orientation; // indicates whether x or y is the independent variable	this.modalLock=new Array(); // Objects to deactivate (using their activate property) while plotting is acivated	this.plot=plot;	this.message=message; // Function to process data of independent variable to return dependent variable	this.head=head; // header for printout	this.parent=parent; // parent area object (used by plot method) *** MUST BE INITIALISED BY AREA OBJECT OR MANUALLY ***	this.graph=graph; // draws graph automatically}function graph(min,max,step){ // Draws finished graph, data in true values	var p,x,y;	while (min<=max){		if (this.orientation=="x"){ // x is independent variable			x=Math.round(min/this.scaleX); // physical x coordinate			y=Math.round(this.message.set(min)/this.scaleY);		}else{ // y is independent variable			y=Math.round(min/this.scaleY); // physical y coordinate			x=Math.round(this.message.set(min)/this.scaleX);		}		this.plot(x,y,1); // coordinates in pixels relative to origin		min+=step;	}}function undo(){	if (this.daughterLayers.length<1) return;	this.undoneLayers[this.undoneLayers.length]=this.daughterLayers[this.daughterLayers.length-1];	hide(this.undoneLayers[this.undoneLayers.length-1]);	this.daughterLayers=this.daughterLayers.slice(0,this.daughterLayers.length-1);}function undoCurve(){	var total=this.daughterLayers.length;	for (var i=0;i<total;i++) this.undo();}function redo(){	if (this.undoneLayers.length<1) return;	this.daughterLayers[this.daughterLayers.length]=this.undoneLayers[this.undoneLayers.length-1];	show(this.daughterLayers[this.daughterLayers.length-1]);	this.undoneLayers=this.undoneLayers.slice(0,this.undoneLayers.length-1);}function movea(x,y){ // method of area object (corresponds to move for the slider object)	y=this.bottom-y;	x-=this.left;	this.paper.plot(x-this.paper.offsetX,y-this.paper.offsetY,0);// output coordinates are relative to origin}function inside(areas,x,y){ // utility returns object which was hit. Object must have scaleTop, scaleLeft, scaleBottom, scaleRight, and dragTop (+ more) properties	var ins=null; // just shorthand	for (var i=0;i<areas.length;i++){		ins=areas[i]; // check if hit in scale area		if	(x>=ins.scaleLeft&&y>=ins.scaleTop&&x<=ins.scaleRight&&y<=ins.scaleBottom){			if (ins.activeClick&&ins.v) return(ins);		}		if (!isNaN(ins.dragTop)&&ins.activeClick&&ins.v){ // check if hit in draggable area			if	(x>=ins.dragLeft&&y>=ins.dragTop&&x<=ins.dragRight&&y<=ins.dragBottom){				ins.dragging=true;				return(ins);			}		}	}	return(null);}function move(x,y){ // Method of slider object computes physical values. (x,y) are document coordinates.	var xpos=null;	var ypos=null;	if (this.orientation=="x"){		if (x==this.old) return;		this.old=x;	}else{		if (y==this.old) return;		this.old=y;	}	var r=0;	if (this.orientation=="x"){		if (x<this.scaleLeft) x=this.scaleLeft;		if  (x>this.scaleRight) x=this.scaleRight;		this.set((x-this.scaleLeft)*this.scaleFactor);	}else{		if (y>this.scaleBottom) y=this.scaleBottom;		if (y<this.scaleTop) y=this.scaleTop;		this.set(this.scaleFactor*(this.scaleBottom-y));	}	if (this.onChange!=null) this.onChange();}function set(z){ // Method of slider object. Sets slider physically using an input scalar of data	this.value=z;	var	x,y;	var z=Math.round(z/this.scaleFactor);	if (this.orientation=="x"){		x=z+this.scaleLeft-this.arrowOffset;	if  (x>this.scaleRight) x=this.scaleRight;		moveX(this.name,x);		moveX(this.digital,x+18); // *** HARD CODED OFFSET ***	}else{		y=this.scaleBottom-z;		if (y<this.top) y=this.top;		moveY(this.name,y-this.arrowOffset);		moveY(this.digital,y-4); // *** HARD CODED TO TEXT SIZE ***	}	var dig=" <font size='-2' face='arial'>"+edit(this.value,this.decimals)+"</font>";	writeToLayer(this.digital,dig);	var res=0;	if (this.message!=null) res=this.message.process(this.value);	return(res);}function powerCurve(diameter,rpm,id,color,rotorLayer,rotormGif,rotorsGif,ps){ // object used by power object NOTE!!! Do not add arguments without changing last loop!!!	this.id=id; // id for printing	this.diameter=diameter;	this.rpm=rpm;	this.rotorLayer=rotorLayer; // layername for rotor	this.rotormGif=rotormGif; // path of image of rotor moving	this.rotorsGif=rotorsGif; // path of image of rotor still	this.rotorName=this.rotorLayer.substring(0,this.rotorLayer.length-1); // name of image must be thes same as layer, but without the final "z"	this.curve=new Array();	this.getPower=getPower;	this.color=color; // curve colour	for (var i=7;i<arguments.length;i++) this.curve[i-7]=arguments[i]; // Do not add arguments without changing last loop!!!}function getPower(speed){ // method of powerCurve object	var f=Math.floor(speed);	if (f<0) f=0;	if (f>=this.curve.length) f=0;	var c=Math.ceil(speed);	if (c<0) c=0;	if (c>=this.curve.length) c=0;	var r=speed-f;	var p=Math.round(this.curve[f]*(1-r)+this.curve[c]*r);	if (this.curve[f]==0||this.curve[c]==0) p=0;	if (isNaN(p)||!isFinite(p)) alert("Prog error, notify SK: Bad speed="+speed+" p="+p+" f="+f+" c="+c+" r="+r+" curve="+this.curve.toString()+" this.curve[f]="+this.curve[f]+" this.curve[c]="+this.curve[c]);  	p=parseFloat(p);  	return(p);}function power(x){	this.pcurves=new Array();	for (var i=0;i<arguments.length;i++) this.pcurves[i]=arguments[i];	this.process=newSpeed;	this.changeTurbine=changeTurbine;	this.turbineNo=0; // current turbine number}function newSpeed(speed){ // method of power	var p=this.pcurves[this.turbineNo].getPower(speed);	powerSlider.set(p);	var stopped=false;	if (heightSlider.value<=heightSlider.minimum) stopped=true;	var a=this.pcurves[this.turbineNo]; // shorthand	var showsRota=getURL(a.rotorName,a.rotorLayer).indexOf("m.gif")!=-1; // check for moving rotor gif	if (p==0||stopped){		if (showsRota) changeURL(a.rotorsGif,a.rotorName,a.rotorLayer);	}else{		if (!showsRota) changeURL(a.rotormGif,a.rotorName,a.rotorLayer);	}	oldp=p;	return(p); // Return for the sake of paper}function changeTurbine(n){ // method of power	hide(this.pcurves[this.turbineNo].rotorLayer); // hide old rotor	this.turbineNo=n;	var a=this.pcurves[this.turbineNo]; // shorthand	changeURL(a.rotorsGif,a.rotorName,a.rotorLayer); // mount a still standing rotor	heightSlider.minimum=a.diameter/2;	speedSlider.set(speedSlider.value); // provoke speed slider to show correct rotor	if (theTower.height<=heightSlider.minimum) theTower.process(heightSlider.value);	show("tower"); // included for initial turbine choice	show(a.rotorLayer);}function tower(button,r0,r1,r2,r3,r4){	this.button=button; // Layer name of button to operate roughness classes	this.buttonRed=button+"Red"; // Layer name of red indicator must be button+"Red"	this.activate=activateT; // Method to show or hide button and indicator	this.gifs=new Array(r0,r1,r2,r3,r4); // landscape gifs	this.lengths=new Array(0.0002,0.03,0.1,0.4,1.6); // roughness lengths corresponding to the roughnes classes 0-4	this.height=60; // Hub height	this.speed=7.32; // wind speed at hub height in m/s	this.roughness=0.1; // Roughness length in m	this.baseSpeed=5;	this.baseHeight=10;	this.baseRoughness=0.1;	this.process=newHeight; // method	this.newRoughness=newRoughness; // method	this.classNo=2; // current class number}function activateT(huh){  // Method to show or hide button and indicator	huh ? show(this.button,this.buttonRed) : hide(this.button,this.buttonRed);}function newHeight(height){ // method of tower object under the name of process	if (height<heightSlider.minimum){		heightSlider.set(heightSlider.minimum);		height=heightSlider.minimum;	}	this.height=height;	this.speed=0;	if (this.height>this.roughness){		this.speed=WSpeed(this.height,this.roughness,this.baseHeight,this.baseSpeed,this.baseRoughness);	}	var a=thePower.pcurves[thePower.turbineNo]; // shorthand	var showsRota=getURL(a.rotorName,a.rotorLayer).indexOf("m.gif")!=-1; // check for moving rotor gif	if (heightSlider.value==heightSlider.minimum&&showsRota) changeURL(a.rotorsGif,a.rotorName,a.rotorLayer);	else if (heightSlider.value!=heightSlider.minimum&&!showsRota) changeURL(a.rotormGif,a.rotorName,a.rotorLayer);	moveY(a.rotorLayer,278-(heightSlider.value+thePower.pcurves[thePower.turbineNo].diameter/2)/heightSlider.scaleFactor); // *** HARD CODED ****	moveY("tower",270-heightSlider.value/heightSlider.scaleFactor); // *** HARD CODED ****	var save=speedSlider.decimals;	speedSlider.decimals=2;	speedSlider.set(this.speed);	speedSlider.decimals=save;	return(this.speed);}function WSpeed(height,roughness,refHeight,refSpeed,refRoughness){	return(refSpeed*Math.log(height/roughness)/Math.log(refHeight/refRoughness));}function edit(n,decs){	var r="";	if (decs==0) r=Math.round(n);	if (decs==1){		var d=Math.round(10*n).toString();		if (d.length<2) return("0,"+d);		r=d.substring(0,d.length-1)+","+d.substring(d.length-1,d.length);	}else{		if (decs==2){			var d=Math.round(100*n).toString();			if (d.length<2) return("0,0"+d);			if (d.length<3) return("0,"+d);			r=d.substring(0,d.length-2)+","+d.substring(d.length-2,d.length);		}	}	return(r);}function newRoughness(n){ // method of tower	moveX("roughRed",214+16*n); // Move arrow *** HARD CODED ***	changeURL(this.gifs[n],"lndscp","landscape");	restart();	this.classNo=n;	// recalculate to h m	var h=28000; // *** HARD CODED IMPLICIT HEIGHT ***	this.baseHeight=this.height;	this.baseSpeed=speedSlider.value;	this.speed=WSpeed(h,this.roughness,this.baseHeight,this.baseSpeed,this.baseRoughness);	theTower.baseSpeed=this.speed;	theTower.baseHeight=h;	theTower.baseRoughness=this.lengths[n];		this.roughness=this.lengths[n];	this.process(theTower.height,heightSlider);}function measureLayer(layerName){ // method of slider and area and powerCurve	if (document.layers){		this.top=document.layers[layerName].top;		this.left=document.layers[layerName].left;		this.bottom=this.top+document.layers[layerName].clip.height;		this.right=this.left+document.layers[layerName].clip.width;	}	else if (document.all){		this.top=parseInt(document.all(layerName).style.posTop);		this.left=parseInt(document.all(layerName).style.posLeft);		this.bottom=parseInt(this.top+document.all(layerName).offsetHeight);		this.right=parseInt(this.left+document.all(layerName).offsetWidth);	}}function hideLayers(a){	for (var i=0;i<a.length;i++) hide(a[i]);}function showLayers(a){	for (var i=0;i<a.length;i++) show(a[i]);}function popup(scale,spacing,items,method,help,onChange){ // popup menu object	this.scale=scale; // Name of layer	this.activate=activateP; // method to show or hide popup menu	this.zIndex=getZ(this.scale); // Original z-index	this.spacing=spacing; // Vertical spacing per item in pixels	this.items=items; // number of items used (excluding lowermost tab)	this.pop=pop; // method to store data and deactivate menu	this.active=false;	this.ypos=getY(this.scale); // original y coordinate to layer top	this.method=method; // method to use for processing of number, called with the popup number	this.help=help; // help method	this.onChange=onChange; // method to call when a selection is made}function activateP(huh){ // method of popup	huh ? show(this.scale) : hide(this.scale);}function pop(n){ // metod of popup	moveZ(this.scale,500);	this.active=!this.active;	if (this.active){		moveY(this.scale,this.ypos);		return;	}	if (n!=-1){		moveZ(this.scale,this.zIndex);		var d=this.ypos+(this.items-n)*this.spacing;		moveY(this.scale,d);		this.method(n);		if (this.onChange!=null) this.onChange(n);	}}function popT(n){	thePower.changeTurbine(n);}function popW(n){	// process wind stat data in a climate object, and show result}function hlp(h,s){	var h="<font face='gillsans,frutiger,helvetica,arial,geneva' color='#0066CC'><b>"+translate(h)+"</b></font><br>"	var s="<font size='-1'>"+translate(s)+"</font><p><font face='gillsans,frutiger,helvetica,arial,geneva'><b><a href='javascript:helpWin.openA(0)'>Close</a></b></font>";	if (document.layers) writeToLayer("helptext","<table width='311' height='238' border='0' cellspacing='0' cellpadding='0'><tr><td>"+h+s+"</td></tr></table>");	if (document.all) writeToLayer("helptext",h+s);	helpWin.openA(1);}function help_speed(){	var s="You can use the horizontal slide to set the wind speed.<P>Click on the scale or drag the red slide.<BR>The slide is graduated in metres per second (m/s).<BR>When you opened this window the value was "+edit(this.value,1)+" m/s.";	hlp("Wind speed",s);}function help_power(){	var s="You can see how much power the wind turbine generator is producing at the current wind speed.<BR>The slide is graduated in kilowatt (kW).<BR> When you opened this window the value was "+edit(powerSlider.value,0)+" kW.";	hlp("Power",s);}function help_height(){	var s="<P><font size='-1'>You can use the vertical slide to set the hub height.<BR>Click on the scale or drag the red slide.<P>The slide is graduated in metres.<BR>When you opened this window the value was "+edit(heightSlider.value,2)+" m.<BR>You can move the entire scale by dragging the top of it.";	hlp("Hub height",s)}function help_rough(){	var s="Landscapes with many scattered <B>obstacles</B> are called <B>rough</B> landscapes. You can press the roughness class buttons and control how the landscape should look.<BR><font face='gillsans,frutiger,helvetica,arial,geneva' color='#0000FF'><b>0</b></font> is a completely smooth landscape where the entire surface is water.<BR><font face='gillsans,frutiger,helvetica,arial,geneva' color='#0099cc'><b>1</b></font> is completely open with grass and only a few trees or houses.<BR><font face='gillsans,frutiger,helvetica,arial,geneva' color='#009900'><b>2</b></font> is a landscape where there are windbreaks as well as houses, but it still appears open.<BR><font face='gillsans,frutiger,helvetica,arial,geneva' color='#cc9900'><b>3</b></font> is a landscape with woods, scattered buildings and windbreaks.<BR><font face='gillsans,frutiger,helvetica,arial,geneva' color='#ff0000'><b>4</b></font> is an urban area.";	hlp("Roughness class",s)}function help_turb(){	var s="Click one of the wind turbines in the menu to see how much electricity it produces.<P>In the menu you can also see the size of the generator and the size of the rotor diameter."	hlp("Wind turbine",s);}function help_loc(){	var s="Click one of the places in the menu to find out how common the different wind speeds are";	hlp("Wind chart",s);}function help_worksheet(){	var s="Click to get a window with a graph paper. You can get a much better overview of your observations by drawing a graph.";	hlp("Graph paper",s);}function help_plotArea(){	helpWin.startDrag(getX("help"),getY("help"));	helpWin.drag(this.right,this.top);	helpWin.stopDrag();	var s='You can plot points in the coordinate by clicking on the squared paper.<br>The "Delete" button will delete the last cross.<br>"Delete All" will delete all points.<br>Click "Repeat" to undo deleting a point.<br>"Solution" will make the programme show you the solution.<br>"Print" can open a window with the graph which you can print using ctrl-P (command-P on a Mac). Watch out! The "Print"-window may hide behind the big browser window you are working in, if you accidentially click several times.';	hlp("Graph paper",s);}function help_cal(){	var s="You can use the calculator for calculating as well as typing your answers to questions asked by the programme. You can use both the keys on the screen and the real keys on your keyboard.<br>If you answer a question, you need to press the Enter key when you are done typing.";	hlp("Calculator",s);}function help_controls(){	helpWin.startDrag(getX("help"),getY("help"));	helpWin.drag(0,670);	helpWin.stopDrag();	var s="By checking the boxes you can control exactly which slides, buttons and menus you want to be visible on screen.";	hlp("Tailor your own wind turbine simulator",s);}function translate(v){	v=v.replace(//g,"&aelig;");	v=v.replace(//g,"&oslash;");	v=v.replace(//g,"&aring;");	v=v.replace(//g,"&Aelig;");	v=v.replace(//g,"&Oslash;");	v=v.replace(//g,"&Aring;");	return(v);}function restart(){	var a=thePower.pcurves[thePower.turbineNo]; // shorthand	var it=getURL(a.rotorName,a.rotorLayer);	changeURL("../../../kres/t.gif",a.rotorName,a.rotorLayer);	changeURL(it,a.rotorName,a.rotorLayer);}