﻿
/* --- NTREEV JS Framework v0.7 @ script by pRix, 2008.12.26 --- */

// setting
Ntreev = window;
Ntreev.setting =
{
	info : 'Ntreev JS framework v0.7',
	JSpath : '/',
	deburg : true,
	JSfilter : /\<script[^\>]+\>[^\>]+\<\/script\>/i,
	emptyElement : document.createElement('div')
};

// advance commander
document.readyList = [];
document.ready = function()
{
	for (var i=0; arguments[i]; i++)
		this.readyList.push(arguments[i]);

	// readyStatue 프로퍼티는 브라우져에 따라 지원하지 않거나 상태에 대한 정확도가 불일치함
	// getElementsByTagName 명령을 사용하여 body tag가 사용가능하면 html 부분의 문서로딩이 끝났음을
	// 정확히 알 수 있기에 interval 을 사용하여 체크
	this.readyTimer = setInterval(function()
	{
		if (document.getElementsByTagName('body')[0] && (!this.readyState || this.readyState == 'complete'))
		{
			clearInterval(document.readyTimer);
			setTimeout( function() { document.readyList.each().clear() }, 100 );
		}
	}, 10)
};

// Global HTMLElement extender
HTMLExtender = function(target)
{
	if (!target) return target;
	for ( var i=0, el = $A(target); el[i]; i++)
		{ if (!el[i].__) Util.extend(el[i], HTMLMethods.clone) };

	return target;
};

HTMLCreator = function(html)
{
	Ntreev.setting.emptyElement.innerHTML = html;
	return Ntreev.setting.emptyElement.firstChild;
};

// Class creator
Class =
{
	create : function(obj)
	{
		return function()
		{
			(obj['install']||Function()).apply(this, arguments);
			Util.extend(this.constructor.prototype, obj);
		}
	},

	object : function(obj)
	{
		var temp = Class.create(obj)
		return new temp();
	}
};

// Utility Function's
Util =
{
	// Methods n Property extender
	extend : function(target, source)
	{
		// source 가 가진 모든 프로퍼티 및 메서드를 target 으로 복사
		for (var m in source)
			target[m] = source[m];

		return target;
	},

	toClipboard : function(txt)
	{
		// flash 를 이용한 클립보드 복사
		return;
	},

	countValue : 1,
	count : function()
	{
		return this.countValue++;
	},

	randomCount : function(min, max)
	{
		return min+Math.round(Math.random() * (max - min));
	},

	toggle : function(value)
	{
		return this['__toggle_'+value] = this['__toggle_'+value] ? false : true;
	},

	evalJS : function(data)
	{
		try {
			for (var data = data.remove(/\n|\r/gm), js = []; Ntreev.setting.JSfilter.test(data); data = data.remove(Ntreev.setting.JSfilter))
				js.push(Ntreev.setting.JSfilter.exec(data));

			js.each(function(jsData) {
				eval( /\>(.+)\</i.exec(jsData)[1] );
			})
		} catch(e) { }
		return data;
	},

	commender : function(data)
	{
		Util.bounce(
			function() { eval(data) },
			function() { data() },
			function() { alert(data) }
		)
	},

	bounce : function()
	{
		// 애규먼트들을 차례데로 try 문으로 감싸서 실행
		for (var i=0; arguments[i]; i++) {
			try {
				return ($Function(arguments[i]) ? arguments[i]() : eval(arguments[i])) || EfCT;
			} catch(e) {}
		}
		return false; // 하나도 건지지 못하면 false 반환. 그것이 인생
	}
};

// Cookie controller
Cookie =
{
	set :  function(name,value,delay)
	{
		var today = new Date();
		today.setDate(today.getDate()+(delay||1));

		// cookie data는 특수기호, 공백등에 대한 처리응 위하여 escape 처리
		document.cookie = name+'='+escape(value || '')+'; path=/; '+(delay ? 'expires='+today.toGMTString() : '')+';';
	},

	get : function(name)
	{
		// 기록당시의 상태로 되돌리기윟 unescape 처리
		return unescape($S(RegExp(name+'=[^\s^;]+').exec(document.cookie+'; ') || '').remove(/.+=/));
	},

	remove : function(name)
	{
		this.set(name,'',-1);
	},

	clear : function()
	{
		var cookie = $S(document.cookie).split(';');
		for (var i=0; cookie[i]; i++)
			this.remove( /.*(?=\=)/.exec(cookie[i].trim()) );
	}
};

Util.extend(Array.prototype,
{
	each : function(fn)
	{
		try {
			for (var i=0; this[i]; i++ )
				if (!fn && $Function(this[i])) this[i]();
				else if ($String(fn)) eval('this[i].'+fn);
				else if ($Function(fn)) fn(this[i]);
		} catch(e) {}

		return this;
	},

	indexOf : function(target)
	{
		for (var i=0; this[i]; i++)
			if ( this[i] == target ) return String(i);

		return false;
	},

	filter : function(fn)
	{
		for (var i=0; i < this.length; )
			if (!fn(this[i])) this.cut(i); else i++;

		return this;
	},

	cut : function(target)
	{
		this.splice($Number(target) ? target : this.indexOf(target), 1);
		return this;
	},

	clear : function()
	{
		this.length = 0;
		return this;
	},

	cleanUp : function(resort)
	{
		if (resort) this.sort();
		for (var c=0; c < this.length;)
			if (!this[c] || this[c] == '' || this[c] == this[c+1]) this.cut(c); else c++;

		return this;
	},

	randomSort : function()
	{
		this.sort(function(){return Math.random()*3-2;});
		return this;
	}
});

Util.extend(String.prototype,
{
	remove : function()
	{
		for (var i=0, str = $A(arguments), string=this; str[i]; i++)
			string = string.replace(str[i], '')

		return string;;
	},

	size : function()
	{
		for (var i=0,bytes = 0; this.charCodeAt(i); i++)
			bytes += (this.charCodeAt(i) > 128) ? 2 : 1;

		return bytes;
	},

	camelize : function()
	{
		for (var w=this; /-\w| +\w/.test(w);)
			w = w.replace(/-\w| +\w/,/-\w| +\w/.exec(w)[0].remove(/[- ]/).toUpperCase());

		return w.trim();
	},

	trim : function()
	{
		return this.remove(/(^\s*)|(\s*$)/g);
	}
});

Util.extend(Number.prototype,
{
	max : function(m, type)
	{
		return type ? (this > m ? false : true) : Math.min(this, m);
	},

	min : function(m, type)
	{
		return type ? (this < m ? false : true) : Math.max(this, m);
	},

	range : function(m1, m2, type)
	{
		return type ? (this > m1 && this < m2 ? true : false) : this.max(Math.max(m1,m2)).min(Math.min(m1,m2));
	},

	end: function(n, range)
	{
		var range = range || 0.5;
		return n + range > this && n - range < this ? n : this;
	}
});

Util.extend(Function.prototype,
{
	bind : function(obj)
	{
		var ar = $A(arguments), obj = ar.shift(), func = this;
		return function() { func.apply(obj, ar.length ? ar : arguments) }
	},
	callback : function()
	{
		var fn = this;
		return function() { return (_____ = fn.apply(this, arguments)) != undefined ? _____ : this }
	}
});

Util.extend(Date.prototype,
{
	create : function(template)
	{
		var data = this.toGMTString().split(' '), time = this.getHours() > 12;
		return template
			.replace(/\$YYYY/g,data[3])
			.replace(/\$YY/g,data[3].substr(2,2))
			.replace(/\$MMM/g,data[2]+['uary','ruary','ch','ill','','e','y','ust','tember','ober','ember','ember'][this.getMonth()])
			.replace(/\$MM/g,data[2])
			.replace(/\$M/g,this.getMonth()+1)
			.replace(/\$D/g,data[1])
			.replace(/\$WWW/g,['일','월','화','수','목','금','토'][this.getDay()])
			.replace(/\$WW/g,data[0].substr(0,3)+['','','s','nes','rs','','ur'][this.getDay()]+'day')
			.replace(/\$W/g,data[0].substr(0,3))
			.replace(/\$TT/g,time ? '오후' : '오전')
			.replace(/\$T/g,time ? 'PM' : 'AM')
			.replace(/\$hh/g,time ? this.getHours() - 12 : this.getHours())
			.replace(/\$h/g,this.getHours())
			.replace(/\$m/g,this.getMinutes())
			.replace(/\$s/g,this.getSeconds());
	}
});


// Command function
Util.extend(window,
{
	$ : function(query, noCache)
	{
	    var noCache = true;
	    
		// arguments 가 없으면 최상위 document 객채를 반환
		if (!arguments.length) return $gecko ? document.body : document.documentElement || document.body;

		// query selector 가 불필요한 상황이면 바로 반환
		if (typeof query == 'object') return HTMLExtender(query);
		if (/^\<.*\>$/.exec(query)) return HTMLExtender(HTMLCreator(query));
		if (/^#\w+$/.exec(query) && !this.nodeName) return HTMLExtender(document.getElementById($P(query)));

		// 쿼리 depth 및 selector 분리, root element 설정
		var query = query.split(' '), q = query.shift(), selector = $getSelector(q), root = this.nodeName ? this : document.body;

		// Cache 가 되어있고 noCache 명령이 없다면 Cache 사용
		if ( root['$'+q] && !noCache )
			var result = root['$'+q];
		else
		{
			// 우선순위별 셀렉터를 이용하여 비교대상 검색
			var result = $A
				(
					selector.Dir? root.childNodes :
					selector.Tag ? root.getElementsByTagName(selector.Tag) :
					selector.Name && !this.nodeName ? document.getElementsByName(selector.Name) :
					selector.Id && !this.nodeName ? document.getElementById(selector.Id) :
					root.getElementsByTagName('*')
				);

			// 셀렉터별 유효성검사를 진행하여 불합격할경우 검색결과에서 삭제
			for ( var n=0; result[n];) {
				if ( $elementValidation(result[n], selector) ) n++; else result.cut(n);
			};
		}

		// 2depth 셀렉터가 있을경우 1depth 의 결과를 binding 하여 재요청
		// 재 요청시마다 하위 셀렉터가 있을경우 재요청함으로 마지막 depth 까지 한번에 진행된다
		if (result.length && query.length)
		{
			for (var i=0, sd=[]; result[i]; i++)
				sd = sd.concat($.call(result[i], query.join(' '), noCache));

			return sd;
		}

		return HTMLExtender(root['$'+q] = result);
	},
	$getSelector : function(q)
	{
		return {
			Dir : /^\//.exec(q),
			Tag : $P(/^\w+|^\/\w+/.exec(q)),
			Id : $P(/#\w+/.exec(q)),
			Name : $P(/@\w+/.exec(q)),
			Class : $P(/\.[\w\-]+/.exec(q))
		}
	},
	$elementValidation : function(el, s)
	{
		return s.Tag && !RegExp('^'+s.Tag+'$','i').test(el.nodeName) ? false :
				 s.Id && el.id != s.Id ? false :
				 s.Class && !RegExp('(?:^| )'+s.Class+'(?= |$)').test(el.className) ? false :
				 s.Name && el.name != s.Name ? false : true;
	},

	$F : function(fname)
	{
		var f = document.forms;
		for (var i=0; f[i]; i++)
			if (f[i][fname])
				return Util.extend(f[i][fname], HTMLMethods.clone);
	},

	$Form : function(fname)
	{
		var form = fname ? document.forms[fname] : document.forms[0];
		return form ? Util.extend(form, FORMMethods) : false;
	},

	$hashUrl : function()
	{
		return $S(/#.+/.exec(document.location.href)).remove(/^#/);
	},

	// arguments같은 복수의 데이타를 가지고있지만 배열이 아닌 객채를 배열 객채로 변환
	 $A : function(obj)
	 {
		 var ar = [];
		 if (obj && obj.length != undefined)
			 for (var i=0; i < obj.length; i++)  ar.push(obj[i]);
		 else
			 if (obj) ar.push(obj);

		 return ar;
	},

	// 문자열 객채로 변환
	$S : function(str)
	{
		var s = String(str);
		return /false|undefined|null/i.test(s) ? '' : s;
	},

	// 문자열부분을 제거하고 숫자만을 반환, no 값이 유효하지 않을경우 0 반환
	$N : function(no)
	{
		return no ? $S(no).remove(/[^\s\d]+/g).replace(/\s+/g,' ').trim().replace(/\s/g,',') : Number(0);
	},

	// 문자열일정규 정규식으로 변환
	$R : function(str, option)
	{
		return $RegExp(str) ? str : RegExp(str, option||'');
	},

	// 특수문자를 제거하고 영문, 한글, 숫자만을 반환, str 값이 유효하지 않을경우 '' 반환
	$P : function(str)
	{
		return str ?  /[\w\sㄱ-ㅎ가-힣\-]+/.exec(String(str)) : '';
	},

	isNot : function(obj) { return $Array(obj) ? obj.length == 0 : obj == undefined && obj != 0 ? true : false },

	// 현재 페이지의 프로토콜
	$http : /^.+\/\//.exec(window.location.href),
	$secure : /^https/.test(window.location.href),

	// 정규식을 이용한 브라우져 판별용 프로퍼티
	$msie : /msie/i.test(navigator.userAgent),
	$msie6 : /msie 6/i.test(navigator.userAgent) && !/msie 7/i.test(navigator.userAgent),
	$safari : /safari/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent),
	$firefox : /firefox/i.test(navigator.userAgent),
	$opera : /opera/i.test(navigator.userAgent),
	$chrome : /chrome/i.test(navigator.userAgent),
	$webKit : /applewebKit/i.test(navigator.userAgent),
	$gecko : /khtml/i.test(navigator.userAgent),

	// constructor를 이용한 데이타 형식 체크
	$Function : function(obj) { try { return obj.constructor == Function } catch(e) { return false } },
	$Array : function(obj) { try { return obj.constructor == Array } catch(e) { return false } },
	$String : function(obj) { try { return obj.constructor == String } catch(e) { return false } },
	$Number : function(obj) { try { return obj.constructor == Number } catch(e) { return false } },
	$RegExp : function(obj) { try { return obj.constructor == RegExp } catch(e) { return false } },
	$Element : function(obj) { try { return obj.nodeName ? true : false } catch(e) { return false } }
});

// element 에 methods 를 확장하려면 HTMLElement 에 prototype 으로 연결하면 간단하지만
// HTMLElement 를 ie에서 지원하지 않는 관계로 별도의  객채를 생성한다
HTMLMethods =
{
	__ : true, // 중복 체크용 프로퍼티

	opacity : function(op)
	{
		try {
			this.style.opacity = op/100;
			this.style.filter = "alpha(opacity="+op+")";
		} catch(e) {}
	},

	settingByElement : function(target)
	{
		var offset = target.getPosition();
		this.css(
			'position:absolute',
			'top:'+offset.y+'px',
			'left:'+(offset.x-target.offsetLeft)+'px',
			'width:'+target.clientWidth+'px',
			'height:'+target.clientHeight+'px'
		)
	},

	showCloud : function(color, alpha, depth)
	{
		if (!this.cloudElement) this.cloudElement = $('<div>');
		this.cloudElement
			.css('background-color:'+(color||'#fff'),'z-index:'+(depth||98))
			.settingByElement(this).opacity(alpha||50).show();

		document.body.appendChild(this.cloudElement);
	},
	hideCloud : function()
	{
		if (this.cloudElement) this.cloudElement.hide();
	},

	showIndicator : function(img, alpha, depth, top, left)
	{
		if (!this.indicatorElement) {
		    this.indicatorElement = $(new Image());
		    this.indicatorElement.style.position = 'absolute';
		    this.indicatorElement.src = img;
		}
		var pos = this.getPosition();
		var i = this.indicatorElement;
		i.style.top = (pos.y+this.clientHeight/2-(top||i.height/2)) + 'px';
		i.style.left = (pos.x+this.clientWidth/2-(left||30)) + 'px';
		i.style.zIndex = depth||'99';

		document.body.appendChild(i.opacity(alpha||50));
	},
	hideIndicator : function()
	{
		if (this.indicatorElement) this.indicatorElement.hide();
	},

	changeImg : function(by,to)
	{
		if (this.src) this.src = this.src.replace(by,to);
	},
	toggleImg : function(by, to)
	{
		if (RagExp(by).test(this.src))
			this.changeImg(by, to);
		else
			this.changeImg(to, by);
	},

	show : function(opacity)
	{
		this.style.display = 'block';
		var opacity = opacity || 100;
		try {
			this.style.opacity = op/100;
			this.style.filter = "alpha(opacity="+op+")";
		} catch(e) {};
	},
	hide : function()
	{
		this.style.display = 'none';
	},
	toggleDisplay : function()
	{
		this.style.display = this.css('display') != 'none' ? 'none' : '';
	},

	changeClass : function(by, to)
	{
		if(!this.hasClass(to)) this.className = this.className.replace(RegExp('(?:^| )'+by+'(?= |$)'),' '+to+' ');
	},
	hasClass : function(c)
	{
		return RegExp('(?:^| )'+c+'(?= |$)').test(this.className);
	},
	setClass : function(c)
	{
		this.className = c;
	},
	addClass : function(c)
	{
		if(!this.hasClass(c)) this.className = this.className.trim() + ' ' + c;
	},
	removeClass : function(c)
	{
		this.className = this.className.remove(RegExp('(?:^| )'+c+'(?= |$)'));
	},
	toggleClass : function(by, to)
	{
		if (this.hasClass(by))
			this.changeClass(by, to);
		else
			this.changeClass(to, by);
	},

	// style 컨트롤
	css : function(name)
	{
		if (/^\w+$/i.test(name)) {
			var S = name.camelize();
			return this.style[S] || this.currentStyle ? this.currentStyle[S] : document.defaultView.getComputedStyle(this,null).getPropertyValue(s) || '';
		} else {
			for (var i=0; arguments[i]; i++) {
				var styles = arguments[i].split(':') || [];
				this.style[ styles[0].camelize() ] = $S(styles[1]).trim();
			}
		}
	},

	// position 컨트롤
	setPosition : function(x, y)
	{
		var objOffset = this.getPosition();
		if ($S(x)) this.style.left = x - (objOffset.x - this.offsetLeft) + 'px';
		if ($S(y)) this.style.top = y - (objOffset.y- this.offsetTop) + 'px';
	},
	getPosition : function()
	{
		var par = this.offsetParent ? $(this.offsetParent).getPosition() : { x:0, y:0};
		return {
			x : this.offsetLeft + par.x,
			y : this.offsetTop + par.y
		}
	},

	// delete Node
	remove : function()
	{
		this.parentNode.removeChild(this);
	},

	// Node search
	prev : function(query)
	{
		for (var u=1,p=this.previousSibling, s=$getSelector(query); p; p=p.previousSibling)
			if ($elementValidation(p, s)) return $(p);

		return false;
	},
	next : function(query)
	{
		for (var u=1,p=this.nextSibling, s=$getSelector(query); p; p=p.nextSibling)
			if ($elementValidation(p, s)) return $(p);

		return false;
	},
	parent : function(query)
	{
		for (var u=1,p=this.parentNode, s=$getSelector(query); p; p=p.parentNode)
			if ($elementValidation(p, s)) return $(p);

		return false;
	},
	child : function(query)
	{
		for (var u=0,p=this.childNodes, s=$getSelector(query); p[u]; u++)
			if ($elementValidation(p[u], s)) return $(p[u]);

		return false;
	},
	find : function(query)
	{
		return $.call(this, query);
	},

	// Node append
	appendIndex : function(node, index) {
		if (this.childNodes.length > index)
			this.insertBefore(node, this.childNodes[index||0]);
		else
			this.appendChild(node);
	},
	appendPrev : function(node) {
		this.parentNode.insertBefore(node, this);
	},
	appendNext : function(node)
	{
		if( this.next())
			this.next().appendPrev(node);
		else
			this.parentNode.appendChild(node);
	},
	appendTo : function(target, index)
	{
		$(target).appendIndex(this, index);
	},

	// HTML controll
	html : function(html)
	{
		this.innerHTML = html;
	},
	clearHTML : function()
	{
		this.innerHTML = '';
	},
	shiftHTML : function(html)
	{
		this.innerHTML =  html + this.innerHTML;
	},
	addHTML : function(html)
	{
		this.innerHTML = this.innerHTML + html;
	},

	// Event 컨트롤
	addEvent : function(name, func)
	{
		// 브라우져마다 다른 wheel 캡쳐명령을 정리
		var name = name == 'wheel' ? window.attachEvent || $gecko ? 'mousewheel' : 'DOMMouseScroll' : name, obj = this;

		// addEvent 로 추가된 이벤트에서도 this로 이벤트가 일어난 element 를 참조하기 위하여
		// 해당 element의 프로퍼티에 배열객채를 만들어 이벤트액션을 저장
		if (obj['___'+name]) obj['___'+name].cut(func).push(func); else // 이미 프로퍼티가 만들어져있으면 간단히 push
		{
			obj['___'+name] = [func];
			var temp = function(e) { obj['___'+name].each(function(fn) { fn.call(obj,e) }) };
			Util.bounce(
				function() { obj.attachEvent("on"+name, temp) },
				function() { obj.addEventListener(name, temp, false) }
			)
		}
	},
	removeEvent : function(name, func)
	{
		if(this['___'+name]) this['___'+name].cut(func);
	},
	clearEvent : function(name)
	{
		if(this['___'+name]) this['___'+name].clear();
	},

	scrollTo : function(top, left, option) {
		Effect.property(this, 'scrollTop', this.scrollTop, top, option); if($Number(top) && option && option.callback) option.callback = null;
		Effect.property(this, 'scrollLeft', this.scrollLeft, left, option);
	},

	// for Input element
	val : function()
	{
		return /option/i.test(this.nodeName) ? this.selected  ? this.value.trim() : '' :
			/radio|checkbox/i.test(this.type) ? this.checked ? this.value.trim() : '' :
			this.value ? this.value.trim() : '';
	},
	check : function()
	{
		this.checked = true;
	},
	uncheck : function()
	{
		this.checked = false;
	},
	disable : function(swc)
	{
		this.disabled = swc && this.checked ? false : true;
	},
	enable : function()
	{
		this.disabled = false;
	},
	serialize : function()
	{
		var name = /option/i.test(this.nodeName) ? this.parentNode.name||this.parentNode.id : this.name||this.id;
		return this.val() && name ? name+'='+escape(this.val()) : '';
	},
	setKeycontroll : function(func)
	{
		this.addEvent('keydown', function(e) { func(new Event(e).key)  });
	},
	setEnter : function(func)
	{
		this.onkeypress = function(e) { if(new Event(e).key == 13) { func.apply(this, arguments); return false; } }
	}
};
HTMLMethods.clone = {};
for (var _m_  in HTMLMethods)
{
	HTMLMethods.clone[_m_] = $Function(HTMLMethods[_m_]) ? HTMLMethods[_m_].callback() : HTMLMethods[_m_];
	(function(cm) {
		Array.prototype[cm] = function() {
			for (var s=0,ar=[]; this[s]; s++) ar.push(this[s][cm].apply(this[s],arguments));
			return cm == 'serialize' ? ar.cleanUp().join('&') : HTMLExtender(ar.cleanUp(), HTMLMethods.clone);
		}
	})(_m_);
}

// HTMLMethods 와 마찮가지로 form element 확장되는 메서드
FORMMethods =
{
	__ : true,
	validationCatch : true,
	validationMsg : function(msg) { alert(msg) },
	validation : function()
	{
		if (!this._submit) this._submit = this.submit;

		for (var i=0, result; arguments[i]; i++)
		{
			var input = this[arguments[i][0]]
			var value = $F(arguments[i][0]);
			var func = arguments[i][1]
			var msg = arguments[i][2]

			result = func == null ? value:
				       $Function(func) ? func(value) :
				       $RagExp(func)  ? func.test(value) :
				       func == value;

			this.submit = result ? this._submit : Function();
			if (!result && msg) this.validationMsg(msg);
			if (!result && this.validationCatch) return input.select ? input.select() : false;
		}

		return result;
	},

	serialize : function()
	{
		var result = [], names = $A(arguments);

		if (!names.length)
			{ for (var n=0; this[n]; n++) result.push( $F(this[n]).serialize() ) }
		else
			{ for (var i=0; names[i]; i++) result.push($F(this[names[i]]).serialize()) };

		return "?" + result.cleanUp(1).join('&');

	}
};

// Effect creator
var Effect =
{
	calculation : function(o) {
		return (o.elastic ? 1.7+o.speed/10 : o.speed)*(o.start-o.end)+o.elastic*(o.prev-o.end)+o.end;
	},

	// option check
	option : function(op) {
		return {
			___ : op.___,
			speed : isNot(op.speed) ? 0 : op.speed,
			elastic : isNot(op.elastic) ?  0 : op.elastic,
			callback : op.callback
		}
	},

	// create auto loop
	action : function(obj, name, start, end, op, func) {

		if (isNot(start)||isNot(end)||(start==end)) return;
		var timer = '__timer__'+name, data = '__data__'+name;

		op.stop = 0;
		op.start = start;
		op.end = end;
		op.prev = obj[data] ? obj[data] : op.start;
		op.speed = op.speed ? 1 - ((op.elastic ? op.speed - op.elastic*1.3 : op.speed) ||100).range(-99, 99)/300 : 0;
		op.elastic = op.speed && op.elastic ? -0.80 - (op.elastic||0).range(0, 99)/700 : 0;

		clearInterval(obj[timer]);
		obj[timer] = setInterval(function() {
			op.temp = op.start;
			try { func(obj, name, op.start = Effect.calculation(op)) } catch(e) { };
			op.prev = obj[data] = op.temp;

			if (op.start.end(op.end, 0.5) == op.end) op.stop++;
			if (op.stop > 4)
			{
				clearInterval(obj[timer]);
				func(obj, name, op.end);
				if (op.callback) op.callback.apply(obj);
				if (op.___) op.___.apply(obj);
			};
		}, 13);

	},

	style : function(obj, name, start, end, op) {
		this.action(obj, name, start, end, this.option(op||{}), function(o, p, r) { o.style[p.camelize()] = r+'px' });
	},
	property : function(obj, name, start, end, op) {
		this.action(obj, name, start, end, this.option(op||{}), function(o, p, r) { o[p] = r });
	},
	method : function(obj, name, start, end, op) {
		this.action(obj, name, start, end, this.option(op||{}), function(o, p, r) { o[p](r) });
	}
};

// Flash Class
Flash = Class.create
({
	install : function(f, w, h, vars, wmode)
	{
		this.__name = '__FlashObj'+Util.count();
		this.file = f || '';
		this.width = w || '';
		this.height = h || '';
		this.wmode = wmode || 'transparent';
		this.param = vars || null;
	},
	create : function()
	{
		var code = ['<object width="'+this.width+'" height="'+this.height+'" id="'+this.__name+'" name="'+this.__name+'" ',
			document.all ? 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+$http+'fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0" align="middle"><param name="movie" value="'+this.file+'" />' : 'object type="application/x-shockwave-flash" data="'+this.file+'">',
			'<param name="allowScriptAccess" value="always" />',
			'<param name="quality" value="high" />',
			'<param name="wmode" value="'+this.wmode+'">',
			'<param name="showMenu" value="false">',
			'<param name="Menu" value="false">',
			'<param name="flashVars" value="'+this.param+'">',
			this.replace || '',
			'</object>'].join('');

		return code;
	},
	remove : function()
	{
		if (this.object)
		{
			this.object.parentNode.removeChild(this.object);
			this.object = null;
		}
	},
	write : function(target)
	{
		if (this.object) this.remove();
		if (target)
			$(target).innerHTML = this.create();
		else
			document.write(this.create());

		this.object = window[this.__name] = window.document[this.___name] || document.getElementById(this.__name);
	}
});

// Skin Class
Skin = Class.create
({
	install : function(txt)
	{
		this.template = txt || ''; // 인스턴스시에도 템플릿 설정을 할 수 있도록
		this.code = '';
	},

	create : function(data, html)
	{
		var value, subcode, toggleName;
		var canvas = (html || this.template).replace(/([^\[])%([^\]])/gm,'$1&#37;$2');

		// 스킨치환
		for(var t in data)
		{
			if ($Array(data[t]))
			{
				value = RegExp('\\[@'+t+'\\](.+)\\['+t+'@\\]');
				subcode = value.exec(this.template) || [];

				for (var i=0, trans=''; subcode[1] && data[t][i]; i++)
					trans += this.create(data[t][i], subcode[1]);

				canvas = canvas.replace(value , trans);
			}
			else if (data[t])
			{
				value = RegExp('\\[#'+t+'#\]','g');
				canvas =  canvas.replace(value , $S(data[t]).replace(/([^\[])%([^\]])/gm,'$1&#37;$2'));
			}
		}

		// 간이스킨 toggle
		while (/\[%[^\]]*\]/.test(canvas))
		{
			toggleName = /\[%([^\]]*)\]/.exec(canvas) || [];
			canvas = data[toggleName[1]] ?
				canvas.replace(RegExp('\\[%'+toggleName[1]+'\\]'),'').replace($R('\\['+toggleName[1]+'%\\]'), '') :
				canvas.replace(RegExp('\\[%'+toggleName[1]+'[^%]+'+toggleName[1]+'%\\]'), '');
		}

		// 사용되지 않은 치환자를 제거
		return this.code = unescape(canvas.remove(/\[#[^#]+#\]|\[@.+@\]/ig));
	},

	write : function(target)
	{
		if (target)
			$(target).innerHTML = this.code;
		else
			document.write(this.code);
	}
});

// Ajax Class
Ajax = Class.create
({
	install : function(m,u,p,c)
	{
		// 기본 프로퍼티 설정
		this.onFailed = function(code, msg) { alert('\n'+Ntreev.setting.info+'\n\nAjax status error : '+code+' / '+msg+'\n') };
		this.onReady = this.onComplete = null;
		this.responseType = 'auto';
		this.cacheObject = {};
		this.cache = false;
		this.onSuccess = c || null;
		this.url = u || '';
		this.param = p || '';

		// 다중 예외처리기를이용한 브라우져별 xmlHttp 객채 생성
		this.XHR = Util.bounce(
			'new XMLHttpRequest()',
			'new ActiveXObject("Msxml2.XMLHTTP")',
			'new ActiveXObject("Microsoft.XMLHTTP")'
		)

		// 간편실행을 위한 요소가 준비되어있을경우 바로 콜 요청을 실시
		if (m,u,c) this[m]();
	},
	request : function(obj, method, sync)
	{
		// 필수 요소 검사
		if ( !obj.onSuccess || !obj.url )
			return alert('Ajax 요청에 필요한 필수항목 ( url, onSuccess ) 을 확인해주세요');

		// 캐쉬컨트롤
		var cacheName = (obj.url+obj.param+obj.responseType).remove(/\W/g);
		if (obj.cache && obj.cacheObject[cacheName])
				return obj.onSuccess(obj.cacheObject[cacheName]);

		// onReady 함수가 정의되어있으면 실행
		if ( obj.onReady ) obj.onReady();

		// sync 값으로 비동기, 동기 선택
		obj.XHR.open(method, obj.url, sync || true);
		obj.XHR.onreadystatechange = function()
		{
			if ( obj.XHR.readyState == 4 )
			{
				if ( obj.onComplete ) obj.onComplete();
				if ( obj.XHR.status == 200 || obj.XHR.status == 304 )
				{
					obj.onSuccess(obj.cacheObject[cacheName] = obj.setResponse(obj.XHR));
				}
				else
				{
					obj.cacheObject[cacheName] = false;;
					obj.onFailed(obj.XHR.status, obj.XHR.status.statussText); // 응답오류시 Failed 함수로 xmlHttp 객채를 넘기면서 호출
				}
			}
		}
		obj.XHR.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
		obj.XHR.setRequestHeader("Cache-Control", "no-store, no-cache, must-revalidate");
		obj.XHR.setRequestHeader("Pragma", "no-cache");
		obj.XHR.send(obj.param);
	},

	post : function(sync)
	{
		// url 에 param 문이 있을경우를 대비하여 분리
		this.param = this.param || this.url.remove(/^.*\?/) || '';
		this.url = this.url.remove(/\?.*$/);
		this.request(this, 'POST', sync);
	},

	get : function(sync)
	{
		// param을 별도로 입력하였을경우 자동 병합
		// 몇몇 브라우져는 get 요청시 파라메타값이 null 이여야만 하는 경우를 대비하여 null 값 처리
		this.url = this.url + (this.param ? '?'+this.param.remove(/^\?/) : '');
		this.param = null;
		this.request(this, 'GET', sync);
	},

	// xmlHttp 객채의 response data type 을 판단하는 함수
	setResponse : function(obj)
	{
		var type = this.responseType;
		return Util.bounce(
			function() { return /xml|auto/i.test(type) ? obj.responseXML.documentElement : false },
			function() { return /json|auto/i.test(type) ? eval('this.temp = '+obj.responseText.remove(/^\t+|^\s|\n|\r|\s$/mg,/,(?=\})/mg,/,(?=\])/mg)) : false },
			function() { return /text|auto/i.test(type) ? obj.responseText : A },
			function() { return obj }
		);
	}
});

// Event object sync
Event = function(e)
{
	var evt = e ? e : window.event;
	if (this.__event == evt) return this.__event;

	evt.element = $(evt.target || evt.srcElement);
	try { evt.keyCode = evt.keyCode || evt.which;} catch(e) { };
	evt.pointerX = evt.clientX + $().scrollLeft;
	evt.pointerY = evt.clientY + $().scrollTop;

	var wheelData = evt.wheelDelta || evt.detail;
	if ($firefox || $opera) wheelData -= wheelData;
	evt.wheel = wheelData > 1 ? -20 : wheelData < 1 ? 20 : 0;

	evt.isKey = function(code) {
	    try {
		    return evt.keyCode == code;
		} catch(e) {
		    return false;
		}
	}

	evt.isLeft = (evt.button == 0) || (evt.which == 1 && !evt.metaKey);

	evt.cancle = function() {
		if (window.event)
			window.event.cancelBubble = true;
		else
			evt.stopPropagation();
	}

	return this.__event = evt;
};


// IE6 플리커버그 패치
try { document.execCommand("BackgroundImageCache",false,true) } catch (e) {};

// hideFocus for IE ( T_T )
document.onfocusin = function(e) {
    Event(e).element.hideFocus = true;
}