
/*
	SoundManager 2: Javascript Sound for the Web
	http://schillmania.com/projects/soundmanager2/

	Copyright (c) 2008, Scott Schiller. All rights reserved.
	Code licensed under the BSD License:
	http://schillmania.com/projects/soundmanager2/license.txt

	V2.5b.20080525
*/
function SoundManager(smURL,smID){var self=this;this.version='V2.5b.20080525';this.url=(smURL||'soundmanager2.swf');this.debugMode=true;this.useConsole=true;this.consoleOnly=false;this.waitForWindowLoad=false;this.nullURL='data/null.mp3';this.defaultOptions={'autoLoad':false,'stream':true,'autoPlay':false,'onid3':null,'onload':null,'whileloading':null,'onplay':null,'onpause':null,'onresume':null,'whileplaying':null,'onstop':null,'onfinish':null,'onbeforefinish':null,'onbeforefinishtime':5000,'onbeforefinishcomplete':null,'onjustbeforefinish':null,'onjustbeforefinishtime':200,'multiShot':true,'position':null,'pan':0,'volume':100};this.allowPolling=true;this.swfLoaded=false;this.enabled=false;this.o=null;this.id=(smID||'sm2movie');this.oMC=null;this.sounds=[];this.soundIDs=[];this.isIE=(navigator.userAgent.match(/MSIE/));this.isSafari=(navigator.userAgent.match(/safari/i));this.debugID='soundmanager-debug';this._debugOpen=true;this._didAppend=false;this._appendSuccess=false;this._didInit=false;this._disabled=false;this._windowLoaded=false;this._hasConsole=(typeof console!='undefined'&&typeof console.log!='undefined');this._debugLevels=['log','info','warn','error'];this.sandbox={'type':null,'types':{'remote':'remote (domain-based) rules','localWithFile':'local with file access (no internet access)','localWithNetwork':'local with network (internet access only, no local access)','localTrusted':'local, trusted (local + internet access)'},'description':null,'noRemote':null,'noLocal':null};this._overHTTP=(document.location?document.location.protocol.match(/http/i):null);this._waitingforEI=false;this._initPending=false;this._tryInitOnFocus=(this.isSafari&&typeof document.hasFocus=='undefined');this._isFocused=(typeof document.hasFocus!='undefined'?document.hasFocus():null);this._okToDisable=!this._tryInitOnFocus;var flashCPLink='http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html';this.supported=function(){return(self._didInit&&!self._disabled);};this.getMovie=function(smID){return self.isIE?window[smID]:(self.isSafari?document.getElementById(smID+'-embed')||document[smID+'-embed']:document.getElementById(smID+'-embed'));};this.loadFromXML=function(sXmlUrl){try{self.o._loadFromXML(sXmlUrl);}catch(e){self._failSafely();return true;};};this.createSound=function(oOptions){if(!self._didInit)throw new Error('soundManager.createSound(): Not loaded yet - wait for soundManager.onload() before calling sound-related methods');if(arguments.length==2){oOptions={'id':arguments[0],'url':arguments[1]};};var thisOptions=self._mergeObjects(oOptions);if(self._idCheck(thisOptions.id,true)){return self.sounds[thisOptions.id];};self.sounds[thisOptions.id]=new SMSound(self,thisOptions);self.soundIDs[self.soundIDs.length]=thisOptions.id;try{self.o._createSound(thisOptions.id,thisOptions.onjustbeforefinishtime);}catch(e){self._failSafely();return true;};if(thisOptions.autoLoad||thisOptions.autoPlay)self.sounds[thisOptions.id].load(thisOptions);if(thisOptions.autoPlay)self.sounds[thisOptions.id].playState=1;return self.sounds[thisOptions.id];};this.destroySound=function(sID){if(!self._idCheck(sID))return false;for(var i=0;i<self.soundIDs.length;i++){if(self.soundIDs[i]==sID){self.soundIDs.splice(i,1);continue;};};self.sounds[sID].unload();delete self.sounds[sID];};this.load=function(sID,oOptions){if(!self._idCheck(sID))return false;self.sounds[sID].load(oOptions);};this.unload=function(sID){if(!self._idCheck(sID))return false;self.sounds[sID].unload();};this.play=function(sID,oOptions){if(!self._idCheck(sID)){if(typeof oOptions!='Object')oOptions={url:oOptions};if(oOptions&&oOptions.url){oOptions.id=sID;self.createSound(oOptions);}else{return false;};};self.sounds[sID].play(oOptions);};this.start=this.play;this.setPosition=function(sID,nMsecOffset){if(!self._idCheck(sID))return false;self.sounds[sID].setPosition(nMsecOffset);};this.stop=function(sID){if(!self._idCheck(sID))return false;self.sounds[sID].stop();};this.stopAll=function(){for(var oSound in self.sounds){if(self.sounds[oSound]instanceof SMSound)self.sounds[oSound].stop();};};this.pause=function(sID){if(!self._idCheck(sID))return false;self.sounds[sID].pause();};this.resume=function(sID){if(!self._idCheck(sID))return false;self.sounds[sID].resume();};this.togglePause=function(sID){if(!self._idCheck(sID))return false;self.sounds[sID].togglePause();};this.setPan=function(sID,nPan){if(!self._idCheck(sID))return false;self.sounds[sID].setPan(nPan);};this.setVolume=function(sID,nVol){if(!self._idCheck(sID))return false;self.sounds[sID].setVolume(nVol);};this.mute=function(sID){if(!sID){var o=null;for(o in self.sounds){self.sounds[o].mute();}}else{if(!self._idCheck(sID))return false;self.sounds[sID].mute();}};this.unmute=function(sID){if(!sID){var o=null;for(o in self.sounds){self.sounds[o].unmute();}}else{if(!self._idCheck(sID))return false;self.sounds[sID].unmute();}};this.setPolling=function(bPolling){if(!self.o||!self.allowPolling)return false;self.o._setPolling(bPolling);};this.disable=function(){if(self._disabled)return false;self._disabled=true;for(var i=self.soundIDs.length;i--;){self._disableObject(self.sounds[self.soundIDs[i]]);};self.initComplete();self._disableObject(self);};this.getSoundById=function(sID,suppressDebug){if(!sID)throw new Error('SoundManager.getSoundById(): sID is null/undefined');var result=self.sounds[sID];if(!result&&!suppressDebug){};return result;};this.onload=function(){};this.onerror=function(){};this._idCheck=this.getSoundById;this._disableObject=function(o){for(var oProp in o){if(typeof o[oProp]=='function'&&typeof o[oProp]._protected=='undefined')o[oProp]=function(){return false;};};oProp=null;};this._failSafely=function(){var fpgssTitle='You may need to whitelist this location/domain eg. file:///C:/ or C:/ or mysite.com, or set ALWAYS ALLOW under the Flash Player Global Security Settings page. The latter is probably less-secure.';var flashCPL='<a href="'+flashCPLink+'" title="'+fpgssTitle+'">view/edit</a>';var FPGSS='<a href="'+flashCPLink+'" title="Flash Player Global Security Settings">FPGSS</a>';if(!self._disabled){self.disable();};};this._createMovie=function(smID,smURL){if(self._didAppend&&self._appendSuccess)return false;if(window.location.href.indexOf('debug=1')+1)self.debugMode=true;self._didAppend=true;var html=['<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" width="16" height="16" id="'+smID+'"><param name="movie" value="'+smURL+'"><param name="quality" value="high"><param name="allowScriptAccess" value="always" /></object>','<embed name="'+smID+'-embed" id="'+smID+'-embed" src="'+smURL+'" width="1" height="1" quality="high" allowScriptAccess="always" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash"></embed>'];var toggleElement='<div id="'+self.debugID+'-toggle" style="position:fixed;_position:absolute;right:0px;bottom:0px;_top:0px;width:1.2em;height:1.2em;line-height:1.2em;margin:2px;padding:0px;text-align:center;border:1px solid #999;cursor:pointer;background:#fff;color:#333;z-index:706" title="Toggle SM2 debug console" onclick="soundManager._toggleDebug()">-</div>';var debugHTML='<div id="'+self.debugID+'" style="display:'+(self.debugMode&&((!self._hasConsole||!self.useConsole)||(self.useConsole&&self._hasConsole&&!self.consoleOnly))?'block':'none')+';opacity:0.85"></div>';var appXHTML='soundManager._createMovie(): appendChild/innerHTML set failed. Serving application/xhtml+xml MIME type? Browser may be enforcing strict rules, not allowing write to innerHTML. (PS: If so, this means your commitment to XML validation is going to break stuff now, because this part isn\'t finished yet. ;))';var sHTML='<div style="position:absolute;left:-256px;top:-256px;width:1px;height:1px" class="movieContainer">'+html[self.isIE?0:1]+'</div>'+(self.debugMode&&((!self._hasConsole||!self.useConsole)||(self.useConsole&&self._hasConsole&&!self.consoleOnly))&&!document.getElementById(self.debugID)?'x'+debugHTML+toggleElement:'');var oTarget=(document.body?document.body:(document.documentElement?document.documentElement:document.getElementsByTagName('div')[0]));if(oTarget){self.oMC=document.createElement('div');self.oMC.className='movieContainer';self.oMC.style.position='absolute';self.oMC.style.left='-256px';self.oMC.style.width='1px';self.oMC.style.height='1px';try{oTarget.appendChild(self.oMC);self.oMC.innerHTML=html[self.isIE?0:1];self._appendSuccess=true;}catch(e){throw new Error(appXHTML);};if(!document.getElementById(self.debugID)&&((!self._hasConsole||!self.useConsole)||(self.useConsole&&self._hasConsole&&!self.consoleOnly))){var oDebug=document.createElement('div');oDebug.id=self.debugID;oDebug.style.display=(self.debugMode?'block':'none');if(self.debugMode){try{var oD=document.createElement('div');oTarget.appendChild(oD);oD.innerHTML=toggleElement;}catch(e){throw new Error(appXHTML);};};oTarget.appendChild(oDebug);};oTarget=null;};};this._writeDebug=function(sText,sType){};this._writeDebug._protected=true;this._writeDebugAlert=function(sText){alert(sText);};if(window.location.href.indexOf('debug=alert')+1&&self.debugMode){self._writeDebug=self._writeDebugAlert;};this._toggleDebug=function(){var o=document.getElementById(self.debugID);var oT=document.getElementById(self.debugID+'-toggle');if(!o)return false;if(self._debugOpen){oT.innerHTML='+';o.style.display='none';}else{oT.innerHTML='-';o.style.display='block';};self._debugOpen=!self._debugOpen;};this._toggleDebug._protected=true;this._debug=function(){};this._mergeObjects=function(oMain,oAdd){var o1=oMain;var o2=(typeof oAdd=='undefined'?self.defaultOptions:oAdd);for(var o in o2){if(typeof o1[o]=='undefined')o1[o]=o2[o];};return o1;};this.createMovie=function(sURL){if(sURL)self.url=sURL;self._initMovie();};this.go=this.createMovie;this._initMovie=function(){if(self.o)return false;self.o=self.getMovie(self.id);if(!self.o){self._createMovie(self.id,self.url);self.o=self.getMovie(self.id);};};this.waitForExternalInterface=function(){if(self._waitingForEI)return false;self._waitingForEI=true;if(self._tryInitOnFocus&&!self._isFocused){return false;};if(!self._didInit){};setTimeout(function(){if(!self._didInit){if(!self._overHTTP){};};if(!self._didInit&&self._okToDisable)self._failSafely();},750);};this.handleFocus=function(){if(self._isFocused||!self._tryInitOnFocus)return true;self._okToDisable=true;self._isFocused=true;if(self._tryInitOnFocus){window.removeEventListener('mousemove',self.handleFocus,false);};self._waitingForEI=false;setTimeout(self.waitForExternalInterface,500);if(window.removeEventListener){window.removeEventListener('focus',self.handleFocus,false);}else if(window.detachEvent){window.detachEvent('onfocus',self.handleFocus);};};this.initComplete=function(){if(self._didInit)return false;self._didInit=true;if(self._disabled){self.onerror.apply(window);return false;};if(self.waitForWindowLoad&&!self._windowLoaded){if(window.addEventListener){window.addEventListener('load',self.initUserOnload,false);}else if(window.attachEvent){window.attachEvent('onload',self.initUserOnload);};return false;}else{if(self.waitForWindowLoad&&self._windowLoaded){};self.initUserOnload();};};this.initUserOnload=function(){try{self.onload.apply(window);}catch(e){throw e;};};this.init=function(){self._initMovie();if(self._didInit){return false;};if(window.removeEventListener){window.removeEventListener('load',self.beginDelayedInit,false);}else if(window.detachEvent){window.detachEvent('onload',self.beginDelayedInit);};try{self.o._externalInterfaceTest();self.setPolling(true);self.enabled=true;}catch(e){self._failSafely();self.initComplete();return false;};self.initComplete();};this.beginDelayedInit=function(){self._windowLoaded=true;setTimeout(self.waitForExternalInterface,500);setTimeout(self.beginInit,20);};this.beginInit=function(){if(self._initPending)return false;self.createMovie();self._initMovie();self._initPending=true;return true;};this.domContentLoaded=function(){if(document.removeEventListener)document.removeEventListener('DOMContentLoaded',self.domContentLoaded,false);self.go();};this._externalInterfaceOK=function(){if(self.swfLoaded)return false;self.swfLoaded=true;self._tryInitOnFocus=false;if(self.isIE){setTimeout(self.init,100);}else{self.init();};};this._setSandboxType=function(sandboxType){var sb=self.sandbox;sb.type=sandboxType;sb.description=sb.types[(typeof sb.types[sandboxType]!='undefined'?sandboxType:'unknown')];if(sb.type=='localWithFile'){sb.noRemote=true;sb.noLocal=false;}else if(sb.type=='localWithNetwork'){sb.noRemote=false;sb.noLocal=true;}else if(sb.type=='localTrusted'){sb.noRemote=false;sb.noLocal=false;};};this.destruct=function(){if(self.isSafari){for(var i=self.soundIDs.length;i--;){if(self.sounds[self.soundIDs[i]].readyState==1)self.sounds[self.soundIDs[i]].unload();};};self.disable();};function SMSound(oSM,oOptions){var self=this;var sm=oSM;this.sID=oOptions.id;this.url=oOptions.url;this.options=sm._mergeObjects(oOptions);if(sm.debugMode){var stuff=null;var msg=[];var sF=null;var sfBracket=null;var maxLength=64;for(stuff in this.options){if(this.options[stuff]!=null){if(this.options[stuff]instanceof Function){sF=this.options[stuff].toString();sF=sF.replace(/\s\s+/g,' ');sfBracket=sF.indexOf('{');msg[msg.length]=' '+stuff+': {'+sF.substr(sfBracket+1,(Math.min(Math.max(sF.indexOf('\n')-1,maxLength),maxLength))).replace(/\n/g,'')+'... }';}else{msg[msg.length]=' '+stuff+': '+this.options[stuff];};};};};this.id3={};self.resetProperties=function(bLoaded){self.bytesLoaded=null;self.bytesTotal=null;self.position=null;self.duration=null;self.durationEstimate=null;self.loaded=false;self.loadSuccess=null;self.playState=0;self.paused=false;self.readyState=0;self.didBeforeFinish=false;self.didJustBeforeFinish=false;};self.resetProperties();this.load=function(oOptions){self.loaded=false;self.loadSuccess=null;self.readyState=1;self.playState=(oOptions.autoPlay||false);var thisOptions=sm._mergeObjects(oOptions);if(typeof thisOptions.url=='undefined')thisOptions.url=self.url;try{sm.o._load(self.sID,thisOptions.url,thisOptions.stream,thisOptions.autoPlay,(thisOptions.whileloading?1:0));}catch(e){};};this.unload=function(){self.setPosition(0);sm.o._unload(self.sID,sm.nullURL);self.resetProperties();};this.play=function(oOptions){if(!oOptions)oOptions={};var thisOptions=sm._mergeObjects(oOptions,self.options);thisOptions=sm._mergeObjects(thisOptions);if(self.playState==1){var allowMulti=thisOptions.multiShot;if(!allowMulti){return false;}else{};};if(!self.loaded){if(self.readyState==0){thisOptions.stream=true;thisOptions.autoPlay=true;self.load(thisOptions);}else if(self.readyState==2){return false;}else{};}else{};if(self.paused){self.resume();}else{self.playState=1;self.position=(typeof thisOptions.position!='undefined'&&!isNaN(thisOptions.position)?thisOptions.position/1000:0);if(thisOptions.onplay)thisOptions.onplay.apply(self);self.setVolume(thisOptions.volume);self.setPan(thisOptions.pan);if(!thisOptions.autoPlay){sm.o._start(self.sID,thisOptions.loop||1,self.position);};};};this.start=this.play;this.stop=function(bAll){if(self.playState==1){self.playState=0;self.paused=false;if(self.options.onstop)self.options.onstop.apply(self);sm.o._stop(self.sID);};};this.setPosition=function(nMsecOffset){self.options.position=nMsecOffset;sm.o._setPosition(self.sID,nMsecOffset/1000,self.paused||!self.playState);};this.pause=function(){if(self.paused)return false;self.paused=true;sm.o._pause(self.sID);if(self.options.onpause)self.options.onpause.apply(self);};this.resume=function(){if(!self.paused)return false;self.paused=false;sm.o._pause(self.sID);if(self.options.onresume)self.options.onresume.apply(self);};this.togglePause=function(){if(!self.playState){self.play({position:self.position/1000});return false;};if(self.paused){self.resume();}else{self.pause();};};this.setPan=function(nPan){if(typeof nPan=='undefined')nPan=0;sm.o._setPan(self.sID,nPan);self.options.pan=nPan;};this.setVolume=function(nVol){if(typeof nVol=='undefined')nVol=100;sm.o._setVolume(self.sID,nVol);self.options.volume=nVol;};this.mute=function(){sm.o._setVolume(self.sID,0);};this.unmute=function(){sm.o._setVolume(self.sID,self.options.volume);};this._whileloading=function(nBytesLoaded,nBytesTotal,nDuration){self.bytesLoaded=nBytesLoaded;self.bytesTotal=nBytesTotal;self.duration=nDuration;self.durationEstimate=parseInt((self.bytesTotal/self.bytesLoaded)*self.duration);if(self.readyState!=3&&self.options.whileloading)self.options.whileloading.apply(self);};this._onid3=function(oID3PropNames,oID3Data){var oData=[];for(var i=0,j=oID3PropNames.length;i<j;i++){oData[oID3PropNames[i]]=oID3Data[i];};self.id3=sm._mergeObjects(self.id3,oData);if(self.options.onid3)self.options.onid3.apply(self);};this._whileplaying=function(nPosition){if(isNaN(nPosition)||nPosition==null)return false;self.position=nPosition;if(self.playState==1){if(self.options.whileplaying)self.options.whileplaying.apply(self);if(self.loaded&&self.options.onbeforefinish&&self.options.onbeforefinishtime&&!self.didBeforeFinish&&self.duration-self.position<=self.options.onbeforefinishtime){self._onbeforefinish();};};};this._onload=function(bSuccess){bSuccess=(bSuccess==1?true:false);if(!bSuccess){if(sm.sandbox.noRemote==true){};if(sm.sandbox.noLocal==true){};};self.loaded=bSuccess;self.loadSuccess=bSuccess;self.readyState=bSuccess?3:2;if(self.options.onload){self.options.onload.apply(self);};};this._onbeforefinish=function(){if(!self.didBeforeFinish){self.didBeforeFinish=true;if(self.options.onbeforefinish)self.options.onbeforefinish.apply(self);};};this._onjustbeforefinish=function(msOffset){if(!self.didJustBeforeFinish){self.didJustBeforeFinish=true;if(self.options.onjustbeforefinish)self.options.onjustbeforefinish.apply(self);;};};this._onfinish=function(){self.playState=0;self.paused=false;if(self.options.onfinish)self.options.onfinish.apply(self);if(self.options.onbeforefinishcomplete)self.options.onbeforefinishcomplete.apply(self);self.setPosition(0);self.didBeforeFinish=false;self.didJustBeforeFinish=false;};};if(window.addEventListener){window.addEventListener('focus',self.handleFocus,false);window.addEventListener('load',self.beginDelayedInit,false);window.addEventListener('beforeunload',self.destruct,false);if(self._tryInitOnFocus)window.addEventListener('mousemove',self.handleFocus,false);}else if(window.attachEvent){window.attachEvent('onfocus',self.handleFocus);window.attachEvent('onload',self.beginDelayedInit);window.attachEvent('beforeunload',self.destruct);}else{soundManager.onerror();soundManager.disable();};if(document.addEventListener)document.addEventListener('DOMContentLoaded',self.domContentLoaded,false);};var soundManager=new SoundManager();


/* Page inline player */
function PagePlayer() {
	var self = this;
	var pl = this;
	var sm = soundManager;	 // soundManager instance
	var isIE = navigator.userAgent.match(/msie/i);

	this.config = {
		allowRightClick:true,	 // let users right-click MP3 links ("save as...", etc.) or discourage (can't prevent.)
		useThrottling: false,	 // try to rate-limit potentially-expensive calls (eg. dragging position around)
		playNext: true,				 // stop after one sound, or play through list until end
		updatePageTitle: true, // change the page title while playing sounds
		emptyTime: '-:--'			 // null/undefined timer values (before data is available)
	}

	this.css = {						 // CSS class names appended to link during various states
		sDefault: 'sm2_link',	 // default state
		sLoading: 'sm2_loading',
		sPlaying: 'sm2_playing',
		sPaused: 'sm2_paused'
	}

	this.links = [];
	this.sounds = [];
	this.soundsByURL = [];
	this.lastSound = null;
	this.soundCount = 0;
	this.strings = [];
	this.dragActive = false;
	this.dragExec = new Date();
	this.dragTimer = null;
	this.pageTitle = document.title;
	this.lastWPExec = new Date();

	this.oControls = document.getElementById('control-template').cloneNode(true);
	this.oControls.id = '';

	this.addEventHandler = function(o,evtName,evtHandler) {
		typeof(attachEvent)=='undefined'?o.addEventListener(evtName,evtHandler,false):o.attachEvent('on'+evtName,evtHandler);
	}

	this.removeEventHandler = function(o,evtName,evtHandler) {
		typeof(attachEvent)=='undefined'?o.removeEventListener(evtName,evtHandler,false):o.detachEvent('on'+evtName,evtHandler);
	}

	this.hasClass = function(o,cStr) {
		return (typeof(o.className)!='undefined'?o.className.indexOf(cStr)+1:false);
	}

	this.addClass = function(o,cStr) {
		if (!o || !cStr) return false; // safety net
		if (self.hasClass(o,cStr)) return false;
		o.className = (o.className?o.className+' ':'')+cStr;
		return true;
	}

	this.removeClass = function(o,cStr) {
		if (!o || !cStr) return false; // safety net
		if (!self.hasClass(o,cStr)) return false;
		o.className = o.className.replace(new RegExp('( '+cStr+')|('+cStr+')','g'),'');
		return true;
	}

	this.getElementsByClassName = function(className,tagNames,oParent) {
		var doc = (oParent||document);
		var matches = [];
		var i,j;
		var nodes = [];
		if (typeof(tagNames)!='undefined' && typeof(tagNames)!='string') {
			for (i=tagNames.length; i--;) {
				if (!nodes || !nodes[tagNames[i]]) {
					nodes[tagNames[i]] = doc.getElementsByTagName(tagNames[i]);
				}
			}
		} else if (tagNames) {
			nodes = doc.getElementsByTagName(tagNames);
		} else {
			nodes = doc.all||doc.getElementsByTagName('*');
		}
		if (typeof(tagNames)!='string') {
			for (i=tagNames.length; i--;) {
				for (j=nodes[tagNames[i]].length; j--;) {
					if (self.hasClass(nodes[tagNames[i]][j],className)) {
						matches[matches.length] = nodes[tagNames[i]][j];
					}
				}
			}
		} else {
			for (i=0; i<nodes.length; i++) {
				if (self.hasClass(nodes[i],className)) {
					matches[matches.length] = nodes[i];
				}
			}
		}
		return matches;
	}
	
	this.getOffX = function(o) {
		// http://www.xs4all.nl/~ppk/js/findpos.html
		var curleft = 0;
		if (o.offsetParent) {
			while (o.offsetParent) {
				curleft += o.offsetLeft;
				o = o.offsetParent;
			}
		}
		else if (o.x) curleft += o.x;
		return curleft;
	}

	this.isChildOfClass = function(oChild,oClass) {
		if (!oChild || !oClass) return false;
		while (oChild.parentNode && !self.hasClass(oChild,oClass)) {
			oChild = oChild.parentNode;
		}
		return (self.hasClass(oChild,oClass));
	}

	this.getParentByNodeName = function(oChild,sParentNodeName) {
		if (!oChild || !sParentNodeName) return false;
		sParentNodeName = sParentNodeName.toLowerCase();
		while (oChild.parentNode && sParentNodeName != oChild.parentNode.nodeName.toLowerCase()) {
			oChild = oChild.parentNode;
		}
		return (oChild.parentNode && sParentNodeName == oChild.parentNode.nodeName.toLowerCase()?oChild.parentNode:null);
	}
	
	this.getTime = function(nMSec,bAsString) {
		// convert milliseconds to mm:ss, return as object literal or string
		var nSec = Math.floor(nMSec/1000);
		var min = Math.floor(nSec/60);
		var sec = nSec-(min*60);
		// if (min == 0 && sec == 0) return null; // return 0:00 as null
		return (bAsString?(min+':'+(sec<10?'0'+sec:sec)):{'min':min,'sec':sec});
	}

	this.getSoundByURL = function(sURL) {
		return (typeof self.soundsByURL[sURL] != 'undefined'?self.soundsByURL[sURL]:null);
	}

	this.getSoundIndex = function(sURL) {
		for (var i=self.links.length; i--;) {
			if (self.links[i].href == sURL) return i;
		}
		return -1;
	}

	this.setPageTitle = function(sTitle) {
		if (!self.config.updatePageTitle) return false;
		try {
			document.title = (sTitle?sTitle+' - ':'')+self.pageTitle;
		} catch(e) {
			// oh well
			self.setPageTitle = function() {return false;}
		}
		return true;
	}

	this.events = {

		// handlers for sound events as they're started/stopped/played

		play: function() {
			pl.removeClass(this._data.oLI,this._data.className);
			this._data.className = pl.css.sPlaying;
			pl.addClass(this._data.oLI,this._data.className);
			self.setPageTitle(this._data.originalTitle);
		},

		stop: function() {
			pl.removeClass(this._data.oLI,this._data.className);
			this._data.className = '';
			this._data.oPosition.style.width = '0px';
			self.setPageTitle();
		},

		pause: function() {
			if (pl.dragActive) { return false; }
			pl.removeClass(this._data.oLI,this._data.className);
			this._data.className = pl.css.sPaused;
			pl.addClass(this._data.oLI,this._data.className);
			self.setPageTitle();
			return true;
		},

		resume: function() {
			if (pl.dragActive) { return false; }
			pl.removeClass(this._data.oLI,this._data.className);
			this._data.className = pl.css.sPlaying;
			pl.addClass(this._data.oLI,this._data.className);
			return true;
		},

		finish: function() {
			pl.removeClass(this._data.oLI,this._data.className);
			this._data.className = '';
			this._data.oPosition.style.width = '0px';
			// play next if applicable
			if (self.config.playNext && this._data.nIndex<pl.links.length-1) {
				pl.handleClick({target:pl.links[this._data.nIndex+1]}); // fake a click event - aren't we sneaky. ;)
			} else {
				self.setPageTitle();
			}
		},

		whileloading: function() {
			this._data.oLoading.style.width = (((this.bytesLoaded/this.bytesTotal)*100)+'%'); // theoretically, this should work.
			if (!this._data.didRefresh && this._data.metadata) {
				this._data.didRefresh = true;
				this._data.metadata.refresh();
			}
		},

		onload: function() {
			if (!this.loaded) {
		var oTemp = this._data.oLI.getElementsByTagName('a')[0];
		var oString = oTemp.innerHTML;
		var oThis = this;
		oTemp.innerHTML = oString+' <span style="font-size:0.5em"> | Load failed, d\'oh! '+(sm.sandbox.noRemote?' Possible cause: Flash sandbox is denying remote URL access.':(sm.sandbox.noLocal?'Flash denying local filesystem access':'404?'))+'</span>';
		setTimeout(function(){
			oTemp.innerHTML = oString;
			// pl.events.finish.apply(oThis); // load next
		},5000);
		} else {
				if (this._data.metadata) {
					this._data.metadata.refresh();
				}
			}
		},

		whileplaying: function() {
			var d = null;
			if (pl.dragActive || !pl.config.useThrottling) {
				self.updateTime.apply(this);
				this._data.oPosition.style.width = (((this.position/self.getDurationEstimate(this))*100)+'%');
				if (this._data.metadata) {
					d = new Date();
					if (d && d-self.lastWPExec>500) {
						self.refreshMetadata(this);
						self.lastWPExec = d;
					}
				}
			} else {
				d = new Date();
				if (d-self.lastWPExec>500) {
					self.updateTime.apply(this);
					if (this._data.metadata) self.refreshMetadata(this);
					this._data.oPosition.style.width = (((this.position/self.getDurationEstimate(this))*100)+'%');
					self.lastWPExec = d;
				}
			}
		}
	
	} // events{}

	this.refreshMetadata = function(oSound) {
		// Display info as appropriate
		// console.log('refreshMetaData()');
		var index = null;
		var now = oSound.position;
		var metadata = oSound._data.metadata.data;
		for (var i=0, j=metadata.length; i<j; i++) {
			if (now >= metadata[i].startTimeMS && now <= metadata[i].endTimeMS) {
				index = i;
				break;
			}
		}
		if (index != metadata.currentItem) {
			// update
			oSound._data.oLink.innerHTML = metadata.mainTitle+' <span class="metadata"><span class="sm2_divider"> | </span><span class="sm2_metadata">'+metadata[index].title+'</span></span>';
			self.setPageTitle(metadata[index].title+' | '+metadata.mainTitle);
			metadata.currentItem = index;
		}
	}
	
	this.updateTime = function() {
		var str = self.strings['timing'].replace('%s1',self.getTime(this.position,true));
		str = str.replace('%s2',self.getTime(self.getDurationEstimate(this),true));
		this._data.oTiming.innerHTML = str;
	}

	this.getTheDamnTarget = function(e) {
		return (e.target||e.srcElement||window.event.srcElement);
	}
	
	this.withinStatusBar = function(o) {
		return (self.isChildOfClass(o,'controls')); // (self.hasClass(o,'statusbar')||self.hasClass(o,'loading')||self.hasClass(o,'position')||self.hasClass(o,'sub-track')));
	}

	this.handleClick = function(e) {
		// a sound (or something) was clicked - determine what and handle appropriately
		if (e.button == 2) {
			if (!pl.config.allowRightClick) pl.stopEvent(e);
			return (pl.config.allowRightClick); // ignore right-clicks
		}
		var o = self.getTheDamnTarget(e);
		if (self.dragActive) self.stopDrag(); // to be safe
		if (self.withinStatusBar(o)) {
			// self.handleStatusClick(e);
			return false;
		}
		if (o.nodeName.toLowerCase() != 'a') {
			o = self.getParentByNodeName(o,'a');
		}
		if (!o) {
			// not a link
			return true;
		}
		var sURL = o.getAttribute('href');
		if (!o.href || !o.href.match(/.mp3$/i)) {
			if (isIE && o.onclick) {
				return false; // IE will run this handler before .onclick(), everyone else is cool?
			}
			return true; // pass-thru for non-MP3/non-links
		}
		// sm._writeDebug('handleClick()');
		var soundURL = (o.href);
		var thisSound = self.getSoundByURL(soundURL);
		// sm._writeDebug('click: thisSound:'+thisSound);
		if (thisSound) {
			// sound already exists
			// sm._writeDebug('sound exists');
			self.setPageTitle(thisSound._data.originalTitle);
			if (thisSound == self.lastSound) {
				// ..and was playing (or paused) and isn't in an error state
		if (thisSound.readyState != 2) {
					thisSound.togglePause();
		} else {
			sm._writeDebug('Warning: sound failed to load (security restrictions or 404)',2);
		}
			} else {
				// ..different sound
				// sm._writeDebug('sound different than last sound: '+self.lastSound.sID);
				if (self.lastSound) self.stopSound(self.lastSound);
				thisSound.togglePause(); // start playing current
			}
		} else {
			// create sound
			thisSound = sm.createSound({
				id:'mp3Sound'+(self.soundCount++),
				url:soundURL,
				onplay:self.events.play,
				onstop:self.events.stop,
				onpause:self.events.pause,
				onresume:self.events.resume,
				onfinish:self.events.finish,
				whileloading:self.events.whileloading,
				whileplaying:self.events.whileplaying,
				onload:self.events.onload
			});
			// append control template
			var oControls = self.oControls.cloneNode(true);
			o.parentNode.appendChild(oControls);
			self.soundsByURL[soundURL] = thisSound;
			// tack on some custom data
			thisSound._data = {
				oLink: o, // DOM reference within SM2 object event handlers
				oLI: o.parentNode,
				oControls: self.getElementsByClassName('controls','div',o.parentNode)[0],
				oStatus: self.getElementsByClassName('statusbar','div',o.parentNode)[0],
				oLoading: self.getElementsByClassName('loading','div',o.parentNode)[0],
				oPosition: self.getElementsByClassName('position','div',o.parentNode)[0],
				oTiming: self.getElementsByClassName('timing','div',o.parentNode)[0].getElementsByTagName('div')[0],
				nIndex: self.getSoundIndex(soundURL),
				className: self.css.sPlaying,
				originalTitle: o.innerHTML,
				metadata: null
			};
			// "Metadata"
			// if (self.getElementsByClassName('tracks',thisSound._data.oLI,'div').length) {
			if (thisSound._data.oLI.getElementsByTagName('ul').length) {
				thisSound._data.metadata = new Metadata(thisSound);
			}
			// set initial timer stuff (before loading)
			var str = self.strings['timing'].replace('%s1',self.config.emptyTime);
			str = str.replace('%s2',self.config.emptyTime);
			thisSound._data.oTiming.innerHTML = str;
			self.sounds.push(thisSound);
			if (self.lastSound) self.stopSound(self.lastSound);
			thisSound.play();
		}
		self.lastSound = thisSound; // reference for next call
		return self.stopEvent(e);
	}
	
	this.handleMouseDown = function(e) {
		// a sound link was clicked
		if (e.button == 2) {
			if (!pl.config.allowRightClick) pl.stopEvent(e);
			return (pl.config.allowRightClick); // ignore right-clicks
		}
		var o = self.getTheDamnTarget(e);
		if (!self.withinStatusBar(o)) return true;
		self.dragActive = true;
		self.lastSound.pause();
		self.setPosition(e);
		self.addEventHandler(document,'mousemove',self.handleMouseMove);
		self.addClass(self.lastSound._data.oControls,'dragging');
		// self.addEventHandler(document,'mouseup',self.stopDrag);
		self.stopEvent(e);
		return false;
	}
	
	this.handleMouseMove = function(e) {
		// set position accordingly
		if (self.dragActive) {
			if (self.config.useThrottling) {
				// be nice to CPU/externalInterface
				var d = new Date();
				if (d-self.dragExec>20) {
					self.setPosition(e);
				} else {
					window.clearTimeout(self.dragTimer);
					self.dragTimer = window.setTimeout(function(){self.setPosition(e)},20);
				}
				self.dragExec = d;
			} else {
				// oh the hell with it
				self.setPosition(e);
			}
		} else {
			self.stopDrag();
		}
		return false;
	}
	
	this.stopDrag = function(e) {
		if (self.dragActive) {
			self.removeClass(self.lastSound._data.oControls,'dragging');
			self.removeEventHandler(document,'mousemove',self.handleMouseMove);
			// self.removeEventHandler(document,'mouseup',self.stopDrag);
			if (!pl.hasClass(self.lastSound._data.oLI,self.css.sPaused)) {
				self.lastSound.resume();
			}
			self.dragActive = false;
			self.stopEvent(e);
			return false;

		} else {
			return true;
		}
	}
	
	this.handleStatusClick = function(e) {
		self.setPosition(e);
		if (!pl.hasClass(self.lastSound._data.oLI,self.css.sPaused)) self.resume();
		return self.stopEvent(e);
	}
	
	this.stopEvent = function(e) {
	 if (typeof e != 'undefined' && typeof e.preventDefault != 'undefined') {
			e.preventDefault();
		} else if (typeof event != 'undefined' && typeof event.returnValue != 'undefined') {
			event.returnValue = false;
		}
		return false;
	}
 
	this.setPosition = function(e) {
		// called from slider control
		var oThis = self.getTheDamnTarget(e);
		var oControl = oThis;
		while (!self.hasClass(oControl,'controls') && oControl.parentNode) {
			oControl = oControl.parentNode;
		}
		var oSound = self.lastSound;
		var x = parseInt(e.clientX);
		// play sound at this position
		var nMsecOffset = Math.floor((x-self.getOffX(oControl)-4)/(oControl.offsetWidth)*self.getDurationEstimate(oSound));
		if (!isNaN(nMsecOffset)) nMsecOffset = Math.min(nMsecOffset,oSound.duration);
		if (!isNaN(nMsecOffset)) oSound.setPosition(nMsecOffset);
	}

	this.stopSound = function(oSound) {
		sm._writeDebug('stopping sound: '+oSound.sID);
		soundManager.stop(oSound.sID);
		soundManager.unload(oSound.sID);
	}

	this.getDurationEstimate = function(oSound) {
		return (!oSound._data.metadata || !oSound._data.metadata.data.givenDuration?oSound.durationEstimate:oSound._data.metadata.data.givenDuration);
	}

	this.init = function() {
		sm._writeDebug('pagePlayer.init()');
		var oLinks = document.getElementsByTagName('a');
		// grab all links, look for .mp3
		var foundItems = 0;
		for (var i=0; i<oLinks.length; i++) {
			if (oLinks[i].href.match(/.mp3$/i)) {
				self.links[self.links.length] = oLinks[i];
				self.addClass(oLinks[i],self.css.sDefault); // add default CSS decoration
				foundItems++;
			}
		}
		if (foundItems>0) {
			var oTiming = document.getElementById('sm2_timing');
			self.strings['timing'] = oTiming.innerHTML;
			oTiming.innerHTML = '';
			oTiming.id = '';
			self.addEventHandler(document,'click',self.handleClick);
			self.addEventHandler(document,'mousedown',self.handleMouseDown);
			self.addEventHandler(document,'mouseup',self.stopDrag);
		}
		sm._writeDebug('pagePlayer.init(): Found '+foundItems+' relevant items.');
	}

var Metadata = function(oSound) { // self.sounds[]
	var self = this;
	var oLI = oSound._data.oLI;
	var o = oLI.getElementsByTagName('ul')[0];
	var oItems = o.getElementsByTagName('li');
	var oTemplate = document.createElement('div');
	oTemplate.innerHTML = '<span>&nbsp;</span>';
	oTemplate.className = 'annotation';
	var oTemplate2 = document.createElement('div');
	oTemplate2.innerHTML = '<span>&nbsp;</span>';
	oTemplate2.className = 'annotation alt';

	var oTemplate3 = document.createElement('div');
	oTemplate3.className = 'note';

	this.totalTime = 0;
	this.strToTime = function(sTime) {
		var segments = sTime.split(':');
		var seconds = 0;
		for (var i=segments.length; i--;) {
			seconds += parseInt(segments[i])*Math.pow(60,segments.length-1-i,10); // hours, minutes
		}
		return seconds;
	}
	this.data = [];
	this.data.givenDuration = null;
	this.data.currentItem = null;
	this.data.mainTitle = oSound._data.oLink.innerHTML;
	for (var i=0; i<oItems.length; i++) {
		this.data[i] = {
			o: null,
			title: oItems[i].getElementsByTagName('p')[0].innerHTML,
			startTime: oItems[i].getElementsByTagName('span')[0].innerHTML,
			startSeconds: self.strToTime(oItems[i].getElementsByTagName('span')[0].innerHTML.replace(/[()]/g,'')),
			duration: 0,
			durationMS: null,
			startTimeMS: null,
			endTimeMS: null,
			oNote: null
		}
	}
	var oDuration = pl.getElementsByClassName('duration','div',oLI);
	this.data.givenDuration = (oDuration.length?self.strToTime(oDuration[0].innerHTML)*1000:0);
	for (i=0; i<this.data.length; i++) {
		this.data[i].duration = parseInt(this.data[i+1]?this.data[i+1].startSeconds:(self.data.givenDuration?self.data.givenDuration:oSound.durationEstimate)/1000)-this.data[i].startSeconds;
		this.data[i].startTimeMS = this.data[i].startSeconds*1000;
		this.data[i].durationMS = this.data[i].duration*1000;
		this.data[i].endTimeMS = this.data[i].startTimeMS+this.data[i].durationMS;
		// console.log('start/end MS: '+this.data[i].startTimeMS+'/'+this.data[i].endTimeMS);
		this.totalTime += this.data[i].duration;
	}
	// make stuff
	this.createElements = function() {
		var oFrag = document.createDocumentFragment();
		var oNode = null;
		var oNodeSpan = null;
		var oNode2 = null;
		for (var i=0; i<self.data.length; i++) {
			oNode = (i%2==0?oTemplate:oTemplate2).cloneNode(true);
			oNodeSpan = oNode.getElementsByTagName('span')[0];
			oNode.rel = i;
			self.data[i].o = oNode;
			oNode2 = oTemplate3.cloneNode(true);
			if (i%2==0) oNode2.className = 'note alt';
			oNode2.innerHTML = this.data[i].title;
			// pl.addEventHandler(oNode,'mouseover',self.mouseover);
			// pl.addEventHandler(oNode,'mouseout',self.mouseout);
			// evil old-skool event handlers
			oNode.onmouseover = self.mouseover;
			oNode.onmouseout = self.mouseout;
			this.data[i].oNote = oNode2;
			oSound._data.oControls.appendChild(oNode2);
			oFrag.appendChild(oNode);
			// oFrag.appendChild(oNode2);
		}
		self.refresh();
		oSound._data.oStatus.appendChild(oFrag);
	}

	this.refresh = function() {
		// console.log('refresh()');
		var offset = 0;
		var relWidth = null;
		var duration = (self.data.givenDuration?self.data.givenDuration:oSound.durationEstimate);
		for (var i=0; i<self.data.length; i++) {
			if (duration) {
				relWidth = (((self.data[i].duration*1000)/duration)*100);
				// self.data[i].o.style.width = (Math.max(0,relWidth)+'%');
				self.data[i].o.style.left = (offset?offset+'%':'-2px'); // (offset?(offset/self.totalTime)+'%':'0px');
				self.data[i].oNote.style.left = (offset?offset+'%':'0px');
				offset += relWidth; // parseInt(self.data[i].duration);
			}
		}
	}

	this.mouseover = function(e) {
		self.data[this.rel].oNote.style.visibility = 'hidden';
		self.data[this.rel].oNote.style.display = 'inline-block';
		self.data[this.rel].oNote.style.marginLeft = -parseInt(self.data[this.rel].oNote.offsetWidth/2)+'px';
		self.data[this.rel].oNote.style.visibility = 'visible';
	}

	this.mouseout = function() { 
		// console.log('mouseout()');
		self.data[this.rel].oNote.style.display = 'none';
	}

	this.createElements();
	this.refresh();
	
}

	this.init();
}

var pagePlayer = null;

soundManager.debugMode = (window.location.href.toString().match(/debug=1/i)?true:false); // enable with #debug=1 for example

soundManager.url = '/downloads/soundmanager2.swf'; // path to movie

soundManager.onload = function() {
	pagePlayer = new PagePlayer();
}

