/**
 * @author hooriza (ajaxUI team)
 */

var SPS = { __inst : {} };
SPS.debugMode = true; // ?debug=true 일 경우에 디버깅 모드를 쓰려면

SPS.learningLang = ''; // 학습언어 (en/zh)
SPS.autoCompleteURL = 'http://devac.nciku.com:8080';

// 각종 메세지
SPS.text = function(sKey) {
	var sMsg = SPS.text[sKey];
	sMsg = sMsg || 'The language file is not included';
	
	for (var i = 1, sVal; sVal = arguments[i]; i++)
		sMsg = sMsg.replace('%' + i, sVal);
	
	// 맨 앞에 오는 영어는 대문자로 변경
	return sMsg.replace(/^(.)/, function(e) { return e.toUpperCase(); });;
};

SPS.text.set = function(oData) {
	for (var k in oData) SPS.text[k] = oData[k];
};

// NHN Flash UI common - Flash Contents
// v1.0 lastUpdate : 2007. 6. 14 (modified by hooriza - 20071019)
(function() {

	var fc_isIE  = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
	var fc_isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
	var fc_isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;
	
	window.checkFlashPlayerVersion = function(){
		var _version;
		var _e;
		try {
			var _axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.5");		// check flash player ver. 5 or higher
			_version = _axo.GetVariable("$version");
		} catch (_e) {
			_version = -1;
		}
		return _version;
	};
	
	window.showFlash = function(_swfURL_,_flashID_,_width_,_height_,_wmode_,_flashVars_,_bgColor_){
		_wmode_ = (_wmode_ == undefined)? "transparent" : _wmode_;		// wmode = "window/ opaque/ transparent"
		_bgColor_ = (_bgColor_ == undefined)? "#FFFFFF" : _bgColor_;	// default "#000000" -> "#FFFFFF" _change 2007. 6. 14
		
		if(fc_isIE && fc_isWin && !fc_isOpera){
			_object_ ='<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+_width_+'" height="'+_height_+'" id="'+_flashID_+'" align="middle">';
			_object_ += '<param name="allowScriptAccess" value="always" />';
			_object_ += '<param name="quality" value="high" />'; 
			_object_ += '<param name="movie" value="'+_swfURL_+'" />';
			_object_ += '<param name="wmode" value="'+_wmode_+'" />'; 
			_object_ += '<param name="bgcolor" value="'+_bgColor_+'" />'; 
			_object_ += '<param name="FlashVars" value="'+_flashVars_+'">';
			_object_ += '</object>';
		}else{
			_object_ = '<embed src="'+_swfURL_+'" quality="high" wmode="'+_wmode_+'" FlashVars="'+_flashVars_+'" bgcolor="'+_bgColor_+'" width="'+_width_+'" height="'+_height_+'" name="'+_flashID_+'" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />'; 
		}
		
		document.write(_object_);
	
	};
	
	window.findFlashObj = function(_flashID_){
		var tarObj = fc_isIE ? document.all[_flashID_] : document[_flashID_];	
		return tarObj;
	};
	
	// for 'Out of memory line at 56' error _add 2007. 6. 12
	window.flashExternalCleanup = function() {
		__flash_unloadHandler = function(){
			externalProbSet = true;
			obj = document.getElementsByTagName('OBJECT');
		  	for (i=0;i<obj.length;i++){
				var theObj = eval(obj[i]);
				theObj.style.display = "none";
		   	for (var prop in theObj){
		    		if (typeof(theObj[prop]) == "function"){
		     			try { theObj[prop]=null } catch(e) {}
		    		}
		   	}
		  	}
		};
		if (window.onunload != __flash_unloadHandler){
			__flash_savedUnloadHandler = window.onunload;
			window.onunload = __flash_unloadHandler;
		}
	};
	
	window.onbeforeunload=flashExternalCleanup;
	
	/////////////////////////
	
})();

/**
 * debug hotkey
 */
/*
(function() {
	
	var __DEBUG = {
		codes : [ 68, 69, 66, 85, 71, 38, 39, 40, 37, 39, 37, 39, 37, 16, 192 ],
		index : 0
	};
	
	function getMatched(keyCode) {

		var matched = __DEBUG.codes[__DEBUG.index] == keyCode;
		if (matched) __DEBUG.index++;
		
		return matched;
	
	}

	$Fn(function(oEvent) {
		
		var keyCode = oEvent.key().keyCode;
		var matched = getMatched(keyCode);
		if (!matched) {
			__DEBUG.index = 0;
			matched = getMatched(keyCode);
		}

		if (__DEBUG.index == __DEBUG.codes.length) {
		
			SPS.debugMode = true;
			alert('DEBUG MODE turn on!');
			
			__DEBUG.index = 0;
		}
		
	}).attach(document, 'keydown');
	
})();
*/

// prototype override
(function() {

	// toHTML
	String.prototype.toHTML = function() {
		return this.replace(/</g, '&lt;').replace(/>/g, '&gt;');
	};
	
	// toValue
	String.prototype.toValue = function() {
		return this.replace(/&lt;/g, '<').replace(/&gt;/g, '>');
	};
	
	// repeat
	String.prototype.repeat = function(n) {
		var r = '';
		for (var i = 0; i < n; i++) r += this;
		return r;
	};
	
	// stripTags
	String.prototype.stripTags = function() {
		return this.replace(/<[^>]*>/g, '');
	};
	
	// trim
	String.prototype.trim = function() {
		return this.replace(/^\s+/, '').replace(/\s+$/, '');
	};
	
	// bytesLength
	String.prototype.bytesLength = function() {
		
		var nRet = 0;
		
		for (var i = 0, nLen = this.length; i < nLen; i++)
			nRet += this.charCodeAt(i) > 128 ? 2 : 1;

		return nRet;
		
	};
	
	// bytesCut
	String.prototype.bytesCut = function(nMaxLength) {
	
		var nRet = 0;
		
		for (var i = 0, nLen = this.length; i < nLen; i++) {
			var nCharLen = this.charCodeAt(i) > 128 ? 2 : 1;
			if (nMaxLength < nRet + nCharLen)
				return this.substr(0, i);
			nRet += nCharLen;
		}

		return this;
	
	};
	
	// 받침이 있는지
	String.prototype.hasFinalConsonant = function() {
		
		var datas = "가나다라마바사아자차카타파하";
	
		var first, last;
		var code = this.charCodeAt(this.length - 1);
	
		for (var i = 0; i < datas.length; i++) {
			
			first = datas.charCodeAt(i);
			last = first + 560;
	
			if (code >= first && code <= last && (code - first) % 14 == 0)
				return false;
		}
	
		return true;
		
	};

	// 조사 붙히기
	String.prototype.addPostword = function(sPostword) {
	
		var case1, case2;
	
		switch(sPostword)
		{
		case "를":
		case "을":
			case1 = "를";
			case2 = "을";
			break;
	
		case "가":
		case "이":
			case1 = "가";
			case2 = "이";
			break;
	
		case "는":
		case "은":
			case1 = "는";
			case2 = "은";
			break;
	
		case "와":
		case "과":
			case1 = "와";
			case2 = "과";
			break;
	
		default:
			case1 = case2 = what;
		}
		
		return this + (this.hasFinalConsonant() ? case2 : case1);

	};
	
	// Jindo2 기능 확장
	$Element.prototype.has = function(oElement) {
	
		var n = this.$value();
		var o = $Element(oElement).$value();
	
		for (; o; o = o.parentNode)
			if (o == n) return true;
	
		return false;
	};
	
	/*
	$Element.prototype.hasClass = function(className) {
		var oEl = this.$value();
		return (" " + oEl.className + " ").indexOf(" " + className + " ") != -1;
	};
	
	$Element.prototype.addClass = function(className) {
		var oEl = this.$value();
		if (!this.hasClass(className)) oEl.className = (oEl.className+' '+className).replace(/^\s+/,'');
	};
	
	$Element.prototype.removeClass = function(className) {
		var oEl = this.$value();
		for (var i = 0, className; className = arguments[i]; i++)
			oEl.className = oEl.className.replace(new RegExp('\\b' + className + '(\\s+|$)', 'g'), '');
	};
	*/
	
	$Element.prototype.findElement = function(sRelative, fCallback, bIncl) {
	
		var oEl = this.$value();
		fCallback = fCallback || function(oEl) { return true; };
		
		if (!bIncl) oEl = oEl[sRelative];
		
		for (; oEl; oEl = oEl[sRelative])
			if (oEl.nodeType == 1 && fCallback(oEl))
				return $Element(oEl);
				
		return null;
		
	};
	
	$Event.prototype.getRelatedElement = function() {

		var e = this._event;
		return e.relatedTarget || (e.type == "mouseover" ? e.fromElement : e.toElement);
		
	};
	
	$Event.prototype.of = function(parent) {
		
		var el;
		var ret = true;
		
		var bMustHaveRelated = this._event.type == 'mouseover' || this._event.type == 'mouseout';  
		
		if (el = this.element)
			ret &= $Element(parent).has(el);
			
		if (el = this.getRelatedElement())
			ret &= $Element(parent).has(el);
		else if (bMustHaveRelated)
			ret = false;
	
		return ret;				
	};
	
	$Fn.prototype.owner = function(oThis) {
	
		var f = this.$value();
	
		return $Fn(function() { return f.apply(oThis, arguments); });
	
	};
	
	$Element.prototype._orgOffset = $Element.prototype.offset;  
	
	$Element.prototype.offset = function(top, left) {
		var e = this._element;
		var t = 0, l = 0;
	
		if (typeof top == "number" && typeof left == "number") {
			return this._orgOffset(top, left);
		}
	
		while(typeof e != "undefined" && e != null) {
			t += e.offsetTop;
			l += e.offsetLeft;
			
			e = e.offsetParent;
			
			if (e && e.tagName) {
			
				var sTagName = e.tagName.toUpperCase(); 
				if (sTagName != 'BODY' && sTagName != 'HTML') {
					t -= e.scrollTop;
					l -= e.scrollLeft;
				}
			
			}

		}
	
		return {top:t, left:l};
	}
})();

/**
 * 기타 잡다구리한 Misc 함수들
 * @author hooriza (ajaxUI)
 */
(function() {

	SPS.uniqid = function() {
		return (new Date().getTime() % 31536000000) * 100 + parseInt(Math.random() * 100);	
	};

	SPS.dirname = function(sPath) {
	
		var nPos = sPath.lastIndexOf('/');
		if (nPos == -1) return '';
		
		return sPath.substr(0, nPos + 1);
	
	};
	
	SPS.setCookie = function(sKey, sValue, nExpire, sPath, sDomain) {
		
		var sOptions = '';
		
		sPath = sPath || '/'; // 사이트 전체에 적용되게 하자
		
		if (typeof nExpire != 'undefined') {
		
			var oExpire = new Date();
			oExpire.setDate(oExpire.getDate() + nExpire);
			
			sOptions += ';expires=' + oExpire.toGMTString();
			
		}
		
		if (typeof sPath != 'undefined') sOptions += ';path=' + sPath;
		if (typeof sDomain != 'undefined') sOptions += ';domain=' + sDomain;
		
		document.cookie = sKey + '=' + escape(sValue) + sOptions;
		
	};
	
	SPS.getCookie = function(sKey) {
		
		var sCookie = document.cookie;
		if (sCookie.length < 1) return;
		
		var rReg = new RegExp('\\b' + sKey + '=([^;]*)(;|$)');
		var aMatch = sCookie.match(rReg);
		
		return aMatch && aMatch[1];
		
	};
	
	/**
	 * 사파리에서 input[type=text] 의 border 가 사라지지 않는 문제 다른 방법으로 회피
	 * @author hooriza (ajaxUI)
	 */
	SPS.borderNoneSafari = function(oEl) {
	
		if (!$Agent().navigator().safari) return;
	
		var eWrap;
		var eEl = $Element(oEl);
		if (eEl.hasClass('_border_none_safari')) {
		
			eWrap = $Element(oEl.parentNode);

		} else {
		
			eWrap = $Element($("<div>"));
			eEl.addClass('_border_none_safari');

			eEl.before(eWrap);

			eEl.css({
				margin : '0px',
				position : 'relative',
				left : '-1px',
				top : '-2px'
			});
		
			eWrap.append(eEl);
		
		}
		
		eWrap.css({
			width : oEl.offsetWidth - 6 + 'px',
			height : oEl.offsetHeight - 5 + 'px',
			padding : '0',
			margin : '0',
			overflow : 'hidden',
			display : 'inline-block',
			'float' : 'left'
		});
	
		return eWrap;
	
	};
	
	SPS.getParentForm = function(oEl) {
	
		for (; oEl; oEl = oEl.parentNode)
	 		if (oEl.tagName && oEl.tagName.toUpperCase() == 'FORM') return oEl;
	
		return oEl;
	
	};
	
	SPS.setBeforeSubmit = function(oForm, sButtonSelector, fValidator) {
		
		fValidator = fValidator || function() { return true; };
		
		var oSubmit = $$(sButtonSelector, oForm)[0];
		var fCheck = function(oEvent) {
			
			if (!fValidator()) {
				oEvent.stop();
				return false;
			}
				
			SPS.protectLossData.setChanged(false);
			return true;
			
		};
					
		$Fn(fCheck).attach(oForm, 'submit');
	
		$Fn(function(oEvent) {
			
			if (fCheck(oEvent))
				oForm.submit();
				
			oEvent.stop();
	
		}).attach(oSubmit, 'click');	
		
	};
	
	SPS.getJsonList = function(oForm, aKeys) {
		
		var aList = [];
		var oObj = null;
		
		var bSingle = typeof aKeys == 'string';
			
		for (var i = 0, oEl; oEl = oForm[i]; i++) {
			
			var sName = oEl.name;
			if (oEl.type == 'radio' && !oEl.checked) continue;
	
			if (sName && (/\[[0-9]*\]$/).test(sName)) {
			
				sName = sName.replace(/\[[0-9]*\]$/, '');
				
				if (bSingle) {
					
					if (aKeys != sName) continue;
					aList.push(oEl.value);
					
				} else {
					
					if ($A(aKeys).indexOf(sName) < 0) continue;
					if (!oObj) oObj = {};
				
					if (typeof oObj[sName] != 'undefined') {
						aList.push(oObj);
						oObj = {};
					}
					
					oObj[sName] = oEl.value;
					
				}
				
			}
			
		}
		
		if (!bSingle) aList.push(oObj);
		return $Json(aList).toString();
			
	};
	
	SPS.moveLocationToValue = function(oEl) {
		
		var sVal = SPS.getFormValue(oEl);
		if (sVal) location.href = sVal;
		
	};
	
	SPS.autoPosition = function(oEl, oLayer, aGap, bUpper) {
		
		aGap = aGap || [ 0, 0 ];
		
		var oPos = $Element(oEl).offset();
		var nPitch = bUpper ? -(oLayer.offsetHeight + aGap[1]) : oEl.offsetHeight + aGap[1];
		
		$Element(oLayer).css({ left : oPos.left + aGap[0] + 'px', top : oPos.top + nPitch + 'px' });
		
	};
	
	SPS.parseQueryString = function(sQuery) {
	
		var aQuery = sQuery.split('&');
		var oQuery = {};
		
		for (var i = 0, nLen = aQuery.length; i < nLen; i++) {
			var aPart = aQuery[i].split('=', 2);

			try { aPart[0] = decodeURIComponent(aPart[0]); } catch(e) {}
			try { aPart[1] = decodeURIComponent(aPart[1]); } catch(e) {} 

			oQuery[aPart[0]] = aPart[1];
		}
		
		return oQuery;
		
	};
	
	SPS.makeQueryString = function(oQuery) {
	
		var aQuery = [];
	
		$H(oQuery).forEach(function(sValue, sKey) {
			aQuery.push(encodeURIComponent(sKey) + '=' + encodeURIComponent(sValue));
		});
		
		return aQuery.join('&');
		
	};
	
	SPS.query = SPS.parseQueryString(location.search.substr(1));
	SPS.debugMode = SPS.debugMode ? SPS.query.debug == 'true' : false;
	
	SPS.decToHex = function(nNum) {
		
		var sHex = '';
		var aHexes = [ 'A', 'B', 'C', 'D', 'E', 'F' ];
		
		do {
			var n = nNum % 16;
			sHex = (n >= 10 ? aHexes[n - 10] : String(n)) + sHex;
			nNum = parseInt(nNum / 16);
		} while (nNum);
		
		return sHex;
		
	};
	
	SPS.isCharCode = function(nCode) {
		
		if (
				(nCode >= 8 && nCode <= 46) ||
				(nCode >= 91 && nCode <= 105) ||
				(nCode == 110) ||
				(nCode >= 112 && nCode <= 123) ||
				(nCode == 144)
		) {
			return false;
		}
		
		return true;
		
	};
	
	SPS.getParentByClassName = function(oEl, sClassName) {
		
		var eEl = $Element(oEl);
		
		eEl = eEl.hasClass(sClassName) ? eEl : eEl.findElement('parentNode', function(oEl) { return $Element(oEl).hasClass(sClassName); });
		return eEl;
		
	};
	
	SPS.addOption = function(oSelectbox, sText, sValue) {
	
		var oOption = $('<option>');
		
		oOption.innerHTML = sText.toHTML();
		oOption.value = sValue;
		
		oSelectbox.appendChild(oOption);
		
		return oSelectbox.length - 1;
		
	};
	
	SPS.extend = function(oSrc, oExt) {
		$H(oExt).forEach(function(oVal, sKey) { oSrc[sKey] = oVal; });
		return oSrc;
	};
	
	/** 폼을 Ajax 로 submit 함
	 *
	 * @author hooriza (ajaxUI team)
	 */
	SPS.ajaxSubmit = function(oForm, onLoad) {
		
		onLoad = onLoad || function() {};
	
		var sUrl = oForm.action;
		
		var oAjax = $Ajax(sUrl, { 
			type : oForm.method || 'get',
			onload : onLoad
		});
		
		var oData = {};
		var oEl;
		
		for (var i = 0, oEl; oEl = oForm[i]; i++) {
			if (!oEl.name) continue;
			oData[oEl.name] = oEl.value;
		}
		
		oAjax.request(oData);
		
	};
	
	SPS.getFormValue = function(oEl) {
		
		var sValue = null;
		
		var sTagName = oEl.tagName.toUpperCase();
		if (sTagName != 'INPUT' && sTagName != 'TEXTAREA' && sTagName != 'SELECT') return null;
		
		if (sTagName == 'SELECT' && oEl.selectedIndex > -1) {
			
			sValue = oEl.options[oEl.selectedIndex].getAttribute('value') || null;
			
		} else {
			
			var sType = oEl.type.toUpperCase();
			
			if (sType == 'CHECKBOX') {
				sValue = oEl.checked ? oEl.value : null;
			} else if (sType == 'RADIO') {

				var oDoc = oEl.ownerDocument || document;
				var aRadios = oDoc.getElementsByName(oEl.name);
				for (var i = 0, oRadio; oRadio = aRadios[i]; i++)
					if (oRadio.checked) sValue = oRadio.value;
				
			} else {
				sValue = oEl.value;
			}
			
		}
		
		return sValue;
		
	};
	
	SPS.login = function (bEl,sGoURL,sSubURL){
	
		var sCurLocation = document.location.href;
		var sGenLocation = new String();
		var sGoLocation = new String();
		
		switch (bEl){
			case true:
				// Login
					sGentLocation = sSubURL + encodeURIComponent(sCurLocation);
				break;
			case false:
				// Logout
					sGentLocation = sSubURL;
				break;
		}
		
		sGentLocation = encodeURIComponent(sGentLocation);
		sGoLocation = sGoURL + "?go=" + sGentLocation;
		
		document.location.href = sGoLocation;
		
	}
	
})();

/**
 * @author hooriza (ajaxUI team)
 * 엘리먼트의 클래스명을 이용한 Form Validator
 *
 * 사용방법 :
 *	엘리먼트의 class 어트리뷰트에 지정된 클래스를 추가
 *	예) <input type="text" class="notnull" />
 *	
 * 조건 클래스 종류
 *	notnull										: 반드시 채워져 있어야 함
 *  notspace									: 반드시 채워져 있고 빈칸만으로만 이루어지지 않아야 함
 *	name(STRING)							: 유효성 검사에서 걸렸을때 onValidate 로 전달되는 값
 *
 * 판단 클래스 종류 :
 *	length(INTEGER~INTEGER)					: 허용 문자열 수
 *	group(STRING)										: 상호 동일해야 하는 값의 그룹
 *	number(NUMBER~NUMBER)						: 숫자만 가능 (영역 지정은 옵션)
 *	integer(INTEGER~INTEGER)				: 정수만 가능 (영역 지정은 옵션)
 *	only(E1,E2,E3)									: E1, E2, E3 로만 구성되어야 함
 *	deny(E1,E2,E3)									: E1, E2, E3 는 하나도 없어야 함
 *	TODO : any(E1,E2,E3)							: E1, E2, E3 가 하나라도 있어야함
 *		chinese (한자)
 *		korean (한글)
 *		english (영문)
 *		number (숫자)
 *		
 *	TODO : callback(FUNCTION_NAME)	: 유효성 검사를 위한 콜백함수 지정
 */
(function() {		
	
	SPS.validator = {
		
		_prefix : '-', // 클래스 prefix
		
		_rules : 'notnull,notspace,length,group,only,deny,any,number,integer,callback'.split(','),
		_defaultOnInvalid : function(oEl, sType, sName, sError, oParam) {

			if (sError) {
			
				switch (sType) {
				case 'integer':

					if (sError == 'INTEGER_TEST')
						if (oParam.value < 1 || isNaN(oParam.value))
							sError = 'INTEGER_TEST_NONZERO';
				
					alert(SPS.text(sError, sName, oParam.from, oParam.to));
					break;
					 
				case 'length':
					alert(SPS.text(sError, sName, oParam.from, oParam.to));
					break; 

				default:
					alert(SPS.text(sError, sName));
					break;
				}

			} else {

				switch (sType) {
				case 'notnull':
				case 'notspace':
					alert(SPS.text('NOTNULL', sName));
					break;
					
				case 'integer':
					alert(SPS.text('INTEGER', sName, oParam.from, oParam.to));
					break;
					
				case 'length':
					alert(SPS.text('LENGTH', sName, parseInt(oParam.to / 2), oParam.to));
					break;
				
				case 'any':
				
					var dummy = SPS.validator;
				
					var sValue = SPS.getFormValue(oEl);
					var rRegExp = new RegExp('(' + dummy._filters.chinese + '|' + dummy._filters.english + ')');
				
					if (oParam['catch'] == 'english') {
					
						// 영어도 중국어도 모두 없으면 true
						if (sValue.search(rRegExp) == -1) return true;
						
						alert(SPS.text('ANY_ENGLISH', sName));
						break;
						
					} else if (oParam['catch'] == 'chinese') {
					
						// 영어도 중국어도 모두 없으면 true
						if (sValue.search(rRegExp) == -1) return true;
						
						alert(SPS.text('ANY_CHINESE', sName));
						break;
						
					}
										
				default:
					alert(SPS.text('OTHER', sName));
				}
				
			}
	
			try {
				oEl.focus();
				oEl.select();
			} catch(e) {}
			
			return false;
			
		},
		
		_getRange : function(sArg, bFloat) {
	
			var aRange = sArg.split('~');
			
			if (bFloat) aRange = [ parseFloat(aRange[0]), parseFloat(aRange[1]) ];
			else aRange = [ parseInt(aRange[0], 10), parseInt(aRange[1], 10) ];
			
			if (isNaN(aRange[0])) aRange[0] = -Infinity;
			if (isNaN(aRange[1])) aRange[1] = Infinity;		
			
			return aRange;
			
		},
		
		_filters : {
			'chinese' : '[一-龥]', // '[\\u4E00-\\u9FFF]', for Safari
			'korean' : '[ㄱ-힣]',
			'english' : '[A-Z|a-z]',
			'number' : '[0-9]',
			'url' : '(http|https|ftp)://\\w+(\.\\w+)+(/.*)?'
		},
		
		_functions : {
			
			'notnull' : function(oEl, sValue) {
				return (typeof sValue == 'string' && sValue.length > 0) ? false : {};
			},
			
			'notspace' : function(oEl, sValue) {
				return (typeof sValue == 'string' && sValue.trim().length > 0) ? false : {};
			},
			
			'length' : function(oEl, sValue, sArg) {
			
				var aRange = SPS.validator._getRange(sArg);
				var nLen = sValue.bytesLength();
				
				return (aRange[0] <= nLen && nLen <= aRange[1]) ? false : {
					'from' : aRange[0],
					'to' : aRange[1]
				};
				
			},
			
			'only' : function(oEl, sValue, sArg) {
				
				var aTypes = sArg.split(',');
				var aFilters = [];
				
				$A(aTypes).forEach(function(sType) {
					aFilters.push(SPS.validator._filters[sType]);
				});
				
				var rRegex = new RegExp('^(' + aFilters.join('|') + ')*$');
				return (rRegex.test(sValue)) ? false : {
					'types' : aTypes
				};
				
			},
			
			'deny' : function(oEl, sValue, sArg) {
			
				var aTypes = sArg.split(',');
				var bPassed = true;
				var rRegex;
				
				var sCatch = '';
				var bCatch;

				$A(aTypes).forEach(function(sType) {

					rRegex = new RegExp(SPS.validator._filters[sType]);
					bCatch = (sValue.search(rRegex) > -1 ? false : true);
					bPassed = bPassed && bCatch;
					
					if (!bCatch) {
						sCatch = sType;
						$A.Break();
					} 
				});
				
				return bPassed ? false : {
					'type' : aTypes,
					'catch' : sCatch
				};
				
			},
			
			'any' : function(oEl, sValue, sArg) {

				var aTypes = sArg.split(',');
				var bPassed = true;
				var rRegex;
				
				var sCatch = '';

				$A(aTypes).forEach(function(sType) {
					rRegex = new RegExp(SPS.validator._filters[sType]);
					if (sValue.search(rRegex) == -1) {
						bPassed = false;
						sCatch = sType;
						$A.Break();
					}
				});
				
				return bPassed ? false : {
					'type' : aTypes,
					'catch' : sCatch		
				};
			
			},
			
			'number' : function(oEl, sValue, sArg) {
				
				var rExp = /^[-+]?[0-9]+(\.[0-9]+)?$/;
				if (!rExp.test(sValue)) sValue = 'NaN';
				
				var nValue = parseFloat(sValue);
				
				if (typeof sArg != 'undefined') {

					var aRange = SPS.validator._getRange(sArg, true);
					return (!isNaN(nValue) && aRange[0] <= nValue && nValue <= aRange[1]) ? false : {
						'value' : nValue,
						'from' : aRange[0],
						'to' : aRange[1]
					};
					
				}
				
				return false;
				
			},
			
			'integer' : function(oEl, sValue, sArg) {
				
				var rExp = /^[-+]?[0-9]+(\.[0-9]+)?$/;
				if (!rExp.test(sValue)) sValue = 'NaN';
				
				var nValue = parseInt(sValue, 10);
				
				if (typeof sArg != 'undefined') {
					
					var aRange = SPS.validator._getRange(sArg);
					
					return (!isNaN(nValue) && aRange[0] <= nValue && nValue <= aRange[1]) ? false : {
						'value' : nValue,
						'from' : aRange[0],
						'to' : aRange[1]
					};
					
				}
				
				return false;
				
			},
			
			'group' : function(oEl, sValue, sArg, oVars) {
				
				if (oVars.oGroups[sArg]) return false;
				oVars.oGroups[sArg] = true;

				var bMatch = true;
				var rExp = new RegExp('\\bgroup\\(' + sArg + '\\)(\\s|$)');
				
				for (var i = 0, oDst; oDst = oVars.aEls[i]; i++) {
					
					if (oDst.nodeType != 1 || oEl === oDst) continue;
					if (rExp.test(oDst.className))
						if (oEl.value != oDst.value) bMatch = false;
					
				}
				
				return bMatch ? false : {};

			}
			
		},
		
		_fireEvent : function(fHandler, oEl, sType, sError, oParam) {
			
			var bFlag;
			var sClassName = oEl.className;
			
			var aMatch = sClassName.match(/\bname\(([^)]*)\)(\s|$)/);
			var sName = aMatch ? aMatch[1] : 'undefined';
			
			fHandler = fHandler || this._defaultOnInvalid;
			return fHandler(oEl, sType, sName, sError, oParam);
			
		},
		
		validate : function(oForm, oOptions) {
			
			var bValid = true;
			
			if (oForm instanceof Array) {

				for (var i = 0, len = oForm.length; i < len; i++)
					if (!this.validate(oForm[i], oOptions))
						return false;
						
				return true;
							
			}
			
			var aEls = oForm.all || oForm.getElementsByTagName('*');
			oOptions = oOptions || {};
			
			var oVars = {
				'aEls' : aEls,
				'oGroups' : { },
				'oRadios' : { }
			};
			
			aEls[aEls.length] = oForm;
			
			for (var i = 0, oEl; oEl = aEls[i]; i++) {
				
				if (oEl.nodeType != 1) continue;
				
				var bFlag = this._validateElement(oEl, oOptions, oVars);
				bValid &= bFlag;
				
				if (bFlag === null) return bValid; // validate 을 바로 멈춤
				
			}
			
			return bValid;
			
		},
		
		_validateElement : function(oEl, oOptions, oVars) {
			
			var sTagName = oEl.tagName.toUpperCase();
			if (sTagName != 'INPUT' && sTagName != 'TEXTAREA' && sTagName != 'SELECT') return true;
			
			var bValid = true;
			
			var sValue = SPS.getFormValue(oEl);
			var sClassName = oEl.className;
			
			if (sTagName == 'INPUT' && oEl.type.toUpperCase() == 'RADIO') { // 라디오 버튼에서 같은 name 에서의 체크는 한번만
				
				var sName = oEl.name;
				
				if (oVars.oRadios[sName]) return true;
				oVars.oRadios[sName] = true;
				
			}
			
			for (var i = 0, sKey; sKey = this._rules[i]; i++) {
			
				// var rExp = new RegExp('\\b(' + sKey + ')(\\(([^)]*)\\))?(\\s|$)');
				var rExp = new RegExp('\\b(' + sKey + ')(\\((([^:)]+):)?([^)]*)\\))?(\\s|$)');
				var aMatch = sClassName.match(rExp);
				if (!aMatch) continue;
				
				var oParam;
				
				var fFunc = this._functions[aMatch[1]];
				if (typeof fFunc == 'function') { // validator 함수가 있으면 검사
					
					oParam = fFunc(oEl, sValue, aMatch[5], oVars);
					var bFlag = oParam ? false : true;
					
					if (!bFlag) { // validator 함수에 걸렸으면
						if (!this._fireEvent(oOptions.onInvalid, oEl, aMatch[1], aMatch[4], oParam)) // 이벤트 날리고 false 이면 validate 중지
							return null;
						else // onInvalid 가 true 리턴하면 성공한걸로 간주
							bFlag = true;
					}

					bValid &= bFlag;							
				}
				
			}
			
			return bValid;

		}
		
	};
		
})();

/**
 * 폼에서 변경 사항 있을때 자동 경고창
 *
 * @author hooriza (ajaxUI team)
 */
SPS.protectLossData = function(oEl, sWarnMsg) {
	
	if (typeof SPS.protectLossData._changed == 'undefined') {
		SPS.protectLossData._changed = false;
		SPS.protectLossData._message = sWarnMsg || 'Warning!';
	}
	
	oEl = oEl || document;
	
	var aInputs = oEl.getElementsByTagName('input');
	var aTextareas = oEl.getElementsByTagName('textarea');
	var aSelects = oEl.getElementsByTagName('select');
	
	var fChanged = $Fn(function() {
		SPS.protectLossData.setChanged(true);
	});
	
	var fDetectEls = function(aEls) {
		
		$A(aEls).forEach(function(oEl) {
			
			var eEl = $Element(oEl);
			if (eEl.hasClass('_protect_loss')) return;

			fChanged.attach(oEl, 'change');
			
			eEl.addClass('_protect_loss');
			
		});
		
	};
	
	fDetectEls(aInputs);
	fDetectEls(aTextareas);
	fDetectEls(aSelects);
	
};

SPS.protectLossData.setChanged = function(bFlag) {
	SPS.protectLossData._changed = bFlag;
	
	if (bFlag) {
		window.onbeforeunload = function() { return SPS.protectLossData._message; };
	} else {
		window.onbeforeunload = null;
	}
	
};

/**
 * 타이머
 *
 * @author hooriza (ajaxUI team)
 */
SPS.timer = $Class({

	_bInterval : false,
	_oInstance : null,

	$init : function(sType) {
		this._bInterval = sType.toLowerCase() == "interval";
	},

	start : function(nTime, fCallback) {

		this.stop();

		if (this._bInterval) {

			this._oInstance = window.setInterval(fCallback, nTime);

		} else {
			
			var self = this;

			this._oInstance = window.setTimeout(function() {
				fCallback();
				self.stop();
			}, nTime);

		}

	},

	stop : function() {

		var fFunc = window[this._bInterval ? "clearInterval" : "clearTimeout"];

		if (this._oInstance)
			fFunc(this._oInstance);

		this._oInstance = null;

	}

});

/**
 * 지연된 요청
 *
 * @author hooriza (ajaxUI team)
 */
SPS.delayedRequest = $Class({
	
	_timer : null,
	
	_delay : null,
	_count : null,
	
	_remained : null,
	
	$init : function(nDelay, nCount) {

		this._timer = new SPS.timer('timeout');
				
		this._delay = nDelay;
		this._count = nCount;
		
		this._remained = this._count;
		
	},
	
	request : function(fFunc, oOwner) {
		
		var aArgs = [];
		
		for (var i = 2, len = arguments.length; i < len; i++)
			aArgs.push(arguments[i]);
			
		// 지금 바로 실행해야 되면
		if (this._remained-- < 1) {
			
			this._remained = this._count;
			
			this._timer.stop();
			return fFunc.apply(oOwner, aArgs);
			
		}
		
		this._timer.start(this._delay, function() { fFunc.apply(oOwner, aArgs); });
		
	},
	
	stop : function() {
		this._timer.stop();
	}
	
});

/**
 * TTS 플레이
 *
 * @author hooriza (ajaxUI team)
 */
SPS.tts = $Class({
	
	_sUniq : null,
	
	_oFrame : null,
	_oOptions : null,
	
	_oTimer : null,
	_sOrgUrl : null,
	
	$init : function(oOptions) {
		
		this._sUniq = "TTS" + parseInt(Math.random() * 10000000);
		SPS.tts._instances[this._sUniq] = this;
		
		this._oOptions = oOptions || {};

		// iframe 만들기
		var oBody = document.body;
	
		this._oFrame = $('<iframe>');
		this._oFrame.src = oOptions.frameSrc;
		
		with (this._oFrame.style) {
			position = "absolute";

			if (SPS.debugMode) {
				right = "0";
				top = "0";
				position = "fixed";
				width = "400px";
				height = "400px";
			} else {
				left = "-999999px";
				top = "-999999px";
				width = "1px";
				height = "1px";
				/*
				left = "300px";
				top = "150px";
				width = "400px";
				height = "400px";
				*/
			}

		}
		
		oBody.insertBefore(this._oFrame, oBody.firstChild);		
		
	},
	
	_execute : function(sMethod) {
		
		var aArgs = [];
		for (var i = 1, nLen = arguments.length; i < nLen; i++)
			aArgs.push(arguments[i]);

		var oWnd = this._oFrame.contentWindow;

		try {
			return oWnd[sMethod].apply(oWnd, aArgs);
		} catch(e) { }
		
	},
	
	_sReservedUrl : null,
	
	playDictation : function(sText, bEnglish, nCount) {

		if (!SPS.tts._ttsEnable) {
			alert(SPS.text('TTS_NOT_SUPPORTED'));
			return;		
		}
		
		this.play(SPS.tts.textToUrl(sText, bEnglish), false, nCount);
	},
	
	_status : null,
	
	play : function(sUrl, bSuspend, nCount) {
		
		if (!nCount) nCount = 9999999;
		
		if (sUrl) this._sReservedUrl = sUrl;
		if (!bSuspend) {
			this._execute('play', this._sUniq, sUrl || this._sReservedUrl, nCount);
			this._status = 'play';
		}
	},
	
	stop : function() {
		if (this._status == 'stop') return;
		
		this._execute('stop', this._sUniq);
		this._status = 'stop';
	}
	
});

SPS.tts.textToUrl = function(sText, bEnglish) {

	var fUcssafeutf8 = function(str) {
		
		var rtn = "";
		var for_i = 0;
		var str_length = str.length;
		var u;
		var s;
		for(i=0; i < str_length ; i++)
		{
			u = str.charCodeAt(i);
			if		( (u >= 0x00) && (u <= 0x7f) )
			{
				s= "0" + u.toString(16);
				rtn += "%" + s.substr(s.length-2);
			}
			else if	( u > 0x1fffff )
			{
				rtn += "%" + (oxf0 + ((u & 0x1c0000) >> 18)).toString(16);
				rtn += "%" + (0x80 + ((u & 0x3f000) >> 12)).toString(16);
				rtn += "%" + (0x80 + ((u & 0xfc0) >> 6)).toString(16);
				rtn += "%" + (0x80 + (u & 0x3f)).toString(16);
			}
			else if	( u > 0x7ff )
			{
				rtn += "%" + (0xe0 + ((u & 0xf000) >> 12)).toString(16);
				rtn += "%" + (0x80 + ((u & 0xfc0) >> 6)).toString(16);
				rtn += "%" + (0x80 + (u & 0x3f)).toString(16);
			}
			else 
			{
				rtn += "%" + (0xc0 + ((u & 0x7c0) >> 6)).toString(16);
				rtn += "%" + (0x80 + (u & 0x3f)).toString(16);
			}
		}
		return rtn;
		
	};

	var nId = bEnglish ? 100 : 200; // 100 이면 영어발음, 200 이면 중국어 발음
	var sSafeText = fUcssafeutf8(sText.trim());
	var spd = 100;
	if(nId==100){
		spd = 100;
	}else{
		spd = 100;
	}
	
	return "http://tts.nciku.com/tts/tts.cgi?text=" + sSafeText + "&spk_id=" + nId + "&text_fmt=0&pitch=100&volume=100&speed=" + spd + "&wrapper=0&enc=0&lb_ip=218.240.10.38&lb_port=80";
	
};

SPS.tts._ttsEnable = true;
if ($Agent().navigator().ie) {
	try { new ActiveXObject('WMPlayer.OCX'); } catch(e) {
		SPS.tts._ttsEnable = false;
	}
}

SPS.tts._instances = [];
SPS.tts._getInstance = function(sKey) { return this._instances[sKey]; };

/**
 * 탭 UIO 와 Panel 과 연결하는거
 *
 * @author hooriza (ajaxUI team)
 */
SPS.tab = function(sTabID, aPanelIDs, oOptions) {

	sTabID = $(sTabID);
	oOptions = oOptions || {};	
	
	var aTabs = [];
	
	if (sTabID.tagName.toUpperCase() == 'UL') {
		
		for (var oEl = sTabID.firstChild; oEl; oEl = oEl.nextSibling)
			if (oEl.tagName && oEl.tagName.toUpperCase() == 'LI') aTabs.push(oEl);
		
	} else {
		
		aTabs = $$('ul>li', sTabID);
		
	}

	var aPanels = [];
	var nSelected = 0;

	$A(aPanelIDs).forEach(function(sPanelID) {
		aPanels.push($Element($(sPanelID)));
	});

	var showPanel = function(nIdx) {
		
		var oRet = { 'tab' : null, 'panel' : null };

		$A(aPanels).forEach(function(ePanel, nI) {
			
			if (nI == nIdx) {
				
				oRet.tab = aTabs[nI];
				oRet.panel = ePanel.$value();
				
				ePanel.show();  	
				
				/* 20071221 modify */
				if ($Agent().navigator().ie) {
				    ePanel.css('zoom', '1');
				    setTimeout(function() { ePanel.css('zoom', ''); }, 0);
				}
				/* 20071221 modify end */
				Element.addClass(aTabs[nI], 'selected');
				
			} else {
				
				ePanel.hide();	
				Element.removeClass(aTabs[nI], 'selected');
				
			}
			
		});
		
		return oRet;

	};

	$A(aTabs).forEach(function(oTab, nIdx) {

		if (Element.hasClass(oTab, 'selected')) nSelected = nIdx;

		$Fn(function(oEvent) {
			
			var oRet = showPanel(this);

			if (typeof oOptions.onChange == 'function')
				oOptions.onChange(oRet.tab, oRet.panel);
			
			oEvent.stop();

		}).owner(nIdx).attach(oTab, 'click');

	});

	showPanel(nSelected);

};

/**
 * 셀렉트박스
 *
 * @author hooriza (ajaxUI team)
 */
SPS.selectbox = $Class({

	_agent : $Agent().navigator(),
	
	_o : null,
	_timer : null,
	
	_options : null,
	
	$init : function(oEl, oOptions) {
		
		/*
		var o = this._o = {
			wrap : oEl,
			label : $$('.label', oEl)[0],
			layer : $$('.layer', oEl)[0],
			list : $$('.list', oEl)[0],
			resource : $$('.resource', oEl)[0]
		};
		*/
		
		var o = this._o = {
			wrap : oEl,
			label : $$('p', oEl)[0],
			layer : $$('ul', oEl)[0],
			list : $$('ul', oEl)[0],
			button : $$('.btn', oEl)[0]
		};

		var eSrc = $Element(o.wrap).findElement('nextSibling', function(oEl) { return oEl.tagName && oEl.tagName.toUpperCase() == 'SELECT'; });
		if (!eSrc) return;
		
		$Element(oEl).addClass('selectbox-skip');
		SPS.selectbox._instances.push(this);

		o.resource = eSrc.$value();
		eSrc.css({
			position : 'absolute',
			left : '-999999px'
		});
		
		o.button.removeAttribute('href');
		
		o.wrap.style.display = 'block';
		o.list.style.display = 'none';
		
		/////////
		
		this._options = oOptions || { showNULL : true };
		
		this._timer = new SPS.timer('timeout');
		
		this._bindEvents();
		this._touchLabel();
		
	},
	
	_findAbove : function(nIndex) {
		
		var o = this._o;

		for (; nIndex > -1; nIndex--)
			if (o.resource.options[nIndex].getAttribute('value'))
				return nIndex;
				
		return -1;
		
	},
	
	_findBelow : function(nIndex) {
		
		var o = this._o;
		var nLen = o.resource.options.length;

		for (; nIndex < nLen; nIndex++)
			if (o.resource.options[nIndex].getAttribute('value'))
				return nIndex;
				
		return -1;
		
	},
	
	_showList : function(bFlag) {
		
		var o = this._o;
		if (o.resource.selectedIndex == -1) return;
		
		var sMethod = bFlag ? 'show' : 'hide';
		if (typeof bFlag == 'undefined') sMethod = 'toggle';
		
		var eLayer = $Element(o.layer);
		eLayer[sMethod]();
		
		var bVisible = eLayer.visible();
		if (bVisible) this._touchList();
		
		// SPS.debug(m + ' : ' + bVisible);
		
	},
	
	_fireOnChangeEvent : function() {
		
		var o = this._o;
		
		if (document.createEvent) {
			
			var e = document.createEvent('HTMLEvents');
			e.initEvent('change', true, true);
			o.resource.dispatchEvent(e);
			
		} else {
			
			var e = document.createEventObject();
			o.resource.fireEvent('onchange', e);
			
		}
		
	},

	_bindEvents : function() {
		
		var o = this._o;
		
		// 진짜 셀렉트 박스에서 휠 for IE6 below
		$Fn(function(oEvent) {
			var nDelta = oEvent.mouse().delta;
			o.list.scrollTop -= nDelta * 15;
			//alert(nDelta);
			//o.list.fireEvent('onmousewheel', oEvent._event);
			oEvent.stop();
		}).owner(this).attach(o.resource, 'mousewheel');
		
		// 진짜 셀렉트 박스에 포커스
		$Fn(function(oEvent) {
			
			var eWrap = $Element(o.wrap);
			
			if (!eWrap.hasClass('selectbox-focus'))
				eWrap.addClass('selectbox-focus');
				
			this._timer.stop();
			// this._showList(true);
			
		}).owner(this).attach(o.resource, 'focus');
		
		// 진짜 셀렉트 박스에 포커스 잃음
		$Fn(function(oEvent) {

			var eWrap = $Element(o.wrap);
			var self = this;
			
			this._timer.start(50, function() {
				
				if (eWrap.hasClass('selectbox-focus'))
					eWrap.removeClass('selectbox-focus');
					
				self._showList(false);
				
			});
			
		}).owner(this).attach(o.resource, 'blur');
		
		// 셀렉트 박스에서 키보드 눌렀을때
		$Fn(function(oEvent) {
			
			var self = this;
			
			var nKeyCode = oEvent.key().keyCode;
			var nSrcIndex = this._getSelectedIndex();
			
			switch (nKeyCode) {
			case 33, 36, 37, 38: // 감소
			case 34, 39, 40, 45: // 증가
				break;
				
			case 32: // space
				this._showList();
				oEvent.stop();
				return;
			}
			
			setTimeout(function() {
				
				if (!self._options.showNULL) {
					
					var nIndex = self._getSelectedIndex();
					var bMustFind = o.resource.options[nIndex].getAttribute('value') ? false : true;
					
					if (nIndex > nSrcIndex) { // 밑으로 내려가는 거면
						
						var nLen = o.resource.options.length;
						
						nIndex = self._findBelow(nIndex);
						if (nIndex == -1) nIndex = self._findAbove(nLen - 1);
						
					} else { // 위로 올라가는 거면
						
						nIndex = self._findAbove(nIndex);
						if (nIndex == -1) nIndex = self._findBelow(0);
						
					}
					
					if (self._agent.firefox || self._agent.safari) bMustFind = true;
					
					if (nIndex != -1) {
						o.resource.selectedIndex = nIndex;

						if (nIndex != nSrcIndex && bMustFind)
							self._fireOnChangeEvent();
					}
					
				}
				
				self._touchLabel();
				
			}, 0);

		}).owner(this).attach(o.resource, this._agent.opera ? 'keypress' : 'keydown');

		// 가짜 셀렉트 박스 클릭했을때
		$Fn(function(oEvent) {
			
			var self = this;
			setTimeout(function() { self._showList(); o.resource.focus(); }, 1);
			
		}).owner(this).attach(o.wrap, 'mousedown');
		
		// 목록의 아이템 위에 마우스 올렸을때
		$Fn(function(oEvent) {
			
			var eItem = $Element(oEvent.element).findElement('parentNode', function(e) { return $Element(e).hasClass('item'); }, true);
			if (!eItem) return;
		
			this._setHighlight(eItem);
			
		}).owner(this).attach(o.list, 'mouseover');
		
		// 목록의 아이템을 클릭했을때
		$Fn(function(oEvent) {
			
			var self = this;
			
			var eItem = $Element(oEvent.element).findElement('parentNode', function(e) { return $Element(e).hasClass('item'); }, true);
			if (!eItem) {
				SPS.debug("FOO");
				setTimeout(function() { self._timer.stop(); o.resource.focus(); }, 1);
				oEvent.stop();
				return;
			}
			
			var oItem = eItem.$value();
			var nIndex = parseInt(oItem.className.match(/__au_index_([0-9]+)/)[1]);
		
			o.resource.selectedIndex = nIndex;
			this._setSelect(eItem);
			this._touchLabel();
			
			if (this._agent.firefox || this._agent.ie) self._fireOnChangeEvent();
			setTimeout(function() { self._showList(false); }, 50);
			
		}).owner(this).attach(o.list, 'mousedown');
		
	},
	
	_setHighlight : function(eItem) {
		
		if (this._highlighted) this._highlighted.removeClass('item-highlight');
		eItem.addClass('item-highlight');
		this._highlighted = eItem;
		
		var oItem = eItem.$value();
		var oList = this._o.list;

		var oTop = oItem.offsetTop;
		if (oList.scrollTop > oTop) oList.scrollTop = oTop;
		
		var oBottom = oTop + oItem.offsetHeight;
		if (oList.scrollTop + oList.clientHeight < oBottom) oList.scrollTop = oBottom - oList.clientHeight; 
		
	},
	
	_setSelect : function(eItem) {
		
		if (this._selected) this._selected.removeClass('item-select');
		eItem.addClass('item-select');
		this._selected = eItem;
		
		this._setHighlight(eItem);
		
	},
	
	_highlighted : null,
	_selected : null,
	
	_getSelectedIndex : function() {
		
		var o = this._o;
		var nIndex = o.resource && o.resource.selectedIndex;
		
		if (nIndex > -1) return nIndex;
		return -1;
		
	},
	
	_touchLabel : function() {
		
		var o = this._o;
		
		var nIndex = this._getSelectedIndex();
		if (nIndex == -1) {
			o.label.innerHTML = '';
			return;
		}
		
		var sText = o.resource.options[nIndex].text;
		o.label.innerHTML = sText;
		
		var oItem = $$('.__au_index_' + nIndex, o.list)[0];
		if (oItem) this._setSelect($Element(oItem));
		
	},
	
	_touchList : function() {
		
		var o = this._o;
		var aOptions = o.resource.options;
		var oItem;

		var sText, sValue;
		
		o.list.innerHTML = '';
		
		this._highlighted = null;
		this._selected = null;
		
		for (var nIndex = 0, nLen = aOptions.length; nIndex < nLen; nIndex++) {
			
			sText = aOptions[nIndex].text;
			sValue = aOptions[nIndex].getAttribute('value');
			
			if (this._options.showNULL || sValue) {

				oItem = $('<li>');
				oItem.className = 'item __au_index_' + nIndex;
				
				oItem.innerHTML = aOptions[nIndex].text;
				o.list.appendChild(oItem);
				
			}
			
		}
		
		this._touchLabel();
		
	},
	
	touch : function() {
		this._touchLabel();
	}
	
});

SPS.selectbox._version = 3;
SPS.selectbox._instances = [];

SPS.selectbox.touchAll = function(sClassName, oDoc) {

	if (!sClassName) {
		$A(this._instances).forEach(function(oInst) { oInst.touch(); });
		return;
	}
	
	var aEls = $$('.' + sClassName, oDoc || document);
	$A(aEls).forEach(function(oEl) {
		if ($Element(oEl).hasClass('selectbox-skip')) return;
		var oInst = new SPS.selectbox(oEl);
	});
	
};

/**
 * 팝업
 *
 * sample code :
 *
 
 SPS.popup('http://naver.com', 400, 300, {
	canResize : true,
	canScroll : true,
	name : 'hello',
	center : true 
 });
 
 SPS.popup('http://naver.com', 400, 300);
 
 */
SPS.newWin = function(sUrl, sName) { // 무조건 새창 띄우기

	var a = [];

	a.push('chanellmode=1');
	a.push('directories=1');
	a.push('fullscreen=0');
	a.push('location=1');
	a.push('menubar=1');
	a.push('scrollbars=1');
	a.push('status=1');
	a.push('toolbar=1');
	a.push('resizable=1');

	return window.open(sUrl, sName || SPS.uniqid(), a.join(','), false);
		
};

SPS.popup = function(sUrl, nWidth, nHeight, oOptions) {
	
	nWidth = nWidth || 300;
	nHeight = nHeight || 200;
	
	oOptions = oOptions || {};
	
	oOptions.canResize = oOptions.canResize || false;
	oOptions.canScroll = oOptions.canScroll || false;
	
	oOptions.name = oOptions.name || 'sps_popup';
	oOptions.center = oOptions.center || false; // 듀얼모니터일때 정상작동 안됨
	
	var a = [];
	a.push('chanellmode=0');
	a.push('directories=0');
	a.push('fullscreen=0');
	a.push('location=0');
	a.push('menubar=0');
	a.push('scrollbars=' + (oOptions.canScroll ? '1' : '0'));
	a.push('status=0');
	a.push('toolbar=0');
	a.push('resizable=' + (oOptions.canResize ? '1' : '0'));
	a.push('width=' + nWidth);
	a.push('height=' + nHeight);
	
	var aScrSize = [ window.screen.availWidth, window.screen.availHeight ];
	var aPos = [ parseInt((aScrSize[0] - nWidth) / 2), parseInt((aScrSize[1] - nHeight) / 2) ];
	
	a.push('left=' + aPos[0]);
	a.push('top=' + aPos[1]);
	
	return window.open(sUrl, oOptions.name, a.join(','), false);
	
};

SPS.popup.image = function(sUrl, nWidth, nHeight, oOptions) {

	if (typeof sUrl == 'object')
		sUrl = sUrl.getAttribute('src');

	nWidth = nWidth || 30;
	nHeight = nHeight || 30;

	return SPS.popup('/html/popup.htm?img=' + encodeURIComponent(sUrl), nWidth, nHeight, {
		canResize : true,
		name : 'image_pop'
	});
	
};

SPS.popup.mini = function(oEl) {

	return SPS.popup(oEl.href, 450, 540, {
		canResize : false,
		canScroll : false,
		name : 'mini_pop',
		center : true
	});

};

SPS.popup.stroke = function(oEl) {

	return SPS.popup(oEl.href, 350, 360, {
		canResize : false,
		canScroll : false,
		name : 'stroke_pop',
		center : true
	});

};

/**
 * 한번에 하나의 엘리먼트만 숨기기
 *
 * @author hooriza (ajaxUI team)
 */
SPS.hideOne = {
	
	_beforeEl : null,
	
	hide : function(oEl, sClassName) {
		
		var eEl = null;
		
		if (sClassName) eEl = SPS.getParentByClassName(oEl, sClassName);
		else eEl = $Element(oEl);
			
		if (!eEl) return;
		
		this.show();
			
		eEl.hide();
		this._beforeEl = eEl;
		
	},
	
	show : function() {
		
		if (this._beforeEl)
			this._beforeEl.show();
			
		this._beforeEl = null;
			
	}
	
};

/**
 * 한번에 하나의 엘리먼트만 보여주기
 *
 * @author hooriza (ajaxUI team)
 */
SPS.showOne = {
	
	_beforeEl : null,
	
	show : function(oEl, sClassName) {
		
		var eEl = null;
		
		if (sClassName) eEl = SPS.getParentByClassName(oEl, sClassName);
		else eEl = $Element(oEl);
			
		if (!eEl) return;
		
		this.hide();
			
		eEl.show();
		this._beforeEl = eEl;
		
	},
	
	hide : function() {
		
		if (this._beforeEl)
			this._beforeEl.hide();
			
		this._beforeEl = null;
			
	}
	
};

/**
 * 엘리먼트 내에서 적용된 값 얻고 셋팅하기
 *
 * @author hooriza (ajaxUI team)
 */
SPS.data = {

	setValue : function(sPrefix, oWrap, oData, bHtml) {
		
		$H(oData).forEach(function(sValue, sKey) {
			
			var oEl = $$(sPrefix + sKey, oWrap)[0];
			var sTag = oEl.tagName.toUpperCase();
			
			if (sTag == 'INPUT' || sTag == 'TEXTAREA' || sTag == 'SELECT')
				oEl.value = sValue;
			else
				oEl.innerHTML = bHtml ? sValue : new String(sValue).toHTML();
			
		});
		
	},
		
	getValue : function(sPrefix, oWrap, aKeys, bHtml) {
			
		var oRet = {};
		
		$A(aKeys).forEach(function(sKey) {
			
			var oEl = $$(sPrefix + sKey, oWrap)[0];
			var sTag = oEl.tagName.toUpperCase();
			
			if (sTag == 'INPUT' || sTag == 'TEXTAREA' || sTag == 'SELECT')
				oRet[sKey] = SPS.getFormValue(oEl);
			else
				oRet[sKey] = bHtml ? (oEl.innerText || oEl.textContent) : oEl.innerHTML;
			
		});
		
		return oRet;
		
	}
	
};

/**
 * 팝업 레이어
 *
 * @author hooriza (ajaxUI team)
 */
SPS.layer = {
	
	oLayer : null,

	oBlind : null,
	eBlind : null,

	bPoped : false,
	bCenter : false,

	orgPopup : null,
	orgZIndex : null,

	createBlind : function() {

		if (this.oBlind) return;

		var oAgent = $Agent().navigator();

		var bIE55 = oAgent.ie && oAgent.version < 6;
		var bIE6 = oAgent.ie && oAgent.version < 7;
		
		var bFF = oAgent.firefox;

		if (bIE55) { // IE5.5 이하면

			this.oBlind = document.createElement('<table border="0" cellpadding="0" cellspacing="0"></table>');
			this.oBlind.insertRow(0).insertCell(0).innerHTML = '&nbsp;';

		} else {
			this.oBlind = $("<div>");
		}

		this.eBlind = $Element(this.oBlind);

		document.body.insertBefore(this.oBlind, document.body.firstChild);

		this.eBlind.css({
			position : 'fixed',
			background : '#000',
			left : (bIE55 ? 0 : -0) + 'px', // body 의 padding:10px 이므로
			top : (bIE55 ? 0 : -0) + 'px',
			width : '100%', // 100%
			height : '100%',
			display : 'none',
			zIndex : 999
		});
		
		if (bIE6 || bFF) { // IE6 이하 브라우저면

			this.eBlind.css('position', 'absolute');

			if (bIE55) $Fn(this.fitBlindSize).owner(this).attach(window, 'scroll');
			$Fn(this.fitBlindSize).owner(this).attach(window, 'resize');
		}

		$Fn(this.moveToCenter).owner(this).attach(window, 'scroll');
		$Fn(this.moveToCenter).owner(this).attach(window, 'resize');

		this.eBlind.opacity(0.3);

	},

	fitBlindSize : function() {

		if (!this.bPoped) return;

		var oAgent = $Agent().navigator();

		var bIE55 = oAgent.ie && oAgent.version < 6;
		var bIE6 = oAgent.ie && oAgent.version < 7;

		// if (!bIE6) return; // IE7 이상이면 필요없음

		var aClientSize = this.getClientSize();

		if (bIE55) { // IE5.5 이하면

			var oDoc = document.body;

			this.eBlind.css({
				width : aClientSize[0] + 'px',
				height : aClientSize[1] + 'px',
				left : oDoc.scrollLeft + 'px',
				top : oDoc.scrollTop + 'px'
			});

		} else {

			this.eBlind.css({ width : '0px', height : '0px' });

			var self = this;
			var oDoc = document.documentElement || document;

			setTimeout(function() {

				var aScrollSize = [
					oDoc.scrollWidth,
					oDoc.scrollHeight
				];

				var aSize = [
					Math.max(aScrollSize[0], aClientSize[0]),
					Math.max(aScrollSize[1], aClientSize[1])
				];

				self.eBlind.css({
					width : aSize[0] + 'px', height : aSize[1] + 'px'
				});

			}, 1);

		}

	},

	getClientSize : function() {

		var oAgent = $Agent().navigator();
		var bIE55 = oAgent.ie && oAgent.version < 6;

		var oDoc = document.documentElement || document;
		if (bIE55) oDoc = document.body;

		return [ oDoc.clientWidth, oDoc.clientHeight ];

	},

	moveToCenter : function() {

		if (!this.bCenter) return;
		
		var aScrSize = this.getClientSize();
		var aPopSize = [ this.orgPopup.width(), this.orgPopup.height() ];

		var aPos = [ parseInt((aScrSize[0] - aPopSize[0]) / 2), parseInt((aScrSize[1] - aPopSize[1]) / 2) ];

		var oDoc = document.documentElement || document;
		this.orgPopup.css({ left : aPos[0] + oDoc.scrollLeft + 'px', top : aPos[1] + oDoc.scrollTop + 'px' });

	},

	pop : function(oEl) {

		this.createBlind();

		this.bPoped = true;
		this.fitBlindSize();

		if (this.orgPopup)
			this.orgPopup.css('zIndex', this.orgZIndex);

		this.orgPopup = $Element(oEl);
		this.orgZIndex = this.orgPopup.css('zIndex');
		
		var sPosition = this.orgPopup.css('position');

		if (sPosition != 'absolute' && sPosition != 'relative')
			this.orgPopup.css('position', 'relative');

		this.orgPopup.css('zIndex', 1000);

	},

	unpop : function() {

		this.bPoped = false;

		if (this.orgPopup) {

			if (this.orgZIndex !== null)
				this.orgPopup.css('zIndex', this.orgZIndex);

			this.orgPopup = null;
			this.orgZIndex = null;
		}

	},
	
	show : function(oEl, bCenter, bNoBlind) {

		var oLayer = this.oLayer = oEl;
		var eLayer = $Element(oLayer);
		
		eLayer.show();
		this.pop(oLayer);

		if (!bNoBlind)
			this.eBlind.show();
			
		var sPosition = eLayer.css('position');

		var oNavigator = $Agent().navigator();
		if (oNavigator.ie && oNavigator.version < 7) {
			
			eLayer.css('position', 'static');
			eLayer.css('position', sPosition);
			
		}

		if (sPosition == 'absolute') { // absolute 일때만 sFlag 셋팅 먹이기

			this.bCenter = bCenter;
			this.moveToCenter();

		}

	},

	hide : function(bHideOne) {
		
		if (!this.oLayer) return;

		this.bCenter = null;

		this.unpop();
		this.eBlind.hide();

		$Element(this.oLayer).hide();
		this.oLayer = null;
		
		if (bHideOne) SPS.hideOne.show();

	}

};

SPS.fontSize = $Class({
		
	_o : null,
	_size : 0,
	
	_dragging : false,
	
	$init : function(sEl) {
		
		var oEl = $(sEl);
		
		var aAnchors = $$('.txtsize_ctr a', oEl);
		
		var o = this._o = {
			smaller : aAnchors[0],
			bigger : aAnchors[1],
			track : $$('.txtsize_slide', oEl)[0],
			grap : $$('.move', oEl)[0]
		};
		
		$Fn(function() {
			
			o.panels = $$('.font_reslzable');
			this._setSize(1);
			
			this._bindEvents();
			
		}).owner(this).attach(window, 'load');

	},
	
	_setSize : function(nSize) {
		
		var o = this._o;
		
		this._size = nSize;
		if (this._size > 2) this._size = 2;
		if (this._size < 0) this._size = 0;
		
		this._applySize();
		
	},
	
	_applySize : function() {
		
		var o = this._o;
		
		var nLeft = this._size * 15;
		var nSize = this._size * 3 + 12;
		
		$Element(o.grap).css({ 'left' : nLeft + 'px', 'display' : 'block' });
		
		$A(o.panels).forEach(function(oPanel) {
			oPanel.style.fontSize = nSize + 'px';
		});
		
	},
	
	_handlerDrag : function(oEvent) {
	
		var o = this._o;
		
		if (!this._dragging) return;
		
		var oPos = $Element(o.track).offset();
		var nLeft = oEvent.pos().pageX - oPos.left;
		
		this._setSize(parseInt((nLeft + 6) / 16));
		
	},
	
	_bindEvents : function() {
		
		var o = this._o;
		
		$Fn(function(oEvent) {

			this._setSize(this._size - 1);
			oEvent.stop();
			
		}).owner(this).attach(o.smaller, 'click');

		$Fn(function(oEvent) {
			
			this._setSize(this._size + 1);
			oEvent.stop();
			
		}).owner(this).attach(o.bigger, 'click');
		
		// 드래그 시작
		$Fn(function(oEvent) {
			this._dragging = true;
			this._handlerDrag(oEvent);
			oEvent.stop();
		}).owner(this).attach(o.track, 'mousedown');
		
		$Fn(function(oEvent) { oEvent.stop(); }).owner(this).attach(o.track, 'dragstart');
		$Fn(function(oEvent) { oEvent.stop(); }).owner(this).attach(o.track, 'selectstart');
		
		// 드래그 진행
		$Fn(this._handlerDrag).owner(this).attach(document, 'mousemove');
		
		// 드래그 끝
		$Fn(function(oEvent) { this._dragging = false; }).owner(this).attach(document, 'mouseup');

	}

});

SPS.selection = {

	_holded : false,

	block : function() {
		if (this._holded) return;
		document.body.onselectstart = function() { return false; };
	},
	
	allow : function() {
		if (this._holded) return;
		document.body.onselectstart = null;
	},
	
	hold : function(bFlag) {
		this._holded = bFlag;
	}
	
};

/**
 * Dynamic Script Including
 *
 * @author hooriza at nhncorp.com
 * @version 0.95
 *
 * @created Nov.1.2007.
 */
SPS.Include = function() {
	
	var self = this;
	
	this._uniqID = SPS.uniqid();
	this._requests = {};
	
	if (!SPS.Include._instance) SPS.Include._instance = {};
	SPS.Include._instance[this._uniqID] = this;
	
	this._gcTimer = setInterval(function() { self._gc(); }, this._gcInterval);
	
};

SPS.Include.prototype = {
	
	_uniqID : null,
	_requests : null,
	
	_trID : null,
	_callback : null,

	_gcTimer : null,
	_gcInterval : 30000, // 30초마다 gc 실행
	
	_head : null,
	
	request : function(sUrl, pCallback) {
		
		var nTrID = SPS.uniqid();
		
		var sMethod = 'SPS.Include._response(' + this._uniqID + ', ' + nTrID + ')';
		
		if (sUrl.indexOf('?') == -1) sUrl += '?';
		sUrl += '&callback=' + encodeURIComponent(sMethod);
		
		this._trID = nTrID;
		this._callback = pCallback;
		
		if (SPS.debugMode) window.console.debug(sUrl);
		
		this._createScript(nTrID, sUrl);
		
	},
	
	abort : function() {
		this._trID = null;
	},
	
	_createScript : function(nTrID, sUrl) {
	
		if (!this._head) this._head = document.getElementsByTagName('head')[0]; 
		
		var oScript = document.createElement('script');
		var nTime = SPS.uniqid();

		with (oScript) {
			src = sUrl;
			id = nTime; // 생성시간
			language = 'javascript';
			type = 'text/javascript';
		};
		
		this._requests[nTrID] = oScript;
		this._head.appendChild(oScript);
		
		return oScript;
		
	},
	
	_destroyScript : function(nTrID, nExpires, nNow) {
		
		var oScript = this._requests[nTrID];
		
		// 생성된지 지정된 시간이 지난 것만 삭제
		if (nExpires) {

			nNow = nNow || new Date().getTime();
			
			if (parseInt(oScript.id) > nNow - nExpires)
				return;

		}
		
		var self = this;

		setTimeout(function() { self._head.removeChild(oScript); }, 10); // IE5.5 버그 회피
		delete this._requests[nTrID];
		
	},
	
	_gc : function() {
		
		var nNow = new Date().getTime();
		
		for (var nTrID in this._requests)
			this._destroyScript(nTrID, this._gcInterval, nNow);
			
	}
	
};

SPS.Include._response = function(nUniqID, nTrID) {
	
	var pIgnore = function() { };
	
	var oInst = this._instance[nUniqID];
	if (!oInst) return pIgnore;

	oInst._destroyScript(nTrID);
	if (oInst._trID != nTrID) return pIgnore;
	
	var pCallback = oInst._callback;

	return function(oData) { return pCallback(oData); };
	
};

SPS.findDo = function(oEl, oEvent, pFindFunc, sMethod) {

	var eEvent = $Event(oEvent);
	var oEventEl = eEvent.element;
	
	var bTTSButton = SPS.getParentByClassName(oEventEl, 'tts_button');
	if (bTTSButton) return;

	if (typeof pFindFunc == 'string')
		pFindFunc = SPS.findDo[pFindFunc];
		
	var oTar = pFindFunc(oEl);
	if (oTar) return oTar[sMethod]();
};

SPS.findDo.translation = function(oEl) {

	var eEl = $Element(oEl.parentNode).findElement('nextSibling', function(o) {
		return o.tagName.toUpperCase() == 'TR';
	});
	
	if (eEl) eEl.toggle();

};

/**
 * @author hooriza
 */
SPS.autohide = $Class({
	
	_panel : null,
	_areas : null,
	
	_options : null,
	
	$init : function(oPanel, aAreas, oOptions) {
		
		this._panel = oPanel;
		this._areas = aAreas || [];
		
		this._options = oOptions || {};
		
		this._bindEvents();
		
	},
	
	_bindEvents : function() {
		
		$Fn(function(oEvent) {
			
			var oElement = oEvent.element;
			
			if (this._panel && oEvent.of(this._panel)) return;
			
			for (var i = 0, oArea; oArea = this._areas[i]; i++)
				if (oArea && oEvent.of(oArea)) return;
			
			if (this._panel) $Element(this._panel).hide();
			
		}).owner(this).attach(document, 'click');
		
	},
	
	toggle : function() {
		
		var bVisible = $Element(this._panel).visible();
		this[bVisible ? 'hide' : 'show']();
		
	},
	
	show : function() {
		
		$Element(this._panel).show();
		if (typeof this._options.onShow == 'function')
			this._options.onShow();
		
	},
	
	hide : function() {
		
		$Element(this._panel).hide();
		if (typeof this._options.onHide == 'function')
			this._options.onHide();
		
	}
	
});

SPS.debug = function(sMsg) {

	if (!SPS.debugMode) return;

	if (!this._wnd) {
	
		this._wnd = $Element($('<ul>'));
		this._wnd.css({
			'position' : 'absolute',
			'right' : '10px',
			'bottom' : '10px',
			'border' : '5px solid #f00',
			'padding' : '10px',
			'background' : '#fff'
		});
		
		document.body.insertBefore(this._wnd.$value(), document.body.firstChild);
		
	}
	
	var oLog = $('<li>');
	oLog.innerHTML = sMsg;
	
	this._wnd.append(oLog);

};

SPS.sortTable = function(oEl) {

	var eTH = $Element(oEl).findElement('parentNode', function(e) { var t = e.tagName.toUpperCase(); return (t == 'TD' || t == 'TH'); }, true);
	var eTable = eTH.findElement('parentNode', function(e) { return e.tagName.toUpperCase() == 'TABLE'; });
	var oTable = eTable.$value();
	
	var oTH = eTH.$value();
	var nColIndex = oTH.cellIndex;
	
	var aTRs = $$('.sortable', oTable);
	var aDatas = [];
	
	var oBtnImg = $$('img.sorting', oTH)[0];
	var sBtnSrc = oBtnImg.src;
	
	var bDesc = sBtnSrc.indexOf('btn_usorting.gif') == -1;
	
	var pFillZero = function(sStr, nLen) {
	
		var sStr = new String(sStr);
		for (var i = 0, len = sStr.length; i < nLen - len; i++)
			sStr = '0' + sStr;

		return sStr;
			
	};
	
	$A(aTRs).forEach(function(oTR) {
		
		var oTD = oTR.cells[nColIndex];
		var sSortKey = oTD.className.match(/\bsortkey\((\w+)\)(\b|$)/);
		
		if (sSortKey && sSortKey[1]) {
			var aSortKey = sSortKey[1].split('_');
			var sSortKey = '';
			
			for (var i = 0, len = aSortKey.length; i < len; i++)
				sSortKey += pFillZero(aSortKey[i], 15) + '_';
			
		} else {
			sSortKey = (oTD.innerText || oTD.textContent).trim();
		}
			
		aDatas.push({ key : sSortKey, object : oTR });
	});

	if (bDesc) sBtnSrc = sBtnSrc.replace('btn_sorting.gif', 'btn_usorting.gif');
	else sBtnSrc = sBtnSrc.replace('btn_usorting.gif', 'btn_sorting.gif');

	oBtnImg.src = sBtnSrc;
	
	$A($$('img.sorting', oTable)).forEach(function(oImg) {
		
		if (oImg == oBtnImg) return;
		
		if (bDesc) oImg.src = oImg.src.replace('btn_sorting.gif', 'btn_usorting.gif');
		else oImg.src = oImg.src.replace('btn_usorting.gif', 'btn_sorting.gif');
		
	});
	
	var pAsc = function(a, b) { return a.key < b.key ? -1 : (a.key == b.key ? 0 : 1); };
	var pDesc = function(a, b) { return a.key < b.key ? 1 : (a.key == b.key ? 0 : -1); };
	
	aDatas.sort(!bDesc ? pDesc : pAsc);
	
	for (var i = 0; oData = aDatas[i]; i++) {
		
		var oNewTR = oData.object.cloneNode(true);
		var oOldTR = aTRs[i];
		
		oOldTR.parentNode.insertBefore(oNewTR, oOldTR);
		oOldTR.parentNode.removeChild(oOldTR);
		
	}

};

SPS.switchMemorized = function(oEl) {

	var sTrID = SPS.uniqid();
	SPS.switchMemorized.trID = sTrID;
	
	var oAjax = $Ajax(oEl.href, { 
		onload : function(oRes) {

			var oData = null;
			try { eval('oData = ' + oRes.text() + ';'); } catch(e) {}
			
			if (!oData) return;
			
			var oEl;
			location.reload();
			return;
			
			/*
			trID:'3010374439012',
			text : 'Not Memorized',
			memorizedCount : '-4',
			notMemorizedCount : '21',
			percentage : '-23'
			*/
			
			oEl = $('SM' + oData.trID);
			if (oEl) oEl.innerHTML = oData.text;
			
			// 가장 최근 trID 것만 적용하게
			if (oData.trID != SPS.switchMemorized.trID) return;

			var eAnchor;
			
			oEl = $$('.mem_percentage')[0];
			oEl.innerHTML = oData.percentage + '%';

			oEl = $$('.mem_memorized')[0];
			if (oEl) {
				if (oEl) oEl.innerHTML = oData.memorizedCount;
				eAnchor = $Element(oEl).findElement('parentNode', function(o) { return o.tagName.toUpperCase() == 'A'; });
				if (eAnchor) {
					var bNoLink = oData.memorizedCount == '0';
					var oAnchor = eAnchor.$value(); 
					eAnchor[bNoLink ? 'addClass' : 'removeClass']('nolink');
					if (bNoLink) {
						oAnchor.setAttribute('_href', oAnchor.href);
						oAnchor.removeAttribute('href');
					} else {
						oAnchor.href = oAnchor.getAttribute('_href');
					} 
				} 
			}
			
			oEl = $$('.mem_notmemorized')[0];
			if (oEl) {
				if (oEl) oEl.innerHTML = oData.notMemorizedCount;
				eAnchor = $Element(oEl).findElement('parentNode', function(o) { return o.tagName.toUpperCase() == 'A'; });
				if (eAnchor) {
					var bNoLink = oData.notMemorizedCount == '0';
					var oAnchor = eAnchor.$value(); 
					eAnchor[bNoLink ? 'addClass' : 'removeClass']('nolink');
					if (bNoLink) {
						oAnchor.setAttribute('_href', oAnchor.href);
						oAnchor.removeAttribute('href');
					} else {
						oAnchor.href = oAnchor.getAttribute('_href');
					} 
				} 
			}
 
		}
	});
	
	oEl.id = 'SM' + sTrID;
	oAjax.request({ trID : sTrID });

};

SPS.DomLoaded = {

	_callbacks : [],
	_loaded : false,
	
	_onLoaded : function() {
	
		var self = SPS.DomLoaded;
		
		for (var i = 0, pCallback; pCallback = self._callbacks[i]; i++)
			pCallback();
	},
	
	_monitorInterval : function() {
	
		var self = SPS.DomLoaded;
	
		if (self._loaded) return;
		if (document.readyState == 'loaded' || document.readyState == 'complete') {
			self._onLoaded();
			self._loaded = true;
		} else {
			setTimeout(self._monitorInterval, 100);
		} 

	},
	
	addCallback : function(pCallback) {
		this._callbacks.push(pCallback);
	},
	
	monitor : function() {

		if (document.addEventListener && !$Agent().navigator().safari) {
			document.addEventListener("DOMContentLoaded", SPS.DomLoaded._onLoaded, false);
		} else {
			setTimeout(this._monitorInterval, 100);
		}	
	}

};

SPS.DomLoaded.monitor();

SPS.banWords = '';

SPS.checkBanWords = $Fn(function(oEvent) {

	var oEl = oEvent.element;
	var sTagName = (oEl.tagName || '').toUpperCase();
	
	if (sTagName != 'INPUT' && sTagName != 'TEXTAREA') return;

	// class="skip_banword" 가 되어있으면 욕 체크 안하기
	if ($Element(oEl).hasClass('skip_banword')) return;

	var sValue = oEl.value;
	var bExist = false;

	for (var i = 0, banWord; banWord = SPS.banWords[i]; i++) { 
		if (sValue.indexOf(banWord) == -1) continue;

		bExist = true;
		sValue = sValue.replace(new RegExp(banWord, 'gi'), '');

	}
	
	if (bExist) {
		oEl.value = sValue;
		alert(SPS.text('BANWORDS'));
	}

});

SPS.checkBanWords.attach(document, 'keyup');
SPS.checkBanWords.attach(document, 'blur');

SPS.transition = function(oEl, nCount, nInterval, nLeft, nTop, oOptions) {

	var nPercent = 0;

	var nStep = 1 / nCount;
	var aOrgPos = [ parseInt(oEl.style.left), parseInt(oEl.style.top) ];

	var pProgress = function() {
	
		nPercent += nStep;
		
		var nP = (function(v) { var v = Math.sin(v * (Math.PI / 2)); return v * v; })(nPercent); 
		
		var aNewPos = [
						(nLeft - aOrgPos[0]) * nP + aOrgPos[0],
						(nTop - aOrgPos[1]) * nP + aOrgPos[1]
		];
		
		oEl.style.left = aNewPos[0] + 'px';
		oEl.style.top = aNewPos[1] + 'px';
		
		nCount--;
		
		if (nCount > 0) setTimeout(pProgress, nInterval);
		else if (oOptions.onEnd) oOptions.onEnd();

	};
	
	pProgress();
	
}; 

