(function() {
    var m = document.uniqueID /*IE*/
    && document.compatMode /*>=IE6*/
    && !window.XMLHttpRequest /*<=IE6*/
    && document.execCommand ;

    try{
        if(!!m){
            m("BackgroundImageCache", false, true) /* = IE6 only */
        }
    }catch(oh){};
});

var trans = function() {
	var args = $A( arguments );
	var msgCategory = args.shift();
	var msgID = args.shift();
	if( !msgCategory || !msgID ) return '';

	var msgDic = _LANG_MESSAGE_FRONT[ msgCategory ];
	if( !msgDic ) return '';

	var msg = msgDic[ msgID ] || '';
	if( msg.indexOf( '#{' ) == -1 ) return msg;

	for( var i = 0 , len = args.size() , eData = {} ; i < len ; i++ ) eData[ 'ARG_' + ( i +1 ) ] = args[ i ];

	return ( new Template( msg ).evaluate( eData ) );
};

var getSetting = function( settingID ) {
	return _LANG_SETTINGS[ settingID ] || null;
}

var regExp_email = /^[a-zA-Z\-\_\d][\w\.-]*[a-zA-Z0-9\-\_]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/;
var regExp_domain = /^[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/;
var regExp_name = /^[^\'\"\/\\]+$/;
var regExp_phone = /^[\d\-]*$/;

var globalData = {
	get : function( type , callback ) {
		if( type == 'callbacks' ) { throw 'NOT USE callbacks'; return; }
		if( typeof( globalData.callbacks ) != 'object' ) {
			globalData.callbacks = {};
		}
		globalData.callbacks[ type ] = callback;
	}
	, set : function( type , data ) {
		if( type == 'callbacks' ) { throw 'NOT USE callbacks'; return; }

		globalData[ type ] = data;

		if( typeof( globalData.callbacks ) != 'object' ) {
			globalData.callbacks = {};
		}

		if( typeof( globalData.callbacks[ type ] ) == 'function' ) {
			globalData.callbacks[ type ]( globalData[ type ] );
		}
	}
};

// auto resizable textarea
var textareaResizer = Class.create( {
	'initialize' : function( id , limit ) {
		this.element = $( id );
		this.prevHeight = null;
		this.lineHeight = 17;
		this.limit = limit;
		if( !this.element ) return;

		this.element.observe( 'click' , this.checkIt.bindAsEventListener( this ) );
		this.element.observe( 'propertychange' , this.checkIt.bindAsEventListener( this ) );
		this.element.observe( 'input' , this.checkIt.bindAsEventListener( this ) );
		this.element.observe( 'paste' , this.checkIt.bindAsEventListener( this ) );
		this.element.observe( 'keyup' , this.checkIt.bindAsEventListener( this ) );

		this.checkIt();

		return this.element;
	}
	, 'checkIt' : function( ev ) {
		if( ev && this.eventCaptured ) {
			Event.stop( ev );
			return;
		}
		this.eventCaptured = true

		var scrH = this.element.scrollHeight;

		if( !this.prevHeight ) this.prevHeight = scrH;
		/*if( !this.lineHeight ) this.lineHeight = scrH||this.element.offsetHeight;
		if( !this.lineHeight ) {
			this.eventCaptured = false;
			return;
		}*/

		if( scrH > ( this.lineHeight * this.limit ) ) {
			this.element.style.overflowY = 'auto';
			this.element.style.height = ( this.lineHeight * this.limit ) + 'px';
			this.eventCaptured = false;
			return;
		}
		else {
			this.element.style.height = null;
			scrH = ( this.element.scrollHeight || this.lineHeight );
			this.element.style.height = scrH + 'px';
			this.element.style.overflowY = 'hidden';
		}
		if( this.prevHeight == scrH ) {
			this.eventCaptured = false;
			return;
		}

		this.element.style.height = ( scrH || this.lineHeight ) + 'px';
		this.prevHeight = scrH;

		this.eventCaptured = false;
		return;
	}
} );

// auto complete input expand class
Ajax.AutocompleterTo = Class.create( Ajax.Autocompleter , {
	'onObserverEvent' : function( $super ) {
		this.changed = false;
		this.tokenBounds = null;
		if (this.getToken().length >= this.options.minChars && !this.disabled ) {
			this.getUpdatedChoices();
		} else {
			  this.active = false;
			  this.hide();
		}
		this.oldElementValue = this.element.value;

		var img = $("mainMenuFileOpen").down( 'img' );
		var isOpened = !( img.src.indexOf( 'minus' ) == -1 );
		AA.isOpened = ( isOpened ) ? 'show' : 'hide';
	}
	,  selectEntry: function() {
    this.active = false;
	AA.aaActivexArea();
    this.updateElement(this.getCurrentEntry());
  }
	, updateChoices: function(choices) {
		if (!this.changed && this.hasFocus) {
			this.update.innerHTML = choices;
			Element.cleanWhitespace(this.update);
			Element.cleanWhitespace(this.update.down());

			var suObj = $('SWFUpload_0');
			if (this.update.firstChild && this.update.down().childNodes.length > 0) {
				this.entryCount =  this.update.down().childNodes.length;
				for (var i = 0; i < this.entryCount; i++) {
				  var entry = this.getEntry(i);
				  entry.autocompleteIndex = i;
				  this.addObservers(entry);
				}
				if( suObj ) suObj.hide();
				AA.aaActivexArea();
			} else {
				this.entryCount = 0;
				if( suObj ) suObj.show();
				AA.aaActivexArea();
			}
			this.stopIndicator();
			this.index = 0;

			if(this.entryCount==1 && this.options.autoSelect) {
				this.selectEntry();
				this.hide();
			} else {
				this.render();
			}
		}
	}
	, onClick: function(event) {
		var element = Event.findElement(event, 'LI');
		this.index = element.autocompleteIndex;

		if (this.index == null) {
			var li = element.up('li');
			var re_li = Element.toggleClassName(li, 'selected');
			this.index = re_li.autocompleteIndex;
		}
		this.selectEntry();
		this.hide();
		var suObj = $('SWFUpload_0');
		if( suObj ) suObj.show();
		AA.aaActivexArea();
	  }
	, onBlur: function(event) {
		// needed to make click events working
		setTimeout(this.hide.bind(this), 250);
		this.hasFocus = false;
		this.active = false;
		var suObj = $('SWFUpload_0');
		if( suObj ) suObj.show();
		AA.aaActivexArea();
	}
	, 'disable' : function() { this.disabled = true; }
	, 'enable' : function() { this.disabled = false; }
} );

Element.addMethods( {
	'toHtmlString' : function( element ) {
		if( typeof( element ) != 'object' ) return element;
		if( !element.tagName ) return element;
		if( Prototype.Browser.IE ) return element.outerHTML||element;

		var attrs = [];
		$A( element.attributes ).each( function( A ) {
			if( ( A.nodeValue === null ) || ( A.nodeValue === undefined ) || ( A.nodeValue === NaN ) || ( A.nodeValue === '' ) ) return;
			if( typeof( A.nodeValue ) == 'object' ) return;
			attrs.push( A.nodeName + '="' + A.nodeValue + '"' );
		} );
		var output = '<' + element.tagName + ( attrs.length > 0 ? ' ' + attrs.join( ' ' ) : '' );
		output +=  ( element.innerHTML === undefined ) ? ' />' : '>' + element.innerHTML + '</' + element.tagName + '>';
		return output;
	}
} );

// Ajax call에 대한 상태변화 표시
function setResponders() {
	if( !Ajax ) return;
	if( !Ajax.Responders ) return;
	if( Ajax.Responders.isSetResponders ) return;

	/*var requestDisplay = new Element( 'div' , { 'id' : 'requestDisplay' , 'name' : 'requestDisplay' , 'class' : 'requestDisplay' } ).insert( new Element( 'div' , { 'id' : 'requestDisplayText' } ) ).insert( new Element( 'div' , { 'id' : 'requestDisplayProgress' , 'class' : 'mtBlank4' } ).setStyle( { 'width' : '0px' } ).update( '<br />' ) );
	requestDisplay.hide();
	$( document.body ).insert( requestDisplay );*/

	var mEffect = null;

	Ajax.Responders.register( {
		onException : function() { throw( trans( 'error' , 'SERVICE_NOT_AVAIL' ) ); }
		, onCreate : function() {
			$( 'requestDisplay' ).show();
			if( mEffect !== null ) { mEffect.cancel(); mEffect = null; }
			$( 'requestDisplayProgress' ).setStyle( { 'width' : '50px' } );
			$( 'requestDisplayText' ).update( 'Initializing...' );
			Element.hide.delay( 2 , $( 'requestDisplay' ) );
		}
		, onLoading : function() {
			$( 'requestDisplay' ).show();
			if( mEffect !== null ) { mEffect.cancel(); mEffect = null; }
			mEffect = new Effect.Morph( 'requestDisplayProgress' , { 'duration' : 2 , 'style' : 'width:120px' } );
			$( 'requestDisplayText' ).update( 'Loading...' );
			Element.hide.delay( 2 , $( 'requestDisplay' ) );
		}
		, onLoaded : function() {
			$( 'requestDisplay' ).show();
			if( mEffect !== null ) { mEffect.cancel(); mEffect = null; }
			mEffect = new Effect.Morph( 'requestDisplayProgress' , { 'duration' : 0.5 , 'style' : 'width:130px' } );
			$( 'requestDisplayText' ).update( 'Loaded...' );
			Element.hide.delay( 2 , $( 'requestDisplay' ) );
		}
		, onInteractive : function() {
			$( 'requestDisplay' ).show();
			if( mEffect !== null ) { mEffect.cancel(); mEffect = null; }
			mEffect = new Effect.Morph( 'requestDisplayProgress' , { 'duration' : 2 , 'style' : 'width:190px' } );
			$( 'requestDisplayText' ).update( 'Receiving...' );
			Element.hide.delay( 2 , $( 'requestDisplay' ) );
		}
		, onComplete : function() {
			$( 'requestDisplayText' ).update( 'Complete.' );
			if( mEffect !== null ) { mEffect.cancel(); mEffect = null; }
			mEffect = new Effect.Morph( 'requestDisplayProgress' , { 'duration' : 0.5 , 'style' : 'width:200px' } );
			Element.hide.delay( 1 , $( 'requestDisplay' ) );
		}
	} );
	Ajax.Responders.isSetResponders = true;
}

Event.onDOMReady( setResponders );

// 처리 결과를 callback에 전달.. 만약 json response가 없으면 json화 해서 전달;
// callback은 function aaa( obj ) 형식.
// 반환값이 list이라면 obj.totalCnt = 10 , obj.dataCnt = 5 , obj.data[ 0 ] ~ [ 4 ]
function requestFront( url , reqData , callback , options ) {
	if( !url ) return;
	if( callback && ( typeof( callback ) != 'function' ) ) return;

	var reqParams = '';
	if( reqData ) {
		reqParams = ( typeof( reqData ) == 'object' ) ? $H( reqData ).toQueryString() : reqData
	}

	try {
		var options = Object.extend( {
			postBody : reqParams
			, evalJSON : false
			, onSuccess : function( transport ) {
				if( callback ) {
					try {
					var jsonData = transport.responseText.evalJSON();
					} catch( jerr ) { throw 'json error : ' + transport.responseText; }

					if( jsonData.code && ( parseInt( jsonData.code ) == 9999 ) ) {
						location.replace( '/intro.php' );
						return;
					}

					if( jsonData.code && ( parseInt( jsonData.code ) == 2001 ) ) {
						throw jsonData;
						return;
					}
					if( jsonData.code && ( parseInt( jsonData.code ) == 2002 ) ) {
						throw jsonData;
						return;
					}
					callback( jsonData );

					/*if( transport.responseJSON ) {
						if( transport.responseJSON.code && ( parseInt( transport.responseJSON.code ) == 2001 ) ) {
							throw transport.responseJSON;
							return;
						}
						if( transport.responseJSON.code && ( parseInt( transport.responseJSON.code ) == 2002 ) ) {
							throw transport.responseJSON;
							return;
						}
						callback( transport.responseJSON );
					}
					else {
						var jsonData = transport.responseText.evalJSON( true );
						if( jsonData.code && ( parseInt( jsonData.code ) == 2001 ) ) {
							throw jsonData;
							return;
						}
						if( jsonData.code && ( parseInt( jsonData.code ) == 2002 ) ) {
							throw jsonData;
							return;
						}
						callback( jsonData );
					}*/
				}
			}
		} , options || {} );

		var r = new Ajax.Request( url + '?tId=' + ( new Date ).getTime() , options );
	} catch( e ) {
		throw e;
		return;
	}
}

function onlyNumber( ev ) {
	ev = Event.extend( ev );
	var target = Event.element( ev );
	var isIE = window.attachEvent ? true : false;
	var code = ( ev.charCode ? ev.charCode : ( isIE ? ev.keyCode : ev.which ) );

	if( ( ( code > 47 ) && ( code < 58 ) ) || ( isIE && ( code > 95 ) && ( code < 106 ) ) ) {
	}
	else {
		if( code == 8 ) return;
		if( code == 9 ) return;
		if( code == 46 ) return;
		Event.stop( ev );
	}
}

function alertAndFocus( msg , obj ) {
	if( obj && obj.focus && ( typeof( obj.focus ) == 'function' ) ) {
		obj.focus();
	}
	if( msg ) wmAlert( msg );

	return;
}

// 주소 찾기
Event.onDOMReady( function() {
	if( $( 'addressSearch' ) && getSetting( 'usePostSearch' ) ) {
		$( 'addressSearch' ).up().insert( new Element( 'div' , { 'id' : 'zipList' ,'class' : 'zipList' } ).setStyle( { 'zIndex' : 200 } ) );
		new Ajax.Autocompleter( 'addressSearch' , 'zipList' , '/common/zipcode_data.php' , {
			paramName : 'zipSearch'
			, minChars : 2
			, frequency : 0.5
			, updateElement : function( selected ) {
				var ipt = $( 'addressSearch' );
				ipt.value = selected.innerHTML;
				ipt.focus();

				var code = selected.readAttribute( 'code' );
				if( !code ) return;
				if( $( 'zipcode1' ) ) $( 'zipcode1' ).value = code.substring( 0 , 3 );
				if( $( 'zipcode2' ) ) $( 'zipcode2' ).value = code.substring( 3 );
				ipt.writeAttribute( 'isSet' , ( ipt.value != ipt.title ? 'true' : 'false' ) );
			}
		} );
	}
} );

function zipSearchClick( ev ) {
	if( !getSetting( 'usePostSearch' ) ) return;

	var src = Event.element( ev );
	if( src.value ) src.writeAttribute( '_value' , src.value );
	src.value = '';
}

function zipSearchBlur( ev ) {
	if( !getSetting( 'usePostSearch' ) ) return;

	var src = Event.element( ev );
	if( !src.value ) {
		src.value = src.readAttribute( '_value' ) || src.title;
	}
}

function centerElement( id ) {
	var target = $( id );

	var windowScroll = WindowUtilities.getWindowScroll();
	var pageSize = WindowUtilities.getPageSize();

	var top = ( pageSize.windowHeight - target.getHeight() )/2;
	top += windowScroll.top

	var left = ( pageSize.windowWidth - target.getWidth() )/2;
	left += windowScroll.left

	target.style.left = left + 'px';
	target.style.top = top + 'px';
}

function clearEditorContent( id ) {
	tinyMCE.get(id).setContent('');

	//WYSIWYG.getEditorWindow( id ).document.body.innerHTML = '';
	//WYSIWYG.updateTextArea( id );
}

function getEditorMode( id ) {
	var id = id;
	var tabs = $$( 'ul.tabMenu li.onTab' );
	if( tabs.size() < 1 ) return '';

	return tabs.find( function( T ) {
		T = $( T );

		if( T.readAttribute( 'editor' ) != id ) return false;

		return true;
	} ).readAttribute( 'mode' );
}

function setTextareaContent2Editor( id ) {
	var evalue = '';

    if( getEditorMode( id ) == 'TEXT' ) {
		evalue = text2html($( id ).value);
	}
	else {
		evalue = $( id ).value;
	}

	tinyMCE.get(id).setContent(evalue);
}

function changeTab( ev ) {
	var src = Event.element( ev );
	var ul = src.up( 'ul' );
	$A( ul.getElementsByTagName( 'li' ) ).each( function( L ) {
		L.className = L.className.gsub( /onL/ , 'offL' ).gsub( /onR/ , 'offR' ).gsub( /onTab/ , 'offTab' );
	} );

	src.className = src.className.gsub( /offTab/ , 'onTab' );
	src.previous().className = src.previous().className.gsub( /offL/ , 'onL' );
	src.next().className = src.next().className.gsub( /offR/ , 'onR' );
}


var tab_flag = 0;
function changeEditorMode( ev ) {
	var src = Event.element( ev );
	var mode = src.readAttribute( 'mode' );
	var editor = src.readAttribute( 'editor' );
    var obj = $( editor );
	obj.writeAttribute( 'modeChange' , 'modeChange' );

	if( document.formWebmail ) {
		var receiveFlag = $( document.formWebmail.receive_flag );
		var htmlFlag = $( document.formWebmail.html_flag );
	}

	if( !( mode || !editor ) ) return;

    switch( mode ) {
        case 'WYSIWYG' :
            if(tab_flag == "1") {
				txt = obj.value;
				txt = text2html(txt);
				obj.value = txt;
            }
            tinyMCE.get(editor).show();
            tab_flag = "0";
			if( receiveFlag && receiveFlag.readAttribute( 'origReceiveFlag' ) ) {
				receiveFlag.value = receiveFlag.readAttribute( 'origReceiveFlag' );
			}
			if( htmlFlag && htmlFlag.readAttribute( 'origHtmlFlag' ) ) {
				htmlFlag.value = htmlFlag.readAttribute( 'origHtmlFlag' );
			}
            break;

        case 'TEXT' :
            if(tab_flag == "2") {
	            tinyMCE.get(editor).show();
            }
            tinyMCE.get(editor).hide();
            html = obj.value;
            txt = html2text(html);
            obj.value = txt;
            tab_flag = "1";
			if( receiveFlag ) {
				if( !receiveFlag.readAttribute( 'origReceiveFlag' ) ) {
					receiveFlag.writeAttribute( { 'origReceiveFlag' : receiveFlag.value } );
				}
				if( !htmlFlag.readAttribute( 'origHtmlFlag' ) ) {
					htmlFlag.writeAttribute( { 'origHtmlFlag' : htmlFlag.value } );
				}
				receiveFlag.value = '';
				htmlFlag.value = '';
			}
            break;

        case 'HTML' :
            if(tab_flag == "1") {
				txt = obj.value;
				txt = text2html(txt);
				obj.value = txt;
				tinyMCE.get(editor).show();
            }
            tinyMCE.get(editor).hide();
            tab_flag = "2";
			if( receiveFlag && receiveFlag.readAttribute( 'origReceiveFlag' ) ) {
				receiveFlag.value = receiveFlag.readAttribute( 'origReceiveFlag' );
			}
			if( htmlFlag && htmlFlag.readAttribute( 'origHtmlFlag' ) ) {
				htmlFlag.value = htmlFlag.readAttribute( 'origHtmlFlag' );
			}
            break;
	}
	obj.removeAttribute( 'modeChange' );
}

wmAlert = function( msg , fn , w , h ) {
	var alert = new Window( {
		'maximizable' : false
		, 'resizable' : false
		, 'width' : ( w ? w : 400 )
		, 'height' : ( h ? h : 100 )
		, 'showEffectOptions' : { 'duration' : 0.1 }
		, 'hideEffectOptions' : { 'duration' : 0.1 }
		, 'destroyOnClose' : true
	} );

	var container = new Element( 'div' ).setStyle( { 'margin' : '10px' , 'marginTop' : '40px' , 'marginBottom' : '20px' , 'padding' : '0px' , 'textAlign' : 'center' } );
	alert.setContent( container );

	container.insert( new Element( 'span' ).update( msg ) );
	container.insert( new Element( 'br' ) ).insert( new Element( 'br' ) );
	container.insert( new Element( 'span' , { 'id' : 'alertOk' , 'class' : 'btnContainer style6' } ).insert( new Element( 'button' , { 'hidefocus' : 'hidefocus' } ).observe( 'click' , function( bEvt ) { alert.close(); if( typeof( fn ) == 'function' ) fn(); } ).update( trans( 'common' , 'ok' ) ) ) );

	alert.showCenter( true );
};

wmConfirm = function( msg , ycb , ncb ) {
	var confirm = new Window( {
		'maximizable' : false
		, 'resizable' : false
		, 'width' : 400
		, 'height' : 100
		, 'showEffectOptions' : { 'duration' : 0.1 }
		, 'hideEffectOptions' : { 'duration' : 0.1 }
		, 'destroyOnClose' : true
	} );

	window.confirmed = -1;

	var container = new Element( 'div' ).setStyle( { 'margin' : '10px' , 'marginTop' : '40px' , 'marginBottom' : '20px' , 'padding' : '0px' , 'textAlign' : 'center' } );
	confirm.setContent( container );

	container.insert( new Element( 'span' ).update( msg ) );
	container.insert( new Element( 'br' ) ).insert( new Element( 'br' ) );
	container.insert( new Element( 'span' , { 'id' : 'confirmYes' , 'class' : 'btnContainer style6' } ).insert( new Element( 'button' , { 'hidefocus' : 'hidefocus' } ).observe( 'click' , function( bEvt ) {
		Event.stop( bEvt );
		if( typeof( ycb ) == 'function' ) ycb();
		confirm.close();
	} ).update( trans( 'common' , 'yes' ) ) ) );
	container.insert( new Element( 'span' , { 'id' : 'confirmNo' , 'class' : 'btnContainer style6 mlBlank10' } ).insert( new Element( 'button' , { 'hidefocus' : 'hidefocus' } ).observe( 'click' , function( bEvt ) {
		Event.stop( bEvt );
		if( typeof( ncb ) == 'function' ) ncb();
		confirm.close();
	} ).update( trans( 'common' , 'no' ) ) ) );

	confirm.showCenter( true );
};


function selectOutlookItem( ev ) {
	var src = Event.element( ev );

	var A = null , R = null;
	switch( src.tagName.toUpperCase() ) {
		case 'A' : A = src; R = src.down( '.selector' ); break;
		case 'INPUT' : A = src.up( '.linker' ); R = src; break;
		case 'LABEL' : A = src.up( '.linker' ); R = src.previous( '.selector' ); break;
		case 'IMG' : A = src.up( '.linker' ); R = src.up().previous( '.selector' ); break;
		default : A = src.up( '.linker' ); R = src.down( '.selector' ); break;
	}

	$$( '.outlookSelectContainer a' ).each( function( S ) { $( S ).removeClassName( 'selected' ).down( '.selector' ).checked = false; } );
	A.addClassName( 'selected' );
	R.checked = 'checked';
}

function movePage( ev ) {
	var url = location.href.gsub( /&?pageNo=[\d]+/ , '' );
	var pageNo = Event.element( ev ).readAttribute( 'linkpage' );
	if( parseInt( pageNo ) < 1 ) return;
	location.href = url + ( url.indexOf( '?' ) == -1 ? '?' : '' ) + '&pageNo=' + pageNo;
}

function checkAll( ev ) {
	$A( document.getElementsByName( 'listCheck' ) ).each( function( C ) {
		$( C ).checked = Event.element( ev ).checked;
	} );
}

function getSelected() {
	return $A( document.getElementsByName( 'listCheck' ) ).findAll( function( C ) { return C.checked; } ).compact();
};

function centerObject( obj ) {
	if( typeof( obj ) == 'string' ) {
		if( !$( obj ) ) return;
		obj = $( obj );
	}
	if( typeof( obj ) != 'object' ) return;
	if( !obj.style || ( obj.offsetHeight === undefined ) || ( obj.offsetWidth === undefined ) ) return;

	var windowScroll = WindowUtilities.getWindowScroll( document.body );
	var pageSize = WindowUtilities.getPageSize( document.body );

	var top = ( pageSize.windowHeight - obj.offsetHeight ) /2;
	top += windowScroll.top;

	var left = ( pageSize.windowWidth - obj.offsetWidth ) /2;
	left += windowScroll.left;

	obj.style.left = left + 'px';
	obj.style.top = top + 'px';
}

function getMboxNameFromMbox( mbox , mbox_name ) {
	switch( mbox ) {
		case 'INBOX' :
		case 'Me' :
		case 'nSent' :
		case 'Drafts' :
		case 'Spam' :
		case 'Trash' :
			return trans( 'mbox' , mbox );
		default :
			return mbox_name;
	}
}

//---------------------------------------------------------------------------------
//		자바스크립트 md5
//---------------------------------------------------------------------------------
/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length
 */
function core_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);

}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Calculate the HMAC-MD5, of a key and some data
 */
function core_hmac_md5(key, data)
{
  var bkey = str2binl(key);
  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
  return core_md5(opad.concat(hash), 512 + 128);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert a string to an array of little-endian words
 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
 */
function str2binl(str)
{
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
  return bin;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2str(bin)
{
  var str = "";
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < bin.length * 32; i += chrsz)
    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
  return str;
}

/*
 * Convert an array of little-endian words to a hex string.
 */
function binl2hex(binarray)
{
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
  }
  return str;
}

/*
 * Convert an array of little-endian words to a base-64 string
 */
function binl2b64(binarray)
{
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i += 3)
  {
    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
    }
  }
  return str;
}

/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info/
*
**/

var Base64 = {

    // private property
    _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

    // public method for encoding
    encode : function (input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;

        input = Base64._utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output +
            this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
            this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

        }

        return output;
    },

    // public method for decoding
    decode : function (input) {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        while (i < input.length) {

            enc1 = this._keyStr.indexOf(input.charAt(i++));
            enc2 = this._keyStr.indexOf(input.charAt(i++));
            enc3 = this._keyStr.indexOf(input.charAt(i++));
            enc4 = this._keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }

        }

        output = Base64._utf8_decode(output);

        return output;

    },

    // private method for UTF-8 encoding
    _utf8_encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },

    // private method for UTF-8 decoding
    _utf8_decode : function (utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;

        while ( i < utftext.length ) {

            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        }

        return string;
    }

}

/**
 * 새 창
 * @param array params
 * @example
 * var winParams = {
 *      url: 'about:blank',
 *      name: 'win',
 *      width: 800,
 *      height: 600,
 *      option: 'status=no'
 * };
 * openWin(winParams);
 */
function openWin(params) {
    var url = params.url ? params.url : null;
    var name = params.name ? params.name : '';
    var width = params.width ? parseInt(params.width) : 0;
    var height = params.height ? parseInt(params.height) : 0;
    var option = params.option ? params.option : 'scrollbars=no,status=no,left=0,top=0';

    if( !url ) return;

    if(width > 0) {
        //width += (document.all) ? 0 : 14;
        option += ',width='+width;
    }
    if(height > 0) {
        height += (document.all) ? 0 : 40;
        option += ',height='+height;
    }

    var popup = window.open(url, name, option);
    popup.focus();
}

/*
 * 텍스트를 html형태로 변환
 */
function text2html(text) {
	if( !text ) return '';
	return text.gsub( /(.*)\r?\n|$/ , function( M ) {
		return '<p>' + ( M[ 1 ] || '' ) + '</p>';
	} ) || text;

    /*mce_code = text;
    mce_code = mce_code.replace(new RegExp("\n", "gi"), "<br />");
    mce_code = mce_code.replace(new RegExp("<br /><TBODY", "gi"), "<TBODY");
    mce_code = mce_code.replace(new RegExp("<br /></TBODY", "gi"), "</TBODY");
    mce_code = mce_code.replace(new RegExp("<br /><TR", "gi"), "<TR");
    mce_code = mce_code.replace(new RegExp("<br /></TR", "gi"), "</TR");
    mce_code = mce_code.replace(new RegExp("<br /><TD", "gi"), "<TD");
    mce_code = mce_code.replace(new RegExp("<br /></TD", "gi"), "</TD");
    return mce_code;*/
}

/*
 * html을 텍스트 형태로 변환
 */
function html2text(html) {
	if( !html ) return '';
	var returnValue = html.gsub(
		/<p>(.*)<\/p>\r?\n?/
		, function( M ) { return M[ 1 ] + "\n"; }
	).gsub(
		/<br\s?\/?>\r?\n?/
		, "\n"
	).gsub(
		/&nbsp;/
		, ' '
	) || html;
	return returnValue.stripTags();

    /*
    mce_code = html;
    mce_code = mce_code.replace(new RegExp("<P>&nbsp;</P>", "gi"), "<br />");
    mce_code = mce_code.replace(new RegExp("<P>", "gi"), "");
    mce_code = mce_code.replace(new RegExp("</P>", "gi"), "<br />");
    mce_code = mce_code.replace(new RegExp("<br>", "gi"), "<br />");
    mce_code = mce_code.replace(new RegExp("<br />", "gi"), "\n");
    mce_code = mce_code.replace(new RegExp("<br>", "gi"), "\n");
    mce_code = mce_code.replace(new RegExp("\n\r", "gi"), "");
    return mce_code;
    */
}

/*
 * tinymce 에디터 설정
 */


 if(_LANG == 'jp') {
    _LANG = 'ja';
 } else if(_LANG == 'chGb') {
    _LANG = 'zh';
 } else if(_LANG == 'chBig') {
    _LANG = 'hr';
 }

 var editorSet =
    {
        // General options
        mode : "textareas",
        theme : "advanced",
        language : _LANG,
        //plugins : "safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template,inlinepopups",
		plugins : "safari,table,advimage,advlink,contextmenu,paste,nonbreaking,xhtmlxtras,inlinepopups",
        // Theme options
        theme_advanced_buttons1 : "fontselect,fontsizeselect,|,forecolor,backcolor,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,outdent,indent,|,link,unlink,image,tablecontrols",
        theme_advanced_buttons2 : "",
        theme_advanced_buttons3 : "",
        theme_advanced_toolbar_location : "top",
        theme_advanced_toolbar_align : "left",
        //theme_advanced_statusbar_location : "bottom",
        //theme_advanced_resizing : true,

        theme_advanced_fonts : getSetting( 'editorFonts' ).gsub(/'/,''),
        theme_advanced_font_sizes : "8pt=8pt,9pt=9pt,10pt=10pt,11pt=11pt,12pt=12pt,14pt=14pt,18pt=18pt,24pt=24pt,36pt=36pt",

        relative_urls : false,
        remove_script_host : false,
        forced_root_block : false,
        //force_br_newlines : true,
        //force_p_newlines : false,

        //extended_valid_elements : "*[*]",
        extended_valid_elements : "link[rel|href|type],iframe[style|src|frameborder],param[name|value],embed[src|quality|bgcolor|width|height|name|align|allowScriptAccess|type|pluginspage],style[type]",

        // Example word content CSS (should be your site CSS) this one removes paragraph margins
        //content_css : "/css/front.css",
        content_css : "/editor/tinymce/examples/css/content.css",
		save_callback  : "beforeSaveEditor",
        // Replace values for the template plugin
        template_replace_values : {
            username : "Some User",
            staffid : "991234"
        }
    };

function beforeSaveEditor(element_id, html, body) {
	if( $( element_id ).readAttribute( 'modeChange' ) == 'modeChange' ) return html;
	if( getEditorMode( element_id ) != 'WYSIWYG' ) return html;

	return '<style>p {margin:3px 0px 2px 0px;}</style>' + html;
}

// --------------Language Setting
function languageSet ( language, url ) {
	var now_language = _LANG;
	var sendData = {};
	sendData[ 'sent_savelanguage' ] = language;
	sendData[ 'now_language' ] = now_language;

	if ( now_language !=  sendData[ 'sent_savelanguage' ]) {
		requestFront( '/api/webmail/0.2/FrontSetLanguage.php' , sendData , function( resultData ) {
			if ( resultData.data.language_result ) {
				document.location.href = url;
			}
		} );
	}
}


// progress popup layer
var PopupProgress = Class.create( {
	'defaultOptions' : { 'styles' : { 'width' : '320px' , 'height' : '62px' , 'zIndex' : 2500 , 'float' : 'left' , 'position' : 'absolute' } , 'prefix' : 'progress' , 'start' : true , 'end' : true , 'endCallback' : Prototype.emptyFunction }
	, 'id' : ''
	, 'element' : null
	, 'graph' : null
	, 'percent' : null
	, 'initialize' : function( options ) {
		this.options = $H( this.defaultOptions ).update( options ).toObject();
		this.id = this.options.prefix + new Date().getTime();
		if( this.options.start ) this.start();
	}
	, 'getId' : function() { return this.id || '' }
	, 'start' : function() {
		var progressHtml = '';
		progressHtml += '<table class="roundBox w100p h100p"><tbody><tr><td class="tl"><br/></td><td class="t"><br/></td><td class="tr"><br/></td></tr>';
		progressHtml += '<tr><td class="l"><br/></td><td class="c" style="background-color:#FFFFFF;">';
		progressHtml += '<div class="progress">';
		progressHtml += '<div class="graphContainer">';
		progressHtml += '<span class="graphBg">';
		progressHtml += '<table width="1%" class="graph" id="' + this.id + '_graph">';
		progressHtml += '<tbody>';
		progressHtml += '<tr>';
		progressHtml += '<td class="start"><br/></td>';
		progressHtml += '<td><br/></td>';
		progressHtml += '<td class="end"><div class="baloon"><span id="' + this.id + '_percent"></span></div></td>';
		progressHtml += '</tr>';
		progressHtml += '</tbody>';
		progressHtml += '</table>';
		progressHtml += '</span>';
		progressHtml += '</div>';
		progressHtml += '<table class="indicator">';
		progressHtml += '<tbody><tr>';
		progressHtml += '<td class="start"><br/></td>';
		progressHtml += '<td class="mid"><br/></td>';
		progressHtml += '<td class="end"><br/></td>';
		progressHtml += '</tr>';
		progressHtml += '</tbody></table>';
		progressHtml += '</div>';
		progressHtml += '</td><td class="r"><br/></td></tr>';
		progressHtml += '<tr><td class="bl"><br/></td><td class="b"><br/></td><td class="br"><br/></td></tr></tbody></table>';

		this.element = new Element( 'div' , { 'id' : this.id } ).setStyle( this.options.styles ).update( progressHtml );

		$( document.body ).insert( this.element );

		centerElement( this.id );

		this.graph = $( this.id + '_graph' );
		this.percent = $( this.id + '_percent' )
	}
	, 'update' : function( percent ) {
		if( percent == undefined ) return;
		var percent = parseInt( percent );
		if( percent > 100 ) percent = 100;
		if( percent < 1 ) percent = 0;
		var graphPercent = percent;

		if( graphPercent <= 0 ) graphPercent = 1;
		else if( graphPercent >= 100 ) graphPercent = 99;

		var inst = this;

		this.graph.morph( 'width:' + graphPercent + '%' , {
			duration : 1
			, afterUpdate : function( obj ) {
				var p = parseInt( obj.element.getStyle( 'width' ).replace( '%' , '' ) );
				inst.percent.update( p + '%' );
			}
			, afterFinish : function( obj ) {
				inst.percent.update( percent + '%' );
				if( inst.options.end && ( percent >= 100 ) ) inst.end.bind( inst ).delay( 0.5 );
			}
		} );
	}
	, 'end' : function() {
		$( this.element ).remove();

		if( this.options.endCallback ) this.options.endCallback();

		this.element = null;
		this.options = this.defaultOptions;
		this.id = '';
	}
} );

var TipWindow = Class.create( {
	'defaultOptions' : {
		'styles' : {
			'position' : 'absolute'
			, 'float' : 'left'
			, 'zIndex' : 3000
			, 'backgroundColor' : 'transparent'
			, 'border' : 'none'
		}
		, 'idPrefix' : 'TipWindow'
	}
	, 'id' : ''
	, 'content' : null
	, 'window' : null
	, 'element' : null
	, 'opened' : false
	, 'initialize' : function( contId , options ) {
		this.options = $H( this.defaultOptions ).update( options ).toObject();
		this.id = this.options.idPrefix + '_' + contId;
		this.content = $( contId );
	}
	, 'toggle' : function( ev , relativePosition ) {
		if( this.opened ) {
			return this.close();
		}
		else {
			return this.open( ev , relativePosition );
		}
	}
	, 'open' : function( ev , relativePosition ) {
		this.element = Event.element( ev );
		this.element.writeAttribute( 'twContentId' , this.id );
		this.window = $( this.id );

		var relativePostion = relativePosition || 'BC';

		var docBody = $( document.body );
		var obj = this;
		Event.observe( window , 'resize' , function() {
			obj.setPosition( relativePosition );
		} );

		if( !this.window ) {
			this.window = new Element( 'div' , { 'id' : this.id } ).setStyle( this.options.styles );

			docBody.observe( 'click' , function( bEvt ){
				var src = Event.element( bEvt );
				var oId = obj.id;
				if( src.readAttribute( 'twContentId' ) == obj.id ) {
					if( !src.ancestors().find( function( AE ){ return ( $( AE ).readAttribute( 'twContentId' ) == oId ); } ) ) {
						return;
					}
				}
				if( bEvt.clientX < obj.window.offsetLeft ) return obj.close();
				if( bEvt.clientX > ( obj.window.offsetLeft + obj.window.offsetWidth ) ) return obj.close();
				if( bEvt.clientY < obj.window.offsetTop ) return obj.close();
				if( bEvt.clientY > ( obj.window.offsetTop + obj.window.offsetHeight ) ) return obj.close();
			} );

			docBody.insert( this.window );

			if( !this.content.getStyle( 'margin' ) ) {
				this.content.setStyle( 'margin' , '2px' );
			}
			else {
				[ 'Top' , 'Left' , 'Right' , 'Bottom' ].each( function( K ) {
					this.content.setStyle( 'margin' + K , ( parseInt( this.content.getStyle( 'margin' + K ).sub( 'px' , '' ) ) + 2 ).toString() + 'px' );
				} , this );
			}

			this.window.appendChild( this.content );
		}

		this.setPosition( relativePosition );

		this.window.show();

		this.opened = true;

		if( Prototype.Browser.IE ) this.window.focus();
	}
	, setPosition : function( relativePosition ) {
		var wDim = this.window.getDimensions();

		var position = this.element.cumulativeOffset();
		var dimension = this.element.getDimensions();

		var xPos = 0;
		var yPos = 0;

		switch( relativePosition ) {
			default :
			case 'BC' :
				xPos = ( ( position[ 0 ] + ( dimension.width /2 ) ) - ( wDim.width /2 ) ).ceil();
				yPos = ( position[ 1 ] + dimension.height + 1 ).ceil();
				break;
			case 'BL' :
				xPos = position[ 0 ];
				yPos = ( position[ 1 ] + dimension.height + 1 ).ceil();
				break;
			case 'BR' :
				xPos = position[ 0 ] - ( wDim.width - dimension.width );
				yPos = ( position[ 1 ] + dimension.height + 1 ).ceil();
				break;
			case 'TC' :
				xPos = ( ( position[ 0 ] + ( dimension.width /2 ) ) - ( wDim.width /2 ) ).ceil();
				yPos = ( position[ 1 ] - wDim.height - 1 ).ceil();
				break;
			case 'TL' :
				xPos = position[ 0 ];
				yPos = ( position[ 1 ] - wDim.height - 1 ).ceil();
				break;
			case 'TR' :
				xPos = position[ 0 ] - ( wDim.width - dimension.width );
				yPos = ( position[ 1 ] - wDim.height - 1 ).ceil();
				break;
		}

		this.window.setStyle( { 'left' : xPos + 'px' , 'top' : yPos + 'px' } );
	}
	, close : function() {
		this.opened = false;
		this.window.hide();
	}
} );

TipWindow.allClose = function() {
	$H( TipWindow.contIds ).each( function( TW ) { TW.value.close(); } );
}

TipWindow.getInstance = function( id , options ) {
	if( TipWindow.contIds === undefined ) TipWindow.contIds = {};
	if( !TipWindow.contIds[ id ] ) {
		TipWindow.contIds[ id ] = new TipWindow( id , options );
	}
	return TipWindow.contIds[ id ];
}

// {{{ unserialize
function unserializeu(data){
    var error = function (type, msg, filename, line){throw new window[type](msg, filename, line);};
    var read_until = function (data, offset, stopchr){
        var buf = [];
        var chr = data.slice(offset, offset + 1);
        var i = 2;
        while(chr != stopchr){
            if((i+offset) > data.length){
                error('Error', 'Invalid');
            }
            buf.push(chr);
            chr = data.slice(offset + (i - 1),offset + i);
            i += 1;
        }
        return [buf.length, buf.join('')];
    };
    var read_chrs = function (data, offset, length){
        buf = [];

        for(var i = 0 ; i < length ; i++ ){
            var chr = data.slice(offset + (i - 1),offset + i);
            buf.push(chr);
        }

		var incKor = buf.join( '' ).match( /([ㄱ-힣])+/g );

		if( incKor && incKor.length ) {
			var hCharCnt = incKor.join( '' ).length * 2;
			buf = [];
			for(var i = 0 , len = length - hCharCnt ; i < len ; i++ ){
				var chr = data.slice(offset + (i - 1),offset + i);
				buf.push(chr);
			}
		}

        return [buf.length, buf.join('')];
    };
    var _unserialize = function (data, offset){
        if(!offset) offset = 0;
        var buf = [];
        var dtype = (data.slice(offset, offset + 1)).toLowerCase();

        var dataoffset = offset + 2;
        var typeconvert = new Function('x', 'return x');
        var chrs = 0;
        var datalength = 0;

        switch(dtype){
            case "i":
                typeconvert = new Function('x', 'return parseInt(x)');
                var readData = read_until(data, dataoffset, ';');
                var chrs = readData[0];
                var readdata = readData[1];
                dataoffset += chrs + 1;
            break;
            case "b":
                typeconvert = new Function('x', 'return (parseInt(x) == 1)');
                var readData = read_until(data, dataoffset, ';');
                var chrs = readData[0];
                var readdata = readData[1];
                dataoffset += chrs + 1;
            break;
            case "d":
                typeconvert = new Function('x', 'return parseFloat(x)');
                var readData = read_until(data, dataoffset, ';');
                var chrs = readData[0];
                var readdata = readData[1];
                dataoffset += chrs + 1;
            break;
            case "n":
                readdata = null;
            break;
            case "s":
                var ccount = read_until(data, dataoffset, ':');
                var chrs = ccount[0];
                var stringlength = ccount[1];
                dataoffset += chrs + 2;

                var readData = read_chrs(data, dataoffset+1, parseInt(stringlength));
                var chrs = readData[0];
                var readdata = readData[1];
                dataoffset += chrs + 2;
                if(chrs != parseInt(stringlength) && chrs != readdata.length){
                    error('SyntaxError', 'String length mismatch');
                }
            break;
            case "a":
                var readdata = {};

                var keyandchrs = read_until(data, dataoffset, ':');
                var chrs = keyandchrs[0];
                var keys = keyandchrs[1];
                dataoffset += chrs + 2;

                for(var i = 0;i < parseInt(keys);i++){
                    var kprops = _unserialize(data, dataoffset);
                    var kchrs = kprops[1];
                    var key = kprops[2];
                    dataoffset += kchrs;

                    var vprops = _unserialize(data, dataoffset);
                    var vchrs = vprops[1];
                    var value = vprops[2];
                    dataoffset += vchrs;

                    readdata[key] = value;
                }

                dataoffset += 1;
            break;
            default:
                error('SyntaxError', 'Unknown / Unhandled data type(s): ' + dtype);
            break;
        }
        return [dtype, dataoffset - offset, typeconvert(readdata)];
    };
    return _unserialize(data, 0)[2];
}// }}}

//-----------------------------------------------------------------------------
// 문자열의 byte 길이 반환
// @return : int
//-----------------------------------------------------------------------------
function byteToString(data) {
    var cnt = 0;
    for (var i = 0; i < data.length; i++) {
        if (data.charCodeAt(i) > 127)
            cnt += 2;
        else
            cnt++;
    }
    return cnt;
}