/**
provides: 
	G8:									global namespace. will be created or extended if already set
	G8.dbg:							debugging func
	G8.ax_jqxtnd:				static class with general tools
	$Self(sel,scope):		new jquery-style selector
	String methods:			String objekt extensions
	jQuery methods:			jQuery extensions
*/

window.G8 = window.G8 || {}; //Global Namespace: G8. extend if already available, else create

// +++ Debugging +++ +++ +++ +++ +++ +++ +++
G8.dbg = function(){ 		
	if(console && navigator.userAgent.indexOf("Firefox")!=-1) console.info(arguments);
	else {
		var strOut = "";
		$.each(arguments,function(key,val){
			strOut += val + "\n\n";
		});
		alert(strOut);
	}
};

// +++ Tools +++ +++ +++ +++ +++ +++ +++
/**
Class Static: 	ax_lightbox

package: 				eeElements.gallery

--- --- --- --- --- --- ---
provides:

	public methods:
		objectExtend(destination, source)
		escapeHtml(str)
		unescapeHtml(str)
		inputToHtml
		htmlToInput
		arrayCutFirst
		windowScrollTop
		windowScrollLeft
		readEmbedVideo
		getQueryVal
		cookie

*/

//--- class --- --- --- --- --- --- ---
G8.ax_jqxtnd = (function ax_jqxtnd(){

	function objectExtend(destination, source){ /*
		Native Object Extension */
		
	  for (var property in source) destination[property] = source[property];
	  return destination;
	}
		
	function escapeHtml(str){ /*
		bugfix: diese funktionen sollen eigentlich string prototyp extenden.
		geht aber nicht, weil sie irgendwo (auch in unterfunktion) $() benutzen. kontext problem? */

		return $("<div></div>").text(str).html();
	}
	
	function unescapeHtml(str){
		return $("<div></div>").html(str).text();
	}
	
	function inputToHtml(str){ /*
		wandlung von eingaben aus textfeld für html darstellung */
		
		return escapeHtml(str).nl2br().space2Nbsp();
	}
	
	function htmlToInput(str){ /*
	wandlung von html für textfeld eingabe 
	entfernt auch alle html tags AUSSER "<br />" und "$nbsp;", d.h. "Lorem <br /><a href>ipsum</a>" -> "Lorem \n ipsum" */

	  return unescapeHtml(str.br2nl().nbsp2Space());
	}
	
	function arrayCutFirst(obj){
	  var arr = $.makeArray(obj);
	  arr.shift();
	  return arr;
	}
	
	function windowScrollTop(val){ /*
		diese handelt scrollTop/ScrollLeft für die seite (wegenunterschiede $("body").scrollTop(), $("html").scrollTop(), $(document).scrollTop(), $(window).scrollTop	*/
		
		if(val)	return $("html,body").scrollTop(val);
		else {
			var doc = document.documentElement;
			var body = document.body;
	  	return doc && doc.scrollTop || body && body.scrollTop || 0;
		}
	}
	
	function windowScrollLeft(val){
		if(val)	return $("html,body").scrollLeft(val);
		else {
			var doc = document.documentElement;
			var body = document.body;
	  	return doc && doc.scrollLeft || body && body.scrollLeft || 0;
		}
	}
	
	function readEmbedVideo(par){ /*
	liest aus obj oder string dimensions und src (für <object>, <embed>).
	
	par kann sein:
	 jObj: 						$('<object><embed>...')
	 markup string:		"<object><embed>"
	 direct url:			"http://www.youtube.com?v=123" */
	
	/*
	--- Für diese funzt (markup oder direct link): ---
	www.youtube.com
		-DIRECT: http://www.youtube.com/watch?v=[VIDEOID]
		-EMBED MARKUP: <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/xlRPDhuX1DY&hl=de&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/xlRPDhuX1DY&hl=de&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object>
		->EMBED SRC: http://www.youtube.com/v/[VIDEOID]&hl=de&fs=1
		->THUMBNAIL: http://img.youtube.com/vi/[VIDEOID]/default.jpg oder http://img.youtube.com/vi/[VIDEOID]/   1.jpg,2.jpg,3.jpg
	info: hÃ¤nge &fs=1 an, damit fullscreen button angezeigt wird!
	
	www.youtube-nocookie.com
		gleiches format wie youtube.com, aber www.youtube-nocookie.com domain
	
	www.tudou.com
		-"FLASH EXTERN LINK" (=so Ã¤hnlich wie EMBED): http://www.tudou.com/v/uGV8409kesY
	
	video.aol.com
		-EMBED MARKUP: <object width='400' height='300'><param name='movie' value='http://www.cbs.com/e/Zv0WuHjnuNNvIfP_upkx3EZUuI6K8PCl/aol/1/'></param><param name='allowFullScreen' value='true'></param><param name='allowScriptAccess' value='always'></param><embed width='400' height='300' src='http://www.cbs.com/e/Zv0WuHjnuNNvIfP_upkx3EZUuI6K8PCl/aol/1/'  allowfullscreen='true' allowScriptAccess='always' type='application/x-shockwave-flash'></embed></object>
	
	www.veoh.com
		-DIRECT: http://www.veoh.com/IRGENDWAS/IRGENDWAS.../watch/[VIDEOID]
		direct to embed geht noch nicht
		-EMBED MARKUP: <object width="410" height="341" id="veohFlashPlayer" name="veohFlashPlayer"><param name="movie" value="http://www.veoh.com/static/swf/webplayer/WebPlayer.swf?version=AFrontend.5.4.2.21.1002&permalinkId=[VIDEOID]&player=videodetailsembedded&videoAutoPlay=0&id=anonymous"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.veoh.com/static/swf/webplayer/WebPlayer.swf?version=AFrontend.5.4.2.21.1002&permalinkId=e41596&player=videodetailsembedded&videoAutoPlay=0&id=anonymous" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="410" height="341" id="veohFlashPlayerEmbed" name="veohFlashPlayerEmbed"></embed></object><br /><font size="1">Watch <a href="http://www.veoh.com/browse/videos/category/entertainment/watch/e41596">The Last Woman on Earth</a> in <a href="http://www.veoh.com/browse/videos/category/entertainment">Unterhaltung</a>&nbsp;&nbsp;|&nbsp;&nbsp;View More <a href="http://www.veoh.com">Free Videos Online at Veoh.com</a></font>
	
	vids.myspace.com
		-DIRECT: http://vids.myspace.com/index.cfm?fuseaction=vids.individual&videoid=[VIDEOID]
		direct to embed: noch nicht umgesetzt
		-EMBED MARKUP:<a href="http://vids.myspace.com/index.cfm?fuseaction=vids.individual&videoid=48478127">Mini Beyonce</a><br/><object width="425px" height="360px" ><param name="allowFullScreen" value="true"/><param name="wmode" value="transparent"/><param name="movie" value="http://mediaservices.myspace.com/services/media/embed.aspx/m=48478127,t=1,mt=video,searchID=,primarycolor=,secondarycolor="/><embed src="http://mediaservices.myspace.com/services/media/embed.aspx/m=48478127,t=1,mt=video,searchID=,primarycolor=,secondarycolor=" width="425" height="360" allowFullScreen="true" type="application/x-shockwave-flash" wmode="transparent"/></object>
		->EMBED SRC: http://mediaservices.myspace.com/services/media/embed.aspx/m=[VIDEOID],t=1,mt=video,searchID=,primarycolor=,secondarycolor=
	
	www.break.com
		-EMBED MARKUP: <object width="464" height="376" id="822222" type="application/x-shockwave-flash"><param name="movie" value="http://embed.break.com/ODIyMjIy"></param><param name="allowScriptAccess" value="always"></param><embed src="http://embed.break.com/ODIyMjIy" type="application/x-shockwave-flash" allowScriptAccess=always width="464" height="376"></embed></object><br><font size=1><a href="http://www.break.com/index/crazy-car-accident-at-intersection.html">Crazy Car Accident At Intersection</a> - Watch more <a href="http://www.break.com/">Funny Videos</a></font>
	
	www.vimeo.com
		-DIRECT: http://vimeo.com/3089176
		-EMBED MARKUP:	<object width="400" height="225"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=3089176&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=3089176&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="225"></embed></object><br /><a href="http://vimeo.com/3089176">Mykonos</a> from <a href="http://vimeo.com/grandchildren">Grandchildren</a> on <a href="http://vimeo.com">Vimeo</a>.
	
	video.google.com
		-DIRECT: http://video.google.de/videoplay?docid=-2904170660301853607&hl=de
		-EMBED MARKUP:	<embed id="VideoPlayback" src="http://video.google.de/googleplayer.swf?docid=-2904170660301853607&hl=de&fs=true" style="width:400px;height:326px" allowFullScreen="true" allowScriptAccess="always" type="application/x-shockwave-flash"> </embed>
	
	www.dailymotion.com
		-DIRECT: http://www.dailymotion.com/video/x871vj_obamas-speeches-teach-english_news
		geht direct to embed conversion?
		-EMBED MARKUP:	<div><object width="480" height="381"><param name="movie" value="http://www.dailymotion.com/swf/k4YfbANpEE3q8sVL9t&related=1"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed src="http://www.dailymotion.com/swf/k4YfbANpEE3q8sVL9t&related=1" type="application/x-shockwave-flash" width="480" height="381" allowFullScreen="true" allowScriptAccess="always"></embed></object><br /><b><a href="http://www.dailymotion.com/video/x871vj_obamas-speeches-teach-english_news">Obama's speeches teach English</a></b><br /><i>Hochgeladen von <a href="http://www.dailymotion.com/CNN_International">CNN_International</a></i></div>
	
	www.metacafe.com
		-EMBED MARKUP:	<embed src="http://www.metacafe.com/fplayer/2381956/worst_female_cycling_start_ever.swf" width="400" height="345" wmode="transparent" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" allowFullScreen="true"> </embed><br><font size = 1><a href="http://www.metacafe.com/watch/2381956/worst_female_cycling_start_ever/">Worst Female Cycling Start Ever</a> - <a href="http://www.metacafe.com/">Funny video clips are a click away</a></font>
	
	video.gmx.net
		-PERMALINK: http://www.gmx.net/watch/5885225
		-EMBED MARKUP:	<object style='width:470px;height:406px;' width='470' height='406' type='application/x-shockwave-flash' data='http://video.gmx.net/movie/5885225'><param name='movie' value='http://video.gmx.net/movie/5885225'></param><param name='AllowFullscreen' value='true'></param><embed src='http://video.gmx.net/movie/5885225' width='470' height='406'></embed></object><br/><a href='http://video.gmx.net/watch/5885225/Nackt_an_der_Tankstelle' title='Nackt an der Tankstelle - GMX Video'>Nackt an der Tankstelle - GMX Video</a>
	
	video.web.de:
		-DIRECT: http://video.web.de/watch/5863839/hammer_pool_trick
		-EMBED MARKUP:	<object style='width:470px;height:406px;' width='470' height='406' type='application/x-shockwave-flash' data='http://video.web.de/movie/5863839'><param name='movie' value='http://video.web.de/movie/5863839'></param><param name='AllowFullscreen' value='true'></param><embed src='http://video.web.de/movie/5863839' width='470' height='406'></embed></object><br/><a href='http://video.web.de/watch/5863839/hammer_pool_trick' title='hammer pool trick - WEB.DE Video'>hammer pool trick - WEB.DE Video</a>
	
	liveleak.com
		-DIRECT: http://www.liveleak.com/view?i=1f6_1233641924
		-EMBED MARKUP: <object width="450" height="370"><param name="movie" value="http://www.liveleak.com/e/1f6_1233641924"></param><param name="wmode" value="transparent"></param><embed src="http://www.liveleak.com/e/1f6_1233641924" type="application/x-shockwave-flash" wmode="transparent" width="450" height="370"></embed></object>
	
	www.viddler.com
		-DIRECT: http://www.viddler.com/explore/failblog/videos/250/
		-EMBED MARKUP: <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="437" height="333" id="viddler_44fda3cc"><param name="movie" value="http://www.viddler.com/player/44fda3cc/" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /><embed src="http://www.viddler.com/player/44fda3cc/" width="437" height="333" type="application/x-shockwave-flash" allowScriptAccess="always" allowFullScreen="true" name="viddler_44fda3cc"></embed></object>
		
	juggling.tv
		-EMBED MARKUP: <embed src="http://juggling.tv/nvplayer.swf?config=http://juggling.tv/nuevo/econfig.php?key=36a8c2d8bd3fa91ad3ac" width="488" height="414" wmode="transparent" allowscriptaccess="always" allowfullscreen="false" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" /></embed>
	*/
		//defaults:
		var dataState = false; // false / "ok" / "notSupported"(wenn provider nicht zulÃ¤ssig)
		var supportedProviders = [
			"www.youtube.com","www.youtube-nocookie.com",
			"video.gmx.net","www.gmx.net",
			"video.web.de",
			"www.liveleak.com",
			"www.metacafe.com",
			"video.google.com",
			"www.vimeo.com","vimeo.com",
			"vids.myspace.com","mediaservices.myspace.com",
			"www.break.com","embed.break.com",
			"www.veoh.com",
			"www.tudou.com",
			"video.aol.com","www.cbs.com",
			"www.dailymotion.com",
			"www.viddler.com",
			"juggling.tv"
		];
		var defaultVideoW = "348";
		var defaultVideoH = "282";
		var testObj,videoUrl,videoW,videoH,videoFlashVars;
		var thumbnailSrcs = [];
		var mode = "MarkupObj"; //default
		//ist es direkte URL?
		if(typeof par=="string") if(!par.hasStr("<")) mode = "Url";
		//--- object/markup: dimensions & src lesen
		if(mode == "MarkupObj") {
			var obj = $(par);
			//--- try read from <embed>
			testObj = $Self("embed",obj);
			if(testObj.length){
				videoUrl = testObj.attr("src");
				videoW = testObj.attr("width");
				videoH = testObj.attr("height");
				videoFlashVars = testObj.attr("flashVars");
			//-- try read form <object>
			} else {
				testObj = $Self("object",obj);
				if(testObj.length){
					//aus <object> lesen
					videoUrl = testObj.attr("data");
					videoW = testObj.attr("width");
					videoH = testObj.attr("height");
					//aus <param> lesen
					if(videoUrl=="") videoUrl = testObj.find("param[name='movie']").attr("value");
					videoFlashVars = testObj.find("param[name='FlashVars']").attr("value");
				}
			}
			//correct: z.b. google schreibt dimensions per style
			if(!videoW) videoW = testObj.css("width").stripCssUnit();
			if(!videoH) videoH = testObj.css("height").stripCssUnit();
			//wenn immer noch keine angabe: benutze default
			if(!videoW) videoW = defaultVideoW;
			if(!videoH) videoH = defaultVideoH;
			if(videoUrl){
				//change special youtube domain
				videoUrl = videoUrl.replace("youtube-nocookie.com","youtube.com");
				//--- read videoThumbnail src
				if(videoUrl.hasStr("youtube.com")) {
					var videoId = videoUrl.hasStr("&")? videoUrl.slice(0,videoUrl.indexOf("&")).replace("http://www.youtube.com/v/","") : videoUrl.slice(0).replace("http://www.youtube.com/v/","");
	 				thumbnailSrcs.push('http://img.youtube.com/vi/'+videoId+'/1.jpg');
	 				thumbnailSrcs.push('http://img.youtube.com/vi/'+videoId+'/2.jpg');
	 				thumbnailSrcs.push('http://img.youtube.com/vi/'+videoId+'/3.jpg');
	 				//modify video url: prevent related videos and mod color of playercontrols
	 				videoUrl = "http://www.youtube.com/v/"+videoId+"&fs=1&rel=0&color1=0x464646&color2=0xCDCDCD";
				}
			}
			
		//--- direct url: try to create embed-src from directUrl, use default dimensions/markup
		} else if(mode == "Url"){
			var str = par;
			//strip linebreaks
			var dirVideoUrl = str.stripNl();
			//add "http://"
			if(!dirVideoUrl.hasStr("http://")) dirVideoUrl = "http://"+dirVideoUrl;
			//--- translate direct url to embed url
			//youtube
			if(dirVideoUrl.hasStr("www.youtube.com")) videoUrl = dirVideoUrl.replace("www.youtube.com/watch?v=","www.youtube.com/v/");
			//vimeo
			else if(dirVideoUrl.hasStr("vimeo.com")) videoUrl = dirVideoUrl.replace("vimeo.com/","vimeo.com/moogaloop.swf?clip_id=");
			//gmx
			else if(dirVideoUrl.hasStr("video.gmx.net","www.gmx.net")) videoUrl = dirVideoUrl.replace("www.gmx.net","video.gmx.net").replace("video.gmx.net/watch","video.gmx.net/movie");
			//web.de
			else if(dirVideoUrl.hasStr("video.web.de")) videoUrl = dirVideoUrl.replace("video.web.de/watch","video.web.de/movie");
			//liveleak.com
			else if(dirVideoUrl.hasStr("www.liveleak.com")) videoUrl = dirVideoUrl.replace("www.liveleak.com/view?i=","www.liveleak.com/e/");
			//vids.myspace.com:
			else if(dirVideoUrl.hasStr("vids.myspace.com")) {
				var videoId = dirVideoUrl.match(/videoid=[^&]*/);
				if(videoId) {
					videoId = videoId[0].toString().replace("videoid=","");
					videoUrl = "http://mediaservices.myspace.com/services/media/embed.aspx/m="+videoId; }} 
			//www.veoh.com
			else if(dirVideoUrl.hasStr("www.veoh.com")) {
				var videoId = dirVideoUrl.match(/\/watch\/\S*/);
				if(videoId) {
					videoId = videoId[0].toString().replace("/watch/","");
					videoUrl = "http://www.veoh.com/static/swf/webplayer/WebPlayer.swf?permalinkId="+videoId; }}
	
			videoW = defaultVideoW;
			videoH = defaultVideoH;
		}
		//gültiges video?
		if(videoUrl==undefined || videoUrl.hasStr(" ") || !videoUrl.hasStr(".")) {
			return {dataState:false};
		} else {
			dataState = videoUrl.hasStr(supportedProviders)? "ok" : "notSupported";
			if(videoUrl.hasStr("www.youtube.com") && !videoUrl.hasStr("fs=")) videoUrl = videoUrl+"&fs=1"; //youtube: force "fs=1" for fullscreen button
			return {dataState:dataState, url:videoUrl, width:videoW, height:videoH, flashVars:videoFlashVars, thumbnailSrcs:thumbnailSrcs};
		}
	}
	
	function getQueryVal(queryKey){
		var queryStr = window.location.search.substring(1);
		var pairs = queryStr.split("&");
		var	retVal;
		$.each(pairs,function(key,val){
			var splittedPair = val.split("=");
			if(splittedPair[0]==queryKey){
				retVal = splittedPair.length>1? splittedPair[1] : "";
				return false;
			}
		});
		return retVal;
	}

	function cookie(name, value, options) {
	/**
	 * Cookie plugin
	 *
	 * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
	 * Dual licensed under the MIT and GPL licenses:
	 * http://www.opensource.org/licenses/mit-license.php
	 * http://www.gnu.org/licenses/gpl.html
	
	
	 * Create a cookie with the given name and value and other optional parameters.
	 *
	 * example $.cookie('the_cookie', 'the_value');
	 * desc Set the value of a cookie.
	 * example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
	 * desc Create a cookie with all available options.
	 * example $.cookie('the_cookie', 'the_value');
	 * desc Create a session cookie.
	 * example $.cookie('the_cookie', null);
	 * desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
	 *      used when the cookie was set.
	 *
	 * param String name The name of the cookie.
	 * param String value The value of the cookie.
	 * param Object options An object literal containing key/value pairs to provide optional cookie attributes.
	 * option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
	 *                            If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
	 *                            If set to null or omitted, the cookie will be a session cookie and will not be retained
	 *                            when the the browser exits.
	 * option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
	 * option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
	 * option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
	 *                       require a secure protocol (like HTTPS).
	 * type undefined
	 *
	 * name $.cookie
	 * cat Plugins/Cookie
	 * author Klaus Hartl/klaus.hartl@stilbuero.de
	
	
	 * Get the value of a cookie with the given name.
	 *
	 * example $.cookie('the_cookie');
	 * desc Get the value of a cookie.
	 *
	 * param String name The name of the cookie.
	 * return The value of the cookie.
	 * type String
	 *
	 * name $.cookie
	 * cat Plugins/Cookie
	 * author Klaus Hartl/klaus.hartl@stilbuero.de
	 */
		
	    if (typeof value != 'undefined') { // name and value given, set cookie
	        options = options || {};
	        if (value === null) {
	            value = '';
	            options.expires = -1;
	        }
	        var expires = '';
	        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
	            var date;
	            if (typeof options.expires == 'number') {
	                date = new Date();
	                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
	            } else {
	                date = options.expires;
	            }
	            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
	        }
	        // CAUTION: Needed to parenthesize options.path and options.domain
	        // in the following expressions, otherwise they evaluate to undefined
	        // in the packed version for some reason...
	        var path = options.path ? '; path=' + (options.path) : '';
	        var domain = options.domain ? '; domain=' + (options.domain) : '';
	        var secure = options.secure ? '; secure' : '';
	        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
	    } else { // only name given, get cookie
	        var cookieValue = null;
	        if (document.cookie && document.cookie != '') {
	            var cookies = document.cookie.split(';');
	            for (var i = 0; i < cookies.length; i++) {
	                var cookie = $.trim(cookies[i]);
	                // Does this cookie string begin with the name we want?
	                if (cookie.substring(0, name.length + 1) == (name + '=')) {
	                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
	                    break;
	                }
	            }
	        }
	        return cookieValue;
	    }
	}

	//--- return public methods & properties --- --- --- --- --- --- ---
	return {
		objectExtend:objectExtend,
		escapeHtml:escapeHtml,
		unescapeHtml:unescapeHtml,
		inputToHtml:inputToHtml,
		htmlToInput:htmlToInput,
		arrayCutFirst:arrayCutFirst,
		windowScrollTop:windowScrollTop,
		windowScrollLeft:windowScrollLeft,
		readEmbedVideo:readEmbedVideo,
		getQueryVal:getQueryVal,
		cookie:cookie
	};

})();

//+++ new jQ-Style Selector +++ +++ +++ +++ +++ +++ +++
function $Self(selector,scope){ /*
	wie $, findet aber selector angewendet auf -scope childs und -scope selbst */
	
	return scope.find(selector).add(scope.filter(selector));
}

//+++ String Extension +++ +++ +++ +++ +++ +++ +++
G8.ax_jqxtnd.objectExtend(String.prototype, {

  stripScripts: function(){
    return this.replace(new RegExp('<\s*script[^>]*>([\\S\\s]*?)<\/\s*script[^>]*>', 'img'), '');
  },

  stripTags: function(){
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  truncate: function(length, truncation){
    length = length || 30;
    truncation = truncation === undefined ? '...' : truncation;
    return this.length > length ? this.slice(0, length - truncation.length) + truncation : String(this);
  },

  nl2br: function(){
  	//wandel input-zeilenumbruch in html zeilenumbruch
  	//wandel <br><br> in <br>&nbsp;<br> damit leere zeile im html angezeigt wird
    return this.replace(/(\r\n)|(\n\r)|\r|\n/g,"<br />").replace(/<br \/><br \/>/g,"<br />&nbsp;<br />");
  },

  stripNl: function(){
  	//entfernt linebreaks
    return this.replace(/(\r\n)|(\n\r)|\r|\n/g,"");
  },
  
  stripCssUnit: function(){
  	//entfernt css maÃŸeinheiten
    return parseInt(this);
  },

  br2nl: function(){
    return this.replace(/<br \/>/g,"\n").replace(/<br\/>/g,"\n").replace(/<br>/g,"\n");
  },
  	
  space2Nbsp: function(){
  	//wandel doppel-space in zwei &nbsp;
    return this.replace(/  /g,"&nbsp;&nbsp;");
  },

  nbsp2Space: function(){
    return this.replace(/&nbsp;/g," ").replace(/&#160;/g," ");
  },
  
  hasStr: function(){/*
  parameter: entweder liste von strings ("a","abcd"...) oder array (["a","abc"])
  checkt, ob heuhaufen.indexOf(mindEinerDerNeedles)!=-1. also, ob wenigstens einer der needles im heuhaufen vorkommt
  ist NICHT case sensitive */
  	var strs = $.isArray(arguments[0])? arguments[0] : arguments;
		for(var i=0; i<strs.length; i++) if(this.toLowerCase().indexOf(strs[i].toLowerCase())!=-1) return true;
		return false;
	}
});

//+++ jQuery Obj Extension +++ +++ +++ +++ +++ +++ +++
jQuery.fn.extend({

	fadeInXB: function(speed, callback){
		if($.browser.msie) return this.show(0, callback); //IE transparency bug: just show/hide, no animation
		else return this.fadeIn(speed, callback);
	},
	fadeOutXB: function(speed, callback){
		if($.browser.msie) return this.hide(0, callback); //IE transparency bug: just show/hide, no animation
		else return this.fadeOut(speed, callback);
	},
	tglFadeInXB: function(speed, callback){
		if($.browser.msie) return this.show(0, callback); //IE transparency bug: just show/hide, no animation
		else return this.tglFadeIn(speed, callback);
	},
	tglFadeOutXB: function(speed, callback){
		if($.browser.msie) return this.hide(0, callback); //IE transparency bug: just show/hide, no animation
		else return this.tglFadeOut(speed, callback);
	},

	//wie toggle(switch) von jQuery eigentlich sein sollte: bool==true -> show(); bool==false -> hide()
	//(original fehlerhaft umgesetzt: -man kann nicht chainen und -manchmal funzt der toggle nicht)
	//buginfo: manchmal muss man erst show machen, dann toggle, sonst funzt es nicht. warum?
	//buginfo: nach toggle kann man nicht chain mit .toggle().end().find(nÃ¤chster)... warum?
	tgl: function(bool){
		return bool? this.show() : this.hide();
	},

	//wie toggleClass von jQuery eigentlich sein sollte: bool==true -> addClass(); bool==false -> removeClass()
	//aber jquery funzt nicht
	tglClass: function(cssClass,bool){
		return bool? this.addClass(cssClass) : this.removeClass(cssClass);
	},

  // prüft, ob obj in parentObjs sitzt (oder selbst parentObjs ist).
  // dabei kann parentObjs mehrere objekte sein oder standard selector
  isChildOf: function(parentObjs){
  	//--- wenn selector übergeben, geht auch die standard-methode von jQuery
  	//TODO: geht noch nicht richtig. warum???
  	//if(typeof parentObjs=="string") return this.parents(parentObjs).length>0;
  	//--- prüfe manuell
  	//else {
			var retVal = false;
			var objDOM = this[0];
			$(parentObjs).each(function(){
				//schneller wenn hier direkt verglichen wird anstelle von $(this).children().andSelf() !!
				if(this==objDOM) {
					retVal = true;
					return false;
				} else {
					//TODO: teste, ob weg andersrum (also vom obj.parents() ausgehend) schneller ist
					$(this).find("*").each(function(){
						if(this==objDOM){
							retVal = true;
							return false;
						}
					});
					if(retVal) return false;
				}});
			return retVal;
		//}
  },

  // wie parents, schliesst sich selbst aber ein
  parentsSelf: function(selector){ 
  	return this.parents(selector).add(this.filter(selector));
  },

	unwrap: function(expr){
  	return this.each(function(){
    	$(this).parents(expr).eq(0).after(this).remove();
  	});
	},

  //sleep function: waits x millisecs. works as animation (with queue). wenn andere function ausgeführt werden soll benutze den callback
  sleep: function(speed,callback){
  	//make blank animation, animation of rare used param without any changes
  	//return this.animate({"line-height":this.css("line-height")},speed,callback);
  	//return this.animate({"opacity":this.opacity()},speed,callback);
  	
  	//TODO: sleep macht die nachfolgenden anis langsam. warum?
  	return this;
  },

	//lies teilstirng aus class, die mit prefix beginnt(prefix enthÃ¤lt)
	//beispiel: findet MEINEID per getIdFromClass($(),"needle") aus <div class="text gross needleMEINEID">
	getIdFromClass: function(prefix){
  	var ret = "";
   	if(this.attr("class")){ //error handling
    	$.each(this.attr("class").split(/\s+/), function(){
       	if(this.hasStr(prefix)) ret = this.replace(prefix, "");
     	});
   	}
   	return ret;
	},

	//hÃ¤ngt obj in body (append) und macht display:none (soz. ausgelagert)
	storeDiv: function(){
	  return this.appendTo("body").css({display:"none"});
	},

  //hide div und entfernt es dann komplett
  removeAni: function(speed,callback){
  	var obj = this;
  	this.slideUp(speed,function(){
  		obj.remove();
  		if(callback) callback.call();
  	});
  	return obj;
  },

  //ersetzt class durch andere class (neue class bekommt nur der, der alte class hatte!)
	//"switchClass" gibt es in UI, deswegen anderes naming
	switchClassF: function(oldClass,newClass){
		this.filter("."+oldClass).removeClass(oldClass).addClass(newClass);
		return this;
  },

  //ersetzt einen teil aus src="..." mit neuem string (für img-rollover)
  //val kann string oder regExp sein.
  switchSrc: function(val,newVal){
  	//TODO: wieso function(){return...} ?
    return this.attr("src", function(){return this.src.replace(val, newVal);} );
	},

  //setzt/liest src (einfacher shortcut)
  srcF: function(val){
  	if(val!=undefined) return this.attr("src",val);
  	else return this.attr("src");
	},

  //ersetzt einen teil aus href="..." mit neuem string
  //val kann string oder regExp sein.
  //2do: wenn val=string -> behandel als string, sonst als regExp
  switchHref: function(val,newVal){
  	if(typeof val == "string") val = new RegExp(val);
  	//TODO: wieso function(){return...} ?
    return this.attr("href", function(){return this.href.replace(val, newVal);} );
	},

	//wie stop, aber danach wird NICHTS ausgeführt (schreibt man kommentar in die nÃ¤chste zeile, gibt es fehler im IE!!!!)????
  stopp: function(){
    //return(this.queue([]).stop());
    return this.stop(true);
  },

  outerHtml: function(){
    return $( $('<div></div>').html(this.clone())).html();
  } ,

  //wie fadeIn, aber geeignet für fade Toggling (z.b. item faded-out und wÃ¤hrend fading soll er wieder einfaden)
  tglFadeIn: function(speed, callback){
  	//methode 1: faded von 0-100
  	return this.stopp().hide().opacity(1).fadeIn(speed,callback); //opacity = ziel-opacity!

  	//methode 2: faded von IST-100
  	//return this.stopp().show().fadeTo(speed,1,callback);
  },
  
  tglFadeOut: function(speed, callback){
  	//methode 1: faded von 100-0
  	if(this.is(":visible"))	return this.stopp().show().opacity(1).fadeOut(speed,callback); //opacity = ziel-opacity!
  	//wenn nicht sichtbar: kein fade erzwingen!
  	else return this.hide();

  	//methode 2: faded von IST-0
  	//return this.stopp().show().fadeTo(speed,0,callback);
  },

  //wie slideDown, aber geeignet für fade Toggling (z.b. item slide down und wÃ¤hrend sliding soll er wieder einfaden)
  //TODO: diese func ist noch billig umgesetzt. die origHeight sollte aus objekt gelesen werden (beim ersten mal wo slide passiert)
  //TODO: ausserdem sollten alle animations-arten als eine func umgesetzt werden (tglFadeIn, tglSlidedown usw. als tglFXIn("slide",speed,callback) und tglFXOut(...))
  tglSlideDown: function(speed, origHeight, callback){
  	//methode 1: slided von 0-100
  	return this.stopp().hide().css("height",origHeight).slideDown(speed,callback);

  	//methode 2: faded von IST-100
  	//return this.stopp().show().fadeTo(speed,1,callback);
  },
  
  //TODO: diese func ist noch billig umgesetzt. die origHeight sollte aus objekt gelesen werden (beim ersten mal wo slide passiert)
  tglSlideUp: function(speed, origHeight, callback){
  	//methode 1: slided von 100-0
  	return this.stopp().show().css("height",origHeight).slideUp(speed,callback); 

  	//methode 2: faded von IST-0
  	//return this.stopp().show().fadeTo(speed,0,callback);
  },

  opacity: function(val){
  	if(val || val===0){return this.css({"opacity":val});}
    else return this.css("opacity");
  },

  cloneAsForm: function(obj,opt){
  	opt = opt || {};
  	var wOff = opt.wOff || 0;
  	var hOff = opt.hOff || 0;
  	var color = opt.color || obj.css("color");
  	wOff+=6; //FF3 bug: obwohl form text exakt gleiche metrics hat und textfeld gleiche breite, flieÃŸt text bei umruch anders als im div. deshalb 3 pixel sicherheit
  	
    this.clonePos(obj).css({
    	border: 0,
      fontSize: obj.css("fontSize"),
      color: color,
      backgroundColor: "transparent", //backgroundColor: obj.css("background-color"),
      fontWeight: obj.css("font-weight"),
      fontFamily: obj.css("font-family"),
      textAlign: obj.css("text-align"),
      lineHeight: obj.css("line-height"),
      fontStyle: obj.css("font-style"),
      //textDecoration: obj.css("text-decoration"),
      width: obj.outerWidth()+wOff,
      height: obj.outerHeight()+hOff+(this.get(0).tagName=="TEXTAREA"?15:0)
      //padding: obj.css("padding")
    });

  	return this;
  },


	//--- POSITION ---------------------------------
	
  //windowFixed (default: false): objekt wird im fenster an der position angezeigt (für css:fixed)
  clonePos: function(obj,opts){
  	
  	opts = opts || {};
  	var xOff = opts.xOff || 0;
  	var yOff = opts.yOff || 0;
  	
  	//special:
  	var windowFixed = opts.windowFixed===undefined? false : opts.windowFixed;
  	if(windowFixed) {
    	this.css({
      	left:obj.offset().left-$(window).scrollLeft()+xOff,
      	top:obj.offset().top-$(window).scrollTop()+yOff
    	});
  	
  	//normal
  	} else {  		
  		this.setPosTo(obj,["LEFTI",xOff],["TOPI",yOff]);
  	}
  	
  	return this;
  	/*
  	opts = opts || {};
  	var windowFixed = opts.windowFixed===undefined? false : opts.windowFixed;
  	var xOff = opts.xOff || 0;
  	var yOff = opts.yOff || 0;

  	if(windowFixed) {
    	this.css({
      	left:obj.offset().left-$(window).scrollLeft()+xOff,
      	top:obj.offset().top-$(window).scrollTop()+yOff
    	});
  	} else {
    	this.css({
      	left:obj.offset().left+xOff,
      	top:obj.offset().top+yOff
    	});
    }
    return this;
    */
  },

  left: function(xPos){
    if(xPos==undefined) return this.offset().left;
    else {
      this.css({left:xPos+"px"});
      return this;
    }
  },

  top: function(yPos){
    if(yPos==undefined) return this.offset().top;
    else {
      this.css({top:yPos+"px"});
      return this;
    }
  },

  moveLeft: function(x){
    return this.css({left:this.left()+x});
  },

  moveTop: function(y){
    return this.css({top:this.top()+y});
  },

  //call like:
  //  setPosTo($(obj), "CENTERX");
  //  setPosTo($(obj), "CENTERX", "CENTERY");
  //  setPosTo($(obj), "CENTERX", ["BOTTOMI",-200]);
  //  setPosTo($(obj), ["CENTERX",150], "BOTTOMI");
  
  // wenn man callt:
  //  setPosTo($(window), "CENTERX", "CENTERY"); wird es zentriert auf viewport, sichtbar in der mitte egal wo gecrollt ist
  //  setPosTo($(document), "CENTERX", "CENTERY"); wird es zentriert auf document, in der mitte, also evtl. ausserhalb des viewports
  setPosTo: function(obj, param1, param2){
  	var mode,param;
  	var par = this.parent();
  	var T = {}; //this: das objekt das ausgerichtet wird
  	var P = {}; //par: parent von T
  	var O = {}; //obj: objekt an dem ausgerichtet wird
  	O.isWindow = obj.get(0)==window;
  	O.isDocument = obj.get(0)==document;
    T.height = this.outerHeight();
    T.width = this.outerWidth();
		T.origOpacity = this.css("opacity");
		T.origDisplay = this.css("display");
		if(T.origDisplay=="none") $.browser.msie? this.css({display:"block"}) : this.css({opacity:0,display:"block"}); //show (invisble) //bugfix: IE macht probleme mit png transparency, wenn opacity hier gesetzt wird. besser weglassen
    var xOffset=0;
    var yOffset=0;
    if(this.css("left")=="auto") this.css("left","0px"); //bugfix for all browsers (except FF), if "this" has no explicit left/top setting
    if(this.css("top")=="auto") this.css("top","0px"); //bugfix for all browsers (except FF), if "this" has no explicit left/top setting
    var cssLeft = isNaN(parseFloat(this.css("left")))? 0 : parseFloat(this.css("left"));
    var cssTop = isNaN(parseFloat(this.css("top")))? 0 : parseFloat(this.css("top"));
    var thisParentOffsetX = this.left() - cssLeft;
    var thisParentOffsetY = this.top() - cssTop;
    if(T.origDisplay=="none") $.browser.msie? this.css({display:T.origDisplay}) : this.css({opacity:T.origOpacity,display:T.origDisplay});
    if(O.isWindow || O.isDocument){
	    O.left = 0; //TODO: kann bei document auch anders sein.
  	  O.top = 0;
    	O.height = obj.height();
    	O.width = obj.width();
	    O.scrollLeft = obj.scrollLeft();
  	  O.scrollTop = obj.scrollTop();
  	} else {
	    O.left = obj.left();
  	  O.top = obj.top();
    	O.height = obj.outerHeight();
    	O.width = obj.outerWidth();
	    O.scrollLeft = 0;
  	  O.scrollTop = 0;
  	}
  	var totalParams = param2? 2 : 1;
    for(var i=1; i<=totalParams; i++){ //loop through both params if provided, else only one
    	param = i==1? param1 : param2;
      
      if(typeof param=="object"){ //param is array: maybe offset is provided
        mode = param[0];
        if(param.length==2){ // offset is provided
        	if(mode=="LEFT"||mode=="LEFTI"||mode=="RIGHT"||mode=="RIGHTI"||mode=="CENTERX"){ //provided offset relates to X
        		xOffset = param[1] - thisParentOffsetX + O.scrollLeft; 
        	} else if(mode=="TOP"||mode=="TOPI"||mode=="BOTTOM"||mode=="BOTTOMI"||mode=="CENTERY"){ //provided offset relates to Y
        		yOffset = param[1] - thisParentOffsetY + O.scrollTop;
        	}
        }
      }
      
      else if(typeof param=="string"){ //param is string: no offset
      	mode = param;
     		xOffset = - thisParentOffsetX + O.scrollLeft;
     		yOffset = - thisParentOffsetY + O.scrollTop;
      }
      
      if(this.css("position")=="fixed") xOffset = yOffset = 0; //wenn this position=fixed, gibt es keinen parent offset!

      //--- positionieren
      if(mode=="CENTERX") 			this.left(O.left + Math.round((O.width - T.width)/2) + xOffset);
      else if(mode=="CENTERY") 	this.top(O.top + Math.round((O.height - T.height)/2) + yOffset);
      else if(mode=="LEFT") 		this.left(O.left - T.width + xOffset); //OUTER
      else if(mode=="LEFTI") 		this.left(O.left + xOffset); //INNER
      else if(mode=="TOP") 			this.top(O.top - T.height + yOffset);
      else if(mode=="TOPI") 		this.top(O.top + yOffset);
      else if(mode=="RIGHT") 		this.left(O.left + O.width + xOffset);
      else if(mode=="RIGHTI") 	this.left(O.left + O.width - T.width + xOffset);
      else if(mode=="BOTTOM") 	this.top(O.top + O.height + yOffset);
      else if(mode=="BOTTOMI") 	this.top(O.top + O.height - T.height + yOffset);
    }
    
    return this;
  },

	//--- DIMENSION ---------------------------------
	
  //geht auch für display:none objekte
  // set: macht, dass height + padding + border = wert
  // get: return height incl. padding + border
  totalHeight: function(newHeight){
    if (newHeight==undefined) return this.outerHeight();// return this.height() + pad + bor;
    else {
	  	var pad = this.intPadding().y;
  		var bor = this.intBorder().y;
    	return this.height(newHeight - pad - bor);
    }
  },

  totalWidth: function(newWidth){
    if(newWidth==undefined) return this.outerWidth();//return this.width() + pad + bor;
    else {
	  	var pad = this.intPadding().x;
  		var bor = this.intBorder().x;
    	return this.width(newWidth - pad - bor);
    }
  },
  
  intPadding: function(){
  	var pL = this.intCss("padding-left");
  	var pR = this.intCss("padding-right");
  	var pT = this.intCss("padding-top");
  	var pB = this.intCss("padding-bottom");
  	return {x:pL+pR, y:pT+pB};
	},

  intMargin: function(){
  	var mL = this.intCss("margin-left");
  	var mR = this.intCss("margin-right");
  	var mT = this.intCss("margin-top");
  	var mB = this.intCss("margin-bottom");
  	return {x:mL+mR, y:mT+mB};
	},

  intBorder: function(){
  	//css-schreibweise wichtig (einzig richtige!)
  	var bL = this.intCss("borderLeftWidth"); 
  	var bR = this.intCss("borderRightWidth"); 
  	var bT = this.intCss("borderTopWidth"); 
  	var bB = this.intCss("borderBottomWidth");
  	return {x:bL+bR, y:bT+bB};
	},
	
	intCss: function(str){
		return parseInt(this.css(str));
	},

  cloneWidth: function(obj,xOff){
  	xOff = xOff || 0;
    return this.totalWidth(obj.outerWidth() + xOff);
  },

  cloneHeight: function(obj,yOff){
  	yOff = yOff || 0;
    return this.totalHeight(obj.outerHeight() + yOff);
  },

  cloneDim: function(obj,opts){
  	opts = opts || {};
  	var offWidth = opts.offWidth || 0;
  	var offHeight = opts.offHeight || 0;
  	var margin = opts.margin || false;
    this.css({
      width:obj.outerWidth(margin)+offWidth+"px",
      height:obj.outerHeight(margin)+offHeight+"px"
    });
    return this;
  },

	isInViewport: function(){
 		var win = $(window);
 		var leftScroll = win.scrollLeft();
 		var topScroll = win.scrollTop();
 		var viewportHeight = win.height();
 		var viewportWidth = win.width();
 		
 		var objLeft = this.left();
 		var objRight = objLeft + this.outerWidth();
 		var objTop = this.top();
 		var objBot = objTop + this.outerHeight();
		
		//flags: -1: kleiner als viewport, 0:im viewport, 1: grÃ¶ÃŸer	als viewport
		var leftXFlag = objLeft<leftScroll ? -1 : objLeft>=leftScroll+viewportWidth ? 1 : 0;
		var rightXFlag = objRight<leftScroll ? -1 : objRight>=leftScroll+viewportWidth ? 1 : 0;
		var topYFlag = objTop<topScroll ? -1 : objTop>=topScroll+viewportHeight ? 1 : 0;
		var botYFlag = objBot<topScroll ? -1 : objBot>=topScroll+viewportHeight ? 1 : 0;
		
		//es werden 4 flags returnt (für jede seite des zu prüfenden objekts. 
		//(ausserdem wird noch die viewport breite/hÃ¶he returnt, da man diese oft braucht in verbindung mit isInViewport)
 		return {xLeft:leftXFlag,xRight:rightXFlag,yTop:topYFlag,yBot:botYFlag,viewportHeight:viewportHeight,viewportWidth:viewportWidth};
	}


});


/* 
+++ New Ideas: +++ +++ +++ +++ +++ +++ +++

gute funcs von prototype.js:
-array.uniq(); //macht das mit array, was unique mit objekten macht
-anything.inspect(); //liefert debug string zurück


INFO: mod für in original-jquery:

// Get width or height on the element
//(this.length ? jQuery.css( this[0], type ) : null) :

//FLO MOD: add padding to width/height
(this.length ? jQuery.css(this[0],type)+ (type=="height"?parseInt(this.css("padding-top"))+parseInt(this.css("padding-bottom")):parseInt(this.css("padding-left"))+parseInt(this.css("padding-right"))) : null) :

*/