

/*event listner*/

function attachEventListener(target, eventType, f, c)
{
  if(typeof target.addEventListener != "undefined") //w3c
  {
  	target.addEventListener(eventType, f, c);
  }
  else if (typeof target.attachEvent != "undefined") //IE
  {
  	target.attachEvent("on" + eventType, f);
  }
  else  //IE5Mac
  {
  	var eventName = "on" + eventType;
  	if(typeof target[eventName] == "function")
  	{
  		var prev = target[eventName];
  		target[eventName] = function()
  		                    {
  		                      prev();
  		                      return f();
  		                    };
     }
     else
     {
       target[eventName] = f;
     }
   }
}

/*event listner terminate*/




/*tween starts here*/
function Delegate(){}
Delegate.create=function(o,f){
var a=new Array()
var l=arguments.length
for(var i=2;i<l;i++)a[i-2]=arguments[i]
return function(){
var aP=[].concat(arguments,a)
f.apply(o,aP)}}
Tween=function(obj,prop,func,begin,finish,duration,suffixe){
this.init(obj,prop,func,begin,finish,duration,suffixe)}
var t=Tween.prototype
t.obj=new Object()
t.prop=''
t.func=function(t,b,c,d){return c*t/d+b;}
t.begin=0
t.change=0
t.prevTime=0
t.prevPos=0
t.looping=false
t._duration=0
t._time=0
t._pos=0
t._position=0
t._startTime=0
t._finish=0
t.name=''
t.suffixe=''
t._listeners=new Array()
t.setTime=function(t){
this.prevTime=this._time
if(t>this.getDuration()){
if(this.looping){
this.rewind(t-this._duration)
this.update()
this.broadcastMessage('onMotionLooped',{target:this,type:'onMotionLooped'})
}else{
this._time=this._duration
this.update()
this.stop()
this.broadcastMessage('onMotionFinished',{target:this,type:'onMotionFinished'})}
}else if(t<0){
this.rewind()
this.update()
}else{
this._time=t
this.update()}}
t.getTime=function(){
return this._time}
t.setDuration=function(d){
this._duration=(d==null || d<=0)? 100000 : d}
t.getDuration=function(){
return this._duration}
t.setPosition=function(p){
this.prevPos=this._pos
var a=this.suffixe !='' ? this.suffixe : ''
this.obj[this.prop]=Math.round(p)+a
this._pos=p
this.broadcastMessage('onMotionChanged',{target:this,type:'onMotionChanged'})}
t.getPosition=function(t){
if(t==undefined)t=this._time
return this.func(t,this.begin,this.change,this._duration)}
t.setFinish=function(f){
this.change=f-this.begin}
t.geFinish=function(){
return this.begin+this.change}
t.init=function(obj,prop,func,begin,finish,duration,suffixe){
if(!arguments.length)return
this._listeners=new Array()
this.addListener(this)
if(suffixe)this.suffixe=suffixe
this.obj=obj
this.prop=prop
this.begin=begin
this._pos=begin
this.setDuration(duration)
if(func!=null&&func!=''){
this.func=func}
this.setFinish(finish)}
t.start=function(){
this.rewind()
this.startEnterFrame()
this.broadcastMessage('onMotionStarted',{target:this,type:'onMotionStarted'})}
t.rewind=function(t){
this.stop()
this._time=(t==undefined)? 0 : t
this.fixTime()
this.update()}
t.fforward=function(){
this._time=this._duration
this.fixTime()
this.update()}
t.update=function(){
this.setPosition(this.getPosition(this._time))}
t.startEnterFrame=function(){
this.stopEnterFrame()
this.isPlaying=true
this.onEnterFrame()}
t.onEnterFrame=function(){
if(this.isPlaying){
this.nextFrame()
setTimeout(Delegate.create(this,this.onEnterFrame),0)}}
t.nextFrame=function(){
this.setTime((this.getTimer()-this._startTime)/1000)}
t.stop=function(){
this.stopEnterFrame()
this.broadcastMessage('onMotionStopped',{target:this,type:'onMotionStopped'})}
t.stopEnterFrame=function(){
this.isPlaying=false}
t.continueTo=function(finish,duration){
this.begin=this._pos
this.setFinish(finish)
if(this._duration !=undefined)
this.setDuration(duration)
this.start()}
t.resume=function(){
this.fixTime()
this.startEnterFrame()
this.broadcastMessage('onMotionResumed',{target:this,type:'onMotionResumed'})}
t.yoyo=function(){
this.continueTo(this.begin,this._time)}
t.addListener=function(o){
this.removeListener(o)
return this._listeners.push(o)}
t.removeListener=function(o){
var a=this._listeners
var i=a.length
while(i--){
if(a[i]==o){
a.splice(i,1)
return true}}
return false}
t.broadcastMessage=function(){
var arr=new Array()
for(var i=0;i<arguments.length;i++){
arr.push(arguments[i])}
var e=arr.shift()
var a=this._listeners
var l=a.length
for(var i=0;i<l;i++){
if(a[i][e])
a[i][e].apply(a[i],arr)}}
t.fixTime=function(){
this._startTime=this.getTimer()-this._time*1000}
t.getTimer=function(){
return new Date().getTime()-this._time}
Tween.backEaseIn=function(t,b,c,d,a,p){
if(s==undefined)var s=1.70158
return c*(t/=d)*t*((s+1)*t-s)+b}
Tween.backEaseOut=function(t,b,c,d,a,p){
if(s==undefined)var s=1.70158
return c*((t=t/d-1)*t*((s+1)*t+s)+1)+b}
Tween.backEaseInOut=function(t,b,c,d,a,p){
if(s==undefined)var s=1.70158
if((t/=d/2)<1)return c/2*(t*t*(((s*=(1.525))+1)*t-s))+b
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t+s)+2)+b}
Tween.elasticEaseIn=function(t,b,c,d,a,p){
if(t==0)return b
if((t/=d)==1)return b+c
if(!p)p=d*.3
if(!a || a<Math.abs(c)){
a=c;var s=p/4}
else
var s=p/(2*Math.PI)*Math.asin(c/a)
return-(a*Math.pow(2,10*(t-=1))*Math.sin((t*d-s)*(2*Math.PI)/p))+b}
Tween.elasticEaseOut=function(t,b,c,d,a,p){
if(t==0)return b;if((t/=d)==1)return b+c;if(!p)p=d*.3
if(!a || a<Math.abs(c)){a=c;var s=p/4;}
else var s=p/(2*Math.PI)*Math.asin(c/a)
return(a*Math.pow(2,-10*t)*Math.sin((t*d-s)*(2*Math.PI)/p)+c+b)}
Tween.elasticEaseInOut=function(t,b,c,d,a,p){
if(t==0)return b;if((t/=d/2)==2)return b+c;if(!p)var p=d*(.3*1.5)
if(!a || a<Math.abs(c)){var a=c;var s=p/4;}
else var s=p/(2*Math.PI)*Math.asin(c/a)
if(t<1)return-.5*(a*Math.pow(2,10*(t-=1))*Math.sin((t*d-s)*(2*Math.PI)/p))+b
return a*Math.pow(2,-10*(t-=1))*Math.sin((t*d-s)*(2*Math.PI)/p)*.5+c+b}
Tween.bounceEaseOut=function(t,b,c,d){
if((t/=d)<(1/2.75)){
return c*(7.5625*t*t)+b
}else if(t<(2/2.75)){
return c*(7.5625*(t-=(1.5/2.75))*t+.75)+b
}else if(t<(2.5/2.75)){
return c*(7.5625*(t-=(2.25/2.75))*t+.9375)+b
}else{
return c*(7.5625*(t-=(2.625/2.75))*t+.984375)+b}}
Tween.bounceEaseIn=function(t,b,c,d){
return c-Tween.bounceEaseOut(d-t,0,c,d)+b}
Tween.bounceEaseInOut=function(t,b,c,d){
if(t<d/2)return Tween.bounceEaseIn(t*2,0,c,d)*.5+b
else return Tween.bounceEaseOut(t*2-d,0,c,d)*.5+c*.5+b}
Tween.strongEaseInOut=function(t,b,c,d){
return c*(t/=d)*t*t*t*t+b}
Tween.regularEaseIn=function(t,b,c,d){
return c*(t/=d)*t+b}
Tween.regularEaseOut=function(t,b,c,d){
return-c*(t/=d)*(t-2)+b}
Tween.regularEaseInOut=function(t,b,c,d){
if((t/=d/2)<1)return c/2*t*t+b
return-c/2*((--t)*(t-2)-1)+b}
Tween.strongEaseIn=function(t,b,c,d){
return c*(t/=d)*t*t*t*t+b}
Tween.strongEaseOut=function(t,b,c,d){
return c*((t=t/d-1)*t*t*t*t+1)+b}
Tween.strongEaseInOut=function(t,b,c,d){
if((t/=d/2)<1)return c/2*t*t*t*t*t+b
return c/2*((t-=2)*t*t*t*t+2)+b}
OpacityTween.prototype=new Tween()
OpacityTween.prototype.constructor=Tween
OpacityTween.superclass=Tween.prototype
function OpacityTween(obj,func,fromOpacity,toOpacity,duration){
this.targetObject=obj
this.init(new Object(),'x',func,fromOpacity,toOpacity,duration)}
var o=OpacityTween.prototype
o.targetObject={}
o.onMotionChanged=function(evt){
var v=evt.target._pos
var t=this.targetObject
t.style['opacity']=v/100
t.style['-moz-opacity']=v/100
if(t.filters&&t.filters.alpha)t.filters.alpha['opacity']=v}

/*tween ends here*/



/*resize starts here*/
function equalizeColumns(){
var bottom=0;var stor
if(arguments.length>1){
for(x=0;x<arguments.length;x++){
var column=document.getElementById(arguments[x])
if(column){
column.style.height=null
var colbottom=column.offsetTop+column.clientHeight
if(colbottom>bottom){
bottom=colbottom}}}
if(bottom>0){
for(x=0;x<arguments.length;x++){
var column=document.getElementById(arguments[x])
if(column){
column.style.height=(bottom-column.offsetTop)+'px'}}}}}
function sizePageInterior(fspace){
var page=document.getElementById('page')
var contentFooter=document.getElementById('ridefooter')
var footer=document.getElementById('footer')
var fheight=footer.scrollHeight
var contentBottom=contentFooter.offsetTop
var windowBottom=window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight
if(contentBottom+fspace<windowBottom){
page.style.height=(windowBottom-fheight)+'px'}
else{
page.style.height=(contentBottom+fspace)+'px'}}
function handleOverflowX(minw){
var windowWidth=window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth
var top=document.body
if(windowWidth<minw){
top.style.overflowX='visible'}
else{
top.style.overflowX='hidden'}}

/*resize ends here*/












/*docents starts here*/


var com;
if(!com) { com = {}; } else if(typeof(com) != "object") { throw new Error("can't initialize...com is not an object."); }
if(!com.medialab) { com.medialab = {}; } else if(typeof(com.medialab) != "object") { throw new Error("can't initialize...com.medialab is not an object."); }
if(!com.medialab.sg) { com.medialab.sg = {}; }
if (!com.medialab.sg.gallery1) { com.medialab.sg.gallery1 = {};}


com.medialab.sg.gallery1.docent =
function (xmlPathIn, myNameIn) { 
	if (typeof($ml)=='undefined') { $ml = $; }
	var that=this;
	var myName = myNameIn ? myNameIn : "docent";
	var curExhibit = 0; 
	var prevExhibit = -1;
	var exhibitChange = true;
	var curView = 0;
	var prevView = -1;
	var exhibitCount = 0;
	var thumbsheetCount = 0;
	var galleryXMLpath = xmlPathIn;
	var thumbsheet = null;
	var viewsheet = null;
	var viewsheetOptions = null;
	var exhibitsheetOptions = null;
	var pictureboxOptions = null;
	var bigboxOptions = null;
	var panelOptions = null;
	var bigBox = null;
	var picturebox = null;
	var panel = null;
	var xml = null;
	var thumbsheetDirty = false;
	var viewsheetDirty = false;
	var pictureboxDirty = false;
	var urlViewParamName = "view";
	var urlExhibitParamName = "exb";
	var preload = false;  // preload or not
	var preloads = [];  // array of images to preload
	var preloadMax = 50;
	
	var metaHrefs = null;
	var metaChunks = null;
	var metaDelimOpen = "[[";
	var metaDelimClose = "]]";
	var formMetaData = null;
	
	var useConsole = false;
	var debug = false;
	
 	this.sgalert = function(msg) { if (debug) {	alert(msg);	} };
	function sgalert(msg) { that.sgalert(msg); 	}
	
	this.getCurrentExhibit = function () { return curExhibit; }
	this.getCurrentView = function () { return curView; }
	
	this.getExhibitCount = function () { return exhibitCount; }
	
	this.getName = function () { return myName; }
	
	this.getxml = function() {
		return xml;
	}
	
	this.selectThumb = function (thumbnum, mode, updateThumbsheet) {
		//alert('hi');
		//this.sgalert("Selected thumb (v1)" + thumbnum);
		this.sgconsole("selectthumb. mode: " + mode + " thumbnum: " + thumbnum + ' curexhibit ' + curExhibit);
		if (mode == "exhibit") {
			if (thumbnum != curExhibit) {
				exhibitChange = true;
				prevExhibit = curExhibit;
				curExhibit = thumbnum;
				curView=0;
				prevView=0;
				thumbsheetDirty = updateThumbsheet;
				viewsheetDirty = true;
				pictureboxDirty=true;
				this.sgconsole("About to sync");
				this.sync();
			} else {
				if(panel && panel.goToPanel) {
					panel.goToPanel(thumbnum);
				}
			}
		}
		else {
			if (thumbnum != curView) {
				exhibitChange = false;
				viewsheetDirty=updateThumbsheet;
				pictureboxDirty=true;
				prevView = curView;
				curView = thumbnum;
				this.sync();
			}
		}
//		if(this.getThumbSheetOption(mode,'selectionaction')=='bigbox') {
//			this.openBigbox();
//		}
		return false;
	}
	
//	this.sgalert = function(msg) {	alert("sgalert public"); alert(msg);  	}
	
	this.init = function() {
		var urlExbNum = this.getUrlParam(urlExhibitParamName);
		var urlViewNum = this.getUrlParam(urlViewParamName);
		if(urlExbNum) {
			curExhibit = urlExbNum;
			if(urlViewNum) {
				curView = urlViewNum;
			}
		}

		if(!checkEnvironment()) {
			alert("SiteGrinder gallery missing components!");
			return;
		};
		
		if (!loadGalleryXML()) {
			alert("SiteGrinder gallery can't find XML file!");
			return;
		}
	}
	
	function sync() { that.sgconsole('wrong sync called'); that.sync();}
	
	function getExhibitFromURL() {
		var queryExhibit = getUrlParameter(myName+'_exhibit');
		if(queryExhibit != "" && !isNaN(queryExhibit) && Number(queryExhibit) < exhibitCount) {
			return Number(queryExhibit);
		} else {
			return 0;
		}
	}
	
	function getUrlParameter(name){
		name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
		var regexS = "[\\?&]" + name + "=([^&#]*)";
		var regex = new RegExp(regexS);
		var results = regex.exec(window.location.href);
		if (results == null) 
			return "";
		else 
			return results[1];
	}
	
	function checkEnvironment () {
		sgalert("DOCENT: checkEnvironment()");
		// check for any required libs, like jquery
		if (!$ml) { return false; }
		return true;
	}
	

	this.getThumbsheetOption = function (sheetType,optionIn) { // these are dopplegangered just to avoid constant camelcaps typo bugs
		return this.getThumbSheetOption(sheetType,optionIn);
	}
	
	this.getThumbSheetOption = function (sheetType,optionIn) {
		var options = null;
		if(sheetType == "view") { options = viewsheetOptions; }
		else { options = exhibitsheetOptions; }
		return this.getAnOption(options,optionIn);
	}
	
	this.getPictureboxOption = function (optionIn) { 
		return this.getPictureBoxOption(optionIn);
	}
	
	this.getPictureBoxOption = function (optionIn) {
		return this.getAnOption(pictureboxOptions,optionIn);
	}
	
	this.getBigboxOption = function (optionIn) {
		return this.getBigBoxOption(optionIn);
	}
	
	this.getPanelOption = function (modeIn, optionIn) {
		return this.getAnOption(panelOptions,optionIn);
	}
	
	this.getBigboxOption = function (optionIn) {
		return this.getBigBoxOption(optionIn);
	}
	this.getBigBoxOption = function (optionIn) {
		return this.getAnOption(bigboxOptions,optionIn);
	}
	
	this.getAnOption = function (options,option) {
		var type = $ml('option[varname='+option+']', options).attr("type");
		var valMix = $ml('option[varname='+option+']', options).attr("value");
		if (typeof valMix == 'undefined') {
			this.sgconsole('Docent asked for a non existent option: ' + option);
			return "";
		}
	    var valLower = valMix.toLowerCase();
		if (type == 'undefined') {
			this.sgconsole('option type not found in options for option ' + option);
			if (isNaN(valLower)) {
				if (valLower == "true") {
					return true;
				}
				else 
					if (valLower == "false") {
						return false;
					}
					else {
						return valMix;
					}
			}
			else {
				if (valLower.substring(0, 2) == '0x') {
					return valLower;
				} // color
				else {
					return parseFloat(valMix);
				}
			}
		}
		else {
			var typeLower =type.toLowerCase();
			switch (typeLower) {
				case 'boolean' :
					return (valLower == 'true');
					break; 
				case 'number' :
					return parseFloat(valLower);
					break;
				case 'color':
				default:
				    return valMix;
					break;
			}
		}		
	}
	
	this.getCSSFormattedColor = function(col)  {
		if(col.substring(0,1) == '#') { return col; }
		else if (col.substring(0,2) == '0x') { return '#' + col.substring(2,col.length); }
		else { return '#' + col; }
	}
	
	this.getFlashMovie = function(movieName) {
	  // IE and Netscape refer to the movie object differently.
	  // This function returns the appropriate syntax depending on the browser.
	  this.sgconsole("finding movie " + movieName);
	  if (navigator.appName.indexOf ("Microsoft") !=-1) {
	    return window[movieName];
	  } else {
	    return document[movieName];
	  }
	}	
				
	// thanks to FF windows when the movie isn't visible on screen this routine now has to check for initWithXML...
	// this means all docent-checked fash components must export an initWithXML() with that exact name
	this.flashMovieIsLoaded = function(theMovie) {
	  // First make sure the movie's defined.
	  if (typeof(theMovie) != "undefined" && theMovie!=null) {
	  	this.sgconsole("movie " + theMovie);
	    // If it is, check how much of it is loaded.
		// incredibly IE returns 'unknown' as the type of PercentLoaded() but 'function' for initWithXML()
	    if (typeof theMovie.initWithXML != 'undefined') {
			if (typeof theMovie.PercentLoaded != 'undefined') {
				return theMovie.PercentLoaded() == 100;  // check percentloaded just in case if the func is available
			}
			else{
				return true;  // assume loaded since initWithXML is there
			}
		}
		else {
			return false;
		}
	  } else {
	  	  this.sgconsole("movie undefined");
	    // If the movie isn't defined, it's not loaded.
	    return false;
	  }
	}
	
	
	this.processXML = function (fullGalleryXMLIn){
		// **  Called when ajax has successfully loaded our XML  **
		that.sgconsole("about to process xml");
		xml=$ml(fullGalleryXMLIn);
		that.sgconsole("Docent: processXML (xml loaded)");
		that.postXMLInit();
	}
	
	//
	// setUpPreloads()
	//
	function setUpPreloads(){
		if (preload) {
			if (picturebox) { // current picturebox
				var qString = 'exhibits exhibit:eq(' + curExhibit + ') view:eq('+curView+') picturebox url';
				var result = $ml(qString, xml).get();
				if (result) { preloads = preloads.concat(result);	}
			}
			if (thumbsheet) { // current thumbnail
				var qString = 'exhibits exhibit:eq(' + curExhibit + ') view thumbnail url';
				var result = $ml(qString, xml).get();
				if (result) { preloads = preloads.concat(result);	}
			}
			if (viewsheet) { // add current view thumbnails first
				qString = 'exhibits exhibit:eq(' + curExhibit + ') view viewthumb url';
				var result = $ml(qString, xml).get();
				if (result) { preloads = preloads.concat(result);	}
			}
			if(thumbsheet){  // now load all the exhibit thumbs
				for (var curEx = 0; curEx < exhibitCount; curEx++) {
					qString = 'exhibits exhibit:eq('+ curEx +') view:eq(0) thumbnail url';
					var result = $ml(qString, xml).get();
					if (result) { preloads = preloads.concat(result);	}
				}
			}
			for (curEx = 0; curEx < exhibitCount; curEx++) {
				if (curEx != curExhibit) {  // now add the main pictureboxes and viewthumbs in order from zero
					if (picturebox) {
						qString = 'exhibits exhibit:eq('+curEx+') view:eq(0) picturebox url';
						var result = $ml(qString, xml).get();
						if (result) { preloads = preloads.concat(result);	}
					}
					if(viewsheet) {
						qString = 'exhibits exhibit:eq('+curEx+') view viewthumb url';
						var result = $ml(qString, xml).get();
						if (result) { preloads = preloads.concat(result);	}
					}
				}
			}
			that.sgconsole('preload list has ' + preloads.length + 'items');
			if(preloads.length > preloadMax) { preloads.length = preloadMax; }
			preloadNext();
		}
	}
	
	
	preloadErr = function() {
		this.sgconsole('PRELOADING err ' + this.src);
		preloadNext();
	}
	

	function preloadNext(){
		if(preloads.length > 0) {
			var curSrc = $ml.trim($ml(preloads.shift()).text());
			that.sgconsole('PRELOADING next picturebox image '+ curSrc +'('+ preloads.length +' left)');
			var img = new Image();
			img.onerror = preloadErr;
			img.onload = preloadNext;
			img.src = curSrc;
		}
	}
	
	this.postXMLInit = function() {
		// **  Called to init whatever is necessary after XML loaded
		// the options are stored as an optimization so the whole tree isn't parsed each time an option is looked for
		this.sgconsole("Docent: postXMLInit");
		
		this.sgconsole("About to update metadata");
		this.updateMetadata();
		
		this.sgconsole("binding preloader");
		//$ml(window).bind('load', pictureboxPreload);
		
		exhibitCount = $ml('exhibit',xml).length;
		curExhibit = getExhibitFromURL();
		var thumbsheetCount = $ml('thumbsheet',xml).length;
		$ml('options thumbsheet',xml).each(function(n){
			//console.log("docent making thumbsheet");
			var sheetConstructor = $ml('option[varname="constructor"]',this).attr("value");
			if(!sheetConstructor) { sgalert('No thumbsheet contructor provided in xml!') };
			if (!com.medialab.sg.gallery1[sheetConstructor]) {sgalert('Thumbsheet constructor "' + sheetConstructor + '" not available!')};
			var sheetmode = $ml('option[varname="mode"]',this).attr("value");
			that.sgconsole("Found a "+ sheetmode +" sheet with constructor " + sheetConstructor);
			if(sheetmode == 'exhibit') {
				exhibitsheetOptions = this;
				thumbsheet = new com.medialab.sg.gallery1[sheetConstructor](xml,sheetmode,that);
				//thumbsheet = new window[sheetConstructor](xml,sheetmode,that);
			} 
			else {
				viewsheetOptions = this;
				viewsheet = new com.medialab.sg.gallery1[sheetConstructor](xml,sheetmode,that);
	//				viewsheet = new window[sheetConstructor](xml,sheetmode,that);
			}

		});
		var pictureboxCount = $ml('options picturebox',xml).length;
		if (pictureboxCount > 0) {
			var pboxConstructor = $ml('options picturebox option[varname="constructor"]',xml).attr("value");
			that.sgconsole("Found a picturebox with constructor " + pboxConstructor);
			if(!pboxConstructor) { sgalert('No picturebox contructor provided in xml!') };
			if (!window[pboxConstructor]) {sgalert('Picturebox constructor "' + pboxConstructor + '" not available!')};
			pictureboxOptions = $ml('options picturebox',xml);
			picturebox = new com.medialab.sg.gallery1[pboxConstructor](xml, this);
		}
		
	
	
		var bigboxCount = $ml('options bigbox',xml).length;
		if (bigboxCount > 0) {
			var bboxConstructor = $ml('options bigbox option[varname="constructor"]',xml).attr("value");
			that.sgconsole("Found a bigbox with constructor " + bboxConstructor);
			if(!bboxConstructor) { sgalert('No bigbox contructor provided in xml!') };
			if (!window[pboxConstructor]) {sgalert('Bigbox constructor "' + bboxConstructor + '" not available!')};
			bigboxOptions = $ml('options bigbox',xml);
			this.sgconsole("Found a BIGBOX: " + bboxConstructor);
			bigBox = new com.medialab.sg.gallery1[bboxConstructor](xml, this);
		}
	
		var panelCount = $ml('options panel',xml).length;
		if (panelCount > 0) {
			var panelMode = $ml('options panel option[varname="mode"]',this).attr("value");
			if(typeof(panelMode) == 'undefined') { panelMode = 'exhibit'; }
			var panelConstructor = $ml('options panel option[varname="constructor"]',xml).attr("value");
			that.sgconsole("Found a panel with constructor " + panelConstructor);
			if(!panelConstructor) { sgalert('No panel contructor provided in xml!') };
			if (!window[panelConstructor]) {sgalert('panel constructor "' + panelConstructor + '" not available!')};
			panelOptions = $ml('options panel',xml);
			this.sgconsole("Found a panel!!");
			panel = new com.medialab.sg.gallery1[panelConstructor](xml, panelMode, this);
		}
		
		setUpPreloads();

	
		//this.sync(); 
	}

	this.openBigbox = function(mode) {
		if(!mode) { 
			if(!viewsheet || curView == 0)  {mode='exhibit'; }
			else { mode='view';}
		}
		this.sgconsole('js docent opening '+ mode +' mode bigbox with exhibit ' + curExhibit + ', view ' + curView);
		bigBox.openByView(mode, curExhibit, curView);
	}
	
	// gets image url of picturebox or, if no pbox, bigbox
	this.num2url = function(exhibitNum, viewNum){
		var foundUrl = $ml('exhibits exhibit:eq(' + exhibitNum + ') views view:eq(' + viewNum + ') picturebox url', xml).text(); // check picturebox first
		if (foundUrl) {
			return foundUrl;
		}
		else {
			return $ml('exhibits exhibit:eq(' + exhibitNum + ') views view:eq(' + viewNum + ') bigbox url', xml).text(); // not found so check bigbox
		}
	}
	
	this.updateMetadata = function () {
		this.sgconsole('NOW IN updateMetadata - ' + $ml($ml('form[class*="'+that.getName()+'"] input[value*="[["]')[0]).attr('value'));
		
		// Create an array to preserve the original metadata hrefs along with their nodes for later replacement
		if(metaHrefs == null) {
			metaHrefs = new Array();
			$ml('a[class*=' + that.getName() + ']').each(function (n) {
				var origHref = $ml(this).attr('href');
				var node = this;
				metaHrefs[n] = { origHref: origHref, node:node };
			});
		}
		
		// Create array to collect metadata nodes in forms along with their metadata terms
		if(formMetaData==null) {
			formMetaData = new Array();
			var searchStr = 'form[class*="'+ that.getName() +'"] input[value*="[["]';
			//this.sgconsole('looking for form nodes with ' + searchStr);
			$ml(searchStr).each(function() { 
				var mdWithDelims = $ml(this).attr('value');
				var mdataName = mdWithDelims.substring(2, mdWithDelims.length-2);
				//that.sgconsole('adding form metadata node: ' + mdataName);
				formMetaData.push({node:this, meta:mdataName}); 
			});
		}
		
		//  first do spans that aren't in panels  
		// (panels are done all at once when they are created)
		$ml('exhibit:eq('+ curExhibit +') view:eq(0) metadata',xml).each(function (n) {
			var metadataName = $ml(this).attr('name');
			var mdContent = $ml.trim($ml(this).text());
			var targetClass = '"' + that.getName() + ' ' + metadataName + '"';  // should be ie 'docent1 description'
			// The two class= below were class*= but were getting false positive between "description" and "description writer"
			if($ml('span.[class="'+targetClass+'"]:not(div[id*=panelsheet] span)').length > 0) {
				$ml('span.[class="'+targetClass+'"]:not(div[id*=panelsheet] span)').html(mdContent);
			}
		});
		
		// Now do hrefs
		// as in 
		// $ml('a[class*=docentname]').attr('href', $ml('a').attr('href').replace('45.00','555.00'))
		for(var curHref = 0; curHref < metaHrefs.length; curHref++) {
			var newHref = metaHrefs[curHref].origHref;
			$ml('exhibit:eq('+ curExhibit +') view:eq(0) metadata',xml).each(function (n) {
				var mdContent = $ml.trim($ml(this).text());
				var metadataChunk = '[[' + $ml(this).attr('name') + ']]';
				newHref = newHref.replace(metadataChunk, escape(mdContent));
			});
			//newHref = escape(newHref);
			//console.log("New href with metadata : " + newHref);
			$ml(metaHrefs[curHref].node).attr('href',newHref);
		}
		
		// now do forms, as in
		//
		// <form class="main foxycart">
		//  <input type="hidden" name="price" value="[[price]]" />	
		for (var curFormFieldNum = 0; curFormFieldNum < formMetaData.length; curFormFieldNum++) {
			var mdContent = $ml.trim($ml('exhibit:eq('+ curExhibit +') view:eq(0) metadata[name="'+ formMetaData[curFormFieldNum].meta +'"]', xml).text());
			//that.sgconsole('replacing form content for: ' + mdContent);
			$ml(formMetaData[curFormFieldNum].node).attr('value',mdContent);
		}
		
		//update foxycart
		if (typeof(fc_CookieFix) == "function") { 
			fc_CookieFix();
		}
		
	}
	
	
	 this.sync = function () {
		this.sgconsole('in sync picturebox ' + picturebox + ' dirty ' + pictureboxDirty);
		if (thumbsheet  && thumbsheetDirty) {
			this.sgconsole('sync thumbsheet');
			thumbsheet.select(curExhibit);
			thumbsheetDirty = false;
		}
		
		if (viewsheet && viewsheetDirty) {
			this.sgconsole('sync viewsheet');
			if (exhibitChange) {
				this.sgconsole('exhibitChange, resetting curView to 0');
				curView = 0;
				viewsheet.updateSheet();
			}
			else {
				viewsheet.select(curView);
			}
			viewsheetDirty = false;

		}
		if (panel && panel.goToPanel) {
			this.sgconsole('sync panelsheet');
			panel.goToPanel(curExhibit);
			//panelsheetDirty = false;		
		}
		this.sgconsole("*Syncing: " + curExhibit + "," + curView);
		this.updateMetadata();
		if (picturebox && pictureboxDirty) {
			this.sgconsole('docent calling picturebox.displaybynum with ' + curExhibit);
			picturebox.displayByNum(curExhibit, curView);
		}
	}  
	
	this.hasViewSheet = function() {
		if(viewsheet) { return true; }
		return false;
	}
	
/* Currently unused	*/
	this.pictureboxReady = function() {
		//picturebox.displayByNum(curExhibit,curView);
	}
	
	this.thumbSheetReady = function() {
		
	}
	function errorXML(xhr,errStr,exceptionObj) {
		sgalert("SiteGrinder's Gallery data could not be loaded.  Error: " + errStr);
		//document.write("DOCENT XML READING ERROR: " + errStr + ".  Please report this to <a href='mailto:help@medialab.com'>help@medialab.com</a>");
	}
	
	function initJQUERYAccessors () {
		this.altThumbQuery = "exhibits > exhibit > views > view > thumbnail > src";
		this.altPictureboxQuery = "exhibits > exhibit > views > view > picturebox > src";
	}
		
	
	function setUpGalleryParts () {
		this.thumbsheet = new com.medialab.sg.gallery1.thumbsheet(this.thumbsheetXML);
	}
	
	function loadGalleryXML () {
		var loadMethod = "GET";
		var ie_pain = '';
		if(useUncachedXML()) { loadMethod = "POST"; ie_pain = '?r=' + Math.floor(Math.random() * 10000);}
		// load up the xml file into an xml parseable something or other
		$ml.ajax({
			type: loadMethod,
			url: galleryXMLpath + ie_pain,
			dataType: "xml",
			//dataType: "html",
			success: that.processXML,
			error: errorXML
		});
		return(true);
	}
	
	function useUncachedXML() {     
		return( document.location.href.indexOf('reload=true') != -1);
	}

(function( $ ){
  $.cssRule = function (Selector, Property, Value) {
    // Selector == {}
    if(typeof Selector == "object"){
      $.each(Selector, function(NewSelector, NewProperty){
        $.cssRule(NewSelector, NewProperty);
      });
      return;
    }

    // Selector == "body:background:#F99"
    if((typeof Selector == "string") && (Selector.indexOf(":") > -1)
      && (Property == undefined) && (Value == undefined)){
      Data = Selector.split("{");
      Data[1] = Data[1].replace(/\}/, "");
      $.cssRule($.trim(Data[0]), $.trim(Data[1]));
      return;
    }

    // Check for multi-selector, [ IE don't accept multi-selector on this way, we need to split ]
    if((typeof Selector == "string") && (Selector.indexOf(",") > -1)){
      Multi = Selector.split(",");
      for(x = 0; x < Multi.length; x++){
        Multi[x] = $.trim(Multi[x]);
        if(Multi[x] != "")
          $.cssRule(Multi[x], Property, Value);
      }

      return;
    }

    // Porperty == {} or []
    if(typeof Property == "object"){

      // Is {}
      if(Property.length == undefined){

        // Selector, {}
        $.each(Property, function(NewProperty, NewValue){
          $.cssRule(Selector + " " + NewProperty, NewValue);
        });

      // Is [Prop, Value]
      }else if((Property.length == 2) && (typeof Property[0] == "string") &&
        (typeof Property[1] == "string")){
        $.cssRule(Selector, Property[0], Property[1]);

      // Is array of settings
      }else{
        for(x1 = 0; x1 < Property.length; x1++){
          $.cssRule(Selector, Property[x1], Value);
        }
      }

      return;
    }

    // Parse for property at CSS Style "{property:value}"
    if((typeof Property == "string") && (Property.indexOf("{") > -1)
       && (Property.indexOf("}") > -1)){
      Property = Property.replace(/\{/, "").replace(/\}/, "");
    }

    // Check for multiple properties
    if((typeof Property == "string") && (Property.indexOf(";") > -1)){
      Multi1 = Property.split(";");
      for(x2 = 0; x2 < Multi1.length; x2++){
        $.cssRule(Selector, Multi1[x2], undefined);
      }
      return;
    }

    // Check for property:value
    if((typeof Property == "string") && (Property.indexOf(":") > -1)){
      Multi3 = Property.split(":");
      $.cssRule(Selector, Multi3[0], Multi3[1]);
      return;
    }

    //********************************************
    // Logical CssRule additions
    // Check for multiple logical properties [ "padding,margin,border:0px" ]
    if((typeof Property == "string") && (Property.indexOf(",") > -1)){
      Multi2 = Property.split(",");
      for(x3 = 0; x3 < Multi2.length; x3++){
        $.cssRule(Selector, Multi2[x3], Value);
      }
      return;
    }

    //********************************************
    // Check for Most One Style Sheet
    // jQuery.CssRule need at last one Style Sheet enabled on the page.
    styleSheetsLength = document.styleSheets.length;
    if(styleSheetsLength <= 1){
      // Append for no IE browsers
      if(!document.createStyleSheet){
        var styleSheet = (typeof document.createElementNS != undefined) ?
          document.createElementNS("http://www.w3.org/1999/xhtml", "style") :
          document.createElement("style");
        styleSheet.setAttribute("type", "text/css");
        styleSheet.setAttribute("media", "screen");
        if(styleSheetsLength == 0){
          $($("html")[0]).prepend(styleSheet);
        }
      // Append for IE
      }else{
        BaseStyle = document.getElementsByTagName("style");
        if(BaseStyle.length > 0)
          document.getElementsByTagName("style")[0].disabled = false;
        var styleSheet = document.createElement("style");
        styleSheet.setAttribute("type", "text/css");
        styleSheet.setAttribute("media", "screen");
        styleSheet.disabled = false;
        $($("html")[0]).prepend(styleSheet);
      }
    }

    if((Property == undefined) || (Value == undefined))
      return;

    Selector = $.trim(Selector);
    Property = $.trim(Property);
    Value = $.trim(Value);

    if((Property == "") || (Value == ""))
      return;

    // adjusts on property 
    if($.browser.msie){
      // for IE (@.@)^^^
      switch(Property){
        case "float": Property = "style-float"; break;
      }
    }else{
      // CSS rights
      switch(Property){
        case "float": Property = "css-float"; break;
      }
    }

    CssProperty = (Property || "").replace(/\-(\w)/g, function(m, c){ return (c.toUpperCase()); });

    for(var i = 0; i < document.styleSheets.length; i++){
  	  var Rules = null;
	  CurrentStyleSheet = document.styleSheets[i];
	  if (typeof(CurrentStyleSheet) != 'undefined' && CurrentStyleSheet != null && typeof(CurrentStyleSheet.href) == 'string' 
	      && CurrentStyleSheet.href.indexOf('foxycart') < 0) 
	  {
  		//console.log('checking ' + CurrentStyleSheet.href);
		try {
			if (CurrentStyleSheet['cssRules'] != null && typeof(CurrentStyleSheet['cssRules']) != 'undefined') {
				Rules = CurrentStyleSheet['cssRules'];
			}
			if (CurrentStyleSheet['rules'] != null && typeof(CurrentStyleSheet['rules']) != 'undefined') {
				Rules = CurrentStyleSheet['rules'];
			}
		}
		catch(ex) {
			continue;
		}
		//Rules = (CurrentStyleSheet.cssRules || CurrentStyleSheet.rules);
		LowerSelector = Selector.toLowerCase();

	if (Rules != null && typeof Rules == 'object') {
		if (Rules.length != 0) {
			for (var i2 = 0, len = Rules.length; i2 < len; i2++) {
				if (Rules[i2].selectorText && (Rules[i2].selectorText.toLowerCase() == LowerSelector)) {
					if (Value != null) {
						Rules[i2].style[CssProperty] = Value;
						return;
					}
					else {
						if (CurrentStyleSheet.deleteRule) {
							CurrentStyleSheet.deleteRule(i2);
						}
						else 
							if (CurrentStyleSheet.removeRule) {
								CurrentStyleSheet.removeRule(i2);
							}
							else {
								Rules[i2].style.cssText = "";
							}
					}
				}
			}
		}
	}
	}
	else {
			//console.log('encountered null stylesheet in cssRule()');
	}
   }

    if(Property && Value){
	  var Rules = null;

      for(var i = 0; i < document.styleSheets.length; i++){
	    WorkerStyleSheet = document.styleSheets[i];
		try {  // avoid Firefox security err in case css is remote

	    if(typeof(WorkerStyleSheet) != 'undefined' && WorkerStyleSheet != null && typeof(WorkerStyleSheet.href) == 'string' && WorkerStyleSheet.href.indexOf('foxycart') < 0
		 && (WorkerStyleSheet['cssRules']!=null || WorkerStyleSheet['rules']!=null)) {
	        if(WorkerStyleSheet.insertRule){
			  try {
			  	if (WorkerStyleSheet['cssRules']!=null && typeof(WorkerStyleSheet['cssRules']) != 'undefined') {
			  		Rules = WorkerStyleSheet['cssRules'];
			  	}
			  	if (WorkerStyleSheet['rules']!=null && typeof(WorkerStyleSheet['rules']) != 'undefined') {
			  		Rules = WorkerStyleSheet['rules'];
			  	}
			  }
			  catch(ex) {
			  	continue;
			  }
	          //Rules = (WorkerStyleSheet.cssRules || WorkerStyleSheet.rules);
	          WorkerStyleSheet.insertRule(Selector + "{ " + Property + ":" + Value + "; }", Rules.length);
	        }else if(WorkerStyleSheet.addRule){
	          WorkerStyleSheet.addRule(Selector, Property + ":" + Value + ";", 0);
	        }else{
	          throw new Error("Add/insert not enabled.");
	        }
		}
		else { }
		}
		catch(ex){
			continue
		}
      }
    }
  };
  
  $.tocssRule = function(cssText){
    matchRes = cssText.match(/(.*?)\{(.*?)\}/);
    while(matchRes){
      cssText = cssText.replace(/(.*?)\{(.*?)\}/, "");
      $.cssRule(matchRes[1], matchRes[2]);
      matchRes = cssText.match(/(.*?)\{(.*?)\}/);
    }
  }
})( $ml );

(function( $ ){
           $.fn.toXML = function(){
               var toXML = function(node){
                    var out = '';
                    var attributes = '';
                    var content = '';
                    out += '<' + node.nodeName;
                    if (node.childNodes) {
                        for (var i = 0; i < node.childNodes.length; i++) {
                            switch (node.childNodes[i].nodeType) {
                                case 1: // ELEMENT_NODE
                                    content += toXML(node.childNodes[i]);
                                    break;
                                case 2: // ATTRIBUTE_NODE
                                    attributes += ' ' + node.childNodes[i].nodeName + '="' +
                                    node.childNodes[i].nodeValue +
                                    '"';
                                    break;
                                case 3: // TEXT_NODE
                                case 4: // CDATA_SECTION_NODE
                                case 5: // ENTITY_REFERENCE_NODE
                                case 6: // ENTITY_NODE
                                case 7: // PROCESSING_INSTRUCTION_NODE
                                case 8: // COMMENT_NODE
                                case 9: // DOCUMENT_NODE
                                case 10: // DOCUMENT_TYPE_NODE
                                case 11: // DOCUMENT_FRAGMENT_NODE
                                case 12: // NOTATION_NODE
                                    content += node.childNodes[i].nodeValue;
                                    break;
                            }
                        }
                    }
                    out += attributes;
                    if (content.length > 0) {
                        out += '>' + content;
                        out += '<\/' + node.tagName + '>';
                    }
                    else {
                        out += '/>';
                    }
                    return out;
                }
                var out = '';
                if (this.length > 0) {
                    if (typeof XMLSerializer == 'function' ||
                    typeof XMLSerializer == 'object') {
                        var xs = new XMLSerializer();
                        this.each(function(){
                            out += xs.serializeToString(this);
                        });
                    }
                    else 
                        if (this[0].xml !== undefined) {
                            this.each(function(){
                                out += this.xml;
                            });
                        }
                        else {
                            if (this.length > 0) {
                                this.each(function(){
                                    out += toXML(this);
                                });
                            }
                        }
                } 
                return out;
            }; 
})( $ml );

	this.getUrlParam = function(param) {
	    var regex = '[?&]' + param + '=([^&#]*)';
	    var results = (new RegExp(regex)).exec(window.location.href);
	    if(results) return results[1];
	    return null;
	}
	
	this.sgconsole = function(text) {
		if(useConsole) {
			var msg = "DOCENT : " + text;
			if (window.console && console.log) {
				console.log(msg);
			}
			else 
				if (window.opera && opera.postError) {
					opera.postError(msg);
				}
		}
	}
	
	this.sendMessage = function(where,what) {
		switch (where) {
			case "thumbsheet":
				if(thumbsheet) { return thumbsheet.message(what); }
				else { this.agalert ("There's no thumbsheet to send the message " + what + " to") };
				break;
			case "viewsheet":
				if(viewsheet) { return viewsheet.message(what); }
				else { this.agalert ("There's no viewsheet to send the message " + what + " to") };
				break;
			case "picturebox":
				if(picturebox) { return picturebox.message(what); }
				else { this.agalert ("There's no picturebox to send the message " + what + " to") };
				break;
			case "bigbox":
				if (bigbox) { return bigbox.message(what);	}
				else { this.agalert ("There's no bigbox to send the message " + what + " to") };
				break;
			default:
				this.agalert("Can't send message '"+ what + "' because I don't recognize '"+ where + "' as a message target.");
				break;
		}
		return null;
	}
	
	// for now this only checks the first view, as all views have the same metadata
	this.getMetadata = function(dataLabel, exhibitNum) {
		//this.sgconsole('Getting metadata for exhibit ' + exhibitNum);
		if(typeof(exhibitNum) == 'undefined') { exhibitNum = curExhibit; }
		var mdata="";
		if (typeof(dataLabel) == 'undefined' || dataLabel == null || dataLabel == "") {
			return "";
		}
		mdata = $ml('exhibits > exhibit:eq('+exhibitNum+') > views > view:eq(0) > metadataentries > metadata[name="'+dataLabel+'"]',xml).text();
		return mdata;
	}




	
	this.getThumbImage = function(thumbNum, mode) {
		if(typeof mode =='undefined' || mode == 'exhibit') {
			return  $ml('exhibit:eq('+thumbNum+') > views > view:eq(0) > thumbnail > url', xml).text();
		} else {
			return $ml('exhibit:eq(' + curExhibit + ') view > viewthumb > url', xml).eq(thumbNum).text();
		}
	}
	
	this.iterateExhibitThumbImageUrls = function (iterator,data) {
		var iiterator = iterator;
		var idata = data;
		$ml('exhibit', xml).each(function(n){
			iiterator(n, idata, $ml('views > view > thumbnail > url', this).eq(0).text());
		});
	}
	

	// assumes current exhibit unless specified
	this.iterateViewThumbImageUrls = function(iterator, data, exhibitNumIn) {
		var iiterator = iterator;
		var idata = data;
	
		var curExhibit = exhibitNumIn ? exhibitNumIn : this.getCurrentExhibit();
		
//		if ($ml('exhibit:eq(' + curExhibit + ') view', xml).length > 1) {
			$ml('exhibit:eq(' + curExhibit + ') view', xml).each(function(n){
				iiterator(n, idata, $ml('viewthumb > url', this).eq(0).text());
			});
//		}
	}
	
	this.getNumViews = function(exNumIn) {
		var exNum = exNumIn ? exNumIn : curExhibit;
		var numViews = $ml('exhibit:eq(' + curExhibit + ') view', xml).length;
		this.sgconsole("num views for exhibit "+curExhibit+ " : " + numViews);
		return numViews;
	}
	
	this.pictureboxSelectByNum = function(imageNum, updatePbox) {
		this.sgconsole("Picturebox pictureboxSelectByNum exhibit: " + imageNum);
		if (typeof updatePbox == 'undefined') {
			pictureboxDirty = false;
		} else {
			pictureboxDirty = updatePbox;
		}
		if (imageNum != curExhibit) {
			this.sgconsole("image not current so about to sync");
			prevExhibit = curExhibit;
			curExhibit = imageNum;
			thumbsheetDirty=true;
			viewsheetDirty=true;
			//thumbsheet.select(curExhibit);
			this.sync();
		}
	}
	
	this.sgconsole("docent initializing");
	this.init();
	
	
	// EVENTS:
	this.thumbHover = function (e) { }
	this.thumbClick = function (e) { } 
    this.alt_thumbHover = function (e) { }
    this.alt_thumbClick = function (e) { }
	
/* 
 * 
 *  Navigation functions:
 * 
 * 	next/previous
 *  nextview/previousview
 *  nextpanelset/previouspanelset
 *  nextthumbset/previousthumbset
 *  nextviewset/previousviewset
 *  
 */	

	// NEXT / PREVIOUS
	this.next = function() {  // advance to next exhibit
		this.nextClick(null);
	}
	this.prev = this.previous = function() {  // go to previous exhibit
		this.previousClick(null);
	}
	
	// NEXTVIEW/PREVIOUSVIEW
	this.nextView = function() {  // advance to next view
		if (curView < this.getNumViews()-1) {
			curView++; 
			pictureboxDirty = true;
			viewsheetDirty = true;
			thumbsheetDirty = false;
			exhibitChange = false;
			this.sync();
		}		
	}
	
	this.prevView = this.previousView = function() {  // go to previous view
		if (curView > 0) {
			curView--; 
			pictureboxDirty = true;
			viewsheetDirty = true;
			thumbsheetDirty = false;
			exhibitChange = false;
			this.sync();
		}				
	}
	
	// NEXTTHUMBSET/PREVIOUSTHUMBSET
	this.nextThumbSet = function() {  // advance to next view
		 this.sgconsole('next Thumb set ')
		 if (thumbsheet && thumbsheet.nextThumbSet) {
		 	thumbsheet.nextThumbSet();
		 }
	}
	
	this.prevThumbSet = this.previousThumbSet = function() {  // go to previous view
		 this.sgconsole('prev Thumb set ')
		 if (thumbsheet && thumbsheet.previousThumbSet) {
		 	thumbsheet.previousThumbSet();
		 }
	}
	
	// NEXTVIEWSET/PREVIOUSVIEWSET   --   ARE THESE SUPPORTED YET?
	this.nextViewSet = function() {  // advance to next view
		 this.sgconsole('next View set ')
		 if (viewsheet && viewsheet.nextThumbSet) {
		 	viewsheet.nextThumbSet();
		 }
	}
	
	this.prevViewSet = this.previousViewSet = function() {  // go to previous view
		 this.sgconsole('prev View set ')
		 if (viewsheet && viewsheet.previousThumbSet) {
		 	viewsheet.previousThumbSet();
		 }
	}
		
	// NEXTPANEL/PREVIOUSPANEL
	this.nextPanel = function () {
		 this.sgconsole('next panel set ' + panel)
		 if (panel && panel.nextPanel) {
		 	panel.nextPanel();
		 }
	}
	
	this.prevPanel = this.previousPanel = function () {
		 this.sgconsole('prev panel set ' + panel)
		 if (panel && panel.previousPanel) {
		 	panel.previousPanel();
		 }
	}
	
	// NEXTPANELSET/PREVIOUSPANELSET
	this.nextPanelSet = function () {
		 this.sgconsole('next panel set ' + panel)
		 if (panel && panel.nextPanelSet) {
		 	panel.nextPanelSet();
		 }
	}
	
	this.prevPanelSet = this.previousPanelSet = function () {
		 this.sgconsole('prev panel set ' + panel)
		 if (panel && panel.previousPanelSet) {
		 	panel.previousPanelSet();
		 }
	}
	
	
	
    this.pictureboxNextClick = function (updatePbox,e) { 
		this.sgconsole("Picturebox Next click received.");
		if (curExhibit < exhibitCount-1) {
			curExhibit++; 
			if (updatePbox) {
				pictureboxDirty = true;
			} else {
				pictureboxDirty = false;
			}
			thumbsheetDirty = true;
			viewsheetDirty = true;
			exhibitChange = true;
			this.sync();
		}
	}
	
   this.pictureboxPreviousClick = function (updatePbox, e) {
		if (curExhibit > 0) {
			curExhibit--; 
			thumbsheetDirty = true;
			viewsheetDirty = true;
			if (updatePbox) {
				pictureboxDirty = true;
			} else {
				pictureboxDirty = false;
			}
			exhibitChange = true;
			this.sync();
		}
	}
	
    this.toCSSColor = function(hexColor) {
		if (hexColor != undefined) {
			if(typeof(hexColor)=='number') { return '#' + hexColor;}
			if (hexColor.substring(0, 1) == '#') {
				return hexColor;
			} // already css style for some reason
			else 
				if (hexColor.substring(0, 2) == '0x') {
					return '#' + hexColor.substring(2);
				}
				else 
					if (!isNaN('0x' + hexColor)) {
						return '#' + hexColor;
					}
		}
		return null;
	}
	
    this.thumbNextClick = function (mode,e) { 
		this.sgconsole("thumb Next click received. mode:" + mode);
		if (curExhibit < exhibitCount-1) {
			curExhibit++; 
			if(mode=='view') { thumbsheetDirty = false; /*viewsheetDirty=false;*/exhibitChange = false;} else {thumbsheetDirty = true; /*viewsheetDirty=true;*/exhibitChange = true;}
			viewsheetDirty = true;
			pictureboxDirty=true;
			this.sync();
		}
	}
	
   this.thumbPreviousClick = function (mode,e) {
		this.sgconsole("thumb prev click received. mode:" + mode);
		if (curExhibit > 0) {
			curExhibit--; 
			if(mode=='view') { thumbsheetDirty = false; /*viewsheetDirty=false;*/exhibitChange = false;} else {thumbsheetDirty = true; /*viewsheetDirty=true;*/exhibitChange = true;}
			viewsheetDirty = true;
			pictureboxDirty = true;
			this.sync();
		}
	}
  	// Next exhibit	
    this.nextClick = function (e) { 
		this.sgconsole("Next click received.");
		if (curExhibit < exhibitCount-1) {
			curExhibit++; 
			thumbsheetDirty = true;
			viewsheetDirty = true;
			pictureboxDirty = true;
			exhibitChange = true;
			this.sync();
		}
	}

    this.previousClick = function(e){
		if (curExhibit > 0) {
			curExhibit--;
			thumbsheetDirty = true;
			viewsheetDirty = true;
			pictureboxDirty = true;
			exhibitChange = true;
			this.sync();
		}
	}
			
    this.nextHover = function (e) { }
	this.previousHover = function (e) { }
    this.pictureboxHover = function (e) { }
	
	this.pictureboxIsFlashBased = function() {
		var flashBased = false;
		if (pictureboxOptions) {
			$ml('option', pictureboxOptions).each(function(n){
				var val  = String($ml(this).attr('value'));
				var lVal = val.toLowerCase();
				if(lVal.substring(lVal.length-4) == '.swf') { flashBased = true; }
			});
		}
		return flashBased;
	}
	
	this.gotoCustomUrl = function(exhibitNum, viewNum, windowName, props) {
		if(typeof(exhibitNum)=='undefined') { exhibitNum = curExhibit ; }
		if(typeof(viewNum)=='undefined') { viewNum = curView; }
		var url = $ml.trim($ml('exhibits exhibit:eq('+ exhibitNum  +') views view:eq('+ viewNum +') link',xml).text());
		this.gotoUrl(url, windowName, props);
	}
	
	this.gotoUrl = function(url, newWindowName, props) {
		if (typeof(url) != 'string') {
			return;
		}
		if(typeof(newWindowName)=='undefined') {
			location=url;
		}
		else {
			if (typeof props == 'undefined') { props = ""; }
			window.open(url,newWindowName,props);
		}
	}
	
	this.getJSON = function(url, callback){
//		this.getYQL('select * from rss where url="' + url + '"', callback);
		this.getYQL('select * from feed where url="' + url + '"', callback);
	}
	
	this.getYQL = function(yqlQuery, callback) {
 		var eQuery = escape(yqlQuery);
		eQuery = eQuery.replace(/\//g,'%2F');
		var finalQuery = 'http://query.yahooapis.com/v1/public/yql?q=' + eQuery + '&format=json&callback=?';
		$ml.getJSON(finalQuery,callback);
	}
	
	this.json2GalleryXML = function(jIn, labelsIn) {
		var labels = labelsIn;
		
		var myXML = "<exhibits>";
		$ml.each(data.query.results.item, function(index, item){
			myXML += '<exhibit><views><view><metadataentries>'
			for (var curLabelNum = 0; curLabelNum < labels.length; curLabelNum++) {
				var content = item[labels[curLabelNum]];
				//if (index == 0) {alert(item[labels[curLabelNum]]);}
				if (typeof(content) != 'undefined' && content != "") {
					myXML += '<metadata name="' + labels[curLabelNum] + '">';
					//alert( $ml('p',item.description).text());
					myXML += content;
					//alert(item.description);
					myXML += '</metadata></metadataentries>'
					myXML += '</view></views></exhibit>';
				}
			}
		});
		myXML += '</exhibits>';
		return myXML;
	}
	
	this.getClickUrl = function(mode) {
		if(typeof mode == 'undefined') { mode='exhibit'; }
		if(mode=='exhibit') {
			return $ml.trim($ml('exhibits exhibit:eq('+ curExhibit +') view:eq(0) link',xml).text());;
		}
		else if (mode=='view') { // are separate urls for views supported?
			return $ml.trim($ml('exhibits exhibit:eq('+ curExhibit +') view:eq('+ curView +') link',xml).text());;
		}
		else { return ""; }
	}
	
	this.pictureboxClick = function(updatePbox,clickAction) {
		
		// maybe some code here to assume updatePbox false if a flash pbox?
		if(typeof(updatePbox)=="undefined"  && this.pictureboxIsFlashBased()) { updatePbox=false; }
		
		if (!clickAction) {
			this.sgconsole("docent finding clickaction itself since picturebox did not supply it");
			clickAction = this.getPictureBoxOption('clickaction');
		}
		
		if (typeof(clickAction) == "string") {
			this.sgconsole("docent: picBoxClick: " + clickAction + " updatePbox: " + updatePbox);
			switch (clickAction.toLowerCase()) {
				case 'advance':
					this.pictureboxNextClick(updatePbox, null);
					break;
				case 'url':
					//var url = this.getPictureBoxOption('clickurl');  // Initially this was a DM option but now it's set in the CMS
					var url = this.getClickUrl();
					if(typeof url != 'string' || url=="") { return; }
					if (!this.getPictureBoxOption('newwindow')) {
						this.gotoUrl(url);
					}
					else {
						var newWindowName = this.getPictureBoxOption('newwindowname') || "Untitled";
						var props = "";
						var h = this.getPictureBoxOption('newwindowheight');
						if (h != "" && h != 0) {
							props += "height=" + h;
						}
						
						if (props.length > 0) {	props += ","; }
						var w = this.getPictureBoxOption('newwindowwidth');
						if (w != "" && w != 0) {
							props += "width=" + w;
						}
						
						if (props.length > 0) { props += ","; }
						if (w == "" || h == "" || w == 0 || h == 0) {
							props += "resizable=yes";
						}
						else {
							props += "resizable=no";
						};
						this.gotoUrl(url, newWindowName, props);
					}
					break;
				case 'bigbox':
					this.sgconsole("about to call openBigBox");
					this.openBigbox();
					break;
				default:
					this.sgconsole("unknown picturebox clickaction: " + clickAction);
					break;
			}
		}
		else {
			this.sgconsole("picturebox clicked, but clickaction is null or undefined ");
		}
	}
}

if(!com.medialab.parseUri) { com.medialab.parseUri = {}; }
com.medialab.parseUri.options = {
	strictMode: false,
	key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
	q:   {
		name:   "queryKey",
		parser: /(?:^|&)([^&=]*)=?([^&]*)/g
	},
	parser: {
		strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
		loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
	}
};
com.medialab.parseUri.parse = function(str) {
	var	o   = com.medialab.parseUri.options,
		m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
		uri = {},
		i   = 14;

	while (i--) uri[o.key[i]] = m[i] || "";

	uri[o.q.name] = {};
	uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
		if ($1) uri[o.q.name][$1] = $2;
	});

	return uri;
}


/*docents ends here*/







