/*
 * 	Easy Slider 1.7 - jQuery plugin
 *	written by Alen Grakalic
 *	http://cssglobe.com/post/4004/easy-slider-15-the-easiest-jquery-plugin-for-sliding
 *
 *	Copyright (c) 2009 Alen Grakalic (http://cssglobe.com)
 *	Dual licensed under the MIT (MIT-LICENSE.txt)
 *	and GPL (GPL-LICENSE.txt) licenses.
 *
 *	Built for jQuery library
 *	http://jquery.com
 *
 */

/*
 *	markup example for $("#slider").easySlider();
 *
 * 	<div id="slider">
 *		<ul>
 *			<li><img src="images/01.jpg" alt="" /></li>
 *			<li><img src="images/02.jpg" alt="" /></li>
 *			<li><img src="images/03.jpg" alt="" /></li>
 *			<li><img src="images/04.jpg" alt="" /></li>
 *			<li><img src="images/05.jpg" alt="" /></li>
 *		</ul>
 *	</div>
 *
 */

(function($) {

	$.fn.easySlider = function(options){

		// default configuration properties
		var defaults = {
			prevId: 		'prevBtn',
			prevText: 		'Previous',
			nextId: 		'nextBtn',
			nextText: 		'Next',
			controlsShow:	true,
			controlsBefore:	'',
			controlsAfter:	'',
			controlsFade:	true,
			firstId: 		'firstBtn',
			firstText: 		'First',
			firstShow:		false,
			lastId: 		'lastBtn',
			lastText: 		'Last',
			lastShow:		false,
			vertical:		false,
			speed: 			800,
			auto:			false,
			pause:			2000,
			continuous:		false,
			numeric: 		false,
			numericId: 		'controls'
		};

		var options = $.extend(defaults, options);

		this.each(function() {
			var obj = $(this);
			var s = $("li", obj).length;
			var w = $("li", obj).width();
			var h = $("li", obj).height();
			var clickable = true;
			obj.width(w);
			obj.height(h);
			obj.css("overflow","hidden");
			var ts = s-1;
			var t = 0;
			$("ul", obj).css('width',s*w);

			if(options.continuous){
				$("ul", obj).prepend($("ul li:last-child", obj).clone().css("margin-left","-"+ w +"px"));
				$("ul", obj).append($("ul li:nth-child(2)", obj).clone());
				$("ul", obj).css('width',(s+1)*w);
			};

			if(!options.vertical) $("li", obj).css('float','left');

			if(options.controlsShow){
				var html = options.controlsBefore;
				if(options.numeric){
					html += '<ol id="'+ options.numericId +'"></ol>';
				} else {
					if(options.firstShow) html += '<span id="'+ options.firstId +'"><a href=\"javascript:void(0);\">'+ options.firstText +'</a></span>';
					html += ' <span id="'+ options.prevId +'"><a href=\"javascript:void(0);\">'+ options.prevText +'</a></span>';
					html += ' <span id="'+ options.nextId +'"><a href=\"javascript:void(0);\">'+ options.nextText +'</a></span>';
					if(options.lastShow) html += ' <span id="'+ options.lastId +'"><a href=\"javascript:void(0);\">'+ options.lastText +'</a></span>';
				};

				html += options.controlsAfter;
				$(obj).after(html);
			};

			if(options.numeric){
                                $(document.createElement("li"))
						.attr('id','prevBtn')
						.html('<a href=\"#\">Previous</a>')
						.appendTo($("#"+ options.numericId))
						.click(function(){
							animate("prev",true);
						});
				for(var i=0;i<s;i++){
					$(document.createElement("li"))
						.attr('id',options.numericId + (i+1))
						.html('<a rel='+ i +' href=\"javascript:void(0);\">'+ (i+1) +'</a>')
						.appendTo($("#"+ options.numericId))
						.click(function(){
							animate($("a",$(this)).attr('rel'),true);
						});
				};

                                $(document.createElement("li"))
						.attr('id','nextBtn')
						.html('<a href=\"#\">Next</a>')
						.appendTo($("#"+ options.numericId))
						.click(function(){
							animate("next",true);
						});
			} else {
				$("a","#"+options.nextId).click(function(){
					animate("next",true);
				});
				$("a","#"+options.prevId).click(function(){
					animate("prev",true);
				});
				$("a","#"+options.firstId).click(function(){
					animate("first",true);
				});
				$("a","#"+options.lastId).click(function(){
					animate("last",true);
				});
			};

			function setCurrent(i){
				i = parseInt(i)+1;
				$("li", "#" + options.numericId).removeClass("current");
				$("li#" + options.numericId + i).addClass("current");
			};

			function adjust(){
				if(t>ts) t=0;
				if(t<0) t=ts;
				if(!options.vertical) {
					$("ul",obj).css("margin-left",(t*w*-1));
				} else {
					$("ul",obj).css("margin-left",(t*h*-1));
				}
				clickable = true;
				if(options.numeric) setCurrent(t);
			};

			function animate(dir,clicked){
				if (clickable){
					clickable = false;
					var ot = t;
					switch(dir){
						case "next":
							t = (ot>=ts) ? (options.continuous ? t+1 : ts) : t+1;
							break;
						case "prev":
							t = (t<=0) ? (options.continuous ? t-1 : 0) : t-1;
							break;
						case "first":
							t = 0;
							break;
						case "last":
							t = ts;
							break;
						default:
							t = dir;
							break;
					};
					var diff = Math.abs(ot-t);
					var speed = diff*options.speed;
					if(!options.vertical) {
						p = (t*w*-1);
						$("ul",obj).animate(
							{ marginLeft: p },
							{ queue:false, duration:speed, complete:adjust }
						);
					} else {
						p = (t*h*-1);
						$("ul",obj).animate(
							{ marginTop: p },
							{ queue:false, duration:speed, complete:adjust }
						);
					};

					if(!options.continuous && options.controlsFade){
						if(t==ts){
							$("a","#"+options.nextId).hide();
							$("a","#"+options.lastId).hide();
						} else {
							$("a","#"+options.nextId).show();
							$("a","#"+options.lastId).show();
						};
						if(t==0){
							$("a","#"+options.prevId).hide();
							$("a","#"+options.firstId).hide();
						} else {
							$("a","#"+options.prevId).show();
							$("a","#"+options.firstId).show();
						};
					};

					if(clicked) clearTimeout(timeout);
					if(options.auto && dir=="next" && !clicked){;
						timeout = setTimeout(function(){
							animate("next",false);
						},diff*options.speed+options.pause);
					};

				};

			};
			// init
			var timeout;
			if(options.auto){;
				timeout = setTimeout(function(){
					animate("next",false);
				},options.pause);
			};

			if(options.numeric) setCurrent(0);

			if(!options.continuous && options.controlsFade){
				$("a","#"+options.prevId).hide();
				$("a","#"+options.firstId).hide();
			};

		});

	};

})(jQuery);


/* idTabs ~ Sean Catchpole - Version 2.2 - MIT/GPL */
(function(){
var dep = {"jQuery":"http://code.jquery.com/jquery-latest.min.js"};
var init = function(){

/* Options (in any order):

 start (number|string)
    Index number of default tab. ex: $(...).idTabs(0)
    String of id of default tab. ex: $(...).idTabs("tab1")
    default: class "selected" or index 0
    Passing null will force it to not select a default tab

 change (boolean)
    True - Url will change. ex: $(...).idTabs(true)
    False - Url will not change. ex: $(...).idTabs(false)
    default: false

 click (function)
    Function will be called when a tab is clicked. ex: $(...).idTabs(foo)
    If the function returns true, idTabs will show/hide content (as usual).
    If the function returns false, idTabs will not take any action.
    The function is passed four variables:
      The id of the element to be shown
      an array of all id's that can be shown
      the element containing the tabs
      and the current settings

 selected (string)
    Class to use for selected. ex: $(...).idTabs(".current")
    default: ".selected"

 event (string)
    Event to trigger idTabs on. ex: $(...).idTabs("!mouseover")
    default: "!click"
    To bind multiple event, call idTabs multiple times
      ex: $(...).idTabs("!click").idTabs("!focus")

*/
(function($){

  $.fn.idTabs = function(){
    //Loop Arguments matching options
    var s = {};
    for(var i=0; i<arguments.length; ++i) {
      var a=arguments[i];
      switch(a.constructor){
        case Object: $.extend(s,a); break;
        case Boolean: s.change = a; break;
        case Number: s.start = a; break;
        case Function: s.click = a; break;
        case String:
          if(a.charAt(0)=='.') s.selected = a;
          else if(a.charAt(0)=='!') s.event = a;
          else s.start = a;
        break;
      }
    }

    if(typeof s['return'] == "function") //backwards compatible
      s.change = s['return'];

    return this.each(function(){ $.idTabs(this,s); }); //Chainable
  }

  $.idTabs = function(tabs,options) {
    //Settings
    var meta = ($.metadata)?$(tabs).metadata():{};
    var s = $.extend({},$.idTabs.settings,meta,options);

    //Play nice
    if(s.selected.charAt(0)=='.') s.selected=s.selected.substr(1);
    if(s.event.charAt(0)=='!') s.event=s.event.substr(1);
    if(s.start==null) s.start=-1; //no tab selected

    //Setup Tabs
    var showId = function(){
      if($(this).is('.'+s.selected))
        return s.change; //return if already selected
      var id = "#"+this.href.split('#')[1];
      var aList = []; //save tabs
      var idList = []; //save possible elements
      $("a",tabs).each(function(){
        if(this.href.match(/#/)) {
          aList.push(this);
          idList.push("#"+this.href.split('#')[1]);
        }
      });
      if(s.click && !s.click.apply(this,[id,idList,tabs,s])) return s.change;
      //Clear tabs, and hide all
      for(i in aList) $(aList[i]).removeClass(s.selected).parent().find('header').removeClass(s.selected);
      for(i in idList) $(idList[i]).hide();
      //Select clicked tab and show content
      $(this).addClass(s.selected).parent().find('header').addClass(s.selected);
      $(id).show();
      return s.change; //Option for changing url
    }

    //Bind idTabs
    var list = $("a[href*='#']",tabs).unbind(s.event,showId).bind(s.event,showId);
    list.each(function(){ $("#"+this.href.split('#')[1]).hide(); });

    //Select default tab
    var test=false;
    if((test=list.filter('.'+s.selected)).length); //Select tab with selected class
    else if(typeof s.start == "number" &&(test=list.eq(s.start)).length); //Select num tab
    else if(typeof s.start == "string" //Select tab linking to id
         &&(test=list.filter("[href*='#"+s.start+"']")).length);
    if(test) { test.removeClass(s.selected); test.trigger(s.event); } //Select tab

    return s; //return current settings (be creative)
  }

  //Defaults
  $.idTabs.settings = {
    start:0,
    change:false,
    click:null,
    selected:".selected",
    event:"!click"
  };

  //Version
  $.idTabs.version = "2.2";

  //Auto-run
  $(function(){ $(".idTabs").idTabs(); });

})(jQuery);



} //init

// Check Dependencies
var check = function(o,s){
  s = s.split('.');
  while(o && s.length) o = o[s.shift()];
  return o;
}

// Add Script
var head = document.getElementsByTagName("head")[0];
var add = function(url){
  var s = document.createElement("script");
  s.type = "text/javascript"; s.src = url;
  head.appendChild(s);
}

// Save Self
var s = document.getElementsByTagName('script');
var src = s[s.length-1].src;

// Load Dependencies
var ok=true;
for(d in dep) {
  if(check(this,d)) continue;
  ok=false;
  add(dep[d]);
} if(ok) return init();

// Reload Self
add(src);

})();


/*
 * jTweetsAnywhere V1.2.1
 * http://thomasbillenstein.com/jTweetsAnywhere/
 *
 * Copyright 2010, Thomas Billenstein
 * Licensed under the MIT license.
 * http://thomasbillenstein.com/jTweetsAnywhere/license.txt
 */
(function($)
{
	$.fn.jTweetsAnywhere = function(options)
	{
		// setup the default options
		var options = $.extend(
		{
			/**
			 * The user's name who's tweet feed or list feed is displayed. This
			 * param is also used when a Twitter "Follow Button" is displayed. Usually
			 * this param is a string, but can also be an array of strings. If an array
			 * is supplied (and the params 'list' and 'searchParams' are null), a
			 * combined feed of all users is displayed.
			 *
			 * Sample: 'tbillenstein' or ['twitterapi', '...', '...']
			 */
			username: 'tbillenstein',

			/**
			 * The name of a user's list where the tweet feed is generated from
			 */
			list: null,

			/**
			 * A single search param string or an array of search params, to be used in
			 * a Twitter search call. All Twitter Search Params are supported
			 * See here for the details:
			 * http://apiwiki.twitter.com/Twitter-Search-API-Method%3A-search
			 *
			 * Sample: 'q=twitter' or ['q=twitter', 'geocode=48.856667,2.350833,30km']
			 */
			searchParams: null,

			/**
			 * The number of tweets shown in the tweet feed. If this param is 0, no feed
			 * is displayed. For user or list feeds the maximum count is 20, for search
			 * results the maximum count is 100.
			 *
			 * Unlike in previous releases, since 1.2.0 jTweetsAnywhere is based on a
			 * tweets caching algorithm that will always deliver the requested count of
			 * tweets accepting that this request can only be fullfilled by calling Twitter
			 * more than once.
			 *
			 * IMPORTANT: Please always keep in mind, that the use of the Twitter API is
			 * rate limited. Non-authenticated users are rated IP-based and you have only
			 * 150 calls per hour available. Every retrieval of tweets counts and so does
			 * for example hovering over a profile image to show the hovercard.
			 * jTweetsAnywhere will always check the remaining count of free API calls before
			 * actually calling Twitter to avoid black listing your visitor's IP.
			 */
			count: 0,

			/**
			 * A flag (true/false) that specifies whether to display a profile image in
			 * tweets. If the param is set to null (the default value), a profile image
			 * is displayed only if the feed represents a user's list or the result of a
			 * Twitter search.
			 *
			 * THIS OPTION IS DEPRECATED. You should use showTweetFeed.showProfileImages
			 * instead.
			 */
			tweetProfileImagePresent: null,

			/**
			 * Each tweet that is loaded from Twitter will pass the tweetFilter. if
			 * the filter returns true, the tweet will be added to the tweets cache
			 * otherwise it is ignored. The defaultTweetFilter alsways retruns true
			 * but you can supply your own tweet filter to customize the tweet feed.
			 */
			tweetFilter: defaultTweetFilter,

			/**
			 * A flag (true/false) that specifies whether to display a Tweet Feed
			 * or an object literal representing the configuration options for the
			 * Tweet Feed. This flag works in conjunction with the count parameter:
			 * - if count equals 0, no feed is displayed, ignoring showTweetFeed
			 * - if count not equals 0 and showTweetFeed equals false, no feed
			 *   is displayed
			 * {
			 *     expandHovercards: false,		// Boolean - Show Hovercards in expanded mode.
			 *
			 *     showTimestamp: true, 		// A flag (true/false) that specifies whether to display a tweet's timestamp
			 * 									// or an object literal representing the configuration options for the
			 * 									// timestamp.
			 * 									// {
			 * 									//     refreshInterval: 0,	// Time in seconds to be waited until the
			 * 									//							// timestamps of the displayed tweets get refreshed
		     *									// 							// 0 means no refreshing.
			 * 									// }
			 *
			 *     showSource: false,			// Boolean - Show info about the source of the tweet.
			 *
			 *     showGeoLocation: true,		// Boolean - Show geolocation info and link to Google maps.
			 *
			 *     showInReplyTo: true,			// Boolean - Show link to the "replied to" tweet (if available).
			 *
			 *     showProfileImages: null,		// A flag (true/false) that specifies whether to display a profile image in
			 * 									// tweets. If the param is set to null (the default value), a profile image
			 * 									// is displayed only if the feed represents a user's list or the result of a
			 * 									// Twitter search.
			 *
			 *     showUserScreenNames: null,	// A flag (true/false/null) that specifies whether to display a username in
			 * 									// tweets. If the param is set to null (the default value), a username
			 * 									// is displayed only if the feed represents a user's list or the result of a
			 * 									// Twitter search.
			 *
			 *     showUserFullNames: false,	// A flag (true/false/null) that specifies whether to display a user's full name
			 * 									// in tweets. If the param is set to null, a user's full name
			 * 									// is displayed only if the feed represents a user's list or the result of a
			 * 									// Twitter search.
			 *
			 *	   includeRetweets: true,		// Boolean - Include native retweets in a user's tweet feed
			 *
			 *     paging:						// An object literal representing the configuration options for the
			 *     {							// paging support, that specifies how more/earlier tweets can be loaded
			 *         mode: "none"		   		// by using the supplied UI controls (more/next buttons, scrollbar).
			 *     },                           // Accepted values for mode are: "none" | "more" | "prev-next" | "endless-scroll"
			 *									// if mode equals "endless-scroll" you have to set the height of the tweet feed
			 *									// element (.jta-tweet-list) in your CSS to get a scrollbar! You should also set
			 *									// the "overflow" attribute to "auto".
			 *
		     *     autorefresh:					// An object literal representing the configuration options for the
		     *	   {							// autorefresh behaviour.
		     *
		     *									// IMPORTANT: Please always keep in mind, that using the Twitter API is rate
		     *									// limited. Non-authenticated users are rated IP-based and you have only 150
		     *									// calls per hour available. Every retrieval of tweets counts and so does for
		     *									// example hovering over a profile image to show the hovercard. jTweetsAnywhere will
			 *									// always check the remaining count of free API calls before actually calling
			 *									// Twitter to avoid black listing your visitor's IP.
			 *
			 * 									// However - choose your settings wisely to keep your visitors happy. An update
			 *									// interval of 30 seconds on a feed that is updated averaged once per hour
			 *									// does not make sense and is a total waste of remaining API calls!
			 *
		     *	       mode: "none",            // Accepted values for mode are: "none" | "auto-insert" | "trigger-insert"
		     *									// "none" (the default value) - disables the autorefresh feature
		     *									// "auto-insert" - automatically insert the new tweets on top of the tweet feed
		     *									// "trigger-insert" - if new tweets arrived, show or update a button that displays
		     *									// the number of new tweets. These new tweets are inserted on top of the tweet
		     *									// feed, if the user clicks on the button.
		     *
		     *	       interval: 60,			// Time in seconds to be waited until the next request for new tweets. Minimum
		     *									// value is 30.
		     *
		     *         duration: 3600			// Time in seconds for how long the autorefresh will be active. After
		     *									// this period of time, autorefreshing will stop. A value of -1 means
		     *									// autorefresh for ever.
		     *    }
			 * }
			 */
			showTweetFeed: true,

			/**
			 * A flag (true/false) that specifies whether to display a Twitter "Follow
			 * Button".
			 */
			showFollowButton: false,

			/**
			 * A flag (true/false) that specifies whether to display a Twitter "Connect
			 * Button" or an object literal representing the configuration options for
			 * the "Tweet Box".
			 * {
			 *     size: 'medium'				// String - The size of the Connect Button. Valid values are: small, medium, large, xlarge
			 * }
			 */
			showConnectButton: false,

			/**
			 * A flag (true/false) that specifies whether to display Login Infos.
			 */
			showLoginInfo: false,

			/**
			 * A flag (true/false) that specifies whether to display a Twitter "Tweet
			 * Box" or an object literal representing the configuration options for
			 * the "Tweet Box".
			 * {
			 *     counter: true,				// Boolean - Display a counter in the Tweet Box for counting characters
			 *     width: 515,					// Number - The width of the Tweet Box in pixels
			 *     height: 65,					// Number - The height of the Tweet Box in pixels
			 *     label: "What's happening",	// String - The text above the Tweet Box, a call to action
			 *     defaultContent: <none>,		// String - Pre-populated text in the Tweet Box. Useful for an @mention, a #hashtag, a link, etc.
			 *     onTweet: <none>				// Function - Specify a listener for when a tweet is sent from the Tweet Box. The listener receives two arguments: a plaintext tweet and an HTML tweet
			 * }
			 */
			showTweetBox: false,

			/**
			 * A decorator is a function that is responsible for constructing a certain
			 * element of the widget. Most of the decorators return a HTML string.
			 * Exceptions are the mainDecorator, which defines the basic sequence of
			 * the widget's components, plus the linkDecorator, the usernameDecorator
			 * and the hashtagDecorator which return the string that is supplied as a
			 * function param, enriched with the HTML tags.
			 *
			 * For details, see the implementations of the default decorators. Each
			 * default decorator can be overwritten by your own implementation.
			 */
			mainDecorator: defaultMainDecorator,

			tweetFeedDecorator: defaultTweetFeedDecorator,

			tweetDecorator: defaultTweetDecorator,
			tweetProfileImageDecorator: defaultTweetProfileImageDecorator,
			tweetBodyDecorator: defaultTweetBodyDecorator,
			tweetUsernameDecorator: defaultTweetUsernameDecorator,
			tweetTextDecorator: defaultTweetTextDecorator,
			tweetAttributesDecorator: defaultTweetAttributesDecorator,
			tweetTimestampDecorator: defaultTweetTimestampDecorator,
			tweetSourceDecorator: defaultTweetSourceDecorator,
			tweetGeoLocationDecorator: defaultTweetGeoLocationDecorator,
			tweetInReplyToDecorator: defaultTweetInReplyToDecorator,
			tweetRetweeterDecorator: defaultTweetRetweeterDecorator,

			tweetFeedControlsDecorator: defaultTweetFeedControlsDecorator,
			tweetFeedControlsMoreBtnDecorator: defaultTweetFeedControlsMoreBtnDecorator,
			tweetFeedControlsPrevBtnDecorator: defaultTweetFeedControlsPrevBtnDecorator,
			tweetFeedControlsNextBtnDecorator: defaultTweetFeedControlsNextBtnDecorator,

			tweetFeedAutorefreshTriggerDecorator: defaultTweetFeedAutorefreshTriggerDecorator,
			tweetFeedAutorefreshTriggerContentDecorator: defaultTweetFeedAutorefreshTriggerContentDecorator,

			connectButtonDecorator: defaultConnectButtonDecorator,

			loginInfoDecorator: defaultLoginInfoDecorator,
			loginInfoContentDecorator: defaultLoginInfoContentDecorator,

			followButtonDecorator: defaultFollowButtonDecorator,

			tweetBoxDecorator: defaultTweetBoxDecorator,

			linkDecorator: defaultLinkDecorator,
			usernameDecorator: defaultUsernameDecorator,
			hashtagDecorator: defaultHashtagDecorator,

			loadingDecorator: defaultLoadingDecorator,
			errorDecorator: defaultErrorDecorator,
			noDataDecorator: defaultNoDataDecorator,

			/**
			 * Formatters are currently used for date format processing only.
			 *
			 * The tweetTimestampFormatter formats the tweet's timestamp to be shown
			 * in the tweet attributes section
			 *
			 * For details, see the implementation of the defaultTweetTimestampFormatter.
			 */
			tweetTimestampFormatter : defaultTweetTimestampFormatter,

			/**
			 * The tweetTimestampTooltipFormatter formats the tweet's timestamp to be shown
			 * in the tooltip when hovering over the timestamp link.
			 */
			tweetTimestampTooltipFormatter : defaultTweetTimestampTooltipFormatter,

			/**
			 * A visualizer is a function that is responsible for adding one or more
			 * elements to the DOM and thereby making them visible to the user.
			 * A visualizer might also be responsible to do the opposite effect:
			 * To remove one or more elements from the DOM.
			 *
			 * The tweetVisualizer gets called each time a tweet element should be
			 * appended or prepended to the tweet feed element.
			 *
			 * For details, see the implementation of the defaultTweetVisualizer.
			 *
			 * Each default visualizer can be overwritten by your own implementation.
			 */
			tweetVisualizer: defaultTweetVisualizer,

			/**
			 * The loadingIndicatorVisualizer gets called each time data is retrieved
			 * from Twitter to visualize the loading indicator. This visualizer is also
			 * used to hide the loading indicator.
			 *
			 * For details, see the implementation of the defaultLoadingIndicatorVisualizer.
			 */
			loadingIndicatorVisualizer: defaultLoadingIndicatorVisualizer,

			/**
			 * The autorefreshTriggerVisualizer will be called if the autorefresh
			 * trigger should be visualized or hidden.
			 *
			 * For details, see the implementation of the autorefreshTriggerVisualizer.
			 */
			autorefreshTriggerVisualizer: defaultAutorefreshTriggerVisualizer,

			/**
			 * An event handler is a function that gets called whenever the event you
			 * are interested in, occurs.
			 *
			 * The onDataRequest event handler will be called immediatly before calling
			 * Twitter to retrieve new data and gives you the opportunity to deny
			 * the call by returning false from the function.
			 *
			 * This feature might be used in conjunction with the paging feature,
			 * especially when using the "endless-scroll" paging mode, to avoid the
			 * exhaustion of remaining Twitter API calls, before the rate limit is
			 * reached. The stats parameter contains statistical infos and counters
			 * that you can examine to base your decision whether to return true or
			 * false.
			 */
			onDataRequestHandler: defaultOnDataRequestHandler,

			/**
			 * The onRateLimitData event handler is called each time
			 * jTweetsAnywhere retrieved the rate limit data from Twitter. The actual
			 * rate limit data is contained in the stats object.
			 */
			onRateLimitDataHandler: defaultOnRateLimitDataHandler,

			_tweetFeedConfig:
			{
				expandHovercards: false,
				showTimestamp:
				{
					refreshInterval: 0
				},
				showSource: false,
				showGeoLocation: true,
				showInReplyTo: true,
				showProfileImages: null,
				showUserScreenNames: null,
				showUserFullNames: false,
				includeRetweets: true,
				paging:
				{
					mode: "none",
					_limit: 0,
					_offset: 0
				},
				autorefresh:
				{
					mode: "none",
					interval: 60,
					duration: 3600,
					_startTime: null,
					_triggerElement: null
				},
				_pageParam: 0,
				_maxId: null,
				_recLevel: 0,
				_noData: false,
				_clearBeforePopulate: false
			},
			_tweetBoxConfig:
			{
				counter: true,
				width: 515,
				height: 65,
				label: "What's happening?",
				defaultContent: '',
				onTweet: function(textTweet, htmlTweet) {}
			},
			_connectButtonConfig:
			{
				size: "medium"
			},
			_baseSelector: null,
			_baseElement: null,
			_tweetFeedElement: null,
			_tweetFeedControlsElement: null,
			_followButtonElement: null,
			_loginInfoElement: null,
			_connectButtonElement: null,
			_tweetBoxElement: null,
			_loadingIndicatorElement: null,
			_noDataElement: null,
			_tweetsCache: [],
			_autorefreshTweetsCache: [],
			_stats:
			{
				dataRequestCount: 0,
				rateLimitPreventionCount: 0,
				rateLimit:
				{
					remaining_hits: 150,
					hourly_limit: 150
				}
			}
		}, options);

		// no main decorator? nothing to do!
		if (!options.mainDecorator)
		{
			return;
		}

		options._baseSelector = this.selector;

		// if username is an array, create the search query and flatten username
		if (typeof(options.username) != 'string')
		{
			if (!options.searchParams)
			{
				options.searchParams = ['q=from:' + options.username.join(" OR from:")];
			}

			options.username = options.username[0];
		}

		// if showTweetFeed is not set to a boolean value, we expect the configuration of
		// the tweet feed
		if (typeof(options.showTweetFeed) == 'object')
		{
			$.extend(true, options._tweetFeedConfig, options.showTweetFeed);
		}

		// if showTweetBox is not set to a boolean value, we expect the configuration of
		// the TweetBox
		if (typeof(options.showTweetBox) == 'object')
		{
			options._tweetBoxConfig = options.showTweetBox;
			options.showTweetBox = true;
		}

		// if showConnectButton is not set to a boolean value, we expect the
		// configuration of the Connect Button
		if (typeof(options.showConnectButton) == 'object')
		{
			options._connectButtonConfig = options.showConnectButton;
			options.showConnectButton = true;
		}

		// to be compatible, check the deprecated option 'tweetProfileImagePresent'
		if (options._tweetFeedConfig.showProfileImages == null)
		{
			options._tweetFeedConfig.showProfileImages = options.tweetProfileImagePresent;
		}

		// if _tweetFeedConfig.showProfileImages is not set to a boolean value,
		// we decide to show a profile image if the feed represents a user's
		// list or the results of a Twitter search
		if (options._tweetFeedConfig.showProfileImages == null)
		{
			options._tweetFeedConfig.showProfileImages = (options.list || options.searchParams) && options.tweetProfileImageDecorator;
		}

		// if _tweetFeedConfig.showUserScreenNames is not set to a boolean value,
		// we decide to show a username if the feed represents a user's
		// list or the results of a Twitter search or a tweet is a native retweet
		if (options._tweetFeedConfig.showUserScreenNames == null)
		{
			if (options.list || options.searchParams)
			{
				options._tweetFeedConfig.showUserScreenNames = true;
			}

			if (!options.tweetUsernameDecorator)
			{
				options._tweetFeedConfig.showUserScreenNames = false;
			}
		}

		// if _tweetFeedConfig.showUserFullNames is not set to a boolean value,
		// we decide to show a user's full name if the feed represents a user's
		// list or the results of a Twitter search or a tweet is a native retweet
		if (options._tweetFeedConfig.showUserFullNames == null)
		{
			if (options.list || options.searchParams)
			{
				options._tweetFeedConfig.showUserFullNames = true;
			}

			if (!options.tweetUsernameDecorator)
			{
				options._tweetFeedConfig.showUserFullNames = false;
			}
		}

		options.count = validateRange(options.count, 0, options.searchParams ? 100 : 20);

		options._tweetFeedConfig.autorefresh.interval = Math.max(30, options._tweetFeedConfig.autorefresh.interval);

		options._tweetFeedConfig.paging._offset = 0;
		options._tweetFeedConfig.paging._limit = options.count;

		// internally, the decision of what parts of a widget are to be
		// displayed is based on the existence of the decorators
		if (options.count == 0 || !options.showTweetFeed)
		{
			options.tweetFeedDecorator = null;
			options.tweetFeedControlsDecorator = null;
		}

		if (options._tweetFeedConfig.paging.mode == 'none')
		{
			options.tweetFeedControlsDecorator = null;
		}

		if (!options.showFollowButton)
		{
			options.followButtonDecorator = null;
		}

		if (!options.showTweetBox)
		{
			options.tweetBoxDecorator = null;
		}

		if (!options.showConnectButton)
		{
			options.connectButtonDecorator = null;
		}

		if (!options.showLoginInfo)
		{
			options.loginInfoDecorator = null;
		}

		if (!options._tweetFeedConfig.showTimestamp)
		{
			options.tweetTimestampDecorator = null;
		}

		if (!options._tweetFeedConfig.showSource)
		{
			options.tweetSourceDecorator = null;
		}

		if (!options._tweetFeedConfig.showGeoLocation)
		{
			options.tweetGeoLocationDecorator = null;
		}

		if (!options._tweetFeedConfig.showInReplyTo)
		{
			options.tweetInReplyToDecorator = null;
		}

		// setup ajax
		$.ajaxSetup({ cache: true });

		return this.each(function()
		{
			// the DOM element, where to display the widget
			options._baseElement = $(this);

			// create the widget's necessary sub DOM elements
			options._tweetFeedElement = options.tweetFeedDecorator ? $(options.tweetFeedDecorator(options)) : null;
			options._tweetFeedControlsElement = options.tweetFeedControlsDecorator ? $(options.tweetFeedControlsDecorator(options)) : null;
			options._followButtonElement = options.followButtonDecorator ? $(options.followButtonDecorator(options)) : null;
			options._tweetBoxElement = options.tweetBoxDecorator ? $(options.tweetBoxDecorator(options)) : null;
			options._connectButtonElement = options.connectButtonDecorator ? $(options.connectButtonDecorator(options)): null;
			options._loginInfoElement = options.loginInfoDecorator ? $(options.loginInfoDecorator(options)) : null;

			// add the widget to the DOM
			options.mainDecorator(options);

			populateTweetFeed(options);
			populateAnywhereControls(options);

			// bind event handlers to support paging
			bindEventHandlers(options);

			// install autorefresh support
			options._tweetFeedConfig.autorefresh._startTime = new Date().getTime();
			startAutorefresh(options);
			startTimestampRefresh(options);
		});
	};
	defaultMainDecorator = function(options)
	{
		// defines the default sequence of the widget's elements
		if (options._tweetFeedElement)
		{
			options._baseElement.append(options._tweetFeedElement);
		}

		if (options._tweetFeedControlsElement)
		{
			options._baseElement.append(options._tweetFeedControlsElement);
		}

		if (options._connectButtonElement)
		{
			options._baseElement.append(options._connectButtonElement);
		}

		if (options._loginInfoElement)
		{
			options._baseElement.append(options._loginInfoElement);
		}

		if (options._followButtonElement)
		{
			options._baseElement.append(options._followButtonElement);
		}

		if (options._tweetBoxElement)
		{
			options._baseElement.append(options._tweetBoxElement);
		}
	};
	defaultTweetFeedControlsDecorator = function(options)
	{
		// the default tweet feed's paging controls
		var html = '';

		if (options._tweetFeedConfig.paging.mode == 'prev-next')
		{
			if (options.tweetFeedControlsPrevBtnDecorator)
			{
				html += options.tweetFeedControlsPrevBtnDecorator(options);
			}

			if (options.tweetFeedControlsNextBtnDecorator)
			{
				html += options.tweetFeedControlsNextBtnDecorator(options);
			}
		}
		else if (options._tweetFeedConfig.paging.mode == 'endless-scroll')
		{
			// nothing to do here atm
		}
		else
		{
			if (options.tweetFeedControlsMoreBtnDecorator)
			{
				html += options.tweetFeedControlsMoreBtnDecorator(options);
			}
		}

		return '<div class="jta-tweet-list-controls">' + html + '</div>';
	};
	defaultTweetFeedControlsMoreBtnDecorator = function(options)
	{
		return '<span class="jta-tweet-list-controls-button jta-tweet-list-controls-button-more">' + 'More' + '</span>';
	};
	defaultTweetFeedControlsPrevBtnDecorator = function(options)
	{
		return '<span class="jta-tweet-list-controls-button jta-tweet-list-controls-button-prev">' + 'Prev' + '</span>';
	};
	defaultTweetFeedControlsNextBtnDecorator = function(options)
	{
		return '<span class="jta-tweet-list-controls-button jta-tweet-list-controls-button-next">' + 'Next' + '</span>';
	};
	defaultTweetFeedAutorefreshTriggerDecorator = function(count, options)
	{
		var html = '';

		if (options.tweetFeedAutorefreshTriggerContentDecorator)
		{
			html = options.tweetFeedAutorefreshTriggerContentDecorator(count, options);
		}

		return '<li class="jta-tweet-list-autorefresh-trigger">' + html + '</li>';
	};
	defaultTweetFeedAutorefreshTriggerContentDecorator = function(count, options)
	{
		var content = '' + count + ' new ' + (count > 1 ? ' tweets' : ' tweet');

		return '<span class="jta-tweet-list-autorefresh-trigger-content">' + content + '</span>';
	};
	defaultTweetFeedDecorator = function(options)
	{
		// the default placeholder for the tweet feed is an unordered list
		return '<ul class="jta-tweet-list"></ul>';
	};
	defaultTweetDecorator = function(tweet, options)
	{
		// the default tweet is made of the optional user's profile image and the
		// tweet body inside a list item element
		var html = '';

		if (options._tweetFeedConfig.showProfileImages)
		{
			html += options.tweetProfileImageDecorator(tweet, options);
		}

		if (options.tweetBodyDecorator)
		{
			html += options.tweetBodyDecorator(tweet, options);
		}

		html += '<div class="jta-clear">&nbsp;</div>';

		return '<li class="jta-tweet-list-item">' + html + '</li>';
	};
	defaultTweetProfileImageDecorator = function(tweet, options)
	{
		// if tweet is a native retweet, use the retweet's profile
		var t = tweet.retweeted_status || tweet;

		// the default profile image decorator simply adds a link to the user's Twitter profile
		var screenName = t.user ? t.user.screen_name : false || t.from_user;
		var imageUrl = t.user ? t.user.profile_image_url : false || t.profile_image_url;

		var html =
			'<a class="jta-tweet-profile-image-link" href="http://twitter.com/' + screenName + '" target="_blank">' +
			'<img src="' + imageUrl + '" alt="' + screenName + '"' +
			(isAnywherePresent() ? '' : (' title="' + screenName + '"')) +
			'/>' +
			'</a>';

		return '<div class="jta-tweet-profile-image">' + html + '</div>';
	};
	defaultTweetBodyDecorator = function(tweet, options)
	{
		// the default tweet body contains the tweet text and the tweet's creation date
		var html = '';

		if (options.tweetTextDecorator)
		{
			html += options.tweetTextDecorator(tweet, options);
		}

		if (options.tweetAttributesDecorator)
		{
			html += options.tweetAttributesDecorator(tweet, options);
		}

		return '<div class="jta-tweet-body ' + (options._tweetFeedConfig.showProfileImages ? 'jta-tweet-body-list-profile-image-present' : '') + '">' + html + '</div>';
	};
	defaultTweetTextDecorator = function(tweet, options)
	{
		var tweetText = tweet.text;

		// if usernames should be visible and tweet is a native retweet, use
		// the original tweet text
		if (tweet.retweeted_status &&
			(
				options._tweetFeedConfig.showUserScreenNames ||
				options._tweetFeedConfig.showUserScreenNames == null ||
				options._tweetFeedConfig.showUserFullNames ||
				options._tweetFeedConfig.showUserFullNames == null
			)
		)
		{
			tweetText = tweet.retweeted_status.text;
		}

		// the default tweet text decorator optionally marks links, @usernames,
		// and #hashtags
		if (options.linkDecorator)
		{
			tweetText = options.linkDecorator(tweetText, options);
		}

		if (options.usernameDecorator)
		{
			tweetText = options.usernameDecorator(tweetText, options);
		}

		if (options.hashtagDecorator)
		{
			tweetText = options.hashtagDecorator(tweetText, options);
		}

		if (options._tweetFeedConfig.showUserScreenNames ||
			options._tweetFeedConfig.showUserFullNames ||
			tweet.retweeted_status &&
			(
				options._tweetFeedConfig.showUserScreenNames == null ||
				options._tweetFeedConfig.showUserFullNames == null
			)
		)
		{
			tweetText = options.tweetUsernameDecorator(tweet, options) + ' ' + tweetText;
		}

		return '<span class="jta-tweet-text">' + tweetText + '</span>';
	};
	defaultTweetUsernameDecorator = function(tweet, options)
	{
		// if tweet is a native retweet, use the retweet's profile
		var t = tweet.retweeted_status || tweet;
		var screenName = t.user ? t.user.screen_name : false || t.from_user;
		var fullName = t.user ? t.user.name : null;

		var htmlScreenName;
		if (screenName && (options._tweetFeedConfig.showUserScreenNames || (options._tweetFeedConfig.showUserScreenNames == null && tweet.retweeted_status)))
		{
			htmlScreenName =
				'<span class="jta-tweet-user-screen-name">' +
				'<a class="jta-tweet-user-screen-name-link" href="http://twitter.com/' + screenName + '" target="_blank">' +
				screenName +
				'</a>' +
				'</span>';
		}

		var htmlFullName;
		if (fullName && (options._tweetFeedConfig.showUserFullNames || (options._tweetFeedConfig.showUserFullNames == null && tweet.retweeted_status)))
		{
			htmlFullName =
				'<span class="jta-tweet-user-full-name">' +
				(htmlScreenName ? ' (' : '') +
				'<a class="jta-tweet-user-full-name-link" href="http://twitter.com/' + screenName + '" name="' + screenName + '" target="_blank">' +
				fullName +
				'</a>' +
				(htmlScreenName ? ')' : '') +
				'</span>';
		}

		var html = "";

		if (htmlScreenName)
		{
			html += htmlScreenName;
		}

		if (htmlFullName)
		{
			if (htmlScreenName)
			{
				html += ' ';
			}

			html += htmlFullName;
		}

		if (htmlScreenName || htmlFullName)
		{
			html =
				'<span class="jta-tweet-user-name">' +
				(tweet.retweeted_status ? 'RT ' : '') +
				html +
				'</span>';
		}

		return html;
	};
	defaultTweetAttributesDecorator = function(tweet, options)
	{
		var html = '';

		if (options.tweetTimestampDecorator ||
			options.tweetSourceDecorator ||
			options.tweetGeoLocationDecorator ||
			options.tweetInReplyToDecorator ||
			(tweet.retweeted_status && options.tweetRetweeterDecorator)
		)
		{
			html += '<span class="jta-tweet-attributes">';

			if (options.tweetTimestampDecorator)
			{
				html += options.tweetTimestampDecorator(tweet, options);
			}

			if (options.tweetSourceDecorator)
			{
				html += options.tweetSourceDecorator(tweet, options);
			}

			if (options.tweetGeoLocationDecorator)
			{
				html += options.tweetGeoLocationDecorator(tweet, options);
			}

			if (options.tweetInReplyToDecorator)
			{
				html += options.tweetInReplyToDecorator(tweet, options);
			}

			if (tweet.retweeted_status && options.tweetRetweeterDecorator)
			{
				html += options.tweetRetweeterDecorator(tweet, options);
			}

			html += '</span>';
		}

		return html;
	};
	defaultTweetTimestampDecorator = function(tweet, options)
	{
		// the default tweet timestamp decorator does a little bit of Twitter like formatting.

		// if tweet is a native retweet, use the retweet's timestamp
		var tw = tweet.retweeted_status || tweet;

		// reformat timestamp from Twitter, so IE is happy
		var createdAt = formatDate(tw.created_at);

		// format the timestamp by the tweetTimestampFormatter
		var tweetTimestamp = options.tweetTimestampFormatter(createdAt);
		var tweetTimestampTooltip = options.tweetTimestampTooltipFormatter(createdAt);

		var screenName = tw.user ? tw.user.screen_name : false || tw.from_user;
		var html =
			'<span class="jta-tweet-timestamp">' +
			'<a class="jta-tweet-timestamp-link" data-timestamp="' + createdAt +
			'" href="http://twitter.com/' + screenName + '/status/' + tw.id + '" target="_blank" title="' +
			tweetTimestampTooltip + '">' +
			tweetTimestamp +
			'</a>' +
			'</span>';

		return html;
	};
	defaultTweetTimestampTooltipFormatter = function(timeStamp)
	{
		var d = new Date(timeStamp);

		return d.toLocaleString();
	};
	defaultTweetTimestampFormatter = function(timeStamp)
	{
		var now = new Date();

		var diff = parseInt((now.getTime() - Date.parse(timeStamp)) / 1000);

		var tweetTimestamp = '';
		if (diff < 60)
		{
			tweetTimestamp += diff + ' second' + (diff == 1 ? '' : 's') + ' ago';
		}
		else if (diff < 3600)
		{
			var t = parseInt((diff + 30) / 60);
			tweetTimestamp += t + ' minute' + (t == 1 ? '' : 's') + ' ago';
		}
		else if (diff < 86400)
		{
			var t = parseInt((diff + 1800) / 3600);
			tweetTimestamp += t + ' hour' + (t == 1 ? '' : 's') + ' ago';
		}
		else
		{
			var d = new Date(timeStamp);
			var period = 'AM';

			var hours = d.getHours();
			if (hours > 12)
			{
				hours -= 12;
				period = 'PM';
			}

			var mins = d.getMinutes();
			var minutes = (mins < 10 ? '0' : '') + mins;

			var monthName = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];

			tweetTimestamp += monthName[d.getMonth()] + ' ' + d.getDate();

			if (d.getFullYear() < now.getFullYear())
			{
				tweetTimestamp += ', ' + d.getFullYear();
			}

			var t = parseInt((diff + 43200) / 86400);
			tweetTimestamp += ' (' + t + ' day' + (t == 1 ? '' : 's') + ' ago)';
		}

		return tweetTimestamp;
	};
	exTimestampFormatter = function(timeStamp)
	{
		var diff = parseInt((new Date().getTime() - Date.parse(timeStamp)) / 1000);

		var tweetTimestamp = '';
		if (diff < 60)
		{
			tweetTimestamp += 'less than a minute ago';
		}
		else if (diff < 3600)
		{
			var t = parseInt((diff + 30) / 60);
			tweetTimestamp += t + ' minute' + (t == 1 ? '' : 's') + ' ago';
		}
		else if (diff < 86400)
		{
			var t = parseInt((diff + 1800) / 3600);
			tweetTimestamp += 'about ' + t + ' hour' + (t == 1 ? '' : 's') + ' ago';
		}
		else
		{
			var t = parseInt((diff + 43200) / 86400);
			tweetTimestamp += 'about ' + t + ' day' + (t == 1 ? '' : 's') + ' ago';

			var d = new Date(timeStamp);
			var period = 'AM';

			var hours = d.getHours();
			if (hours > 12)
			{
				hours -= 12;
				period = 'PM';
			}

			var mins = d.getMinutes();
			var minutes = (mins < 10 ? '0' : '') + mins;

			tweetTimestamp += ' ('  + hours + ':' + minutes + ' ' + period + ' ' + (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear() + ')';
		}

		return tweetTimestamp;
	};
	defaultTweetSourceDecorator = function(tweet, options)
	{
		// if tweet is a native retweet, use the retweet's source
		var tw = tweet.retweeted_status || tweet;

		var source = tw.source.replace(/\&lt\;/gi,'<').replace(/\&gt\;/gi,'>').replace(/\&quot\;/gi,'"');
		var html =
			'<span class="jta-tweet-source">' +
			' via ' +
			'<span class="jta-tweet-source-link">' +
			source +
			'</span>' +
			'</span>';

		return html;
	};
	defaultTweetGeoLocationDecorator = function(tweet, options)
	{
		var html = '';

		// if tweet is a native retweet, use the retweet's source
		var tw = tweet.retweeted_status || tweet;

		var q;
		if (tw.geo && tw.geo.coordinates)
		{
			q = tw.geo.coordinates.join();
		}
		else if (tw.place && tw.place.full_name)
		{
			q = tw.place.full_name;
		}

		if (q)
		{
			var location = 'here';
			if (tw.place && tw.place.full_name)
			{
				location = tw.place.full_name;
			}

			var link = 'http://maps.google.com/maps?q=' + q;

			html =
				'<span class="jta-tweet-location">' +
				' from ' +
				'<a class="jta-tweet-location-link" href="' + link + '" target="_blank">' +
				location +
				'</a>' +
				'</span>';
		}

		return html;
	};
	defaultTweetInReplyToDecorator = function(tweet, options)
	{
		// if tweet is a native retweet, use the retweet's source
		var tw = tweet.retweeted_status || tweet;

		var html = '';
		if (tw.in_reply_to_status_id && tw.in_reply_to_screen_name)
		{
			html =
				'<span class="jta-tweet-inreplyto">' +
				' ' +
				'<a class="jta-tweet-inreplyto-link" href="http://twitter.com/' + tw.in_reply_to_screen_name + '/status/' + tw.in_reply_to_status_id + '" target="_blank">' +
				'in reply to ' + tw.in_reply_to_screen_name +
				'</a>' +
				'</span>';
		}

		return html;
	};
	defaultTweetRetweeterDecorator = function(tweet, options)
	{
		var html = '';

		if (tweet.retweeted_status)
		{
			var screenName = tweet.user ? tweet.user.screen_name : false || tweet.from_user;
			var rtc = (tweet.retweeted_status.retweet_count || 0) - 1;

			var link =
				'<a class="jta-tweet-retweeter-link" href="http://twitter.com/' + screenName + '" target="_blank">' +
				screenName +
				'</a>';
			var rtcount = ' and ' + rtc + (rtc > 1 ? ' others' : ' other');
			html =
				'<br/>' +
				'<span class="jta-tweet-retweeter">' +
				'Retweeted by ' + link +
				(rtc > 0 ? rtcount : '') +
				'</span>';
		}

		return html;
	};
	defaultConnectButtonDecorator = function(options)
	{
		// the default placeholder for the @Anywhere ConnectButton
		return '<div class="jta-connect-button"></div>';
	};
	defaultLoginInfoDecorator = function(options)
	{
		// the default placeholder for the LoginInfo
		return '<div class="jta-login-info"></div>';
	};
	defaultLoginInfoContentDecorator = function(options, T)
	{
		// the default markup of the LoginInfo content: the user's profile image, the
		// user's screen_name and a "button" to sign out
		var html = '';

		if (T.isConnected())
		{
			var screenName = T.currentUser.data('screen_name');
			var imageUrl = T.currentUser.data('profile_image_url');

			html =
				'<div class="jta-login-info-profile-image">' +
				'<a href="http://twitter.com/' + screenName + '" target="_blank">' +
				'<img src="' + imageUrl + '" alt="' + screenName + '" title="' + screenName + '"/>' +
				'</a>' +
				'</div>' +
				'<div class="jta-login-info-block">' +
				'<div class="jta-login-info-screen-name">' +
				'<a href="http://twitter.com/' + screenName + '" target="_blank">' + screenName + '</a>' +
				'</div>' +
				'<div class="jta-login-info-sign-out">' +
				'Sign out' +
				'</div>' +
				'</div>' +
				'<div class="jta-clear">&nbsp;</div>'
				;
		}

		return html;
	};
	defaultFollowButtonDecorator = function(options)
	{
		// the default placeholder for the @Anywhere FollowButton
		return '<div class="jta-follow-button"></div>';
	};
	defaultTweetBoxDecorator = function(options)
	{
		// the default placeholder for the @Anywhere TweetBox
		return '<div class="jta-tweet-box"></div>';
	};
	defaultLinkDecorator = function(text, options)
	{
		// the regex to markup links
		return text.replace(/((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi,'<a href="$1" class="jta-tweet-a jta-tweet-link" target="_blank" rel="nofollow">$1<\/a>');
	};
	defaultUsernameDecorator = function(text, options)
	{
		// the regex to markup @usernames. if @Anywhere is present the task is left to
		// them
		return isAnywherePresent() ? text : text.replace(/@([a-zA-Z0-9_]+)/gi,'@<a href="http://twitter.com/$1" class="jta-tweet-a twitter-anywhere-user" target="_blank" rel="nofollow">$1<\/a>');
	};
	defaultHashtagDecorator = function(text, options)
	{
		// the regex to markup #hashtags
		return text.replace(/#([a-zA-Z0-9_]+)/gi,'<a href="http://search.twitter.com/search?q=%23$1" class="jta-tweet-a jta-tweet-hashtag" title="#$1" target="_blank" rel="nofollow">#$1<\/a>');
	};
	defaultLoadingDecorator = function(options)
	{
		// the default loading decorator simply says: loading ...
		return '<li class="jta-loading">Loading ...</li>';
	};
	defaultErrorDecorator = function(errorText, options)
	{
		// the default error decorator shows the error message
		return '<li class="jta-error">ERROR: ' + errorText + '</li>';
	};
	defaultNoDataDecorator = function(options)
	{
		// the default no-data decorator simply says: No more data
		return '<li class="jta-nodata">Napíšte niečo o nás. #omnipublic</li>';
	};

	defaultTweetFilter = function(tweet, options)
	{
		return true;
	};

	defaultTweetVisualizer = function(tweetFeedElement, tweetElement, inserter, options)
	{
		// insert (append/prepend) the tweetElement to the tweetFeedElement
		tweetFeedElement[inserter](tweetElement);
	};
	defaultLoadingIndicatorVisualizer = function(tweetFeedElement, loadingIndicatorElement, options, callback)
	{
		defaultVisualizer(tweetFeedElement, loadingIndicatorElement, 'append', 'fadeIn', 600, 'fadeOut', 200, callback);
	};
	defaultAutorefreshTriggerVisualizer = function(tweetFeedElement, triggerElement, options, callback)
	{
		defaultVisualizer(tweetFeedElement, triggerElement, 'prepend', 'slideDown', 600, 'fadeOut', 200, callback);
	};
	defaultVisualizer = function(container, element, inserter, effectIn, durationIn, effectOut, durationOut, callback)
	{
		// if param container is null element has to be removed from
		// the DOM, else element has to be inserted in container

		// if param callback is not null, the callback function must be called
		// in any case, if the visualizer is done

		var cb = function()
		{
			if (callback)
			{
				callback();
			}
		};

		if (container)
		{
			element.hide();
			container[inserter](element);
			element[effectIn](durationIn, cb);
		}
		else
		{
			element[effectOut](durationOut, function()
			{
				element.remove();
				cb();
			});
		}
	};

	defaultOnDataRequestHandler = function(stats, options)
	{
		return true;
	};
	defaultOnRateLimitDataHandler = function(stats, options)
	{
	};

	updateLoginInfoElement = function(options, T)
	{
		// update the content of the LoginInfo element
		if (options._loginInfoElement && options.loginInfoContentDecorator)
		{
			options._loginInfoElement.children().remove();
			options._loginInfoElement.append(options.loginInfoContentDecorator(options, T));
			$(options._baseSelector + ' .jta-login-info-sign-out').bind('click', function()
			{
				twttr.anywhere.signOut();
			});
		}
	};
	getFeedUrl = function(options, flPaging)
	{
		// create the Twitter API URL based on the configuration options
		var url = ('https:' == document.location.protocol ? 'https:' : 'http:');

		if (options.searchParams)
		{
			url += '//search.twitter.com/search.json?' +
				((options.searchParams instanceof Array) ? options.searchParams.join('&') : options.searchParams) +
				'&rpp=100';
		}
		else if (options.list)
		{
			url += '//api.twitter.com/1/' + options.username + '/lists/' + options.list + '/statuses.json?per_page=20';
		}
		else
		{
			url += '//api.twitter.com/1/statuses/user_timeline.json?screen_name=' + options.username + '&count=20';
			if (options._tweetFeedConfig.includeRetweets)
				url += '&include_rts=true';
		}

		if (flPaging)
		{
			url +=
				(options._tweetFeedConfig._maxId ? '&max_id=' + options._tweetFeedConfig._maxId : '') +
				'&page=' + options._tweetFeedConfig._pageParam;
		}

		url += '&callback=?';

		return url;
	};
	isAnywherePresent = function()
	{
		// check, if @Anywhere is present
		return typeof(twttr) != 'undefined';
	};
	clearTweetFeed = function(options)
	{
		if (options._tweetFeedElement)
		{
			options._tweetFeedElement.empty();
		}
	};
	populateTweetFeed = function(options)
	{
		// if a tweet feed is to be displayed, get the tweets and show them
		if (options.tweetDecorator && options._tweetFeedElement)
		{
			getPagedTweets(options, function(tweets, options)
			{
				if (options._tweetFeedConfig._clearBeforePopulate)
				{
					clearTweetFeed(options);
				}

				hideLoadingIndicator(options, function()
				{
					// process the tweets
					$.each(tweets, function(idx, tweet)
					{
						// decorate the tweet and give it to the tweet visualizer
						options.tweetVisualizer(
							options._tweetFeedElement,
							$(options.tweetDecorator(tweet, options)),
							'append',
							options
						);
					});

					if (options._tweetFeedConfig._noData && options.noDataDecorator && !options._tweetFeedConfig._noDataElement)
					{
						options._tweetFeedConfig._noDataElement = $(options.noDataDecorator(options));
						options._tweetFeedElement.append(options._tweetFeedConfig._noDataElement);
					}

					if (options._tweetFeedConfig._clearBeforePopulate)
					{
						options._tweetFeedElement.scrollTop(0);
					}

					addHovercards(options);
				});
			});
		}
	};
	populateTweetFeed2 = function(options)
	{
		if (options._tweetFeedElement && options._autorefreshTweetsCache.length > 0)
		{
			if (options._tweetFeedConfig.autorefresh.mode == 'trigger-insert')
			{
				if (options._tweetFeedConfig.autorefresh._triggerElement)
				{
					if (options.tweetFeedAutorefreshTriggerContentDecorator)
					{
						options._tweetFeedConfig.autorefresh._triggerElement.html(
							options.tweetFeedAutorefreshTriggerContentDecorator(options._autorefreshTweetsCache.length, options)
						);
					}
				}
				else
				{
					if (options.tweetFeedAutorefreshTriggerDecorator)
					{
						options._tweetFeedConfig.autorefresh._triggerElement =
							$(options.tweetFeedAutorefreshTriggerDecorator(options._autorefreshTweetsCache.length, options));
						options._tweetFeedConfig.autorefresh._triggerElement.bind('click', function()
						{
							options.autorefreshTriggerVisualizer(
								null,
								options._tweetFeedConfig.autorefresh._triggerElement,
								options,
								function()
								{
									insertTriggerTweets(options);
								}
							);
							options._tweetFeedConfig.autorefresh._triggerElement = null;
						});

						options.autorefreshTriggerVisualizer(options._tweetFeedElement, options._tweetFeedConfig.autorefresh._triggerElement, options);
					}
				}
			}
			else
			{
				insertTriggerTweets(options);
			}
		}
	};
	insertTriggerTweets = function(options)
	{
		// populate the tweet feed with tweets from the autorefresh cache
		if (options.tweetDecorator && options._autorefreshTweetsCache.length > 0)
		{
			// process the autorefresh cache
			while (options._autorefreshTweetsCache.length > 0)
			{
				// get the last tweet and remove it from the autorefresh cache
				var tweet = options._autorefreshTweetsCache.pop();

				// put that tweet on top of the tweets cache
				options._tweetsCache.unshift(tweet);

				// adjust paging offset
				options._tweetFeedConfig.paging._offset++;

				// decorate the tweet and give it to the tweet visualizer
				options.tweetVisualizer(
					options._tweetFeedElement,
					$(options.tweetDecorator(tweet, options)),
					'prepend',
					options
				);
			}

			addHovercards(options);
		}
	};
	addHovercards = function(options)
	{
		if (isAnywherePresent())
		{
			// if @Anywhere is present, append Hovercards to @username and
			// profile images
			twttr.anywhere(function(T)
			{
				T(options._baseSelector + ' .jta-tweet-list').hovercards({expanded: options._tweetFeedConfig.expandHovercards});
				T(options._baseSelector + ' .jta-tweet-profile-image img').hovercards(
				{
					expanded: options._tweetFeedConfig.expandHovercards,
					username: function(node) { return node.alt; }
				});
				T(options._baseSelector + ' .jta-tweet-retweeter-link').hovercards(
				{
					expanded: options._tweetFeedConfig.expandHovercards,
					username: function(node) { return node.text; }
				});
				T(options._baseSelector + ' .jta-tweet-user-screen-name-link').hovercards(
				{
					expanded: options._tweetFeedConfig.expandHovercards,
					username: function(node) { return node.text; }
				});
				T(options._baseSelector + ' .jta-tweet-user-full-name-link').hovercards(
				{
					expanded: options._tweetFeedConfig.expandHovercards,
					username: function(node) { return node.name; }
				});
			});
		}
	};
	populateAnywhereControls = function(options)
	{
		if (isAnywherePresent())
		{
			twttr.anywhere(function(T)
			{
				// optionally add an @Anywhere TweetBox
				if (options.tweetBoxDecorator)
				{
					T(options._baseSelector + ' .jta-tweet-box').tweetBox(options._tweetBoxConfig);
				}

				// optionally add an @Anywhere FollowButton
				if (options.followButtonDecorator)
				{
					T(options._baseSelector + ' .jta-follow-button').followButton(options.username);
				}

				// optionally add an @Anywhere ConnectButton
				if (options.connectButtonDecorator)
				{
					var o = $.extend(
					{
						authComplete: function(user)
						{
							// display/update login infos on connect/signin event
							updateLoginInfoElement(options, T);
						},
						signOut: function()
						{
							// display/update login infos on signout event
							updateLoginInfoElement(options, T);
						}
					}, options._connectButtonConfig);

					T(options._baseSelector + ' .jta-connect-button').connectButton(o);

					// display/update login infos
					updateLoginInfoElement(options, T);
				}
			});
		}
	};
	bindEventHandlers = function(options)
	{
		if (options.tweetFeedControlsDecorator)
		{
			if (options._tweetFeedConfig.paging.mode == 'prev-next')
			{
				$(options._baseSelector + ' .jta-tweet-list-controls-button-prev').bind('click', function()
				{
					if (!isLoading(options) && options._tweetFeedConfig.paging._offset > 0)
					{
						prevPage(options, true);
					}
				});
				$(options._baseSelector + ' .jta-tweet-list-controls-button-next').bind('click', function()
				{
					if (!isLoading(options))
					{
						nextPage(options, true);
					}
				});
			}
			else if (options._tweetFeedConfig.paging.mode == 'endless-scroll')
			{
				options._tweetFeedElement.bind("scroll", function()
				{
				    if (!isLoading(options) && ($(this)[0].scrollHeight - $(this).scrollTop() == $(this).outerHeight()))
				    {
				    	nextPage(options, false);
				    }
				});
			}
			else
			{
				$(options._baseSelector + ' .jta-tweet-list-controls-button-more').bind('click', function()
				{
					if (!isLoading(options))
					{
						nextPage(options, false);
					}
				});
			}
		}
	};
	nextPage = function(options, flClear)
	{
		doPage(options, flClear, Math.min(options._tweetFeedConfig.paging._offset + options._tweetFeedConfig.paging._limit, options._tweetsCache.length));
	};
	prevPage = function(options, flClear)
	{
		doPage(options, flClear, Math.max(0, options._tweetFeedConfig.paging._offset - options._tweetFeedConfig.paging._limit));
	};
	doPage = function(options, flClear, newOffset)
	{
		options._tweetFeedConfig.paging._offset = newOffset;
		options._tweetFeedConfig._clearBeforePopulate = flClear;

		populateTweetFeed(options);
	};
	startAutorefresh = function(options)
	{
		if (options._tweetFeedConfig.autorefresh.mode != 'none' &&
			options._tweetFeedConfig.paging.mode != 'prev-next' &&
			options._tweetFeedConfig.autorefresh.duration != 0 &&
			(
				options._tweetFeedConfig.autorefresh.duration < 0 ||
				(new Date().getTime() - options._tweetFeedConfig.autorefresh._startTime) <= options._tweetFeedConfig.autorefresh.duration * 1000
			)
		)
		{
			window.setTimeout(function() { processAutorefresh(options); }, options._tweetFeedConfig.autorefresh.interval * 1000);
		}
	};
	stopAutorefresh = function(options)
	{
		options._tweetFeedConfig.autorefresh.duration = 0;
	};
	processAutorefresh = function(options)
	{
		if (options._tweetFeedConfig.autorefresh.duration != 0)
		{
			// load the data ...
			getRateLimitedData(options, true, getFeedUrl(options, false), function(data, options)
			{
				// reverse the sequence of the autorefresh tweets ...
				var tweets = (data.results || data).slice(0);
				tweets.reverse();

				// ...then process them
				$.each(tweets, function(idx, tweet)
				{
					// if this tweet is already in the standard tweets cache, ignore
					if (!isTweetInCache(tweet, options))
					{
						// optionally filter tweet ...
						if (options.tweetFilter(tweet, options))
						{
							// ... then put it to the top of the autorefresh cache
							options._autorefreshTweetsCache.unshift(tweet);
						}
					}
				});

				populateTweetFeed2(options);
			});

			// restart autorefresh
			startAutorefresh(options);
		}
	};
	startTimestampRefresh = function(options)
	{
		if (
			options.tweetTimestampDecorator &&
			typeof(options._tweetFeedConfig.showTimestamp) == 'object' &&
			options._tweetFeedConfig.showTimestamp.refreshInterval > 0
		)
		{
			window.setTimeout(function() { processTimestampRefresh(options); }, options._tweetFeedConfig.showTimestamp.refreshInterval * 1000);
		}
	};
	processTimestampRefresh = function(options)
	{
		$.each(options._tweetFeedElement.find('.jta-tweet-timestamp-link'), function(idx, element)
		{
			var dataTimestamp = $(element).attr('data-timestamp');

			$(element).html(options.tweetTimestampFormatter(dataTimestamp));
		});

		startTimestampRefresh(options);
	};
	isTweetInCache = function(tweet, options)
	{
		var l = options._tweetsCache.length;

		for (var i = 0; i < l; i++)
		{
			if (tweet.id == options._tweetsCache[i].id)
			{
				return true;
			}
		}

		return false;
	};
	showLoadingIndicator = function(options)
	{
		if (options._tweetFeedElement && options.loadingDecorator && !options._loadingIndicatorElement)
		{
			options._loadingIndicatorElement = $(options.loadingDecorator(options));
			options.loadingIndicatorVisualizer(options._tweetFeedElement, options._loadingIndicatorElement, options, null);
			options._tweetFeedElement.scrollTop(1000000);
		}
	};
	hideLoadingIndicator = function(options, callback)
	{
		if (options._loadingIndicatorElement)
		{
			options.loadingIndicatorVisualizer(null, options._loadingIndicatorElement, options, callback);
			options._loadingIndicatorElement = null;
		}
		else
		{
			if (callback)
			{
				callback();
			}
		}
	};
	isLoading = function(options)
	{
		return options._loadingIndicatorElement != null;
	};
    formatDate = function(dateStr)
	{
    	return dateStr.replace(/^([a-z]{3})( [a-z]{3} \d\d?)(.*)( \d{4})$/i, '$1,$2$4$3');
    };
	validateRange = function(num, lo, hi)
	{
		if (num < lo)
			num = lo;

		if (num > hi)
			num = hi;

		return num;
	};
    showError = function(options, errorText)
	{
    	if (options.errorDecorator && options._tweetFeedElement)
    	{
    		options._tweetFeedElement.append(options.errorDecorator(errorText, options));
    	}
    };
    getPagedTweets = function(options, callback)
    {
    	options._tweetFeedConfig._recLevel = 0;

    	getRecPagedTweets(options, options._tweetFeedConfig.paging._offset, options._tweetFeedConfig.paging._limit, callback);
    };
    getRecPagedTweets = function(options, offset, limit, callback)
	{
    	++options._tweetFeedConfig._recLevel;

    	if (offset + limit <= options._tweetsCache.length ||
    		options._tweetFeedConfig._recLevel > 3 ||
    		options._tweetFeedConfig._noData
    	)
		{
    		// if the requested data is already cached or the max. no. of
    		// consecutive API calls is reached, use the records

    		if (offset + limit > options._tweetsCache.length)
    		{
    			limit = Math.max(0, options._tweetsCache.length - offset);
    		}

			var tweets = [];

			for (var i = 0; i < limit; i++)
			{
				tweets[i] = options._tweetsCache[offset + i];
			}

			callback(tweets, options);
		}
    	else
		{
    		// ... if not, load the data, fill the cache and try again
    		++options._tweetFeedConfig._pageParam;

    		getRateLimitedData(options, false, getFeedUrl(options, true), function(data, options)
    		{
    			var tweets = data.results || data;

    			if (tweets.length == 0)
    			{
    				options._tweetFeedConfig._noData = true;
   				}
    			else
				{
    				$.each(tweets, function(idx, tweet)
    				{
    					// Snowflake support: just update ids that are currently used
    					if (tweet.id_str) { tweet.id = tweet.id_str; }
    					if (tweet.in_reply_to_status_id_str) { tweet.in_reply_to_status_id = tweet.in_reply_to_status_id_str; }

    					// save the first tweet id for subsequent paging requests
    					if (!options._tweetFeedConfig._maxId)
    					{
    						options._tweetFeedConfig._maxId = tweet.id;
    					}

    					// optionally filter tweet ...
    					if (options.tweetFilter(tweet, options))
    					{
    						// then put it into the cache
    						options._tweetsCache.push(tweet);
    					}
    				});
				}

    			getRecPagedTweets(options, offset, limit, callback);
    		});
		}
	};
	getRateLimitedData = function(options, flAutorefresh, url, callback)
	{
		getRateLimit(options, function(rateLimit)
		{
			if (rateLimit && rateLimit.remaining_hits <= 0)
			{
				options._stats.rateLimitPreventionCount++;
				hideLoadingIndicator(options, null);
				return;
			}

			getData(options, flAutorefresh, url, callback);
		});
	};
	getData = function(options, flAutorefresh, url, callback)
	{
		options._stats.dataRequestCount++;

		if (!options.onDataRequestHandler(options._stats, options))
		{
			hideLoadingIndicator(options, null);
			return;
		}

		if (!flAutorefresh)
		{
			showLoadingIndicator(options);
		}

		$.getJSON(url, function(data)
		{
			if (data.error)
			{
				// in case of an error, display the error message
				showError(options, data.error);
			}
			else
			{
				callback(data, options);
			}
		});
	};
	getRateLimit = function(options, callback)
	{
		$.getJSON("http://api.twitter.com/1/account/rate_limit_status.json?callback=?", function(rateLimit)
		{
			options._stats.rateLimit = rateLimit;

			options.onRateLimitDataHandler(options._stats, options);

			callback(rateLimit);
		});
	};
})(jQuery);



/*
 * TwitStream - A jQuery plugin for the Twitter Search API
 * Version 1.2
 * http://kjc-designs.com/TwitStream
 * Copyright (c) 2009 Noah Cooper
 * Licensed under the GNU General Public License <http://www.gnu.org/licenses/>
*/
String.prototype.linkify=function(){
	return this.replace(/[A-Za-z]+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&;\?\/.=]+/g,function(m){
		return m.link(m);
	});
};
String.prototype.linkuser=function(){
	return this.replace(/[@]+[A-Za-z0-9-_]+/g,function(u){
		return u.link("http://twitter.com/"+u.replace("@",""));
	});
};
String.prototype.linktag=function(){
	return this.replace(/[]+[A-Za-z0-9-_]+/,function(t){
		return t;
	});
};
var showTweetLinks='none';
function fetch_tweets(elem){
	elem=$(elem);
	keyword=escape(elem.attr('title'));
	num=elem.attr('class').split(' ').slice(-1);
	var url="http://search.twitter.com/search.json?q="+keyword+"&rpp="+num+"&callback=?";
	$.getJSON(url,function(json){
		$(json.results).each(function(){
			var tTime=new Date(Date.parse(this.created_at));
			var cTime=new Date();
			var sinceMin=Math.round((cTime-tTime)/60000);
			if(sinceMin==0){
				var sinceSec=Math.round((cTime-tTime)/1000);
				if(sinceSec<10)
					var since='less than 10 seconds ago';
				else if(sinceSec<20)
					var since='less than 20 seconds ago';
				else
					var since='half a minute ago';
			}
			else if(sinceMin==1){
				var sinceSec=Math.round((cTime-tTime)/1000);
				if(sinceSec==30)
					var since='half a minute ago';
				else if(sinceSec<60)
					var since='less than a minute ago';
				else
					var since='1 minute ago';
			}
			else if(sinceMin<45)
				var since=sinceMin+' minutes ago';
			else if(sinceMin>44&&sinceMin<60)
				var since='about 1 hour ago';
			else if(sinceMin<1440){
				var sinceHr=Math.round(sinceMin/60);
				if(sinceHr==1)
					var since='about 1 hour ago';
				else
					var since='about '+sinceHr+' hours ago';
			}
			else if(sinceMin>1439&&sinceMin<2880)
				var since='1 day ago';
			else{
				var sinceDay=Math.round(sinceMin/1440);
				var since=sinceDay+' days ago';
			}
			//var tweetBy='<a class="tweet-user" target="_blank" href="http://twitter.com/'+this.from_user+'">@'+this.from_user+'</a> <span class="tweet-time">'+since+'</span>';
                        var tweetBy=' <a class="tweet-user" target="_blank" href="http://twitter.com/'+this.from_user+'">@'+this.from_user+'</a>';
			if(showTweetLinks.indexOf('reply')!=-1)
				tweetBy=tweetBy+' &middot; <a class="tweet-reply" target="_blank" href="http://twitter.com/?status=@'+this.from_user+' &in_reply_to_status_id='+this.id+'&in_reply_to='+this.from_user+'">Reply</a>';
			if(showTweetLinks.indexOf('view')!=-1)
				tweetBy=tweetBy+' &middot; <a class="tweet-view" target="_blank" href="http://twitter.com/'+this.from_user+'/statuses/'+this.id+'">View Tweet</a>';
			if(showTweetLinks.indexOf('rt')!=-1)
				tweetBy=tweetBy+' &middot; <a class="tweet-rt" target="_blank" href="http://twitter.com/?status=RT @'+this.from_user+' '+escape(this.text.replace(/&quot;/g,'"'))+'&in_reply_to_status_id='+this.id+'&in_reply_to='+this.from_user+'">RT</a>';
			//var tweet='<div class="tweet"><div class="tweet-left"><a target="_blank" href="http://twitter.com/'+this.from_user+'"><img width="48" height="48" alt="'+this.from_user+' on Twitter" src="'+this.profile_image_url+'" /></a></div><div class="tweet-right"><p class="text">'+this.text.linkify().linkuser().linktag().replace(/<a/g,'<a target="_blank"')+'<br />'+tweetBy+'</p></div><br style="clear: both;" /></div>';
                        var tweet='<div class="tweet"><p class="text">'+this.text.linkify().linkuser().linktag().replace(/<a/g,'<a target="_blank"')+tweetBy+'</p></div>';
			elem.append(tweet);
		});
	});
	return(false);
}
$(function(){
	showTweetLinks=showTweetLinks.toLowerCase();
	if(showTweetLinks.indexOf('all')!=-1)
		showTweetLinks='reply,view,rt';
	$('.twitStream').each(function(){
		fetch_tweets(this);
	});
});
