/*

  - NOTE - first beta/whatever release, bugs to be fixed. :D
  - 12.02.2007

  [ Schillmania! - 2007/08 Environmental Simulation edition ]
  [ ------------------------------------------------------- ]
  [                                              12.02.2007 ]
  [                                                         ]
  [ A cross-browser/platform implementation inspired by     ]
  [ an earlier "Summer.02" IE-only project, simulating      ]
  [ a setting in front of a pond with interactive bits.     ]
  [                                                         ]
  [ Summer.02 project (IE-only, uses an evil pop-up):       ]
  [ http://www.schillmania.com/summer_02/                   ]
  [                                                         ]
  [ Rather badly hacked-together experimental work,         ]
  [                                                         ]
  [ designed to set CPUs on fire worldwide.                 ]
  [                                                         ]
  [ ..At least, until browsers get faster at rendering      ]
  [ heavy layered opacity, animation effects and other      ]
  [ dynamic content refresh/redraw operations.              ]
  [                                                         ]
  [ Safari 3 and Firefox 3 do this well as of Dec.07.       ]
  [                                                         ]
  [ I don't recommend global objects, UA sniffing or        ]
  [ other numerous bad things I've done here - this         ]
  [ just so happens to still work. ;) I blame Flickr        ]
  [ and Yahoo! for keeping me busy, but in good ways.       ]
  [                                                         ]
  [ The code has been wrapped in a function to avoid        ]
  [ pollution of the global space, but ultimately           ]
  [ could be written a lot cleaner. TBD.                    ]

  Comments, feedback etc.: email:

  i'd like to work at yahoo.com

*/

var $ = function(sID) {return document.getElementById(sID);}

function SCHILLMANIA() {

// giant wrapper constructor, prevents pollution of global namespace

var nAV = navigator.appVersion.toLowerCase();
var nUA = navigator.userAgent.toLowerCase();
var nP = navigator.platform.toLowerCase();
var isIE = nAV.match(/msie/i);
var isOldIE = nAV.match(/msie [5,6]/i);
var isNewerIE = (isIE && !isOldIE);
var isFirefox = nUA.match(/firefox/i);
var isFirefox3 = (nUA.match(/firefox\/[3,4]/i)||nUA.match(/minefield\/[3,4]/i));
var isOpera = nUA.match(/opera/i);
var isSafari = nUA.match(/safari/i);
var isSafari3 = (isSafari && nUA.match(/version\/[3,4]/i));
var isWin32 = nP.match(/win/i);
var isMac = nP.match(/mac/i);
var isiPhone = (nUA.match(/iPhone/i));
var urlBase = urlRoot+'2007/';
if (isOpera) {
  isIE = false;
  isOldIE = false;
}
var IS_FAST_BROWSER = ((isSafari3 || isFirefox3 || isNewerIE) && !isiPhone); // these browsers have been tested as capable of efficiently handling the render load (nested opacity, 24-bit alpha-transparent PNGs, animation etc.)
var IS_SLOW = true;
var FULL_SCREEN = !IS_SLOW;
var IS_MOON_COMPUTER = (window.location.href.indexOf('moon')!=-1); // try ?moon=1 if you think you have a moon computer..

var animDuration = 0.66;

if (typeof window.console == 'undefined') window.console = {log:function(){}}

var soundPlayer = null;

function removeChildNodes(o) {
  // remove children from bottom up
  var nodes = o.childNodes;
  if (!nodes || !o) {
    writeDebug('removeChildNodes('+(o||'null')+'): no nodes to remove.');
    return false;
  }
  for (var i=nodes.length-1; i>=0; i--) {
    o.removeChild(nodes[i]);
  }
}

if (typeof YAHOO.util.BgPosAnim == 'undefined') {

// July 2007: YUI Background Animation subclass, written by Matt Sweeney for Flickr Uploadr. Should be native in future YUI releases.

(function() {
    YAHOO.util.BgPosAnim = function(el, attributes, duration,  method) {
        YAHOO.util.BgPosAnim.superclass.constructor.apply(this, arguments);
    };
    
    YAHOO.extend(YAHOO.util.BgPosAnim, YAHOO.util.Anim);
    // shorthand
    var Y = YAHOO.util;
    var superclass = Y.BgPosAnim.superclass;
    var proto = Y.BgPosAnim.prototype;
    
    proto.toString = function() {
        var el = this.getEl();
        var id = el.id || el.tagName;
        return ("BgPosAnim " + id);
    };

    proto.patterns.bgPos = /^backgroundPosition|background-position$/i;
    
    proto.setAttribute = function(attr, val, unit) {
        if ( this.patterns.bgPos.test(attr) ) {
            val = val[0] + unit[0] + ' ' + val[1] + unit[1];
            YAHOO.util.Dom.setStyle(this.getEl(), attr, val);
        } else {
            superclass.setAttribute.apply(this, arguments);
        }

    },                        

    proto.doMethod = function(attr, start, end) {
        var val;
    
        if ( this.patterns.bgPos.test(attr) ) {
            val = [];
            for (var i = 0, len = start.length; i < len; ++i) {
                val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
            }
        }
        else {
            val = superclass.doMethod.apply(this, arguments);
        }

        return val;
    };

})();
}

var Y = {
 // shortcuts
 A: YAHOO.util.Anim,
 D: YAHOO.util.Dom,
 E: YAHOO.util.Event,
 UE: YAHOO.util.Easing,
 CA: YAHOO.util.ColorAnim,
 BG: YAHOO.util.BgPosAnim
}


function setActiveStyleSheet(title) {
  var i, a;
  var ss = APP_XHTML?document.styleSheets:document.getElementsByTagName('head')[0].getElementsByTagName('link');
  for (i=ss.length; i--;) {
    a = ss[i];
    if (!APP_XHTML) {
      if (a.getAttribute('rel').indexOf('style') != -1 && a.getAttribute('title')) {
        if (a.title == 'light' || a.title == 'dark') {
          a.disabled = true;
          if (a.getAttribute('title') == title) a.disabled = false;
        }
      }
    } else {
      if (a.href.indexOf('light')!=-1 || a.href.indexOf('dark')!=-1) {
        a.disabled = true;
        if (a.href.indexOf(title)!=-1) a.disabled = false;
      }
    }
  }
}

// CONTENT MANAGER - re-re-re-hashed from 2006, re-re-hashed from 2005, re-hashed from 2004 site

function getXHR() {
  var xhr = null;
  if (typeof window.XMLHttpRequest != 'undefined') {
    try {
      xhr = new XMLHttpRequest();
    } catch(e) {
      // d'oh
    }
  }
  if (!xhr) {
    try {
      xhr = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
      try {
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
      } catch(E) {
        xhr = null;
      }
    }
  }
  return xhr;
}

function LastFM() {
  var self = this;
  this.xmlhttp = getXHR();

  // http://sedition.com/perl/javascript-fy.html
  function fisherYates(myArray) {
    var i = myArray.length;
    if (i==0) return false;
    var j,tempi,tempj;
    while (--i) {
      j = Math.floor(Math.random()*(i+1));
      tempi = myArray[i];
      tempj = myArray[j];
      myArray[i] = tempj;
      myArray[j] = tempi;
    }
  }

  this.readystatechangeHandler = function() {
    if (self.xmlhttp.readyState == 4) {
      if (self.onloadHandler) {
        self.onloadHandler();
      }
    }
  }

  this.onloadHandler = function() {
    try {
      var xml = self.xmlhttp.responseXML.documentElement;
      self.parseTopArtistsList(xml);
    } catch(e) {
      // oh well
      if (typeof console != 'undefined' && typeof console.log != 'undefined') console.log('LastFM.onloadHandler(): Warning: invalid XML or parse error');
      Y.D.getElementsByClassName('lastfm','div',$('col2-content'))[0].style.display = 'none';
      return false;
    }
  }

  this.load = function() {
    if (!self.xmlhttp) return false;
    self.xmlhttp.open('GET',urlRoot+'content/lastfm/top-artists/',true);
    self.xmlhttp.onreadystatechange = self.readystatechangeHandler;
    self.xmlhttp.setRequestHeader('Content-Type','text/xml');
    self.xmlhttp.send(null);
  }

  this.parseTopArtistsList = function(xml) {
    var items = xml.getElementsByTagName('artist');
    var data = [];
    var oFrag = document.createElement('ul');
    oFrag.className = 'thumbs';
    var oItem = null;

    for (var i=0; i<items.length; i++) {
      data[i] = {
        name: items[i].getElementsByTagName('name')[0].childNodes[0].data.replace('&','&amp;'),
        thumb: items[i].getElementsByTagName('thumbnail')[0].childNodes[0].data,
        playcount: items[i].getElementsByTagName('playcount')[0].childNodes[0].data
      }
    }

    // fisherYates(data);

    var limit = Math.min(20,items.length);
    for (var i=0; i<limit; i++) {
      oItem = $('lastfm-artist').cloneNode(true);
      oItem.id = '';
      oItem.getElementsByTagName('img')[0].src = data[i].thumb;
      oItem.getElementsByTagName('img')[0].title =  data[i].name;
      oItem.innerHTML = (oItem.innerHTML.replace('%playcount',data[i].playcount).replace('%artist',data[i].name));
      oFrag.appendChild(oItem);
    }
    $('lastfm-stub').appendChild(oFrag);
  }


  this.parseTopTracksList = function(xml) {
    var tracks = xml.getElementsByTagName('track');
    var data = [];
    var oFrag = document.createElement('ul');
    oFrag.className = 'list';
    var oItem = null;

    for (var i=0; i<tracks.length; i++) {
      data[i] = {
        track: tracks[i].getElementsByTagName('name')[0].childNodes[0].data.replace('&','&amp;'),
        artist: tracks[i].getElementsByTagName('artist')[0].childNodes[0].data
      }
    }

    // fisherYates(data);

    var limit = Math.min(20,tracks.length);
    for (var i=0; i<limit; i++) {
      oItem = $('lastfm-track').cloneNode(true);
      oItem.id = '';
      // oItem.innerHTML = (oItem.innerHTML.replace('%track',tracks[i].getElementsByTagName('name')[0].childNodes[0].data).replace('%artist',tracks[i].getElementsByTagName('artist')[0].childNodes[0].data));
      oItem.innerHTML = (oItem.innerHTML.replace('%track',data[i].track).replace('%artist',data[i].artist));
      oFrag.appendChild(oItem);
    }
    $('lastfm-stub').appendChild(oFrag);
  }
  
}

var lastFM = new LastFM();

function ContentManager() {
  var self = this;
  this.xmlhttp = getXHR();
  this.oLast = null;
  this.url = null;

  this.readystatechangeHandler = function() {
    if (self.xmlhttp.readyState == 4) {
      if (self.onloadHandler) {
        self.onloadHandler();
      }
    }
  }

  this.load = function(url) {
    url = (url.href||url.toString());
    self.url = url;
    if (url.indexOf('.xml')>=0 || (url.indexOf('webpad')>=0) || (url.indexOf('theme=')!=-1)) return true;
    if (url.indexOf('react/contact')+1 && APP_XHTML) return true; // script here will fail otherwise
    if (url.indexOf('?')!=-1) return true;
    if (url.indexOf('#')>=0) {
      return false;
    }
    // haaaack
    url = url.replace('../','');
    url = url.replace('schillmania-dev/','');
    if (self.xmlhttp) {
      try {
        target = $('col1');
        url = url.toString();
        if (APP_XHTML||(window.location.href.indexOf('test')>=0)) {
          file = '?xml=true&r='+parseInt(Math.random()*1048576);
        } else {
          file = 'content.html';
        }
        if (window.location.href.indexOf('-dev') != -1) {
          url = url.replace('content/','schillmania-dev/content/');
        }
        self.xmlhttp.open('GET',url+file,true);
        self.xmlhttp.onreadystatechange = self.readystatechangeHandler;
        self.xmlhttp.setRequestHeader('Content-Type', 'text/xml');
        self.xmlhttp.send(null); // xmlDoc
      } catch(e) {
        // something blew up - d'oh!
        // alert('something blew up');
        // console.log('contentManager.load(): error @ '+e.lineNumber+','+e.message);
        return true;
      }
    } else {
      // no XMLHTTP support.
      return true;
    }
    return false;
  }

  this.onloadHandler = function() {
    // if (soundManager) soundManager.play('b4');
    var _title = null;
    c = $('entry-content');
    if (APP_XHTML==true && self.xmlhttp.responseXML) { // safety net: ensure valid XML response.. otherwise, try dirty innerHTML method (may fail)
      removeChildNodes(c);
      c.appendChild(document.importNode(self.xmlhttp.responseXML.documentElement.getElementsByTagName('div')[0],true));
      // _title = self.getInnerText(self.xmlhttp.responseXML.documentElement.getElementsByTagName('h1')[0]);
    } else {
      // Internet explorer etc. get to do it the non-standards way
      try {
        var sData = self.xmlhttp.responseText;
        c.innerHTML = '';
        c.innerHTML = sData;
      } catch(e) {
        window.location = self.url;
        return false;
      }
    }
    try {
      if (_title) document.title = _title+ ' - Schillmania.com';
    } catch(e) {
      // oh well
    }
    runCounter();
  }

  this.getInnerText = function(o) {
    if (o.nodeType == 3 || o.nodeType == 4) return o.data;
    var sText = [];
    for (var i=0; i<o.childNodes.length; i++) {
      sText[sText.length] = self.getInnerText(o.childNodes[i]);
    }
    return sText.join('');
  }

  this.assignHandlers = function() {
    // 2007: SHOULD use event delegation (eg., single event handler, watch for <a>), but I'm lazy and this worked in previous years. Ah well.
    // intercept onclick and load via XMLHTTP where supported
    var o = $('nav').getElementsByTagName('ul')[0];
    var oItems = null;
    for (var i=0; i<o.childNodes.length; i++) {
      if (o.childNodes[i].nodeType != 3) { // non-text
        oItems = o.childNodes[i].getElementsByTagName('a');
        for (var j=oItems.length; j--;) {
          // oItems[j]._class = o.childNodes[i].getElementsByTagName('a')[0].title;
          oItems[j].onclick = self.clickHandler;
        }
      }
    }
    var a = $('nav-list').getElementsByTagName('a');
    for (var i=0; i<a.length; i++) {
      a[i].onclick = self.clickHandler;
    }
  }

  this.lastNavItem = null;

  this.clickHandler = function(e) {
    var o = e?e.target:event.srcElement;
    o = (o&&o.href?o:this);
    if (o.href.indexOf('#'+o._class)==-1) {
      o.parentNode.className = 'selected';
      if (self.lastSelected && self.lastSelected != o.parentNode) {
        self.lastSelected.className = '';
      }
      self.lastSelected = o.parentNode;
    }
    try {
      // ensure focus..
      o.focus();
    } catch(e) {
      // just in case
    }
    if (o.toString().indexOf('#')==-1) {
      try {
        document.title = self.getInnerText(this.parentNode)+' - Schillmania.com';
      } catch(e) {
        // oh well
      }
    }
    return self.load(o);
  }

}

var contentManager = new ContentManager();

function doLoop() {
  if (!IS_SLOW) {
    // continue sounds if enhanced mode is on
    var tmpID = this.sID.substr(0,this.sID.length-1)+(parseInt(this.sID.substr(this.sID.length-1))==0?1:0);
    soundManager.play(tmpID,{onjustbeforefinish:doLoop});
  }
}

function jsAmpHandler() {
  if (xhr.readyState == 4) {
    var c = document.getElementById('player-template');
    if (APP_XHTML==true) {
      c.appendChild(document.importNode(xhr.responseXML.documentElement.getElementsByTagName('div')[0],true));
    } else {
      // Internet explorer etc. get to do it the non-standards way
      c.innerHTML = xhr.responseText;
    }
    // call SP init stuff
    initSPStuff();
  }
}


function initJSAMP() {
  if (soundManager && soundManager.enabled && !soundPlayer) {
    soundPlayer = true; // for later stylesheet switching tests
    var xhr = getXHR();
    xhr.open('GET',urlRoot+'content/jsamp.php'+(APP_XHTML?'?xml=true':''),true);
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4) {
	var c = document.getElementById('player-template');
        Y.D.addClass(c,light.lastState);
    	if (APP_XHTML==true) {
      	  c.appendChild(document.importNode(xhr.responseXML.documentElement.getElementsByTagName('div')[0],true));
    	} else {
      	  // Internet explorer etc. get to do it the non-standards way
      	  c.innerHTML = xhr.responseText;
    	}
/*
        // initialise when user mouses over
        c.onmouseover = function() {
          this.onmouseover = null;
          initSPStuff();
        }
*/
	initSPStuff();
      }
    }
    xhr.send(null);
  } else {
    // jsAMP assumed already active (or unsupported)
  }
}

function initAmbiance() {

  if (!soundManager.getSoundById('car1')) {
    // create sounds
    soundManager.createSound({id:'car1',url:urlBase+'sound/carpass-1.mp3'});
    soundManager.createSound({id:'birds0',url:urlBase+'sound/birds.mp3',volume:1,onjustbeforefinish:doLoop});
    soundManager.createSound({id:'birds1',url:urlBase+'sound/birds.mp3',volume:1,onjustbeforefinish:doLoop});
    soundManager.createSound({id:'crickets0',url:urlBase+'sound/crickets.mp3',volume:1,onjustbeforefinish:doLoop});
    soundManager.createSound({id:'crickets1',url:urlBase+'sound/crickets.mp3',volume:1,onjustbeforefinish:doLoop});
    soundManager.createSound({id:'button0',url:urlBase+'sound/button-0.mp3',volume:100});
    soundManager.createSound({id:'button1',url:urlBase+'sound/button-1.mp3',volume:100});
  }

  soundManager.play('birds0');
  soundManager.play('crickets0');
  // hack: set proper play state, etc.
  soundManager.play('birds1');
  soundManager.play('crickets1');
  soundManager.stop('birds1');
  soundManager.stop('crickets1');
}

function stopAmbiance() {
  soundManager.stop('birds0');
  soundManager.stop('crickets0');
  soundManager.stop('birds1');
  soundManager.stop('crickets1');
}

function doInit() {

/*
  soundManager.createSound({id:'car1',url:urlBase+'sound/carpass-1.mp3'});
  soundManager.createSound({id:'birds0',url:urlBase+'sound/birds.mp3',volume:1,onjustbeforefinish:doLoop});
  soundManager.createSound({id:'birds1',url:urlBase+'sound/birds.mp3',volume:1,onjustbeforefinish:doLoop});
  soundManager.createSound({id:'crickets0',url:urlBase+'sound/crickets.mp3',volume:1,onjustbeforefinish:doLoop});
  soundManager.createSound({id:'crickets1',url:urlBase+'sound/crickets.mp3',volume:1,onjustbeforefinish:doLoop});
  soundManager.createSound({id:'button0',url:urlBase+'sound/button-0.mp3',volume:100});
  soundManager.createSound({id:'button1',url:urlBase+'sound/button-1.mp3',volume:100});
*/
  // soundManager.play('button0',{volume:1});

  doWindowOnload();
  if (typeof XLSF2007 != 'undefined' && !isOldIE && (window.location.href.indexOf('christmas=1')!=-1) || new Date().getMonth() == 11) {
    self.xlsf = new XLSF2007($('nav'));
    // additional delay needed for sound to work, rather odd.
    setTimeout(self.xlsf.initSounds,500);
  }
}

var fakeHour = new Date().getHours();

function Light() {
  var self = this;
  this.oSky = $('header');
  this.oShadeLight = $('sky-shade-light');
  this.oShadeDark = $('sky-shade-dark');
  var d = new Date();
  this.data = {
    hour: d.getHours(),
    minute: d.getMinutes(),
    light: 0,
    dark:0
  }
  this.lastState = null; // last light/dark state
  this.soundMultiplier = 100; // scale for ambient sounds

  this.colors = {
    c0: [187,221,255],
    // c1: [213,207,32],
    c1: [227,171,99],
    c2: [161,191,220],
    c3: [204,204,204]
  }

  this.color = this.colors.c3; // this.colors['c'+Math.floor(Math.random()*4)];

  this.refreshTime = function(nHour) {
    var d = new Date();
    self.data.hour = d.getHours();
    self.data.minute = d.getMinutes();
    if (typeof nHour != 'undefined') {
      // check for invalid data
      if (nHour>0 && nHour<24) self.data.hour = nHour;
    }
    // console.log('refreshTime(): '+self.data.hour+':'+self.data.minute);
  }

  this.refreshLight = function() {
    // find the light (or lack thereof)
    var hour = (self.data.hour>11?self.data.hour-12:self.data.hour);
    var pm = (self.data.hour>11);
    var nLight = Math.round((hour/11)*100)/100; // round to 2 decimal places
    if (pm) nLight = Math.round((1-nLight)*100)/100;
    self.setLight(nLight);
  }

  this.setLight = function(n) {
    self.light = n;
    self.dark = (1-n);
  }

  this.applyNavColor = function(sLinkColor) {
    var oLinks = $('nav').getElementsByTagName('a');
    var oLinks2 = $('theme-options').getElementsByTagName('a');
    for (var i = oLinks.length; i--;) {
      oLinks[i].style.color = sLinkColor;
    }
    $('theme-options').style.color = sLinkColor;
    for (i = oLinks2.length; i--;) {
      oLinks2[i].style.color = sLinkColor;
    }
  }

  this.applyLight = function() {
    // console.log('applyLight/dark: '+self.light+', '+self.dark);
    var c = [parseInt(self.color[0]*self.light),parseInt(self.color[1]*self.light),parseInt(self.color[2]*self.light)];
    var borderColor = parseInt(102+(self.light*102)); // #666 to #ccc
    var bodyColor = parseInt(self.light*255);
    var bodyColorRGB = '#'+dec2hexArray([bodyColor,bodyColor,bodyColor]).join('');

    var skyShades = [
     [0,0,0],
     [0,51,204],
     // [204,204,153], // [255,0,153],
     // [153,51,0], // [238,0,0],
     [255,153,204],
     [204,204,153],
     [153,204,255],
     [255,255,255]
    ]; // night to day, shades

    var skyShadeDiffs = [];
    for (var i=0; i<skyShades.length-1; i++) {
      skyShadeDiffs[i] = [
        skyShades[i+1][0]-skyShades[i][0],
	skyShades[i+1][1]-skyShades[i][1],
	skyShades[i+1][2]-skyShades[i][2],
      ];
    }

    var iShade = Math.floor(self.light*(skyShades.length-2));
    var shade1 = skyShades[iShade];
    var shade2 = skyShades[iShade+1];
    var nSegments = skyShades.length-2; // # of 0-100% transitions from light to dark
    var currentSegment = self.light*nSegments;
    var segRemainder = currentSegment%1; // eg. 1.50%1 = 0.5 .. thus 50% between this and next
    var shadeDiffRatio = segRemainder;
    var sRatio = shadeDiffRatio;
    var shadeDiff = [parseInt(skyShadeDiffs[iShade][0]*sRatio),parseInt(skyShadeDiffs[iShade][1]*sRatio),parseInt(skyShadeDiffs[iShade][2]*sRatio)];
    var resultShade = [shade1[0]+shadeDiff[0],shade1[1]+shadeDiff[1],shade1[2]+shadeDiff[2]];
    resultShade = [parseInt(Math.min(255,Math.max(0,resultShade[0]))),parseInt(Math.min(255,Math.max(0,resultShade[1]))),parseInt(Math.min(255,Math.max(0,resultShade[2])))];
    // find shade between current array index and next one..
    var skyShade = dec2hexArray(resultShade).join('');
    var h = dec2hexArray(c);
    var h2 = dec2hexArray([borderColor,borderColor,borderColor]);
    var h3 = dec2hexArray([bodyColor,bodyColor,bodyColor]);
    self.oSky.style.backgroundColor = 'transparent';
    var oAnim = new Y.CA($('sky'),{backgroundColor:{to:'#'+skyShade}},animDuration);
    var oAnim1 = null;
    var oAnim1_1 = new Y.A($('sky'),{opacity:{to:Math.min(1,Math.max(0.33,self.light))}},animDuration,Y.UE.easeNone);

    if (FULL_SCREEN) {
      oAnim1 = new Y.CA($('page-content'),{backgroundColor:{to:bodyColorRGB}},animDuration);
    } else {
      $('page-content').style.backgroundColor = 'transparent';
      // $('top-strip').style.backgroundColor = bodyColorRGB;
      var oTopStripBG = new Y.CA($('top-strip'),{backgroundColor:{to:bodyColorRGB}},animDuration);
      oTopStripBG.animate();
    }

    var oAnim2 = new Y.A(self.oShadeLight,{opacity:{to:self.light}},animDuration,Y.UE.easeNone);
    var oAnim3 = new Y.A(self.oShadeDark,{opacity:{to:self.dark}},animDuration*2,Y.UE.easeNone);
    var oAnim55 = new Y.A($('stars'),{opacity:{to:self.dark*0.65}},animDuration,Y.UE.easeNone);

    var oAnim6 = new Y.CA($('top-strip'),{backgroundColor:{to:'#'+h.join('')}},animDuration);
    var oAnim7 = new Y.A($('top-strip-dark'),{opacity:{to:self.dark}},animDuration*2,Y.UE.easeNone);
    oAnim7.onTween.subscribe(function(){self.applyDarkSound(Math.max(this.getAttribute('opacity')-0.25,0)/0.75*100);});

    var oAnim8 = new Y.A($('top-strip-light'),{opacity:{to:self.light}},animDuration*2,Y.UE.easeNone);
    oAnim8.onTween.subscribe(function(){self.applyLightSound(Math.max(this.getAttribute('opacity')-0.25,0)/0.75*100);});

    // car
    if (!isIE) {
      var carOpacity = [1-(self.dark*0.65),1-self.light];
      Y.D.setStyle($('wheels'),'opacity',carOpacity[0]);
      Y.D.setStyle($('whip'),'opacity',carOpacity[0]);
      Y.D.setStyle($('whip-lights'),'opacity',carOpacity[1]);
    }

    function setBorderColor() {

      // oh, what a hack. no borderColor animation in YUI anim yet - so grab tween, grab assigned color and go from there.

      var rgbString = this.getAttribute('color');
      rgbString = rgbString.substring(4,rgbString.indexOf(','));
      var rgb = dec2hex(rgbString).toString(); // eg. "rgb(64, 64, 64)" becomes "64"
      var rgbResult = ('#'+rgb+rgb+rgb);

      var nLight = parseInt(rgbString)/255;
      var adjustedRGB = dec2hex(parseInt(51+(nLight*153)));
      rgb = adjustedRGB;

      // set navigation color, in some cases
      // if (isOpera) setNavColor();

      $('header').style.borderColor = rgbResult; // this applies to the nav

      // IF also applying body background color..

      if (FULL_SCREEN) {
        rgbString = this.getAttribute('backgroundColor');
        document.documentElement.style.backgroundColor = rgbString;
        $('page-content').style.borderColor = rgbResult;
      } else {
        // account for border differences
        // var rgbi = dec2hex(255-(51+parseInt(hex2dec(rgb)/255*153))).toString();
        // console.log('inverse: '+'#'+rgbi+rgbi+rgbi);
      }

    }

    // IF backdrop includes opacity, apply accordingly
	if (backdrop.canFade && typeof backdrop.opacityRange != 'undefined') {
	  var oR = backdrop.opacityRange;
	  var oStart = oR[0];
	  var oDiff = oR[1]-oR[0];
          var toOpacity = (oStart+(oDiff*self.light));
	  var oOpacityAnim = new Y.A($('backdrop'),{opacity:{to:toOpacity}},animDuration,Y.UE.easeNone);
          oOpacityAnim.animate();
	} else {
	  // console.log('no opacity range?');
	}

    function setNavColor() {
      if (isOpera) return false;
      var rgbString = this.getAttribute('color');
      rgbString = rgbString.substring(4,rgbString.indexOf(','));
      var rgb = dec2hex(rgbString).toString(); // eg. "rgb(64, 64, 64)" becomes "64"
      var linkColor = ('#'+rgb+rgb+rgb);
      self.applyNavColor(linkColor);
    }

    var color_threshold = 0.6;

    if (self.light<color_threshold) {
      if (self.lastState != 'dark') {
        self.lastState = 'dark';
        var oT = $('theme-options');
        Y.D.removeClass(oT,'light');
        Y.D.addClass(oT,self.lastState);
        $('content').className = self.lastState;
        self.updateNavClass();     
        if (FULL_SCREEN || soundPlayer) {
          Y.D.addClass($('player-template'),'dark');
          Y.D.removeClass($('player-template'),'light');
        }
      }
    } else if (self.lastState != 'light') {
      self.lastState = 'light';
      var oT = $('theme-options');
      Y.D.removeClass(oT,'dark');
      Y.D.addClass(oT,self.lastState);
      // $('theme-options').className = self.lastState;
      $('content').className = self.lastState;
      self.updateNavClass();
      if (FULL_SCREEN || soundPlayer) {
        Y.D.addClass($('player-template'),'light');
        Y.D.removeClass($('player-template'),'dark');
        setActiveStyleSheet(self.lastState);
      }
    }

    if (FULL_SCREEN && $('col2').className != self.lastState) {
      $('col2').className = self.lastState;
    } else if (!FULL_SCREEN && $('col2').className != 'light') {
      $('col2').className = '';
    }

    var pageColor = (self.light<color_threshold?(dec2hex(153+(self.light/(color_threshold-self.light)*102))):dec2hex(51+((1-self.light)*51)));
    pageColor = [pageColor,pageColor,pageColor];

    var oAnim11 = null;
    if (FULL_SCREEN) {
      oAnim11 = new Y.CA($('page-content'),{color:{to:'#'+pageColor.join('')}},animDuration);
    } else {
      // ignore light/dark, border and all that
      $('page-content').style.color = '#333';
      $('page-content').style.borderColor = '#ccc';
    }

    var oAnim12 = null;

    if (backdrop.highContrast != 1) {
      oAnim12 = new Y.CA($('nav'),{color:{to:'#'+pageColor.join('')}},animDuration);
      oAnim12.onTween.subscribe(setNavColor);
    } else {
      // high-contrast case - set nav/link colors once
      var linkColor = (self.lastState=='dark'?'#fff':'#000');
      $('nav').style.color = linkColor;
      self.applyNavColor(linkColor);
    }

    var oAnim13 = null;
    var oAnim14 = null;

    var opacities = (self.light<color_threshold?[0,1]:[1,0]);
    if (!isIE) {
      oAnim13 = new Y.CA($('logo').getElementsByTagName('a')[0],{opacity:{to:opacities[0]}},animDuration);
      oAnim14 = new Y.CA($('logo').getElementsByTagName('div')[0],{opacity:{to:opacities[1]}},animDuration);
    }

/*
    if (isOpera) {
      var oLinks = $('nav').getElementsByTagName('a');
      var linkColor = '#'+pageColor.join('');
      for (var i=oLinks.length; i--;) {
        oLinks[i].style.color = linkColor;
      }
    }
*/
    
    var oAnim10 = new Y.CA($('meaningless'),{color:{to:'#'+h.join('')},backgroundColor:{to:'#'+h3.join('')}},animDuration);
    var oAnim15 = null;

    oAnim10.onTween.subscribe(setBorderColor);

    oAnim.animate();

    if (FULL_SCREEN) {
      oAnim1_1.animate(); // sky opacity
    } else {
      Y.D.setStyle($('sky'),0.33); // reset
    }

    if (oAnim1) oAnim1.animate();

    if (oAnim15) oAnim15.animate();

    if (!isIE) {
      if (FULL_SCREEN) setTimeout(function(){oAnim2.animate()},animDuration*1000*1.1);
      // if (FULL_SCREEN) setTimeout(function(){oAnim2.animate()},20);
      if (FULL_SCREEN) oAnim3.animate();
    }

function animatePhase2() {

    if (!IS_SLOW) oAnim6.animate();

if (FULL_SCREEN) {
    oAnim7.animate();
    oAnim8.animate();
    if (!isIE) oAnim55.animate();
}

    oAnim10.animate();

    if (oAnim11) oAnim11.animate();
    if (oAnim12) oAnim12.animate();
    if (oAnim13) oAnim13.animate();
    if (oAnim14) oAnim14.animate();
}

    animatePhase2();

  }

  this.updateNavClass = function() {
    if (isIE) {
      $('nav').className = self.lastState;
      // $('theme-options').className = self.lastState;
      return false;
    }
        var oS = $('stub');
        var oSHeight = parseInt(oS.offsetHeight);

	function oComplete() {
          $('nav').className = self.lastState;
          oS.style.backgroundImage = 'url('+urlBase+(self.lastState == 'dark'?'image/black-50.png':'image/white-50.png')+')'; // haaaack
          oS.style.backgroundPosition = ('0px -'+(oSHeight+'px'));
	  o2.animate();
	}

	var o = new Y.A(oS,{opacity:{to:0}},0.5,Y.UE.easeNone);
	var o2 = new Y.A(oS,{opacity:{to:1}},0.5,Y.UE.easeNone);

        o.onComplete.subscribe(oComplete);
	o.animate();
  }

  this.applySound = function(nLight,nDark) {
    var light = (typeof nLight != 'undefined'?nLight:self.light);
    var dark = (typeof nDark != 'undefined'?nDark:self.dark);
    self.applyLightSound(Math.max(light-0.25,0)/0.75*self.soundMultiplier);
    self.applyDarkSound(Math.max(dark-0.25,0)/0.75*self.soundMultiplier);
  }

  this.applyLightSound = function(nLight) {
    var light = parseInt(typeof nLight != 'undefined'?Math.floor(nLight):self.light);
    if (isNaN(light) || light == 'undefined') return false;
    soundManager.setVolume('birds0',light);
    soundManager.setVolume('birds1',light);
  }

  this.applyDarkSound = function(nDark) {
    var dark = parseInt(typeof nDark != 'undefined'?Math.floor(nDark):self.dark);
    if (isNaN(dark) || dark == 'undefined') return false;
    soundManager.setVolume('crickets0',dark);
    soundManager.setVolume('crickets1',dark);
  }

  this.refresh = function(nOverride) {
    self.refreshTime(nOverride);
    self.refreshLight();
    self.applyLight();
  }

}

// hex -> dec / dec -> hex
// http://www.southwest.com.au/~jfuller/binary/converter.htm

function dec2hex(cval) {
  if (cval > 255) cval = 255;
  var hexascii = "0123456789ABCDEF";
  var cval0 = Math.floor(cval/16);
  var cval1 = cval-(cval0*16);
  var c1 = hexascii.charAt(cval0);
  var c2 = hexascii.charAt(cval1);
  return (c1+c2);
}

function hex2dec(cval) {
  cval = cval.toUpperCase();
  var tval = 0;
  var hexascii = "0123456789ABCDEF";
  var mychar, ch;
  for (var c=0; c<cval.length; c++) {
    mychar = cval.charAt(c);
    for (ch=0; ch<16; ch++) {
      if (mychar == hexascii.charAt(ch)) {
        tval += ch;
	if (c<cval.length-1) tval *= 16;
      }
    }
  }
  return tval;
}

function hex2decArray(hArray) {
  var result = [];
  for (var i=0,j=hArray.length; i<j; i++) {
    result[i] = hex2dec(hArray[i]);
  }
  return result;
}

function dec2hexArray(dArray) {
  var result = [];
  for (var i=0,j=dArray.length; i<j; i++) {
    result[i] = dec2hex(dArray[i]);
  }
  return result;
}

function car() {
  if (!IS_SLOW && Y.D.hasClass(document.body,'california')) {
    var myAnim = new Y.A('car',{left:{from:-100,to:1280}},2.2,Y.UE.easeOut);
    myAnim.onTween.subscribe(doWheels);
    myAnim.onComplete.subscribe(function(){setTimeout(car,10000+parseInt(Math.random()*45000));});
    soundManager.play('car1',{volume:light.soundMultiplier});
    setTimeout(function(){myAnim.animate()},2300);
  } else {
    // try again in some time
    setTimeout(car,10000+Math.random()*45000);
  }
}

var frame = 0;

/*
var fliesFrame = -1;
var fliesTimer = null;

function doFlies() {
  fliesFrame++;
  if (fliesFrame>3) fliesFrame = -1;
  // console.log('fliesFrame: '+fliesFrame);
  $('streetlight-flies').style.backgroundPosition = '0px -'+(fliesFrame*61)+'px';
}

function startFlies() {
  fliesTimer = window.setInterval(doFlies,50);
}
*/

function doWheels() {
  frame++;
  if (frame>3) frame=0;
  $('wheels').style.backgroundPosition = '0px '+(-72+(24*frame))+'px';
}

function add2008Link() {
  var o = document.createElement('a');
  o.href = '?theme=2008';
  o.innerHTML = '2008';
  // bah, what a hack.
  o.className = 'theme-2008';
  o.title = 'Switch to 2008 theme';
  $('col2-content').appendChild(o);
  
}

function startStuff() {
  if (isOldIE) {
    return false;
  }
  light = new Light();
  setTimeout(function(){light.refresh();light.applySound();},20);
  setTimeout(car,3000+Math.random()*10000);
  // startFlies();
  sliderInit();
}

function doWindowOnload() {
  if (!IS_FAST_BROWSER && !IS_MOON_COMPUTER) {
    $('slow').checked = false;
    // IS_SLOW = true;
  } else {
    // $('slow').checked = true;
    // IS_SLOW = false;
    // Y.D[(IS_SLOW?'addClass':'removeClass')]($('body'),'slow');
    // Y.D[(IS_SLOW?'removeClass':'addClass')]($('body'),'fast');
    // applySpeedSetting();
    $('slow').checked = true;
    setTimeout(function(){toggleSlow.apply($('slow'));},1500);
  }

  doCounter();
  startStuff();

  if (!isIE || (isIE && !isOldIE)) {
    getArkanoidStuff();
    getFlickrStuff();
    lastFM.load();
  }

}

function prepNav() {
  var nav = $('nav');
  var o = nav.getElementsByTagName('dt');
  for (var i=o.length; i--;) {
    if ((i+1)%2==0) {
      o[i].className = 'alt';
    }
  }
  var items = nav.getElementsByTagName('h2');
  // Firefox tooltips can actually break dt:hover+dd
  for (i=items.length; i--;) {
    items[i].title = '';
  }
}

function toggleSlow() {
  if (isOldIE) return false;
  // this.checked = this.checked?false:true;
  IS_SLOW = this.checked?false:true;
  FULL_SCREEN = !IS_SLOW;
  Y.D[(IS_SLOW?'addClass':'removeClass')]($('body'),'slow');
  Y.D[(IS_SLOW?'removeClass':'addClass')]($('body'),'fast');
  light.applyLight();
  applySpeedSetting();
}

function toggleSlowSound() {
  soundManager.play('button'+(IS_SLOW?1:0));
}

function applySpeedSetting() {
  if (!DID_ENHANCED) {
    DID_ENHANCED = 1;
    // call jsAmp stuff
    initJSAMP();
  }
  if (!IS_SLOW) {
    initAmbiance();
  } else {
    stopAmbiance();
    $('top-strip').style.backgroundColor = '#ddd'; // reset
  }
}

function sliderUpdate(nOffset) {
  sliderUpdateCount++;
  if (sliderUpdateCount < 2) return; // ignore first call from YUI(?) and subsequent init call..
  var oS = $('sliderthumb-tip');
  if (oS) {
    oS.style.top = $('sliderthumb').offsetTop+'px';
    oS.style.visibility = 'visible';
  }
  var hour = 12-(nOffset/sliderHeight*12);
  var nLight = Math.round((hour/12)*100)/100; // round to 2 decimal places
  if (sliderUpdateTimer) window.clearTimeout(sliderUpdateTimer);
  sliderUpdateTimer = window.setTimeout(function(){removeSliderTooltip();light.setLight(nLight);light.applyLight(nLight)},500);
}

function removeSliderTooltip() {
  var oS = $('sliderthumb-tip');
  if (oS) {
    var oSAnim = new Y.A($('sliderthumb-tip'),{marginLeft:{from:0,to:32},opacity:{from:1,to:0.01}},animDuration,Y.UE.easeBothStrong);
    oSAnim.onComplete.subscribe(function(){if (oS) oS.parentNode.removeChild(oS);})
    oSAnim.animate();
  }
}

function sliderEnd() {
  // console.log('apply slider value');
}

var sliderHeight = 0;

function sliderDown() {
  $('slider').className = 'active';
  var o = new Y.BG($('sliderlegend'),{backgroundPosition:{from:[-32,8],to:[0,8],unit:['px','px']}},0.33,Y.UE.easeBothStrong);
  var oS = $('sliderthumb-tip');
  if (oS) oS.style.visibility = 'visible';
  o.animate();
  document.onmouseup = sliderUp;
}

function sliderUp() {
  $('slider').className = '';
  var o = new Y.BG($('sliderlegend'),{backgroundPosition:{from:[0,8],to:[-32,8],unit:['px','px']}},0.33,Y.UE.easeBothStrong);
  o.animate();
  document.onmouseup = null;
}

function sliderInit() {
  var oThumb = $('sliderthumb');
  oThumb.title = 'Drag to change environment light.'+(!IS_FAST_BROWSER?' (See top checkbox for enhanced FX)':'');
  sliderHeight = parseInt($('slider').offsetHeight)-16;
  slider = YAHOO.widget.Slider.getVertSlider($('sliderbg'),$('sliderthumb'),0,sliderHeight);
  slider.subscribe('change', sliderUpdate);
  // match current state
  // console.log('current Y position/'+sliderHeight+': '+(sliderHeight*(light.data.hour/24)));
  var hour = (light.data.hour>11?light.data.hour-12:light.data.hour);
  var pm = (light.data.hour>11);
  var lightValue = Math.round((hour/11)*100)/100; // round to 2 decimal places
  if (pm) lightValue = Math.round((1-lightValue)*100)/100;

  slider.subscribe('slideStart',function(){if ($('sliderthumb-tip')) $('sliderthumb-tip').style.visibility = 'hidden';});
  slider.subscribe('slideEnd',function(){if ($('sliderthumb-tip')) $('sliderthumb-tip').style.visibility = 'visible';});

  slider.setValue(sliderHeight-(sliderHeight*lightValue),true,false);

  $('sliderthumb-tip').style.top = (sliderHeight-(sliderHeight*lightValue)-1)+'px';

  var stAnim = new Y.A($('sliderthumb-tip'),{marginLeft:{from:32,to:0},opacity:{from:0.01,to:1}},animDuration,Y.UE.easeBothStrong);

  setTimeout(function(){stAnim.animate();},5000);

  Y.E.addListener(oThumb,'mousedown',sliderDown,oThumb);
}

function getScrollY1() {
  return window.scrollY;
}

function getScrollY2() {
  return ((document.documentElement && document.documentElement.scrollTop?document.documentElement.scrollTop:document.body.scrollTop)||0);
}

var getScrollY = isSafari?getScrollY1:getScrollY2;

function applyScrollSound() {
  _last_scroll_exec = new Date();
  var scrollY = getScrollY();
  var soundBarrier = 600;
  scrollY = Math.max(1,Math.min(soundBarrier,scrollY));
  var vol = Math.max(1,parseInt(Math.floor(100-(100*scrollY/soundBarrier))));
  if (light && light.soundMultiplier != vol) {
    light.soundMultiplier = vol;
    light.applySound();
  }
}

var _scroll_timer = null;
var _last_scroll_exec = new Date();

function watchScroll() {
  var scrollY = getScrollY();
  var o = $('nav');
  // set ambient volume based on scroll
  if (FULL_SCREEN) {
    var interval = 200;
    var now = new Date();
    if (now-_last_scroll_exec>interval) {
      applyScrollSound();
    } else {
      if (_scroll_timer) {
        clearTimeout(_scroll_timer);
        _scroll_timer = null;
      }
      if (!_scroll_timer) _scroll_timer = setTimeout(applyScrollSound,interval);
    }
  }
}

Y.E.addListener(window,'scroll',watchScroll);

function counterLoad() {
  runCounter();
}

function counterReadyState() {
  if (this.readyState == 'loaded' || this.readyState == 'complete') runCounter();
}

function runCounter() {
  if (_re) {
    _re.onload = null;
    _re.onreadystatechange = null;
  }
  if (typeof urchinTracker != 'undefined') urchinTracker();
  setTimeout(function(){if (typeof window.re_ != 'undefined') {window.re_('47064-bd3p5901pd');}},500);
}

function doCounter() {
  if (APP_XHTML && isSafari) {
    // can't get this crap working. Throws "undefined value, line 249" error when served as application/xhtml+xml to Safari 3.
    // return false;
  }
  try {
    _re = document.createElement('script');
    _re.onload = counterLoad;
    _re.onreadystatechange = counterReadyState;
    _re.onReadyStateChange = counterReadyState;
    _re.src = 'http://include.reinvigorate.net/re_.js';
    document.getElementsByTagName('head')[0].appendChild(_re);
  } catch(e) {
    // oh well
  }
  // if (isSafari) setTimeout(runCounter,1500);
}

  var backgrounds = [];

  var bgData = {

    // NOTE: "canFade" property dynamically applied based on isIE

    california: {
      className: 'california',
      description: 'Taken while on 101 (freeway) between Sunnyvale and San Francisco',
      background: 'transparent url(image/california.png) bottom left no-repeat',
      bgURL: urlRoot+'image/california.png',
      opacity: 0,
      highContrast: 0,
      opacityRange: [1,1]
    },

    turntables: {
      background: 'transparent url(image/bg-turntables.png) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.9,1]
    },

    seatac: {
      background: 'transparent url(image/bg-seatac.png) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 1,
      opacityRange: [1,0.9]
    },

    vernon: {
      className: 'vernon',
      description: 'A city in the southern interior of beautiful British Columbia',
      background: 'transparent url(image/vernon.jpg) no-repeat 0px 0px',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.65]
    },

    coit: {
      className: 'coit',
      description: 'A landmark building in San Francisco',
      background: 'transparent url(image/bg-coit-tower.png) no-repeat left bottom',
      bgURL: urlRoot+'image/bg-coit-tower.png',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.9]
    },

    driving: {
      className: 'driving',
      description: 'Long exposure while going along (the) 101 in California',
      background: '#fff url(image/bg-road.jpg) no-repeat 50% 50%',
      opacity: 0,
      highContrast: 1,
      opacityRange: [1,0.5]
    },

    seattle: {
      className: 'seattle',
      description: 'Seattle skyline',
      background: '#fff url(image/bg-seattle-at-night.jpg) no-repeat 0px 0px',
      opacity: 0,
      highContrast: 1,
      opacityRange: [1,0.5]
    },

    monterey: {
      background: 'transparent url(image/monterey-aquarium.jpg) no-repeat 0px 0px',
      description: 'Jellyfish admirers at the Monterey Bay Aquarium, California',
      opacity: 0,
      highContrast: 1,
      opacityRange: [0.90,0.25]
    },

    silverstar: {
      background: 'transparent url(image/bg-silverstar.png) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.9]
    },

    tr42: {
      background: 'transparent url(image/bg-tr42sea.jpg) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 1,
      opacityRange: [0.90,0.25]
    },

    cactus: {
      background: 'transparent url(image/bg-cactus.png) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.9]
    },

    kal_lake: {
      background: 'transparent url(image/bg-kal-lake-park.jpg) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.9]
    },

    silverstar2: {
      background: 'transparent url(image/bg-silverstar-chairlift.png) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.9]
    },

    vernon_lake: {
      background: 'transparent url(image/bg-vernon-lake.png) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.9]
    },

    embarcadero: {
      background: 'transparent url(image/bg-sf-embarcadero.jpg) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.9]
    },

    southpark: {
      background: 'transparent url(image/bg-sf-south-park.jpg) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.9]
    },

    yerba_buena: {
      background: 'transparent url(image/bg-sf-ybl.jpg) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.9]
    },

    pinnacles: {
      background: 'transparent url(image/bg-pinnacles.png) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 0,
      opacityRange: [0.1,0.7]
    },

    pinnacles_hole: {
      background: 'transparent url(image/bg-pinnacles-hole.jpg) no-repeat 0px 0px',
      description: '',
      opacity: 0,
      highContrast: 1,
      opacityRange: [0.1,0.9]
    },

    secret_nuke: {
      className: 'nuke',
      background: 'transparent url(image/bg-beavis-nuke.jpg) no-repeat 0px 0px',
      description: '',
      opacity: 1,
      highContrast: 1,
      opacityRange: [0.9,0.9]
    },

    predator: {
     background: 'transparent url(image/predator.jpg) no-repeat 0px 50%',
     description: 'A famous (and challenging) golf course in Vernon, BC',
     opacity: 0,
      highContrast: 0,
     opacityRange: [0.15, 0.75]
    }

  }
  void function(){
    var temp;
    for (temp in bgData) {
      bgData[temp].canFade = (!isIE || (isIE && typeof bgData[temp].bgURL == 'undefined'));
      backgrounds.push(temp);
    }
  }();

  var backdrop = null;
  var lastBackdrop = null;

var backdropIndex = 0;

function setBackdrop(n) {
  if (lastBackdrop) removeBackdrop(lastBackdrop);
  if (isNaN(n)) {
    backdrop = bgData[n];
  } else {
    var i = (typeof n != 'undefined'?n:++backdropIndex);
    if (i >= backgrounds.length) {
      i = 0;
    } else if (i < 0) {
      i = backgrounds.length-1;
    }
    backdropIndex = i;
    backdrop = bgData[backgrounds[i]];
  }
  applyBackdrop(backdrop);
  lastBackdrop = backdrop;
}

function applyBackdrop(oBackdrop) {
  if (typeof oBackdrop.className != 'undefined') Y.D.addClass($('body'),oBackdrop.className);
  var oBD = $('backdrop');
  var isPNG = oBackdrop.background.match(/.png/);
  if (typeof oBackdrop.background != 'undefined') {
    if (isOldIE && isPNG) {
      // assume there is a PNG URL for IE
      oBD.style.background = 'transparent';
      oBD.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+urlRoot+oBackdrop.bgURL+'",sizingMethod="crop")';
    } else {
      if (isOldIE) oBD.style.filter = '';
      var sBG = oBackdrop.background.replace('url(','url('+urlBase);
      oBD.style.background = sBG;

    }
  }
  if ((!isPNG || (isPNG && !isIE)) && typeof oBackdrop.opacity != 'undefined') {
    Y.D.setStyle(oBD,'opacity',oBackdrop.opacity);
  } else if (isIE && !isOldIE) {
    // Y.D.setStyle(oBD,'opacity',1); // force 100% opacity for new IE
  }
}

var FLICKR = {
 json: null,
 data: null
}

window.jsonFlickrFeed = function(oJSON) {
  FLICKR.json = oJSON;
  doFlickrStuff();
}

var sFlickr = null;

function getFlickrStuff() {
  sFlickr = document.createElement('script');
  sFlickr.src = 'http://api.flickr.com/services/feeds/photos_public.gne?id=12289718@N00&lang=en-us&format=json';
  document.getElementsByTagName('head')[0].appendChild(sFlickr);
}

function doFlickrStuff() {
  var data = FLICKR.json;
  var item = null;
  var photo = null;
  var oFrag = document.createElement('ul');
  oFrag.className = 'thumbs';
  var oItem = null;
  var i = 0;
  var limit = 16;
  for (item in data.items) {
    if (i++<limit) {
      oItem = $('flickr-photo').cloneNode(true);
      oItem.id = '';
      oItem.childNodes[0].href = data.items[item].link;
      oItem.childNodes[0].title = data.items[item].title;
      oItem.childNodes[0].childNodes[0].style.background = 'transparent url('+data.items[item].media.m.replace('_m','_s')+') 50% 50% no-repeat';
      oFrag.appendChild(oItem);
    }
  }
  var oC = document.createElement('div');
  oC.className = 'clear';
  oFrag.appendChild(oC);
  $('flickr-stub').appendChild(oFrag);
}

function getArkanoidStuff() {
  // http://www.schillmania.com/arkanoid/leveldata/user/last_five.js
  var xhr = getXHR();
  if (!xhr) return false;
  function loadHandler() {
    if (!xhr) return false;
    if (xhr.readyState == 4) {
      try {
        eval(xhr.responseText);
      } catch(e) {
        // oh well
      }
      doArkanoidStuff();
    }
  }
  xhr.open('GET','/arkanoid/leveldata/user/last_five.js?rnd='+Math.random(),true);
  xhr.onreadystatechange = loadHandler;
  xhr.setRequestHeader('Content-Type','text/javascript');
  xhr.send(null);
}

function doArkanoidStuff() {
  var nLevels = 16;
  var nOffset = lnOffset+5-nLevels;
  if (nOffset<0) {
    Y.D.getElementsByClassName('arkanoid','div',$('col2-content'))[0].style.display = 'none';
    return false; // something broke - bail.
  }
  var oItem = null;
  var oFrag = document.createElement('ul');
  oFrag.className = 'thumbs';
  for (var i=nOffset; i<nOffset+nLevels; i++) {
    oItem = $('arkanoid-level').cloneNode(true);
    oItem.id = '';
    oItem.childNodes[0].href = ('http://www.schillmania.com/arkanoid/#level'+(i+1));
    oItem.childNodes[0].childNodes[0].src = ('http://www.schillmania.com/arkanoid/preview.php?level='+i+'.png');
    oFrag.appendChild(oItem);
    oItem.childNodes[0].childNodes[0].style.width = '48px';
    oItem.childNodes[0].childNodes[0].style.height = '40px';
  }
  var oC = document.createElement('div');
  oC.className = 'clear';
  oFrag.appendChild(oC);
  $('arkanoid-stub').appendChild(oFrag);
}

function removeBackdrop(oBackdrop) {
  if (typeof oBackdrop.className != 'undefined') Y.D.removeClass($('body'),oBackdrop.className);
}

var themeOptionState = false;

function setThemeOptions(bOpen) {
  var o = $('theme-options');
  function onOA2Complete() {
    Y.D[(bOpen?'addClass':'removeClass')]($('slider'),'disabled');
  }
  function onOAComplete() {
    Y.D[(bOpen?'addClass':'removeClass')](o,'open');
    var oA2 = new Y.A(o,{opacity:{from:0,to:1}},animDuration/2,Y.UE.easeBothStrong);
    oA2.onComplete.subscribe(onOA2Complete);
    oA2.animate();
  }
  var oA = new Y.A(o,{opacity:{from:1,to:0}},animDuration/2,Y.UE.easeBothStrong);
  oA.onComplete.subscribe(onOAComplete);
  oA.animate();
}

function toggleThemeOptions() {
  var o = $('theme-options');
  var oT = $('theme-options-toggle');
  var oS = $('slider');
  themeOptionState = !themeOptionState;
  if (themeOptionState) {
    // Y.D.addClass(o,'open');
    Y.D.addClass(oS,'disabled');
  } else {
    // Y.D.removeClass(o,'open');
    Y.D.removeClass(oS,'disabled');
  }
  setThemeOptions(themeOptionState);
}

var lastNavOpen = null;

function oldBrowserInit() {
  // Apply click handlers to <h2>, toggle class
  var o = $('nav').getElementsByTagName('h2');
  for (var i=o.length; i--;) {
    o[i].onclick = function() {
      var oNext = this.nextSibling;
      oNext.className = (oNext.className == 'open'?'':'open');
      if (lastNavOpen && lastNavOpen != oNext) lastNavOpen.className = '';
      lastNavOpen = oNext;
    }
  }
  $('col2').style.display = 'none';
  $('col2-content').style.display = 'none';
  var oEl = document.createElement('a');
  oEl.style.position = 'absolute';
  oEl.style.right = '2px';
  oEl.style.top = '5px';
  oEl.style.filter = 'alpha(opacity=50)';
  oEl.href = '/?theme=2008';
  oEl.innerHTML = 'Degraded for IE 6 - try 2008 edition';
  $('nav').appendChild(oEl);

}

function preInit() {
  _uacct = "UA-3081630-1";
  // post-parse, pre-load
  var d = new Date();
  Y.D.addClass($('body'),'hasjs');
  if (IS_MOON_COMPUTER) Y.D.addClass($('body'),'moon-computer');
  if (isFirefox) Y.D.addClass(document.getElementsByTagName('html')[0],'isFirefox');
  if (isFirefox3) Y.D.addClass(document.getElementsByTagName('html')[0],'isFirefox3');
  Y.D.addClass($('body'),(IS_SLOW?'slow':'fast'));
  $('speed-form').onsubmit = function() {return false;}
  $('slow').onclick = function(){toggleSlow.apply($('slow'));toggleSlowSound();} // function() {setTimeout(toggleSlow.apply(this),20);}
  // shuffle some things around, relocate end-of-code-order to top/header (improves nav render performance also, interestingly.)
  var oS = $('slider');
  oS.parentNode.removeChild(oS);
  $('header').appendChild(oS);
  var oT = $('theme-options');
  oT.parentNode.removeChild(oT);
  $('options-stub').appendChild(oT);
  var oN = $('nav');
  oN.parentNode.removeChild(oN);
  $('header').appendChild(oN);
  if (isiPhone) {
    // iPhone needs some hacking, apparently. zIndex issue somewhere with the nav, perhaps - doesn't respond to :hover equivalent.
    $('header').style.zIndex = 99;
    $('nav').style.zIndex = 100;
    $('sky').style.zIndex = -1;
    $('sky').style.display = 'none';
    $('header').style.border = '1px solid #ff33ff';
  }
  $('theme-options-toggle').title = 'Toggle theme options';
  $('theme-options-toggle').onclick = function() {
    toggleThemeOptions();
    // setBackdrop();
    // light.applyLight();
    // return false;
  }
  if (isIE) {
    // http://misterpixel.blogspot.com/2006/09/forensic-analysis-of-ie6.html
    try {
      document.execCommand('BackgroundImageCache', false, true);
      function undoCache() {
        document.execCommand('BackgroundImageCache', false, false);
      }
      Y.E.on(window,'beforeunload',undoCache);
    } catch(e) {
      // oh well
    }
  }
  if (!isOldIE) {
    if (isIE) $('logo').getElementsByTagName('div')[0].className = ''; // new IE
    setBackdrop(0);
  } else {
    oldBrowserInit();
  }
  if (snowStorm && snowStorm.preInit) snowStorm.preInit();
  var html = '';
  for (var i=0; i<backgrounds.length; i++) {
    html += '<div><a href="#bg'+i+'">'+backgrounds[i]+'</a></div>\n';
  }
  $('theme-list').innerHTML = html;
  var items = $('theme-list').getElementsByTagName('a');
  function setBG() {
    setBackdrop(this.rel);
    light.applyLight();
    try {
      this.focus();
    } catch(e) {
      // oh well
    }
    return false;
  }
  for (i=items.length; i--;) {
    items[i].title = (bgData[backgrounds[i]].description||'');
    items[i].rel = i;
    items[i].onclick = setBG;
    if (backgrounds[i].match(/secret/i)) items[i].style.display = 'none'; // hide certain stuff
  }
  prepNav();
  $('sliderthumb-tip').title = 'Drag the slider vertically to change the lighting.';

  var oBGC = $('bg-controls');
  oBGC.getElementsByTagName('div')[0].onclick = function(){setBackdrop(backdropIndex-1);light.applyLight();}
  oBGC.getElementsByTagName('div')[1].onclick = function(){setBackdrop(backdropIndex+1);light.applyLight();}
  $('header-extras').appendChild(oBGC);

  contentManager.assignHandlers();

  var d2 = new Date();
  // if (typeof console != 'undefined' && typeof console.log != 'undefined') console.log('preInit2(): runtime: '+(d2-d)+' msec');
  add2008Link();

}

var slider = null;
var sliderUpdateTimer = null;
var sliderUpdateCount = 0;
var light = null;
var DID_ENHANCED = 0;
var nav_state = 0;

var xhr = null;
soundManager.url = urlBase+'soundmanager25.swf';
soundManager.consoleOnly = true;
soundManager.debugMode = false;
soundManager.onload = doInit;
soundManager.onerror = doInit;

window._re = null;
window.re_ = null; // function stub (redefined via call)
// vintage Arkanoid data
var lN = [];
var lnOffset = 0;


// ----------------------

  /* *************** **
  ** -- SNOWSTORM -- **
  ** *************** */


var snowStorm = null;

function SnowStorm() {
  var s = this;
  var storm = this;
  this.timers = [];
  this.flakes = [];
  this.disabled = false;
  this.terrain = [];
  this.active = false;

  var usePNG = true;
  var imagePath = urlBase+'image/snow/'; // relative path to snow images
  var flakeTypes = 6;
  var flakesMax = 128;
  var flakesMaxActive = 64;
  var vMaxX = 8;
  var vMaxY = 4;
  var flakeWidth = 5;
  var flakeHeight = 5;
  var flakeBottom = 300; // Integer for fixed bottom, 0 or null for "full-screen" snow effect
  var snowCollect = true;
  var showStatus = true;

  var zIndex = 0; // CSS "z-index", stacking order applied to each snowflake
  var flakeLeftOffset = 0; // amount to subtract from edges of container
  var flakeRightOffset = 0; // amount to subtract from edges of container

  var targetElement = 'backdrop'; // element which snow will be appended to (document body if undefined)

  // --- End of user section ---

  var isIE = (navigator.appName.toLowerCase().indexOf('internet explorer')+1);
  var isWin9X = (navigator.appVersion.toLowerCase().indexOf('windows 98')+1);
  var isOpera = (navigator.userAgent.toLowerCase().indexOf('opera ')+1 || navigator.userAgent.toLowerCase().indexOf('opera/')+1);
  if (isOpera) isIE = false; // Opera (which may be sneaky, pretending to be IE by default)
  var screenX = null;
  var screenY = null;
  var scrollY = null;
  var vRndX = null;
  var vRndY = null;
  var pngSupported = (!isIE || (isIE && !navigator.userAgent.match(/msie 6/i) && !navigator.userAgent.match(/msie 5/i))); // IE <7 doesn't support PNG nicely, or broken
  var docFrag = document.createDocumentFragment();
  this.oControl = null; // toggle element
  if (flakeLeftOffset == null) flakeLeftOffset = 0;
  if (flakeRightOffset == null) flakeRightOffset = 0;

  function rnd(n,min) {
    if (isNaN(min)) min = 0;
    return (Math.random()*n)+min;
  }

  this.randomizeWind = function() {
    vRndX = plusMinus(rnd(vMaxX,0.2));
    vRndY = rnd(vMaxY,0.2);
    if (this.flakes) {
      for (var i=0; i<this.flakes.length; i++) {
        if (this.flakes[i].active) this.flakes[i].setVelocities();
      }
    }
  }

  function plusMinus(n) {
    return (parseInt(rnd(2))==1?n*-1:n);
  }

  this.resizeHandler = function() {
    if (window.innerWidth || window.innerHeight) {
      screenX = window.innerWidth-(!isIE?24:2)-flakeRightOffset;
      screenY = (flakeBottom?flakeBottom:window.innerHeight);
    } else {
      screenX = (document.documentElement.clientWidth||document.body.clientWidth||document.body.scrollWidth)-(!isIE?8:0)-flakeRightOffset;
      screenY = flakeBottom?flakeBottom:(document.documentElement.clientHeight||document.body.clientHeight||document.body.scrollHeight);
    }
  }

  this.resizeHandlerAlt = function() {
    screenX = targetElement.offsetLeft+targetElement.offsetWidth-flakeRightOffset;
    screenY = flakeBottom?flakeBottom:targetElement.offsetTop+targetElement.offsetHeight;
  }

  this.freeze = function() {
    // pause animation
    if (!s.disabled) {
      s.disabled = 1;
    } else {
      return false;
    }
    for (var i=0; i<s.timers.length; i++) {
      clearInterval(s.timers[i]);
    }
  }

  this.resume = function() {
    if (s.disabled) {
       s.disabled = 0;
    } else {
      return false;
    }
    s.timerInit();
  }

  this.toggleSnow = function() {
    if (!s.flakes.length) {
      // first run
      s.start();
      s.setControlActive(true);
    } else {
      s.active = !s.active;
      if (s.active) {
        s.show();
        s.resume();
        s.setControlActive(true);
      } else {
        s.stop();
        s.freeze();
        s.setControlActive(false);
      }
    }
  }

  this.setControlActive = function(bActive) {
    Y.D[(bActive?'addClass':'removeClass')](s.oControl,'active');
  }

  this.stop = function() {
    this.freeze();
    for (var i=this.flakes.length; i--;) {
      this.flakes[i].o.style.display = 'none';
    }
    // removeEventHandler(window,'resize',this.resizeHandler,false);
  }

  this.show = function() {
    for (var i=this.flakes.length; i--;) {
      this.flakes[i].o.style.display = 'block';
    }
  }

  this.SnowFlake = function(parent,type,x,y) {
    var s = this;
    var storm = parent;
    this.type = type;
    this.x = x||parseInt(rnd(screenX-12));
    this.y = (!isNaN(y)?y:-12);
    this.vX = null;
    this.vY = null;
    this.vAmpTypes = [2.0,1.0,1.25,1.0,1.5,1.75]; // "amplification" for vX/vY (based on flake size/type)
    this.vAmp = this.vAmpTypes[this.type];

    this.active = 1;
    this.o = document.createElement('img');
    this.o.style.position = 'absolute';
    this.o.style.width = flakeWidth+'px';
    this.o.style.height = flakeHeight+'px';
    this.o.style.fontSize = '1px'; // so IE keeps proper size
    this.o.style.zIndex = zIndex;
    this.o.src = imagePath+this.type+(pngSupported && usePNG?'.png':'.gif');
    docFrag.appendChild(this.o);

    this.refresh = function() {
      s.o.style.left = s.x+'px';
      s.o.style.top = s.y+'px';
    }

    this.stick = function() {
      s.o.style.bottom = '0px';
      if (targetElement == document.documentElement) s.o.style.position = 'fixed';
      // set position:fixed?
      // s.o.style.top = (screenY+scrollY-flakeHeight-storm.terrain[Math.floor(s.x)])+'px';
      // called after relative left has been called
    }

    this.vCheck = function() {
      if (s.vX>=0 && s.vX<0.2) {
        s.vX = 0.2;
      } else if (s.vX<0 && s.vX>-0.2) {
        s.vX = -0.2;
      }
      if (s.vY>=0 && s.vY<0.2) {
        s.vY = 0.2;
      }
    }

    this.move = function() {
      s.x += s.vX;
      s.y += (s.vY*s.vAmp);
      s.refresh();

      if (s.vX && screenX-s.x<flakeWidth+s.vX) { // X-axis scroll check
        s.x = 0;
      } else if (s.vX<0 && s.x-flakeLeftOffset<0-flakeWidth) {
        s.x = screenX-flakeWidth; // flakeWidth;
      }
      var yDiff = screenY+scrollY-s.y-storm.terrain[Math.floor(s.x)];
      if (yDiff<flakeHeight) {
        s.active = 0;
        if (snowCollect) {
          var height = [0.75,1.5,0.75];
          for (var i=0; i<2; i++) {
            storm.terrain[Math.floor(s.x)+i+2] += height[i];
          }
        }
        s.o.style.left = (s.x/screenX*100)+'%'; // set "relative" left (change with resize)
        if (!flakeBottom) {
          s.stick();
        }
      }
    }

    this.animate = function() {
      // main animation loop
      // move, check status, die etc.
      s.move();
    }

    this.setVelocities = function() {
      s.vX = vRndX+rnd(vMaxX*0.12,0.1);
      s.vY = vRndY+rnd(vMaxY*0.12,0.1);
    }

    this.recycle = function() {
      s.o.style.position = 'absolute';
      s.setVelocities();
      s.vCheck();
      s.x = parseInt(rnd(screenX-flakeWidth-1));
      s.y = parseInt(rnd(300)*-1)-flakeHeight;
      s.active = 1;
    }

    this.recycle(); // set up x/y coords etc.
    this.refresh();

  }

  this.snow = function() {
    var active = 0;
    var used = 0;
    var waiting = 0;
    for (var i=s.flakes.length; i--;) {
      if (s.flakes[i].active == 1) {
        s.flakes[i].move();
        active++;
      } else if (s.flakes[i].active == 0) {
        used++;
      } else {
        waiting++;
      }
    }
    if (snowCollect && !waiting) { // !active && !waiting
      // create another batch of snow
      s.createSnow(flakesMaxActive,true);
    }
    if (active<flakesMaxActive) {
      with (s.flakes[parseInt(rnd(s.flakes.length))]) {
        if (!snowCollect && active == 0) {
          recycle();
        } else if (active == -1) {
          active = 1;
        }
      }
    }
  }

  this.createSnow = function(limit,allowInactive) {
    if (showStatus) window.status = 'Creating snow...';
    for (var i=0; i<limit; i++) {
      s.flakes[s.flakes.length] = new s.SnowFlake(s,parseInt(rnd(flakeTypes)));
      if (allowInactive || i>flakesMaxActive) s.flakes[s.flakes.length-1].active = -1;
    }
    targetElement.appendChild(docFrag);
    docFrag = document.createDocumentFragment();
    if (showStatus) window.status = '';
  }

  this.timerInit = function() {
    s.timers = (!isWin9X?[setInterval(s.snow,20)]:[setInterval(s.snow,75),setInterval(s.snow,25)]);
  }

  this.init = function() {
    for (var i=0; i<2048; i++) {
      s.terrain[i] = 0;
    }
    s.randomizeWind();
    s.createSnow(snowCollect?flakesMaxActive:flakesMaxActive*2); // create initial batch
    s.timerInit();
  }

this.oJoystick = null;

  this.preInit = function() {
    // create controls
    if (isOldIE) return false;
    s.oControl = document.createElement('div');
    s.oControl.className = 'snow-controls';
    s.oControl.title = 'Toggle snow';
    s.oControl.onclick = s.toggleSnow;
    s.oJoystick = document.createElement('div');
    s.oJoystick.className = 'joystick';
    s.oControl.appendChild(s.oJoystick);
    $('header-extras').appendChild(s.oControl);
  }

  this.start = function() {
    if (typeof targetElement == 'string') {
      targetElement = document.getElementById(targetElement);
      if (!targetElement) throw new Error('Snowstorm: Unable to get targetElement');
    }
    if (targetElement != document.documentElement) s.resizeHandler = s.resizeHandlerAlt; // re-map handler to get element instead of screen dimensions
    s.resizeHandler(); // get bounding box elements
    if (screenX && screenY && !s.disabled) {
      s.init();
      s.active = true;
    }
  }

  if (window.location.href.indexOf('snow=1')!=-1) Y.E.addListener(window,'load',s.start);

}

  snowStorm = new SnowStorm();


  /* *************** **
  ** -- XLSF 2007 -- **
  ** *************** */
  

function XLSF2007(oTarget) {
  var self = this;
  var xlsf = self;
  var animDuration = 1;
  this.oFrag = document.createDocumentFragment();
  this.oTarget = (oTarget||document.documentElement);
  this.oExplosionBox = document.createElement('div');
  this.oExplosionBox.className = 'xlsf-fragment-box';
  this.oExplosionFrag = document.createElement('div');
  this.oExplosionFrag.className = 'xlsf-fragment';
  this.lights = [];
  this.lightGroups = {
    left: [],
    top: [],
    right: [],
    bottom: []
  }
  this.lightSmashCounter = 0;
  this.lightIndex = 0;
  this.lightInterval = 250;
  this.timer = null;
  this.bgBaseX = 0;
  this.bgBaseY = 0;
  this.soundIDs = 0;
  this.soundPan = {
    panValue: 75,
    left: 0,
    mid: 481,
    right: 962
  }

  this.beavis = null;
  this.cover = document.createElement('div');
  this.cover.className = 'xlsf-cover';
  document.documentElement.appendChild(this.cover);

  this.doNukeCheck = function() {
    // Beavis & Butthead "Desert scene" sequence..
    if (self.lightSmashCounter < self.lights.length) return false;
    if (!self.beavis) {
      self.beavis = soundManager.createSound({id:'beavis',url:urlBase+'sound/b&b-fire-mono96vbr.mp3',autoLoad:true,onload:self.nukeSequenceReady});
    } else {
      self.nukeSequenceReady();
    }
  }

  this.nukeSequenceReady = function() {
    window.setTimeout(self.startNukeSequence,1500);
  }

  self.startNukeSequence = function() {
    // Ay - You want to something *really* cool? Huh-huh, huh huh huh, uh-huh..
    soundManager.play('beavis');
    window.setTimeout(self.explodeScreen,8250);
  }

  this.explodeScreen = function() {
    self.cover.style.display = 'block';
    var oA = new Y.A(self.cover,{opacity:{to:0.01}},4,Y.UE.easeNone);
    oA.onComplete.subscribe(self.explodeScreenComplete);
    setTimeout(function(){oA.animate();},2500); // start fading 2.5 seconds out
    var credit = document.createElement('div');
    credit.className = 'xlsf-credit';
    credit.innerHTML = 'Photo credit: <a href="http://flickr.com/photos/faberitius/749852248/">Nuclear Sunset</a> by <a href="http://flickr.com/photos/faberitius/">Faberitius</a>.';
    $('header').appendChild(credit);
    // set background, in the meantime
    // slider update?
    // sliderUpdate(max_value)
    slider.setValue(parseInt($('slider').offsetHeight)-16,true);
    setBackdrop('secret_nuke');
  }

  this.explodeScreenComplete = function() {
    self.cover.style.display = 'none';
    self.cover.style.opacity = 1;
  }

  this.initSounds = function() {
    for (var i=self.lights.length; i--;) {
      self.lights[i].initSound();
    }
    self.initSounds = function() {} // safety net
  }

  this.appendLights = function() {
    self.oTarget.appendChild(self.oFrag);
    self.oFrag = document.createDocumentFragment();
  }

  function ExplosionFragment(nType,sClass,x,y,vX,vY) {
    var self = this;
    this.o = xlsf.oExplosionFrag.cloneNode(true);
    this.nType = nType;
    this.sClass = sClass;
    this.x = x;
    this.y = y;
    this.w = 50;
    this.h = 50;
    this.bgBaseX = 0;
    this.bgBaseY = this.h*this.nType;
    this.vX = vX*(1+Math.random(0.75));
    this.vY = vY*(1+Math.random(0.75));
    this.oA = null;
    this.oA2 = null;
    this.burstPhase = 1; // starting background offset point
    this.burstPhases = 3; // 1+offset (ignore large size)
    this.o.style.backgroundPosition = ((this.w*-this.burstPhase)+'px '+(this.h*-nType)+'px');

    // boundary checks
    if (self.sClass == 'left') {
      this.vX = Math.abs(this.vX);
    } else if (self.sClass == 'right') {
      this.vX = Math.abs(this.vX)*-1;
    }
// */

    this.burstTween = function() {
      // determine frame to show
      var phase = 1+Math.floor((this.currentFrame/this.totalFrames)*self.burstPhases);
      if (phase != self.burstPhase) {
        self.burstPhase = phase;
        self.o.style.backgroundPosition = ((self.w*-self.burstPhase)+'px '+(self.h*-nType)+'px');
      }
    }

    this.burst = function() {
      self.oA = new Y.A(self.o,{marginLeft:{to:(self.vX*8)},marginTop:{to:(self.vY*8)}},animDuration,Y.UE.easeOutStrong);
      self.oA.onTween.subscribe(self.burstTween);
      // self.oA.onComplete.subscribe(self.hide);
      self.oA.animate();
    }

    this.hide = function() {
      if (!isIE) self.o.style.opacity = 0;
    }

    this.reset = function() {
      self.o.style.left = '0px';
      self.o.style.top = '0px';
      self.o.style.marginLeft = '0px';
      self.o.style.marginTop = '0px';
      if (!isIE) self.o.style.opacity = 1;
    }

    this.animate = function() {
      self.reset();
      self.burst();
    }

  }

  function Explosion(nType,sClass,x,y) {
    var oParent = this;
    var self = this;
    this.o = null;
    this.nType = nType;
    this.sClass = sClass;
    this.x = x;
    this.y = y;
    this.boxVX = 0;
    this.boxVY = 0;
    this.o = xlsf.oExplosionBox.cloneNode(true);
    this.o.style.left = x+'px';
    this.o.style.top = y+'px';
    // this.oFrag = document.createDocumentFragment();
    this.fragments = [];

    var mX = x;
    var mY = y;

    this.fragments.push(new ExplosionFragment(nType,sClass,mX,mY,-5,-5));
    this.fragments.push(new ExplosionFragment(nType,sClass,mX,mY,0,-5));
    this.fragments.push(new ExplosionFragment(nType,sClass,mX,mY,5,-5));

    this.fragments.push(new ExplosionFragment(nType,sClass,mX,mY,-5,0));
    this.fragments.push(new ExplosionFragment(nType,sClass,mX,mY,0,0));
    this.fragments.push(new ExplosionFragment(nType,sClass,mX,mY,5,0));

    this.fragments.push(new ExplosionFragment(nType,sClass,mX,mY,5,-5));
    this.fragments.push(new ExplosionFragment(nType,sClass,mX,mY,5,0));
    this.fragments.push(new ExplosionFragment(nType,sClass,mX,mY,5,5));

    this.init = function() {
      for (var i=self.fragments.length; i--;) {
        self.o.appendChild(self.fragments[i].o);
      }
      // xlsf.oTarget.appendChild(self.o);
      // self.oFrag = document.createDocumentFragment();
      if (!IS_MOON_COMPUTER) {
        // faster rendering, particles get cropped
        xlsf.oFrag.appendChild(self.o);
      } else {
        // slower rendering, can overlay body
        $('header').appendChild(self.o); 
      }
    }

    this.reset = function() {
      // clean-up
      // self.o.parentNode.removeChild(self.o);
      self.o.style.display = 'none';
      self.o.style.marginLeft = '0px';
      self.o.style.marginTop = '0px';
      self.o.style.left = self.x+'px';
      self.o.style.top = self.y+'px';
      if (!isIE) self.o.style.opacity = 1;
      for (var i=self.fragments.length; i--;) {
        self.fragments[i].reset();
      }
    }

    this.trigger = function(boxVX,boxVY) {
      self.o.style.display = 'block';
      self.boxVX = boxVX;
      self.boxVY = boxVY;
      // boundary checks
// /*
      if (self.sClass == 'right') {
        self.boxVX = Math.abs(self.boxVX)*-1;
      } else if (self.sClass == 'left') {
        self.boxVX = Math.abs(self.boxVX);
      }
// */
      for (var i=self.fragments.length; i--;) {
        self.fragments[i].animate();
      }
      if (!isIE && (FULL_SCREEN || IS_MOON_COMPUTER)) {
        var oA = new Y.A(self.o,{marginLeft:{to:100*self.boxVX},marginTop:{to:150*self.boxVY},opacity:{to:0.01}},animDuration,Y.UE.easeInStrong);
      } else {
        // even IE 7 sucks w/alpha-transparent PNG + CSS opacity. Boo urns.
        var oA = new Y.A(self.o,{marginLeft:{to:100*self.boxVX},marginTop:{to:150*self.boxVY}},animDuration,Y.UE.easeInStrong);
      }
      oA.onComplete.subscribe(self.reset);
      oA.animate();
      // setTimeout(self.reset,animDuration*1000*1.5);
    }

    this.init();

    // this.trigger(); // boooom!

  }

  function Light(sClass,nType,x,y) {
    var self = this;
    this.o = document.createElement('img');
    this.o.src = urlBase+'image/empty.gif';
    this.sClass = sClass;
    this.nType = (nType||0);
    this.useY = (sClass == 'left' || sClass == 'right');
    this.state = null;
    this.broken = 0;
    this.x = x;
    this.y = y;
    this.w = 50;
    this.h = 50;
    this.bgBaseX = (self.useY?-self.w*this.nType:0);
    this.bgBaseY = (!self.useY?-self.h*this.nType:0);
    this.glassType = parseInt(Math.random()*6);
    this.bonusSounds = ['griffin-laugh','bblaff','bblaff2'];
    this.bonusSound = null;
    this.oExplosion = null;
    this.soundID = 'smash'+xlsf.soundIDs++;
    var panValue = xlsf.soundPan.panValue; // eg. +/- 80%
    this.pan = parseInt(this.x<=xlsf.soundPan.mid?-panValue+((this.x/xlsf.soundPan.mid)*panValue):(this.x-xlsf.soundPan.mid)/(xlsf.soundPan.right-xlsf.soundPan.mid)*panValue);

    this.initSound = function() {
      soundManager.createSound({id:self.soundID,url:urlBase+'sound/glass'+this.glassType+'.mp3',autoLoad:true,pan:self.pan});
    }

    this.setBGPos = function(x,y) {
      self.o.style.backgroundPosition = ((self.bgBaseX+x)+'px '+(self.bgBaseY+y)+'px');
    }

    this.setLight = function(bOn) {
      if (self.broken || self.state == bOn) return false;
      if (!self.w || !self.h) self.getDimensions();
      self.state = bOn;
      if (self.useY) {
        self.setBGPos(0,-this.h*(bOn?0:1));
      } else {
        self.setBGPos(-this.w*(bOn?0:1),0);
      }
    }

    this.getDimensions = function() {
      self.w = self.o.offsetWidth;
      self.h = self.o.offsetHeight;
      self.bgBaseX = (self.useY?-self.w*self.nType:0);
      self.bgBaseY = (!self.useY?-self.h*self.nType:0);
    }

    this.on = function() {
      self.setLight(1);
    }

    this.off = function() {
      self.setLight(0);
    }

    this.flickr = function() {
      self.setLight(Math.random()>=0.5?1:0);
    }

    this.toggle = function() {
      self.setLight(!self.state?1:0);
    }

    this.explode = function(e) {
      // self.oExplosion = new Explosion(self.nType,self.sClass,self.x,self.y);
      self.oExplosion.trigger(0,1); // boooom!
    }

    this.smash = function(e) {
      if (self.broken) return false;
      self.broken = true;
      if (soundManager && soundManager._didInit && !soundManager._disabled) {
        soundManager.play(self.soundID,{pan:self.pan});
        if (self.bonusSound != null) window.setTimeout(self.smashBonus,1000);
      }
      self.explode(e);
      var rndFrame = 2+parseInt(Math.random()*3);
      if (self.useY) {
        self.setBGPos(0,self.h*-rndFrame);
      } else {
        self.setBGPos(self.w*-rndFrame,0);
      }
      xlsf.lightSmashCounter++;
      xlsf.doNukeCheck();
      // window.setTimeout(self.reset,3000); // respawn
    }

    this.smashBonus = function() {
      soundManager.play(self.bonusSounds[self.bonusSound],urlBase+'sound/'+self.bonusSounds[self.bonusSound]+'.mp3');
    }

    this.reset = function() {
      if (!self.broken) return false;
      self.broken = false;
      self.state = null;
      xlsf.lightSmashCounter--;
      // self.oExplosion.reset(); // may not be necessary
      self.flickr();
    }

    this.init = function() {
      self.o.className = 'xlsf-light '+this.sClass;
      self.o.style.left = x+'px';
      self.o.style.top = y+'px';
      // self.o.onmouseover = self.toggle;
      // self.o.onmouseout = self.toggle;
      self.o.onmouseover = self.smash;
      self.o.onclick = self.smash;
      self.flickr();
      xlsf.oFrag.appendChild(self.o);
      self.oExplosion = new Explosion(self.nType,self.sClass,self.x,self.y);
    }

    this.init();
    
  } // Light()

  this.createLight = function(sClass,nType,x,y) {
    var oLight = new Light(sClass,nType,x,y);
    self.lightGroups[sClass].push(oLight);
    self.lights.push(oLight);
    return oLight;
  }

  this.rotateLights = function() {
    self.lights[self.lightIndex==self.lights.length?self.lights.length-1:self.lightIndex].off();
    self.lightIndex++;
    if (self.lightIndex == self.lights.length) {
      self.lightIndex = 0;
    }
    self.lights[self.lightIndex].on();
  }

  this.randomLights = function() {
    self.lights[parseInt(Math.random()*self.lights.length)].toggle();
  }

  
  this.destroyLights = function() {
    self.startSequence(self.destroyLight,20);    
  }

  this.destroyLight = function() {
    var groupSize = 2; // # to smash at a time
    if (self.lightSmashCounter<self.lights.length) {
      var limit = Math.min(self.lightSmashCounter+groupSize,self.lights.length);
      for (var i=self.lightSmashCounter; i<limit; i++) {
        self.lights[self.lightSmashCounter].smash();
      }
    } else {
      self.stopSequence();
    }

  }

  this.uberSmash = function() {
    // make everything explode - including your CPU.
    self.stopSequence();
    var ebCN = Y.D.getElementsByClassName;
    window.setTimeout(function(){self.smashGroup(self.lightGroups.left)},500);
    window.setTimeout(function(){self.smashGroup(self.lightGroups.right)},2000);
    window.setTimeout(function(){self.smashGroup(self.lightGroups.bottom)},4000);
    window.setTimeout(function(){self.smashGroup(self.lightGroups.top)},6000);    
  }

  this.smashGroup = function(oGroup) {
    for (var i=oGroup.length; i--;) {
      oGroup[i].smash();
    }
  }

  this.startSequence = function(fSequence,nInterval) {
    if (self.timer) self.stopSequence();
    self.timer = window.setInterval(fSequence,(typeof nInterval != 'undefined'?nInterval:self.lightInterval));
  }

  this.stopSequence = function() {
    if (self.timer) {
      window.clearInterval(self.timer);
      self.timer = null;
    }
  }

  var i=0;

  for (i=0; i<6; i++) {
    this.createLight('left',parseInt(Math.random()*4),-2,50+i*35);
    this.createLight('right',parseInt(Math.random()*4),962,50+i*35);
  }

  for (i=0; i<27; i++) {
    this.createLight('top',parseInt(Math.random()*4),20+i*35,23);
    this.createLight('bottom',parseInt(Math.random()*4),20+i*35,253);
  }

  var bsCounter = 0;
  for (i=0; i<8; i++) {
    // plant a few random seeds.. er, sounds.
    self.lights[parseInt(Math.random()*self.lights.length)].bonusSound = bsCounter++;
    if (bsCounter>2) bsCounter = 0; // hack - loop through sounds
  }
  

  this.appendLights();

  // post-load/init case in the event this object is created late
  // if (soundManager && soundManager._didInit && !soundManager._disabled) this.initSounds();

  this.startSequence(self.randomLights);

  // setTimeout(this.destroyLights,10000);
  // setTimeout(this.uberSmash,10000);
  
} // --- XLSF2007()

  preInit();

} // ----- SCHILLMANIA()



var s = null;


function preInit() {
  s = new SCHILLMANIA();
}


