// <div style="width:200px"><script>
// OPod - http://eurekaman.com/opod
// Copyright (c) 2006 Rowan Nairn (http://eurekaman.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// OPod includes code from Prototype.js and script.aculo.us as marked below

/*---------------------------------------------------------*/
/* The following section has been extracted from Prototype */
/*---------------------------------------------------------*/

// Prototype JavaScript framework, version 1.3.1
// (c) 2005 Sam Stephenson <sam@conio.net>
//
// For details, see the Prototype web site: http://prototype.conio.net/

var Prototype = {
  Version: '1.3.1',
  emptyFunction: function() {}
}

var Class = {
  create: function() {
    return function() {
		this.initialize.apply(this, arguments);
    }
  }
}

Object.extend = function(destination, source) {
  for (property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Object.prototype.extend = function(object) {
  return Object.extend.apply(this, [this, object]);
}

Function.prototype.bind = function(object) {
  var __method = this;
  return function() {
    __method.apply(object, arguments);
  }
}

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0; i < arguments.length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}

function $() {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);

    if (arguments.length == 1) 
      return element;

    elements.push(element);
  }

  return elements;
}

if (!Array.prototype.push) {
  Array.prototype.push = function() {
		var startLength = this.length;
		for (var i = 0; i < arguments.length; i++)
      this[startLength + i] = arguments[i];
	  return this.length;
  }
}

if (!Function.prototype.apply) {
  // Based on code from http://www.youngpup.net/
  Function.prototype.apply = function(object, parameters) {
    var parameterStrings = new Array();
    if (!object)     object = window;
    if (!parameters) parameters = new Array();
    
    for (var i = 0; i < parameters.length; i++)
      parameterStrings[i] = 'parameters[' + i + ']';
    
    object.__apply__ = this;
    var result = eval('object.__apply__(' + 
      parameterStrings.join(', ') + ')');
    object.__apply__ = null;
    
    return result;
  }
}

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
      function() {return new XMLHttpRequest()}
    ) || false;
  }
}

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      parameters:   ''
    }.extend(options || {});
  },

  responseIsSuccess: function() {
    return this.transport.status == undefined
        || this.transport.status == 0 
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  responseIsFailure: function() {
    return !this.responseIsSuccess();
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events = 
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = (new Ajax.Base()).extend({
  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    this.request(url);
  },

  request: function(url) {
    var parameters = this.options.parameters || '';
    if (parameters.length > 0) parameters += '&_=';

    try {
      if (this.options.method == 'get')
        url += '?' + parameters;

      this.transport.open(this.options.method, url,
        this.options.asynchronous);

      if (this.options.asynchronous) {
        this.transport.onreadystatechange = this.onStateChange.bind(this);
        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
      }

      this.setRequestHeaders();

      var body = this.options.postBody ? this.options.postBody : parameters;
      this.transport.send(this.options.method == 'post' ? body : null);

		if(this.options.onTimeout) this.timer = setTimeout(this.onTimeout.bind(this),5000);
    } catch (e) {
    }
  },

  setRequestHeaders: function() {
    var requestHeaders = 
      ['X-Requested-With', 'XMLHttpRequest',
       'X-Prototype-Version', Prototype.Version];

    if (this.options.method == 'post') {
      requestHeaders.push('Content-type', 
        'application/x-www-form-urlencoded');

      /* Force "Connection: close" for Mozilla browsers to work around
       * a bug where XMLHttpReqeuest sends an incorrect Content-length
       * header. See Mozilla Bugzilla #246651. 
       */
      if (this.transport.overrideMimeType)
        requestHeaders.push('Connection', 'close');
    }

    if (this.options.requestHeaders)
      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

    for (var i = 0; i < requestHeaders.length; i += 2)
      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState != 1)
      this.respondToReadyState(this.transport.readyState);
  },

  onTimeout: function() {
    this.options.onTimeout();
	this.transport.onreadystatechange = Prototype.emptyFunction;
  },

  respondToReadyState: function(readyState) {
    var event = Ajax.Request.Events[readyState];

    if (event == 'Complete'){
      (this.options['on' + this.transport.status]
       || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
       || Prototype.emptyFunction)(this.transport);
	  if(this.timer) clearTimeout(this.timer);
	}

    (this.options['on' + event] || Prototype.emptyFunction)(this.transport);

    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
    if (event == 'Complete')
      this.transport.onreadystatechange = Prototype.emptyFunction;
  }
});

if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
  stop: function(event) {
    if (event.preventDefault) { 
      event.preventDefault(); 
      event.stopPropagation(); 
    } else {
      event.returnValue = false;
		event.cancelBubble = true;
    }
  },

  observers: false,
  
  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];
    if (element.addEventListener) {
      this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
      this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' + name, observer);
    }
  },
  
  unloadCache: function() {
    if (!Event.observers) return;
    for (var i = 0; i < Event.observers.length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;
    
    if (name == 'keypress' &&
        ((navigator.appVersion.indexOf('AppleWebKit') > 0) 
        || element.attachEvent))
      name = 'keydown';
    
    this._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;
    
    if (name == 'keypress' &&
        ((navigator.appVersion.indexOf('AppleWebKit') > 0) 
        || element.detachEvent))
      name = 'keydown';
    
    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      element.detachEvent('on' + name, observer);
    }
  }
});

/* prevent memory leaks in IE */
Event.observe(window, 'unload', Event.unloadCache, false);

var Position = {
  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return [valueL, valueT];
  }
}

/*---------------------------------------------------------------*/
/* The following section has been extracted from script.aculo.us */
/*---------------------------------------------------------------*/

// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// Parts (c) 2005 Justin Palmer (http://encytemedia.com/)
// Parts (c) 2005 Mark Pilgrim (http://diveintomark.org/)

Effect = {}

/* ------------- transitions ------------- */

Effect.Transitions = {}

Effect.Transitions.sinoidal = function(pos) {
  return (-Math.cos(pos*Math.PI)/2) + 0.5;
}

/* ------------- core effects ------------- */

Effect.Base = function() {};
Effect.Base.prototype = {
  setOptions: function(options) {
    this.options = Object.extend({
      transition: Effect.Transitions.sinoidal,
      duration:   1.0,   // seconds
      fps:        25.0,  // max. 100fps
      sync:       false, // true for combining
      from:       0.0,
      to:         1.0
    }, options || {});
  },
  start: function(options) {
    this.setOptions(options || {});
    this.currentFrame = 0;
    this.startOn      = new Date().getTime();
    this.finishOn     = this.startOn + (this.options.duration*1000);
    if(this.options.beforeStart) this.options.beforeStart(this);
    if(!this.options.sync) this.loop();  
  },
  loop: function() {
    var timePos = new Date().getTime();
    if(timePos >= this.finishOn) {
      this.render(1.0);
      if(this.finish) this.finish(); 
      if(this.options.afterFinish) this.options.afterFinish(this);
      return;  
    }
    var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
    var frame = Math.round(pos * this.options.fps * this.options.duration);
    if(frame > this.currentFrame) {
      this.render(pos);
      this.currentFrame = frame;
    }
    this.timeout = setTimeout(this.loop.bind(this), 10);
  },
  render: function(pos) {
    if(this.options.transition) pos = this.options.transition(pos);
    pos *= (this.options.to-this.options.from);
    pos += this.options.from; 
    if(this.options.beforeUpdate) this.options.beforeUpdate(this);
    if(this.update) this.update(pos);
    if(this.options.afterUpdate) this.options.afterUpdate(this);  
  },
  cancel: function() {
    if(this.timeout) clearTimeout(this.timeout);
  }
}

Effect.Parallel = Class.create();
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
  initialize: function(effects) {
    this.effects = effects || [];
    this.start(arguments[1]);
  },
  update: function(position) {
    for (var i = 0; i < this.effects.length; i++)
      this.effects[i].render(position);  
  },
  finish: function(position) {
    for (var i = 0; i < this.effects.length; i++)
      if(this.effects[i].finish) this.effects[i].finish(position);
  }
});

// Internet Explorer caveat: works only on elements the have
// a 'layout', meaning having a given width or height. 
// There is no way to safely set this automatically.
Effect.Opacity = Class.create();
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    options = Object.extend({
      from: 0.0,
      to:   1.0
    }, arguments[1] || {});
    this.start(options);
  },
  update: function(position) {
    this.setOpacity(position);
  }, 
  setOpacity: function(opacity) {
    opacity = (opacity == 1) ? 0.99999 : opacity;
    this.element.style.opacity = opacity;
    this.element.style.filter = "alpha(opacity:"+opacity*100+")";
  }
});


/*----------------------------------------------*/
/* The following section is the core of OPod.js */
/*----------------------------------------------*/

// OPod - http://eurekaman.com/opod
// Copyright (c) 2006 Rowan Nairn (http://eurekaman.com)

Effect.ScrollDivToX = Class.create();
Object.extend(Object.extend(Effect.ScrollDivToX.prototype, Effect.Base.prototype), {
	initialize: function(element,x) {
		this.element = $(element);
		this.scrollStart = element.scrollLeft;
		this.delta = x - this.scrollStart;
		this.start(arguments[2] || {});
	},
	update: function(position) {
		this.element.scrollLeft = this.scrollStart + position*this.delta;
	}
});

Effect.ExpandTo = Class.create();
Object.extend(Object.extend(Effect.ExpandTo.prototype, Effect.Base.prototype), {
  initialize: function(element, toLeft, toWidth) {
	this.element = $(element);
	this.originalLeft  = this.element.offsetLeft;
	this.originalWidth = this.element.offsetWidth;
	this.deltaLeft     = toLeft -this.originalLeft;
	this.deltaWidth    = toWidth - this.originalWidth;
	this.start(arguments[3]);
  },
  update: function(position) {
	this.element.style.left  = (this.originalLeft + position*this.deltaLeft)+'px';
	this.element.style.width = (this.originalWidth + position*this.deltaWidth) +'px';
  }
});

var opmlPod = {
	path: 'http://eurekaman.com/opod',
	xid:0,
	initialize: function(){
		this.head = document.getElementsByTagName("head")[0];
		var link = document.createElement('link');
		link.rel  = 'stylesheet';
		link.href = this.path+'/OPod.css';
		this.head.appendChild(link);
	
		this.element = $('opmlPod');
		this.frameWidth = $('opmlPod_scroller').offsetWidth;
		this.targetWidth = parseInt(this.frameWidth*2.5);
		this.windowWidth = $('opmlPod_window').offsetWidth;
		
		Event.observe(this.element,'mouseover',function(e){
			$('opmlPod_expander').style.visibility = 'visible';
			$('opmlPod_credits').style.visibility = 'visible';
			Event.stop(e);
		});
		Event.observe(document,'mouseover',function(){
			$('opmlPod_expander').style.visibility = 'hidden';
			$('opmlPod_credits').style.visibility = 'hidden';
		});
	},
	expand: function(){
		$('opmlPod_expand').style.display = 'none';
		$('opmlPod_contract').style.display = 'inline';
		
		var element = $('opmlPod_window');
		var o = Position.cumulativeOffset(element);
		var targetLeft = element.offsetLeft;
		
		if(o[0]+element.offsetWidth > (document.documentElement || document.body).offsetWidth/2)
			targetLeft = targetLeft - (this.targetWidth - element.offsetWidth);
	
		this.element.className = 'expanded';
		var scroller = $('opmlPod_scroller');
		scroller.style.overflow = 'scroll';
		this.targetClientWidth = this.targetWidth + scroller.clientWidth - scroller.offsetWidth;
		
		if(this.expandEffect) this.expandEffect.cancel();
		this.expandEffect = new Effect.ExpandTo(element, targetLeft, this.targetWidth);
		this.expanded = true;
	},
	contract: function(){
		$('opmlPod_contract').style.display = 'none';
		$('opmlPod_expand').style.display = 'inline';
		
		var scroller = $('opmlPod_scroller');
		
		if(this.expandEffect) this.expandEffect.cancel();
		if(this.scrollEffect) this.scrollEffect.cancel();
		this.expandEffect = new Effect.Parallel([
			new Effect.ScrollDivToX(scroller, 0, {sync:true}),
			new Effect.ExpandTo($('opmlPod_window'), 0, this.windowWidth, {sync:true})
		],{
			afterFinish: function(){
				scroller.style.overflow = 'hidden';
				this.element.className = 'contracted';
			}
		});
		this.expanded = false;
	},
	insertFrame: function(contents,el,width){
		if(!el) el=$('opmlPod_scroller');
		if(!width) width=opmlPod.frameWidth;
		contents = contents.replace(/>\s+</g,'><'); // IE bug
		el.innerHTML = '<div class="opmlPod_frame" style="width:'+width+'px;">'+contents+'<hr/></div><div style="left:'+width+'px;" class="opmlPod_container"></div>';
		
		var scroller = $('opmlPod_scroller');
		if(this.scrollEffect) this.scrollEffect.cancel();
		this.scrollEffect = new Effect.ScrollDivToX(scroller,scroller.scrollWidth - (this.targetClientWidth || scroller.clientWidth));
		
		new Effect.Opacity(el.firstChild,{
			afterUpdate: function(effect){
				effect.element.style.visibility='visible';
			}
		});
	},
	refresh: function(url,src){
		if(!this.expanded) this.expand();
		el = this.classParent('opmlPod_container',src);
		this.load(url,el,this.frameWidth);
	},
	insert: function(url,src){
		this.selectLink(src);
		el = this.classParent('opmlPod_frame',src).nextSibling;
		this.load(url,el,this.frameWidth);
	},
	load: function(url,el,width){
		if(!el) el=$('opmlPod_scroller');
		el.innerHTML = '<div class="opmlPod_frame" style="visibility:visible;">Loading...</div>';
	
		var script = document.createElement('script');
		script.setAttribute('src','http://grazr.com/perl/xml2on.pl?url='+encodeURIComponent(url)+'&xid='+this.xid);
		this.head.appendChild(script);
		
		this.nextContainer = el;
		++this.xid;
		this.element.style.cursor = 'wait';
		/*new Ajax.Request(this.path+'/opml_async.php',{
			method: 'get',
			parameters:params,
			onSuccess: function(transport){
				opmlPod.insertFrame(transport.responseText,el,width);
			}
		});*/
	},
	onReceive: function(html,xid){
		if(xid == this.xid-1){
			this.element.style.cursor = '';
			this.insertFrame(html,this.nextContainer);
		}
	},
	showList: function(link){
		var list = '<div id="contents" style="position:relative;overflow:hidden;"><ul class="opmlPod_list">'+link.nextSibling.innerHTML+'</ul></div>';
		this.show(list,link,this.frameWidth);
	},
	showSummary: function(link){
		var summary = '<div id="contents" style="position:relative;overflow:hidden;">'+link.nextSibling.innerHTML+'</div>';
		this.show(summary,link,400);
	},
	show: function(html,link,width){
		this.selectLink(link);
		var el = this.classParent('opmlPod_frame',link).nextSibling;
		this.insertFrame(html,el,width);
	},
	selectLink: function(link){
		var ul = this.classParent('opmlPod_list',link);
	
		if(ul.selectedLink) ul.selectedLink.className = 'normal';
		link.className = 'selected';
		ul.selectedLink = link;
		
		if(!this.expanded) this.expand();
	},
	classParent: function(c,el){
		while(el && el.className != c) el = el.parentNode;
		return el;
	}
};

Event.observe(window,'load',function(){
	opmlPod.initialize();
	if(window.initUrl){
		var link = initUrl.match(/^<a href="([^"]+)"/i);
		if(link) initUrl = link[1];
	
		opmlPod.load(initUrl);
	}
});

document.writeln('<div align="left" id="opmlPod" style="position:relative;">'
					+'<div id="opmlPod_expander" style="visibility:hidden;">'
						+'<a id="opmlPod_expand" href="javascript:opmlPod.expand();" style="display:inline;"><img src="'+opmlPod.path+'/expand.gif" border="0"/> expand</a>'
						+'<a id="opmlPod_contract" href="javascript:opmlPod.contract();" style="display:none;"><img src="'+opmlPod.path+'/contract.gif" border="0"/> contract</a>'
					+'</div>'
					+'<div id="opmlPod_credits" style="visibility:hidden;"><a href="http://eurekaman.com/opod">OPod</a>: powered by <a href="http://grazr.com">Grazr</a></div>'
					+'<div id="opmlPod_window" style="position:absolute;width:100%;"><div style="border:1px solid #999;background-color:#FFF;">'
						+'<div><div id="opmlPod_scroller" class="opmlPod_container" style="width:100%;left:0;position:relative;overflow:hidden;"><div class="opmlPod_frame" style="visibilty:visible">Loading...</div></div></div>'
					+'</div></div>'
				+'</div>');

function parseNodes(nodes){
	if(!nodes) return '';
	var html = '';
	for(var i=0; i<nodes.length; i++){
		var outline = nodes[i].outline;
		var text = unescape(outline.attribute.text || outline.attribute.title);
		var type = (unescape(outline.attribute.type) || '').toLowerCase();
		if(type == 'rss-story'){
			var body = unescape(outline.childNodes[3].outline.attribute.text);
			var link = decodeURI(outline.childNodes[4].outline.attribute.htmlUrl);
		
			html += '<li>'
						+'<a class="normal" href="'+link+'" target="_top" onclick="opmlPod.showSummary(this);return false;">'+text+'</a>'
						+'<div>'
							+'<h3><a class="normal" href="'+link+'" target="_top">'+text+'</a></h3>'
							+'<p>'+body+'</p>'
						+'</div>'
					+'</li>';
		} else {
			var url = outline.attribute.xmlUrl || outline.attribute.url || outline.attribute.htmlUrl;
			if(url) url = decodeURI(url);
			
			html += '<li>'
			if(url && (url.search(/\.opml$/) != -1 || type=='opml' || type=='include')){
				html += '<a class="normal" href="'+url+'" onclick="opmlPod.insert(\''+url+'\',this);return false;">'+text+'</a>';
			} else if(url && type!='rss'){
				html += '<a class="link" href="'+url+'" target="_top">'+text+'</a>';
			} else if(url){
				var htmlUrl = decodeURI(outline.attribute.htmlUrl || outline.attribute.url || outline.attribute.xmlUrl);
				var xmlUrl = decodeURI(outline.attribute.xmlUrl || outline.attribute.url);
				html += '<a class="normal" href="'+htmlUrl+'" target="_top" onclick="opmlPod.insert(\''+xmlUrl+'\',this);return false;">'+text+'</a>';
			} else {
				html += '<a class="normal" href="#" target="_top" onclick="opmlPod.showList(this);return false;">'+text+'</a>';
			}
			html += '<ul class="opmlPod_list">'
						+parseNodes(outline.childNodes)
					+'</ul>'
				+'</li>'
		}
	}
	return html;
}

var oldxdReceive = function(){};
if(window.xdReceive) oldxdReceive = xdReceive;
window.xdReceive = function(xid,node){
	oldxdReceive(xid,node);
	document.node = node;
	var nodes = node.opml.childNodes[1].body.childNodes;
	var html = '<div style="position:relative;overflow:hidden;">'
				+'<ul class="opmlPod_list">'
					+parseNodes(nodes)
				+'</ul>'
			+'</div>';
	opmlPod.onReceive(html,xid);
}
				
//</script></div>