		var str_rank = "Rank"
		var str_nextRank = "Next Rank"
		var str_description = "Description"
		var str_levelReq = "Level Req"
		var str_schoolReq = "School Points Req"
		var str_talentReq = "Talent Req"
		var str_learn = "Click to learn"
		var str_unlearn = "Shift-click to unlearn"
		var str_unlearnOpera = "Right-click or Ctrl-click to unlearn"
		var str_points = "point(s)"
		var str_levelReq_sumary = "Level Required"
		var str_totalPoints_sumary = "Total Points"
		var str_levelReq_print = "Minimum Required Level"
		var str_pointsReq_print = "Required Talents Points"
		var str_levelReq_sumary = "Level Required"
		var str_totalPoints_sumary = "Total Points"

		var Utils = new UtilsObj();


		function UtilsObj()
		{
			////////////////////////////
			// Cells painting - TDs' Id

			this.getCellTalentId = function (schId, rowId, colId)
			{
				return "td_talent_" + schId + "_" + colId + "_" + rowId;
			};
			this.getCellTalentSepId = function (schId, rowId, colId)
			{
				return "td_talent_sep_" + schId + "_" + colId + "_" + rowId;
			};
			this.getCellAltId = function (schId, rowId, colId)
			{
				return "td_alt_" + schId + "_" + colId + "_" + rowId;
			};
			this.getCellAltSepId = function (schId, rowId, colId)
			{
				return "td_alt_sep_" + schId + "_" + colId + "_" + rowId;
			};

			/////////////////////////////////////////
			// Cells painting - Content no talents
			this.getCellMainTalentEmpty = function()
			{
				return '<SPAN class="talent"><IMG class="talent_spacer_img" src="/sites/all/modules/tth_talent_calc/js/blank.gif"/></SPAN>';
			};
			this.getCellMainTalentHoriz = function()
			{
				return '<IMG class="spacer_t_h_img" src="/sites/all/modules/tth_talent_calc/js/ht.gif"/>';
			};
			this.getCellMainTalentVert = function()
			{
				return '<IMG class="spacer_t_v_img" src="/sites/all/modules/tth_talent_calc/js/vt.gif"/>';
			};
			this.getCellMainSepEmpty = function()
			{
				return '<IMG class="spacer_h_img" src="/sites/all/modules/tth_talent_calc/js/pix.gif">';
			};
			this.getCellSepTalentEmpty = function()
			{
				return '<IMG class="spacer_v_img" src="/sites/all/modules/tth_talent_calc/js/pix.gif"/>';
			};
			this.getCellSepTalentRight = function()
			{
				return '<IMG class="spacer_h_img" src="/sites/all/modules/tth_talent_calc/js/h_right.gif"/>';
			};
			this.getCellSepTalentLeft = function()
			{
				return '<IMG class="spacer_h_img" src="/sites/all/modules/tth_talent_calc/js/h_left.gif"/>';
			};
			this.getCellTalentSepHoriz = function()
			{
				return '<IMG class="spacer_h_img" src="/sites/all/modules/tth_talent_calc/js/h.gif"/>';
			};
			this.getCellSepSepEmpty = function()
			{
				return '<IMG class="spacer_h_img" src="/sites/all/modules/tth_talent_calc/js/pix.gif"/>';
			};
			this.getCellSepTalentDown = function()
			{
				return '<IMG class="spacer_v_img" src="/sites/all/modules/tth_talent_calc/js/v_down.gif"/>';
			};
			this.getCellTalentSepVert = function()
			{
				return '<IMG class="spacer_v_img" src="/sites/all/modules/tth_talent_calc/js/v.gif"/>';
			};

			this.extractParamsFromUrl = function()
			{

				var qsParm = new Array();
				var query = window.location.search;
				query = Utils.strReplace(query, '??', '?');
				query = query.substring(1);

				var parms = query.split('&');
				for (var i=0; i<parms.length; i++)
				{
					var pos = parms[i].indexOf('=');
					if (pos > 0)
					{
						var av = new Array()
						av[0] = parms[i].substring(0,pos);
						av[1] = parms[i].substring(pos+1);

						qsParm[qsParm.length] = av;
					}
				}

				return qsParm;
			}

			this.splitSchoolsParams = function(parms)
			{
				var qsParm = new Array();

				for (var i=0; i<parms.length; i++)
				{
					var pos = parms[i].indexOf('=');
					if (pos > 0)
					{
						var key = parms[i].substring(0,pos);
						var val = parms[i].substring(pos+1);
						qsParm[key] = val;
					}
				}

				return qsParm;
			}

			this.extractRadicalFromUrl = function()
			{
				var i = window.location.search.length
				var s = window.location + ''

				if (i>0)
					s = s.substring(0, s.length-i);

				if (s.charAt(s.length-1) == "#")
					s = s.substring(0, s.length-1)

				return s;
			}

			this.getPointsTotal = function()
			{
				var cnt = 0;

				for (var i=0; i<_schoolsArray.length; i++)
				{
					var sc = _schoolsArray[i];
					if (sc != null)
						cnt += sc.getSchoolPoints();
				}
				return cnt;
			}

			this.updatePointsTotalDisplay = function()
			{
				var fld = document.getElementById('summary_points');
				if (fld != null)
				{

					var s  = '<SPAN class="txtTitle">' + str_totalPoints_sumary + ': </SPAN>'
						s += '<SPAN class="txtCount">' + this.getPointsTotal() + ' ' + str_points + '</SPAN>'

					fld.innerHTML = s;
				}

				this.updateReqLevelDisplay();
				matchPresetsList();
			}

			this.getReqLevel = function()
			{
				/*
					Points begin accumulating at level 10, at one point per level, but
					two points are gained at every level that ends in a 9. And also for level 80:
				*/

				var total = this.getPointsTotal();

				if (total == 0)
					return 1;


				// // // //
				// First calculate the level out of the total points

					var fl = CurrentGame.first_point_level;
					var ml = CurrentGame.max_level;
					var mp = CurrentGame.max_points;

					var pts = 0;

					var pointslevel = fl;


					// loop thru the levels and add points accordingly
					// when we reach the number of points, that's our level.
					for (; pointslevel<=ml ; pointslevel++)
					{
						pts++;

						if (pointslevel%10 == 9 || pointslevel==80)
							pts++;

						if (pts >= total || pts>= mp)
							break;
					}
					// pointslevel now contains level calculated out of points


				// // // //
				// Now loop thru all the talents and pick up the ne with the highest level_rep

					var talentsLevel = 0;
					for (var i=0; i<_talentsArray.length; i++)
					{
						var tal = _talentsArray[i];
						if (tal != null && tal.active && tal.rank>0 && tal.level_prereq > talentsLevel)
							talentsLevel = tal.level_prereq;
					}


					// // // //
					// return the highest of the 2:

				return pointslevel > talentsLevel ? pointslevel : talentsLevel;
			}

			this.updateReqLevelDisplay = function()
			{
				var fld = document.getElementById('summary_level_req');
				if (fld != null)
				{
					var s  = '<SPAN class="txtTitle">' + str_levelReq_sumary + ': </SPAN>'
						s += '<SPAN class="txtCount">' + this.getReqLevel() + '</SPAN>'
					fld.innerHTML = s;
				}
			}

			this.computeImgPathRoot = function(classNameEncd, schoolNameEncd)
			{
				var imgPath = CurrentGame.image_path;
					imgPath += classNameEncd + '/';
					imgPath += schoolNameEncd;

				return imgPath;
			}

			this.getSchool = function(schoolId)
			{
				return _schoolsArray[schoolId];
			};

			this.strReplace = function(str, strOld, strNew)
			{
				while (str.indexOf(strOld)>=0)
				   str = str.replace(strOld,strNew);
				return str;

			}

			this.isFirefox = function()
			{
				return BrowserDetect.browser.indexOf("Firefox") >=0 ;
			}
			this.isIE = function()
			{
				return BrowserDetect.browser.indexOf("Explorer") >=0 ;
			}
			this.isOpera = function()
			{
				return BrowserDetect.browser.indexOf("Opera") >=0 ;
			}
			this.isSafari = function()
			{
				return BrowserDetect.browser.indexOf("Safari") >=0 ;
			};

			this.setBackgroundImg = function(obj, imgUrl)
			{
				obj.style.background = "url('"+  imgUrl + "') no-repeat top";
			}
		}


// Tabs management


		function showContainer(c,tab)
		{
			var mainContainer = document.getElementById('tabcontent');
			var children = mainContainer.getElementsByTagName('div');

			for (i = 0; i < children.length; i++)
			{
				if(children[i].id.indexOf("tabcontent") != -1)
				{
					if(children[i].id ==  c)
					{
						children[i].className = 'tabvisible';
					} else {
						children[i].className = 'tabinvisible';
					}
				}
			}
			activateTab(document.getElementById(tab));
		}

		function activateTab(t)
		{
			var tabContainer = document.getElementById('tabnav');
			var tabs = tabContainer.getElementsByTagName('li');
			var lastTabName = 0;
			// get the last element in the tabs


			for (i = 0; i < tabs.length; i++)
			{
				if (tabs[i].id == t.id){
					tabs.item(i).className = 'activeTab';
				} else {
					tabs.item(i).className = 'inactiveTab';
				}
			}
		}

		function printVersion()
		{
				var w = window.open("","","resizable=1,toolbar=1,width=400,height=600,status=0 ,scrollbars=1, menubar=1, screenX=100, screenY=100, left=100, top=100");

					var d = new Date()
					var ds = d.toLocaleString()

					var s  = '<HTML><HEAD>'
					s += '<TITLE>' + CurrentGame.name + ' - ' + ds + '</TITLE>'
					s += '</HEAD>'

					s += '<BODY style = "background-color:ffffff; font-family: Verdana,Arial,Helvetica,sans-serif; font-size: 11px;">'
						s += '<TABLE BORDER="0">'
						s += '<TR><TD COLSPAN="4">'

							s += '<SPAN style="font-size: x-large; font-weight: bold;">' +  CurrentClass.name  + '</SPAN>'

					s += '</TD></TR>'
					s += '<TR><TD COLSPAN="4" style="text-align:right;">'

						s += '<SPAN style="font-size: x-small;">(' +  ds  + ')</SPAN><BR><BR>'

					s += '</TD></TR>'
					s += '<TR><TD COLSPAN="3">'

						s += '<SPAN style="font-weight: bold;">' + str_levelReq_print + ': </SPAN>'

					s += '</TD><TD>'

						s += '<SPAN style="font-weight: bold;">' + Utils.getReqLevel() + '</SPAN>'

					s += '</TD></TR>'
					s += '<TR><TD COLSPAN="3">'
						s += '<SPAN  style="font-weight: bold;">' + str_pointsReq_print + ': <SPAN>'

					s += '</TD><TD>'

						s += '<SPAN style="font-weight: bold;">' + Utils.getPointsTotal() + '</SPAN>'

					s += '</TD></TR>'

								for (var j=1; j<=3; j++)
								{
									var sc = getSchoolByPosition(j);

									if (sc != null)
									{


					s += '<TR><TD COLSPAN="4">'

						s += '<BR>'
						s += '<SPAN style="text-decoration: underline; font-weight: bold;">' + sc.name + '</SPAN> - <SPAN style="font-weight: bold;">' + sc.getSchoolPoints() + ' Point(s)</SPAN>'

					s += '</TD></TR>'

											for (var i=0; i<sc.talentsArray.length; i++)
											{
												var t = sc.talentsArray[i];

												if ( t!= null && t.rank >0 )
												{
					s += '<TR><TD>'

						s += '&nbsp;&nbsp;'

					s += '</TD><TD><LI>'

						s += t.name;

					s += '</LI></TD><TD>'

						s += '&nbsp;&nbsp;'

					s += '</TD><TD style="text-align:right">'

						s += t.rank + ' / ' + t.rank_max;

					s += '</TD></TR>'
												}
											}


									}
								}

				s += '</TABLE>'
				s += '</BODY></HTML>';

			w.document.write(s);
			w.document.close();
		}

		function loadImages()
		{
			setTimeout('loadImagesAsynch()', 0)
		}
		function loadImagesAsynch()
		{
			var d = document.getElementById('img_cache')
			if (d != null)
			{
				var s = ''

				// load school bg
				for (var j=3; j>1 ; j--)
				{
					var sc = getSchoolByPosition(j);
					if (sc != null)
						s += '<IMG src="' + sc.getBgImgPath() + '">'
				}

				// load first school first
				/*
				for (var j=1; j<=3 ; j++)
				{
					for (var i=0; i<_talentsArray.length; i++)
					{
						var t = _talentsArray[i]
						if (t != null && t.school != null && t.school.id_ui == j) {
							s += t.getPreloadImgsStr()
						}
					}
				}
				*/

				d.innerHTML = s;
			}

		}

		function initPresets(jsonPresets)
		{
			var el = document.getElementById('schs_presets');
			if (el != null)
			{
				presetEvtHold = true;

				for (var i=0; i<jsonPresets.length; i++)
				{
					var optn = document.createElement("OPTION");
					optn.text = jsonPresets[i].name;
					optn.value = jsonPresets[i].def;
					el.options.add(optn);
				}
				presetEvtHold = false;
			}
		}
