;(function($) {
	// private variables
	var oSettings = {};
	var sCategory = "";
	var aCategory;
	var oCookie = {};
	var aKoekje = new Array(0,1,2);
	var iKoekNm = 0;
	var aValid = new Array();
	var sFr;
	var sTo;
	//
	// default settings
	$.stampomatic = {
		 id: "Stampomatic"
		,version: "0.2.5"
		,defaults: {
			 debug:		true
			,langfr:	"nl"
			,langto:	"hr"
			,langs:		[]
			,hardchars:	{hr:"čćđšž",es:"ñíóáéü¿",de:"äéöüß",fr:"àèéêçùîô"}//fr:"àâäèéêëîïôœùûüÿç
			,cookiemax:	4096
			,cookiemaxnum:	50
			,cookieprefix:"stampomatic"
			,maxscore: 20
			,settings: '{"langfr":"nl","langto":"hr","score":{}}'
			,pagelang:[
				 ["form.vertaal>a",				"add"]
				,["form.vertaal>input:submit",	"translate"]
				,["#toets>h2",					"practise"]
				,["#settings h2:eq(0)",			"settings"]
				,["#settings h2:eq(1)",			"explanation"]
				,["#settings p",				"I have made this to learn Croatian words, but because it makes use of Google-language it is possible to use it for any supported language. It's quite easy. Translate words and sentences. Then add them by using the buttons below the translation. Everything you add is saved as a cookie on your computer. Beware though that Google will not always return the correct translations. If you are not sure about a word try translating that word within a sentence. And sorry about this explanation, for it was also translated with Google-language."]
				,["#settings input:submit",		"save file"]
				,["#settings input.export",		"export cookie data"]
				,["#settings input.import",		"import cookie data"]
				,["#settings input#clear",		"reset cookie data"]
				,["form.addword>h2",			"add word to category"]
			]
		}
		// public functions
		//,foo: function() {
		//	translateSomething();
		//}
	};
	//	zw	zelfstandig naamwoord
	//	bn	bijvoegelijk naamwoord
	//	ww	werkwoord
	//	vz	voorzetsel
	//	vw	voegwoord
	//
	//	pv	persoonlijk voornaamwoord
	//	vv	vragend voornaamwoord
	//	av	aanwijzend voornaamwoord
	//	bv	betrekkelijk voornaamwoord
	//	zv	bezittelijk voornaamwoord
	//
	//	gt	vergrotende trap
	//	ot	overtreffende trap
	// init
	$(function() {
		//$.fn.stampomatic(); // init
	});

	// call
	$.fn.extend({
		stampomatic: function(_settings) {
			trace($.stampomatic.id+" "+$.stampomatic.version);
			// settings
			oSettings = $.extend({}, $.stampomatic.defaults, _settings);
			var oCkSet = invokeCookie("settings",oSettings.settings);
			trace("settings: "+JSON.stringify(oCkSet));
			if (oCkSet.version!=$.stampomatic.version) { // version control
				trace("Version change from "+oCkSet.version+" to "+$.stampomatic.version);
				switch (String(oCkSet.version)) {
					case "undefined":
					case "0.2.4":
						oCkSet.score = {};
					case "0.2.5":
					case "0.2.6":
				}
				oCkSet.version = $.stampomatic.version;
			}
			oSettings = $.extend({}, oSettings, oCkSet);
			// reset score to max
			for (var lng in oSettings.score) {
				for (var cat in oSettings.score[lng]) {
					var aScr = oSettings.score[lng][cat];
					var iTot = aScr[0]+aScr[1]+aScr[2];
					if (iTot!=oSettings.maxscore) {
						trace("score '"+cat+"' reset to"+oSettings.maxscore);
						aScr[1] = aScr[1]/iTot*oSettings.maxscore;
						aScr[2] = aScr[2]/iTot*oSettings.maxscore;
						aScr[0] = oSettings.maxscore - aScr[1] - aScr[2];
					}
				}
			}
			trace("Start: "+oSettings.langfr+" "+oSettings.langto);
			//
			// resetInterface (and cookies) 
			resetInterface();
			//
			//
			// instellingen
			$("div#setsettings,h2.uitleg").click(function(e){
				$("form#settings").toggle("normal");
				//var mSettings = $("form#settings");
				//mSettings.toggle( 
				//	 function(){trace("a")}
				//	,function(){trace("b")}
				//); //.toggle("normal");//,{direction:"up"});//.fadeToggle();
			});
			var sOptions = "";
			for (var sLang in google.language.Languages) sOptions += "<option value=\""+google.language.Languages[sLang]+"\"> "+langName(sLang);+"</option>";
			var mSettings = $("form#settings");
			var mLangFr = mSettings.find("select.langfr");
			var mLangTo = mSettings.find("select.langto");
			mLangFr.html(sOptions);
			mLangTo.html(sOptions);
			mLangFr.find("option[value="+oSettings.langfr+"]").attr("selected","selected");
			mLangTo.find("option[value="+oSettings.langto+"]").attr("selected","selected");
			mSettings.submit(function(e){
				trace("mForm: "+mLangFr.val()+"_"+mLangTo.val());
				if (mLangFr.val()!=mLangTo.val()) {
					oSettings.langfr = mLangFr.val();
					oSettings.langto = mLangTo.val();
					resetInterface();
					$("form#settings").fadeOut();
				}
				return false;
			});
			$("#clear").click(function(e){eraseCookie(oSettings.cookieprefix+"_settings");eraseCookie(oSettings.cookieprefix+"_"+oSettings.langfr+"_"+oSettings.langto);});
			$("input:button.export").click(function(e){
				//var sKoek = JSON.stringify(oCookie).replace(/\{/g,"{\n").replace(/}/g,"\n}\n").replace(/(],)/g,"],\n");
				$("textarea.export").show().html(JSON.stringify(oCookie));
			});
			$("input:button.import").click(function(e){
				if (!$("textarea.export").is(":visible")) {
					$("textarea.export").show();
				} else {
					try {
						var oTst = JSON.parse($("textarea.export").val());
						var aLang = new Array();
						var iCats = 0;
						for (var a in oTst) {
							aLang.push(a);
							for (var b in oTst[a]) iCats++;
						}
						var aFr = aLang[0].split("_");
						var aTo = aLang[1].split("_");
						if (aLang.length==2&&aFr[0]==aTo[1]&&aFr[1]==aTo[0]&&iCats!=0) {
							oSettings.langfr = aFr[0];
							oSettings.langto = aFr[1];
							saveCookie(oTst);
							createCookie(oSettings.cookieprefix+"_settings",'{"langfr":"'+oSettings.langfr+'","langto":"'+oSettings.langto+'","version":"'+$.stampomatic.version+'"}',3650);
							resetInterface();
							$("form#settings").fadeOut();
						}
					} catch (err) {
						trace("invalid import");
					}
				}
				//var sKoek = JSON.stringify(oCookie).replace(/\{/g,"{\n").replace(/}/g,"\n}\n").replace(/(],)/g,"],\n");
//				$("textarea.export").show().html(JSON.stringify(oCookie));
			});
			//
			// hardchars
			$(".hardchars").parent().find("input:text").keyup(function(e){
				var sTxt = $(this).val();
				var sHrd = hard(sTxt);
				if (sTxt!=sHrd) $(this).val(sHrd);
			});
			//
			// vertalen
			$("form.vertaal").submit(function(e){
				var mForm = $(this);
				var mWord = mForm.find("input.vraag");
				var sWord = mWord.val().replace(/[\"\']/g,"");
				trace("sWord "+" "+sWord);
				if (sWord!="") { // stampomatic word
					var bFromTo = mForm.find(".fromto").val()==sTo;
					google.language.translate(sWord,bFromTo?oSettings.langfr:oSettings.langto,bFromTo?oSettings.langto:oSettings.langfr,function(rs){
						if (!rs.error) {
							mForm.find("p.antwoord").text(rs.translation).hide().fadeIn();
						} else {
							trace(rs.status);
							trace(rs.error);
							trace("translation error: "+sTo+" "+rs.error.message);
						}
					});
				}
				return false;
			});
			//
			// voeg toe / addword
			$("form.vertaal>a").click(function(e){
				var mForm = $(this).parent();
				var sId = mForm.find(".fromto").val();
				var mWord = mForm.find("input.vraag");
				var sWord = mWord.val();
				var mAntw = mForm.find("p.antwoord");
				var sAntw = mAntw.text();
				if (sWord&&sWord&&sWord!=""&&sAntw!="") {
					var mFadd = $("form.addword");
					mFadd.find(".qtype").val(sId);
					mFadd.find("p.to").text(sId==sTo?sWord:sAntw);
					mFadd.find("p.fr").text(sId==sTo?sAntw:sWord);
					mFadd.fadeIn();
				}
			});
			$("form.addword").submit(function(e){
				var mForm = $(this);
				var sType = mForm.find(".qtype").val();
				var sWord = mForm.find("p.fr").text();
				var sAntw = mForm.find("p.to").text();
				var mAddC = mForm.find(">input.cat");
				var sAddC = mAddC.val();
				if (sType!=""&&sWord!=""&&sAntw!=""&&sAddC!="") { // add word to new category
					addWord(sType==sFr?sWord:sAntw,sAddC,sType);
					mAddC.val("");
				}
				return false;
			}).find("a").click(function(e){$(this).parent().fadeOut()});
			//
			// oefenen
			vrnieuw();
			$("form#toets").submit(function(){
				var mForm = $(this);
				var sType = mForm.find("input.qtype").val();
				if (sType==sTo) {
					google.language.translate(mForm.find("p#vraag").text(),oSettings.langfr,oSettings.langto,function(rs) {
						if (!rs.error) {
							var t = rs.translation;
							antwoord(rs.translation);
						}
					});
				} else {
					antwoord(mForm.find("input.antw").val());
				}
				return false;
			});
		}
		,fadeToggle: function(speed, easing, callback) { 
			return this.animate({opacity: "toggle"}, speed, easing, callback); 
		}
		,asdf: function() {
			trace("asdf");
		}
		
	});
	//
	// resetInterface
	function resetInterface() {
		sTo = oSettings.langfr+"_"+oSettings.langto;
		sFr = oSettings.langto+"_"+oSettings.langfr;
		// check settings
		if (!oSettings.score[sTo]) oSettings.score[sTo] = {};
		// set main cookie
		var sDflt = oSettings[sTo]?oSettings[sTo]:"{\""+sTo+"\":{},\""+sFr+"\":{}}";
		oCookie = JSON.parse(hard(JSON.stringify(invokeCookie(sTo,sDflt,saveCookie))));
		//trace("oCookie "+JSON.stringify(oCookie));
		// imgs
		var iFw = 19;
		var iFh = 13;
		var aSp = ["fr","to"];
		for (var i in aSp) {
			var sWh = aSp[i];
			var sTlng = oSettings["lang"+sWh];
			var iXo = -(sTlng.charCodeAt(0)-97)*iFw;
			var iYo = -(sTlng.charCodeAt(1)-97)*iFh;
			$("span.flag."+sWh).css({backgroundPosition:iXo+"px "+iYo+"px"}).attr("title",sTlng);
		}
		// hardchars
		if (oSettings.hardchars[oSettings.langto]) {
			var sHchrs = oSettings.hardchars[oSettings.langto];
			var sChrsHtml = "";
			for (var i=0;i<sHchrs.length;i++) sChrsHtml += "<span>"+sHchrs.charAt(i)+"</span>"; //trace("charCode "+oSettings.hardchars.charAt(i)+" "+oSettings.hardchars.charCodeAt(i));
			$(".hardchars").html(sChrsHtml);
			$(".hardchars>span").click(function(i,el){
				var mInp = $(this).parent().parent().find("input:text");
				mInp.val(mInp.val()+$(this).text());
				mInp.focus();
			});
		} else {
			$(".hardchars").html("");
		}
		//
		// validate existing cookies
		var aAllCk = document.cookie.split(";");
		for (var i in aAllCk) {
			var aCk = aAllCk[i].split("=");
			var sCkName = aCk[0].replace(/\s/g,"");
			var aCkName = sCkName.split("_");
			if (aCkName[0]==oSettings.cookieprefix&&aCkName[1]!="settings") {
				var oCkData = JSON.parse(aCk[1]);
				var iCnts = 0;
				for (var a in oCkData) for (var b in oCkData[a]) iCnts++;
				if (iCnts==0) eraseCookie(sCkName);
				else aValid.push([aCkName[1],aCkName[2]]);
			}
		}
		//
		// set vertaal headers
		$("form.vertaal").each(function(i,el){
			var mForm = $(this);
			var sFrTo = mForm.attr("id").replace(/(fr)/gi,oSettings.langfr).replace(/(to)/gi,oSettings.langto);
			mForm.find(".fromto").val(sFrTo);
		});
		for (var sLng in google.language.Languages) {
			if (google.language.Languages[sLng]==oSettings.langfr) {
				google.language.translate(langName(sLng),"en",oSettings.langfr,function(rs){
					if (!rs.error) $("form.vertaal>h2>.fr").text(rs.translation);
				});
			};
			if (google.language.Languages[sLng]==oSettings.langto) {
				google.language.translate(langName(sLng),"en",oSettings.langto,function(rs){
					if (!rs.error) $("form.vertaal>h2>.to").text(rs.translation);
				});
			};
		}
		// global document language (via RESTful jsonp)
		var sUri = "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&langpair=en%7C"+oSettings.langfr;
		for (var i in oSettings.pagelang) sUri += "&q="+oSettings.pagelang[i][1];
		$.ajax({type:"GET", url:sUri, dataType:"jsonp", success:function(rs){
			if (rs.responseStatus==200)	{
				for (var i in rs.responseData) {
					var sText = rs.responseData[i].responseData.translatedText;
					var mNode = $(oSettings.pagelang[i][0]);
					if (mNode.get(0).nodeName=="INPUT") mNode.val(sText);
					else mNode.text(sText);
				}
			}
		}});
		// categorieen
		setupCategories();
	}
	//
	// setupCategories
	function setupCategories() {
		var mAdd = $("form.addword ul.category").html("");
		var mChoose = $("form#toets ul.category").html("");
		aCategory = new Array();
		for (var i=0;i<2;i++) {
			var sWay = i==0?sTo:sFr;
			for (var sCat in oCookie[sWay]) {
				//trace("cat "+sWay+" "+sCat);
				if (oCookie[sWay][sCat].length==0) delete oCookie[sWay][sCat];
				else if (aCategory.indexOf(sCat)==-1) aCategory.push(sCat);
			}
		}
		for (var i in aCategory) {
			var sCat = aCategory[i];
			$("<li id=\"choice_"+sCat+"\">"+sCat+"<div class=\"score\"><div><div><div></li>").appendTo(mChoose).click(function(e){sCategory = $(e.currentTarget).text();vrnieuw();});
			$("<li>"+sCat+"</li>").appendTo(mAdd).click(function(e){
				var mTrg = $(e.currentTarget);
				var sAddC = mTrg.text();
				var mForm = $("form.addword");
				mForm.find("input.cat").val(sAddC);
				mForm.submit();
			});
			// score
			if (!oSettings.score[sTo][sCat]) oSettings.score[sTo][sCat] = [0,1,0];
			setScore(sCat);
		}
		saveSettings();
		$("<li id=\"choiceall\">all categories<div class=\"score\"><div><div><div></li>").prependTo(mChoose).click(function(e){sCategory = "";vrnieuw();});
		setScore("");
		mAdd.find(">li").after(" ");
		mChoose.find(">li").after(" ");
	}
	//
	// addWord
	function addWord(sWord,sCat,sType) {
		trace("addWord "+sWord+" "+sCat+" "+sType);
		if (!oCookie[sType][sCat]) oCookie[sType][sCat] = new Array();
		if (oCookie[sType][sCat].indexOf(sWord)==-1) {
			oCookie[sType][sCat].push(sWord);
			saveCookie();
			setupCategories();
		} else {
			trace("addWord: woord bestaat al");
		}
		var mForm = $("form.addword");
		mForm.find("input.cat").val("");
		mForm.fadeOut();
	}
	//
	// removeWord
	function removeWord(sWord,sCat,sType) {
		if (!oCookie[sType][sCat]) {
			return false;
		} else {
			var iPos = oCookie[sType][sCat].indexOf(sWord);
			if (iPos!=-1) oCookie[sType][sCat].splice(iPos, 1);
			if (oCookie[sType][sCat].length==0) {
				delete oCookie[sType][sCat];
				setupCategories();
			}
			saveCookie();
		}
	}
	//
	// vrnieuw
	function vrnieuw() {
		var sCat = sCategory==""?aCategory[Math.floor(Math.random()*aCategory.length)]:sCategory;
		trace("sCategory:"+sCategory+" sCat:"+sCat);
		try {
			var mForm = $("#toets");
			var iToLen = oCookie[sTo][sCat]?oCookie[sTo][sCat].length:0;
			var iFrLen = oCookie[sFr][sCat]?oCookie[sFr][sCat].length:0;
			var iVrMax = iToLen+iFrLen;
			if (iVrMax==0) {
				trace("category is empty");
			} else {
				if (aKoekje.length!=iVrMax) {
					aKoekje = new Array();
					for (var i=0;i<iVrMax;i++) aKoekje[i] = i;
					aKoekje.sort(function(){return Math.random()<.5?1:-1});
				}
				var iVrNum = (iKoekNm++)%aKoekje.length;
				var sType = iVrNum>=iToLen?sFr:sTo;
				if (iVrNum>=iToLen) iVrNum -= iToLen;
				var sVrg = oCookie[sType][sCat][iVrNum];
				//
				mForm.find("input.qtype").val(sType);
				mForm.find("input.qcat").val(sCat);
				if (sType==sTo) {
					mForm.find("p#vraag").text(sVrg).hide().fadeIn();
				} else {
					mForm.find("input.antw").val(sVrg);
					google.language.translate(sVrg,oSettings.langto,oSettings.langfr,function(rs) {
						trace(sType+": "+sVrg+" "+rs.translation);
						if (!rs.error) {
							mForm.find("p#vraag").text(rs.translation).hide().fadeIn();
						}
					});
				}
			}
		} catch (err) {
			trace("vrnieuw category error: "+sCat+" "+err);
			mForm.find("p#vraag").text("")
		}
	}
	//
	// antwoord
	function antwoord(sHr) {
		var mForm = $("#toets");
		var sType = mForm.find("input.qtype").val();
		var sCat = mForm.find("input.qcat").val();
		var sNl = mForm.find("p#vraag").text();
		var mAnt = mForm.find("input:text");
		var sAnt = mAnt.val();
		trace(sType+": "+sNl+"=="+sHr+"?="+sAnt);
		//
		var fSmlr = similarity(sAnt.toLowerCase().replace(/[\?!\.]/gi,""),sHr.toLowerCase().replace(/[\?!\.]/gi,""));
		if (fSmlr==100) {
			sClass = "goed";
			oSettings.score[sTo][sCat][0] += 1;
		} else if (fSmlr<70) {
			sClass = "fout";
			oSettings.score[sTo][sCat][2] += 1;
		} else if (fSmlr<100) {
			sClass = "bijna";
			oSettings.score[sTo][sCat][1] += 1;
		}
		var sAnswr = "<strong class=\""+sClass+"\">"+sClass+"</strong><br/>"
		sAnswr += "'"+sNl+"' is '<strong>"+sHr+"</strong>'"+(fSmlr!=100?(" en niet '"+sAnt+"'"):"");
		sAnswr += "<br/><a>verwijder</a>";
		mForm.find("p.antwoord").html(sAnswr).find("a").click(function(e){
			removeWord(sType==sTo?sNl:sHr,sCategory,sType);
		});
		mAnt.val("").focus();
		mForm.find("p#vraag").fadeOut();
		saveSettings();
		setScore();
		if (sCategory=="") setScore(sCat);
		vrnieuw();
	}
	//
	// setScore
	function setScore(sCat) {
		if (!sCat) sCat = sCategory;
		trace("setScore "+sCat);
		var aScore;
		var mScore;
		if (!sCat||sCat=="") {
			aScore = [0,0,0];
			for (var i in oSettings.score[sTo]) {
				aScore[0] += oSettings.score[sTo][i][0];
				aScore[1] += oSettings.score[sTo][i][1];
				aScore[2] += oSettings.score[sTo][i][2];
			}
			mScore = $("#choiceall>.score").html("");
		} else {
			aScore = oSettings.score[sTo][sCat];
			trace(""+"#choice_"+sCat+">.score");
			mScore = $("#choice_"+sCat+">.score").html("");
		}
		trace("mScore "+" "+mScore.length);
		var iTotal = aScore[0]+aScore[1]+aScore[2];
		$("<div></div>").appendTo(mScore).css({width:100*(aScore[0]/iTotal)+"%",backgroundColor:"#5b0"});
		$("<div></div>").appendTo(mScore).css({width:100*(aScore[1]/iTotal)+"%",backgroundColor:"#fc0"});
		$("<div></div>").appendTo(mScore).css({width:100*(aScore[2]/iTotal)+"%",backgroundColor:"#d00"});
	}
	//
	// hardchars
	function hard(s) {
		if (oSettings.hardchars[oSettings.langto]) {
			var sHrd = oSettings.hardchars[oSettings.langto];
			for (var i=0;i<sHrd.length;i++) s = s.replace(new RegExp(String.fromCharCode(i+49),"g"),sHrd.charAt(i));
		}
		return s;
	}
	function unhard(s) {
		if (oSettings.hardchars[oSettings.langto]) {
			var sHrd = oSettings.hardchars[oSettings.langto];
			for (var i=0;i<sHrd.length;i++) s = s.replace(new RegExp(sHrd.charAt(i),"g"),String.fromCharCode(i+49));
		}
		return s;
	}
	//
	// rand
	function rand(a) {
		return a[Math.floor(Math.random()*a.length)];
	}
	// similarity
	function similarity(sSrc, sTrg) {
		var ed = editDistance(sSrc, sTrg);
		var maxLen = Math.max(sSrc.length, sTrg.length);
		if (maxLen==0) return 100;
		else return (1 - ed/maxLen) * 100;
	}
	//
	// editDistance
	function editDistance(sSrc,sTrg) {
		if (sSrc==null) sSrc = "";
		if (sTrg==null) sTrg = "";
		if (sSrc==sTrg) return 0;
		var d = new Array();
		var cost;
		var n = sSrc.length;
		var m = sTrg.length;
		if (n==0) return m;
		if (m==0) return n;
		for (var i=0; i<=n; i++) d[i] = new Array();
		for (var i=0; i<=n; i++) d[i][0] = i;
		for (var j=0; j<=m; j++) d[0][j] = j;
		for (var i=1; i<=n; i++) {
			var s_i = sSrc.charAt(i-1);
			for (var j=1; j<=m; j++) {
				var t_j = sTrg.charAt(j-1);
				if (s_i==t_j) cost = 0;
				else cost = 1;
				d[i][j] = _minimum(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1]+cost);
			}
		}
		return d[n][m];
	}
	//
	// _minimum
	function _minimum(a, b, c) {
		return Math.min(a, Math.min(b, Math.min(c,a)));
	}
	//
	// langName
	function langName(s) {
		return s.toUpperCase().substr(0,1)+s.toLowerCase().substr(1);
	}
	//
	// saveCookie
	function saveCookie(data) {
		var oSpeculaas = $.extend(true, {}, data?data:oCookie);
		for (var frto in oSpeculaas) {
			for (var cat in oSpeculaas[frto]) {
				for (var i=0;i<oSpeculaas[frto][cat].length;i++) {
					oSpeculaas[frto][cat][i] = unhard(oSpeculaas[frto][cat][i]);
				}
			}
		}
		var sSave = JSON.stringify(oSpeculaas);
		if (sSave.length<oSettings.cookiemax) {
			var sCkName = oSettings.cookieprefix+"_"+oSettings.langfr+"_"+oSettings.langto;
			createCookie(sCkName,sSave,3650);
			trace("saveCookie '"+sCkName+"' ("+sSave.length+") ");
		} else {
			alert("Je cookie is te groot ("+sSave.length+"), gooi wat woorden weg.");
		}
	}
	//
	// saveSettings
	function saveSettings() {
		var aValues = ["langfr","langto","score","version"];
		var oSet = {};
		for (var i in aValues) oSet[aValues[i]] = oSettings[aValues[i]];
//		trace("oSettings "+JSON.stringify(oSettings.score[sTo]["zinnen"]));
//		trace("oSet "+JSON.stringify(oSet.score));
//		trace("oSet "+JSON.stringify(oSet.score[sTo]));
//		trace("oSet "+JSON.stringify(oSet.score[sTo]["zinnen"]));
//		var oSet = $.extend(true, {}, oSettings);
//		for (var s in oSet) if (aValues.indexOf(s)==-1) delete oSet[s];
		createCookie(oSettings.cookieprefix+"_settings",JSON.stringify(oSet),3650);
		trace("settings saved: "+oSettings.cookieprefix+"_settings: "+JSON.stringify(oSet));
	}				
	//
	// invokeCookie
	function invokeCookie(name,defval,fn) {
		var oReturn;
		var sCkName = oSettings.cookieprefix+"_"+name;
		var sCookie = readCookie(sCkName);
		var bSet = sCookie!=null;
		try {
			if (bSet) oReturn = JSON.parse(sCookie);
			trace("cookie parsed: '"+sCkName+"'");
		} catch (e) {
			trace("cookie parse error: '"+sCkName+"' "+e+"\n\tdata:"+sCookie);
			bSet = false;
		}
		if (!bSet&&defval) {
			trace("cookie '"+sCkName+"' reverting to default data");
			oReturn = JSON.parse(defval);
			if (fn) fn(oReturn);
			else createCookie(sCkName,defval,3650);
		}
		return oReturn;
	}
	//
	///////////////////
	//
	// createCookie
	function createCookie(name,value,days) {
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = 	name+"="+value+expires+"; path=/";
	}
	// readCookie
	function readCookie(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	}
	// eraseCookie
	function eraseCookie(name) {
		createCookie(name,"",-1);
	}
	//
	///////////////////
	//
	// trace
	function trace(o,v) {
		if (window.console&&window.console.log) {//(v||oSettings.debug)&&
			if (typeof(o)=="string")	window.console.log(o);
			else						for (var prop in o) window.console.log(prop+":\t"+String(o[prop]).split("\n")[0]);
		}
	}
})(jQuery);
