/*
File: Kernel
	Các hàm hệ thống của LightJS. File này được truyền vào một cách đặc biệt cho LightJsCompiler khi dịch

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	http://acctech.redirectme.net/wiki/%C4%90%C3%B3ng_g%C3%B3i_JavaScript
*/
var filesWrapper = new Array();
window.store('filesWrapper', filesWrapper);

/*
Function: isset
	Kiểm tra xem một biến có giá trị hay không, cho dù là null hay chưa được định nghĩa, có thể dùng để kiểm tra một key trong mảng

Arguments:
	value - (mixed) Giá trị cần kiểm tra
*/
isset = function(value){
	return !(value == null);
};

in_array = function(needle, arr){
	return !(arr.indexOf(needle) == -1);
}

inArray = function(needle, arr){
	return in_array(needle, arr);
}

count = function(arr){
	return arr.length;
}

namespace = function(spaceName){
	var o, d;
    $each(arguments, function(v) {
        d = v.split(".");
        o = window[d[0]] = window[d[0]] || {};
        $each(d.slice(1), function(v2){
            o = o[v2] = o[v2] || {};
        });
    });
    return o;
}

trim = function(str) {
	str = str.replace(/^\s+/, '');
	for (var i = str.length - 1; i >= 0; i--) {
		if (/\S/.test(str.charAt(i))) {
			str = str.substring(0, i + 1);
			break;
		}
	}
	return str;
}

/*
Function: isEmpty
	Kiểm tra xem một xâu có rỗng không

Arguments:
	value - (string) Xâu cần kiểm tra
*/
isEmpty = function(value){
	return value === '';
};

/*
Function: loadFile
	Load một file vào bộ nhớ

Arguments:
	filePath - (string) Đường dẫn đến file cần load

Syntax:
	(start code)
loadFile(filePath);
	(end)

Example:
	(start code)
loadFile('bridge/boot.js');
	(end)
*/
loadFile = function (filePath){
	var filesWrapper = window.retrieve('filesWrapper');
    var filesList = window.retrieve('filesList');
	if (!isset(filesList)){
		filesList = new Array();
		window.store('filesList', filesList);
	}

	if (filesList.indexOf(filePath) == -1){
		if (isset(filesWrapper[filePath])) {
			filesWrapper[filePath].run();
			filesList.include(filePath);
		}
		else {
			throw "Low level error: Cant find file with path '" + filePath + "'";
		}
	}
};filesWrapper['core/bridge.js'] = function(){
	/*
File: bridge.js
	File kích hoạt khởi động gói core. Phải load vào để khởi động gói core của LightJS

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/*
Function: installDebugger
	Cài đặt debugger để tránh hiển thị lỗi ra ngoài cho người dùng nhìn thấy
*/
installDebugger = function(){
	window.onerror = function(message,url,line){
		if (!getSystemConfig().get('/System/debugMode')){
			return true;
		}
		else {
			getErrorConsole().log('Có lỗi: ' + message + ' tại URL: ' + url + ' dòng thứ ' + line);
		}
	};
};

loadFile('core/LightException.js');
loadFile('core/StaticFunctions.js');
loadFile('core/HelpersFactory.js');
loadFile('core/Element.Light.js');

getSystemConfig().readFromFile('/System', 'core/DefaultConfig.js');
};filesWrapper['core/DefaultConfig.js'] = function(){
	ConfigData = {
	'cookieDomain': '.acc.vn',
	'cookiePath': '/',
	'debugMode': false
};
};filesWrapper['core/Element.Light.js'] = function(){
	/*
Class: Element.Light
	Kết nối Light và Mootools bằng cách bổ sung hàm vào native class Element

	Author - hitori_vodanh <nhanvc@vsmc.vn>
	Copyright -	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	http://mootools.net/docs/Element/Element.Event
*/
Native.implement([Element, Window, Document], {

	/*
	Function: tryEvent
		Chạy thử từng event được yêu cầu cho element. Nếu có hàm trả về là false thì dừng luôn

	Arguments:
		type - (string) Tên của event (e.g. 'submit')
   		args - (mixed, optional) Array hoặc object, là tham số truyền vào cho hàm, nhiều hơn một argument thì phải truyền vào là array.
		delay - (number, optional) Chờ một thời gian (tính bằng ms) để bắt đầu chạy event

	Returns:
		(boolean) Có pass qua tất cả các event hay không
	*/
	tryEvent: function(type, args, delay){
		var events = this.retrieve('events');
		if (!events || !events[type]) return true;
		var passed = true;
		events[type].keys.each(function(fn){
			var result = fn.create({'bind': this, 'delay': delay, 'arguments': args})();
			if (!isset(result)) result = true;
			passed = passed && result;
		}, this);
		return passed;
	}
});

Element.implement({
	/*
	Function: submitHttp
		Hàm giả toàn bộ hoạt động submit của một form, dùng để thay thế hàm submit() vì submit() không gửi event submit
	*/
	submitHttp: function(){
		var result = this.tryEvent('submit');
        if (!result) return this;

        var refreshRate = getSystemConfig().get('/System/G/refreshRate/');
        var formSubmitDelay = getSystemConfig().get('/System/G/formSubmitDelay');
        if (isset(refreshRate) && isset(formSubmitDelay)) {
			this.realSubmit.delay(
				refreshRate + formSubmitDelay,
				this
			);

			// submit delay nhiều hơn refresh rate để đảm bảo mọi lệnh vẽ
			// trong các event submit được vẽ trước khi submit gửi đi
			// chạy thế này để tương thích với gói Light.G
		}
		else {
			this.realSubmit();
		}
		return this;
	},

	/*
	Function: realSubmit
		Làm thế này vì IE ko coi hàm submit là hàm của mootools
	*/
	realSubmit: function(){
		this.submit();
	},

	/*
	Function: clickSimulate
		Giả hoạt động click của một button hoặc link
	*/
	clickSimulate: function(){
		this.fireEvent('click');

		if (
			this.get('tag') == 'button' &&
			this.get('type') == 'submit'
		){
			var form = this.getParent('form');
			if (isset(form)) form.submitHttp();
		}

		if (this.get('tag') == 'a') this.goToHref();
	},

	/*
	Function: goToHref
		Hàm này thể hiện việc chuyển đổi trang hiện tại thành một trang khác tương ứng với thuộc tính của element
	*/
	goToHref: function(){
		var linkUrl = this.get('href');
		if (!isset(linkUrl) || linkUrl === '') linkUrl = window.location;
		window.location = this.get('href');
	}
});
};filesWrapper['core/ErrorConsole.js'] = function(){
	/*
Class: ErrorConsole
	Định nghĩa cách thức thông báo lỗi trong hệ thống. Thông thường, ErrorConsole được lightJS boot sẵn

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
getErrorConsole()
	(end)
*/
/* class */ ErrorConsole /* */
= new Class({
    /*
	Function: throwError
		Quăng một lỗi ra console

	Arguments:
		errorMsg - (string) Xâu thể hiện lỗi
		errorCode - (mixed) Mã lỗi

	Syntax:
		(start code)
getErrorConsole().throwError(errorMsg, [errorCode]);
		(end)
	*/
	throwError: function(errorMsg, errorCode){
		if (getSystemConfig().get('/System/debugMode')){
			if (!isset(errorCode)){
	            if(window.console) console.log('Error: "', errorMsg, '"');
			}
			else {
	            if(window.console) console.log('Error: "', errorMsg, '" with code ', errorCode);
			}
		}

		throw errorMsg;
	},

	/*
	Function: log
		Ghi lại log

	Arguments:
		message - (string) Xâu thể hiện log
	Syntax:
		(start code)
getErrorConsole().log(message);
		(end)
	*/
	log: function(message){
        if(window.console) console.log('Log: ', message);
	}
});
};filesWrapper['core/Helpers/Base64Helper.js'] = function(){
	/*
Class: Base64Helper
	Helper dùng để encode và decode theo dạng base64. Thông thường, helper này có sẵn trong <HelpersFactory>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
HelpersFactory.getBase64Helper()
	(end)
*/
/* class */ Base64Helper /* */
= new Class({
	$keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

	/*
	Function: encode
		Encode xâu thông thường thành dạng base 64

	Arguments:
		input - (string) Xâu thông thường cần encode

	Returns:
		- (string) Xâu đã được encode
	*/
	encode: function(input){
        var output = "";
	   	if (isEmpty(input) || !isset(input)) {
	    	return output;
	   	}

	   	var chr1, chr2, chr3;
	   	var enc1, enc2, enc3, enc4;
	   	var i = 0;
	   	do {
	    	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);
	   	} while (i < input.length);
	   	return output;
	},

	/*
	Function: decode
		Decode xâu base 64 về xâu thông thường

	Arguments:
		input - (string) Xâu base 64 cần decode

	Returns:
		- (string) Xâu thông thường sau khi đã decode
	*/
    decode: function(input){
    	var output = "";
		if (isEmpty(input) || !isset(input)) {
	    	return output;
		}
	   	var chr1, chr2, chr3;
	   	var enc1, enc2, enc3, enc4;
	   	var i = 0;
	   	// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
	   	input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
	   	do {
	    	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);
	      	}
	   } while (i < input.length);
	   return output;
	}
});
};filesWrapper['core/Helpers/CookiesHelper.js'] = function(){
	/*
Class: CookiesHelper
	Helper hỗ trợ việc quản lý cookies. Thông thường, helper này có sẵn trong <HelpersFactory>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
HelpersFactory.getCookiesHelper()
	(end)

See Also:
	- http://mootools.net/docs/Utilities/Cookie
*/
/* class */ CookiesHelper /* */
= new Class({

	/*
	Function: getAll
		Lấy tất cả cookies dưới dạng một mảng
	*/
	getAll: function(){
        var cookiestr = document.cookie.split(';');
        var data = {};
        if (cookiestr.length>0) {
            for (var i=0; i<cookiestr.length; i++){
                var pair = cookiestr[i].split("=");
                pair[0] = pair[0].trim();
                data[ pair[0] ] = unescape( pair[1] );
            }
        }

        return data;
	},

	/*
	Function: setAll
		Gán một mảng các cookies

	Arguments:
		cookies - (Array) Mảng có dữ liệu là tên các cookie đi kèm giá trị của nó và thời gian hủy

	See Also:
		http://mootools.net/docs/Utilities/Cookie#Cookie

	Example:
		- Cấu trúc dữ liệu của mảng cookie, cookieOptions giống options của Cookie như trong mootools
		(start code)
cookies: {
	cookieName: {
		value: cookieValue,
		options: cookieOptions
	}
}
		(end)
	*/
	setAll: function(cookies){
        $each(cookies, function(cookieData, cookieName){
        	if (
        		!isset(cookieData.options) ||
        		!isset(cookieData.options.duration) ||
        		cookieData.options.duration > 0
        	){
        		this.write(cookieName, cookieData.value, cookieData.options);
			}
			else {
				this.dispose(cookieName, cookieData.options);
			}
        }.bind(this));
	},

	/*
	Function: write
		Hàm đóng gói lại write của cookie, nếu không truyền options, sẽ dùng options mặc định

	Arguments:
		key - (string) Tên của cookie
		value - (string) Giá trị cần set
		options - (mixed, optional) Xem thêm options ở <CookiesHelper.setAll>
	*/
	write: function(key, value, options){
		if (!isset(options)){
			var cookieDomain = getSystemConfig().get('/System/cookieDomain');
	        var cookiePath = getSystemConfig().get('/System/cookiePath');
	        options = {
                domain: cookieDomain,
                path: cookiePath
            };
		}

		Cookie.write(key, value, options);
	},

	/*
	Function: read
		Đọc giá trị của một cookie

	Arguments:
		name - (string) Tên của cookie cần đọc
	*/
	read: function(name){
		return Cookie.read(name);
	},

	/*
	Function: dispose
		Hủy một cookie

	Arguments:
		name - (string) Tên của cookie cần hủy
		options - (mixed, optional) Option tương ứng với cookie
	*/
	dispose: function(name, options){
		return Cookie.dispose(name, options);
	}
});
};filesWrapper['core/Helpers/FileHelper.js'] = function(){
	/*
Class: FileHelper
	Helper hỗ trợ một số thao tác với file. Thông thường, helper này có sẵn trong <HelpersFactory>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
HelpersFactory.getFileHelper()
	(end)
*/
/* class */ FileHelper /**/
= new Class({
	/*
	Function: calculateFileSize
		Trả về xâu tính toán kích thước file, từ byte đổi sang KB, MB

	Arguments:
		fileSize - (integer) Kích thước file tính bằng byte

	Returns:
		- (string) Kích thước đã đổi ra xâu, có KB hoặc MB ở sau
	*/
	calculateFileSize: function(fileSize){
        var oneKB = 1024;
		var oneMB = 1024 * 1024;
		var unit; var num;

		if (fileSize >= oneKB && fileSize < oneMB){
			unit = 'KB';
			num = Math.round(fileSize / oneKB);
		}
		else if (fileSize >= oneMB){
			unit = 'MB';
			num = Math.round(fileSize / oneMB * 100)/100;
		}
		else {
			unit = 'bytes';
			num = fileSize;
		}

		return num + ' ' + unit;
	}
});
};filesWrapper['core/Helpers/HtmlHelper.js'] = function(){
	/*
Class: HtmlHelper
	Cung cấp các phương thức để hỗ trợ việc khai thác một xâu HTML. Thông thường, helper này có sẵn trong <HelpersFactory>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
HelpersFactory.getHtmlHelper()
	(end)
*/
/* class */ HtmlHelper /**/
= new Class({
    /*
	Function: execute
		Chạy tất cả các lệnh nhúng JavaScript trong đoạn HTML đó

	Arguments:
		html - (string) Xâu HTML yêu cầu chạy JS
	*/
	execute: function(html){
		// we will strip the script tag
		var insideScript;
        var extraHtml = html.stripScripts(function(script){
			insideScript = script;
		});
		// then run
		$exec(insideScript);
	},

	/*
	Function: cleanup
		Dọn dẹp HTML (thường là HTML có trong iframe) để trở nên sạch hơn

	Arguments:
		source - (string) Nguồn của HTML

	Returns:
		- (string) HTML đã làm sạch
	*/
    cleanup: function(source, semantics, xhtml) {
    	//console.log(source);

    	if (!isset(semantics)) semantics = true;
    	if (!isset(xhtml)) xhtml = true;

		do {
			var oSource = source;

			// Webkit cleanup
			source = source.replace(/<br class\="webkit-block-placeholder">/gi, "<br />");
			source = source.replace(/<span class="Apple-style-span">(.*)<\/span>/gi, '$1');
			source = source.replace(/ class="Apple-style-span"/gi, '');
			source = source.replace(/<span style="">/gi, '');

			// Remove padded paragraphs
			source = source.replace(/<p>\s*<br ?\/?>\s*<\/p>/gi, '<p>\u00a0</p>');
			source = source.replace(/<p>(&nbsp;|\s)*<\/p>/gi, '<p>\u00a0</p>');
			if (semantics) {
				source = source.replace(/\s*<br ?\/?>\s*<\/p>/gi, '</p>');
			}


			// Replace improper BRs (only if XHTML : true)
			if (xhtml) {
				source = source.replace(/<br>/gi, "<br />");
			}

			if (semantics) {
				//remove divs from <li>
				if (Browser.Engine.trident) {
					source = source.replace(/<li>\s*<div>(.+?)<\/div><\/li>/g, '<li>$1</li>');
				}
				//remove stupid apple divs
				if (Browser.Engine.webkit) {
					source = source.replace(/^([\w\s]+.*?)<div>/i, '<p>$1</p><div>');
					source = source.replace(/<div>(.+?)<\/div>/ig, '<p>$1</p>');
				}

				//<p> tags around a list will get moved to after the list
				if (['gecko', 'presto','webkit'].contains(Browser.Engine.name)) {
					//not working properly in safari?
					source = source.replace(/<p>[\s\n]*(<(?:ul|ol)>.*?<\/(?:ul|ol)>)(.*?)<\/p>/ig, '$1<p>$2</p>');
					source = source.replace(/<\/(ol|ul)>\s*(?!<(?:p|ol|ul|img).*?>)((?:<[^>]*>)?\w.*)$/g, '</$1><p>$2</p>');
				}

				source = source.replace(/<br[^>]*><\/p>/g, '</p>');			//remove <br>'s that end a paragraph here.
				source = source.replace(/<p>\s*(<img[^>]+>)\s*<\/p>/ig, '$1\n'); 	//if a <p> only contains <img>, remove the <p> tags

				//format the source
				source = source.replace(/<p([^>]*)>(.*?)<\/p>(?!\n)/g, '<p$1>$2</p>\n');  	//break after paragraphs
				source = source.replace(/<\/(ul|ol|p)>(?!\n)/g, '</$1>\n'); 			//break after </p></ol></ul> tags
				source = source.replace(/><li>/g, '>\n\t<li>'); 				//break and indent <li>
				source = source.replace(/([^\n])<\/(ol|ul)>/g, '$1\n</$2>');  			//break before </ol></ul> tags
				source = source.replace(/([^\n])<img/ig, '$1\n<img'); 				//move images to their own line
				source = source.replace(/^\s*$/g, '');						//delete empty lines in the source code (not working in opera)
			}

			// Remove leading and trailing BRs
			source = source.replace(/<br ?\/?>$/gi, '');
			source = source.replace(/^<br ?\/?>/gi, '');

			// Remove useless BRs
			//TODO: Kiểm tra kỹ cái này, tại sao cho vào bị lỗi cà? Trong khi lý thuyết thì ko lỗi ha
			//source = source.replace(/><br ?\/?>/gi, '>');

			// Remove BRs right before the end of blocks
			source = source.replace(/<br ?\/?>\s*<\/(h1|h2|h3|h4|h5|h6|li|p)/gi, '</$1');

			// Semantic conversion
			source = source.replace(/<span style="font-weight: bold;">(.*)<\/span>/gi, '<strong>$1</strong>');
			source = source.replace(/<span style="font-style: italic;">(.*)<\/span>/gi, '<em>$1</em>');
			source = source.replace(/<b\b[^>]*>(.*?)<\/b[^>]*>/gi, '<strong>$1</strong>');
			source = source.replace(/<i\b[^>]*>(.*?)<\/i[^>]*>/gi, '<em>$1</em>');
			source = source.replace(/<u\b[^>]*>(.*?)<\/u[^>]*>/gi, '<span style="text-decoration: underline;">$1</span>');

			// Replace uppercase element names with lowercase
			source = source.replace(/<[^> ]*/g, function(match){return match.toLowerCase();});

			// Replace uppercase attribute names with lowercase
			source = source.replace(/<[^>]*>/g, function(match){
				   match = match.replace(/ [^=]+=/g, function(match2){return match2.toLowerCase();});
				   return match;
			});

			// Put quotes around unquoted attributes
			source = source.replace(/<[^>]*>/g, function(match){
				   match = match.replace(/( [^=]+=)([^"][^ >]*)/g, "$1\"$2\"");
				   return match;
			});

			//make img tags xhtml compatable
			if (xhtml) {
				source = source.replace(/(<(?:img|input)[^/>]*)>/g, '$1 />');
			}

			//remove double <p> tags and empty <p> tags
			source = source.replace(/<p>(?:\s*)<p>/g, '<p>');
			source = source.replace(/<\/p>\s*<\/p>/g, '</p>');
			source = source.replace(/<p>\W*<\/p>/g, '');

			//remove empty div tag
			source = source.replace(/<div([^>]*)>\W*<\/div>/g, '');  	//break after paragraphs
			//source = source.replace(/<br \/>/g, '<br/>\n');

			// Final trim
			source = source.trim();
		} while (source != oSource);

		return source;
	}

});
};filesWrapper['core/Helpers/LadHelper.js'] = function(){
	/*
Class: LadHelper
	Cung cấp phương thức để giải mã và execute dữ liệu vẽ được encode kiểu LAD (Light Ajax Data). Thông thường, helper này có sẵn trong <HelpersFactory>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
HelpersFactory.getLadHelper()
	(end)
*/
/* class */ LadHelper /**/
= new Class({
    /*
	Function: decode
		Decode xâu được encode để tạo ra một mảng dữ liệu trả về có thể execute được

	Arguments:
		responseString - (string) Xâu encode kiểu LAD, thường được trả về từ một HTTP Request

	Returns:
		- (array) Mảng dữ liệu có thể execute được

	See Also:
		<execute>
	*/
	decode: function(responseString){
		try {
			var decodedData = JSON.decode(responseString);
		}
		catch(e){
			getErrorConsole().throwError('Có lỗi trong quá trình giải mã LAD');
		}

		return decodedData;
	},

    /*
	Function: execute
		Chạy dữ liệu đã được decode và vẽ theo yêu cầu

	Arguments:
		decodedData - (array) Dữ liệu đã được decode bởi LAD
	*/
	execute: function(decodedData){
		if (getSystemConfig().get('/System/debugMode')){
			getErrorConsole().log(decodedData);
		}

        $each(decodedData,function(commandData){
        	var drawingCommandKey = commandData.command;
        	var tempFnc = $empty;

            switch(drawingCommandKey)
			{
				case 'resetHtml':
					tempFnc = HelpersFactory.getLadPaintHelper().resetHtml;
			  		break;
				case 'injectHtml':
					tempFnc = HelpersFactory.getLadPaintHelper().injectHtml;
			  		break;
			  	case 'destroyElement':
			  		tempFnc = HelpersFactory.getLadPaintHelper().destroyElement;
			  		break;
			  	case 'executeHtml':
			  		tempFnc = HelpersFactory.getLadPaintHelper().executeHtml;
			  		break;
				default:
			  		getErrorConsole().throwError("Invalid drawing data command key");
			  		break;
			}


			try {
				tempFnc.run([commandData], HelpersFactory.getLadPaintHelper());
			}
			catch(e){
				if (getSystemConfig().get('/System/debugMode')){
					if (isset(e.getMessage)) getErrorConsole().log(e.getMessage());
					else getErrorConsole().log(e);
				}
			}
		});
	},

	getModifiedElementIds: function(decodedData){
		var modifiedElementIds = new Array();
		$each(decodedData,function(commandData){
			var drawingCommandKey = commandData['command'];
        	if (drawingCommandKey != 'inject' && drawingCommandKey != 'executeHtml') {
        		var elementId = commandData['elementId'];
        		modifiedElementIds.include(elementId);
			}
		});

		return modifiedElementIds;
	},

    /*
	Function: decodeAndExecute
		Decode dữ liệu và execute cùng một lúc

	Arguments:
		responseString - (string) Xâu encode kiểu LAD, thường được trả về từ một HTTP Request
	*/
	decodeAndExecute: function(responseString){
		var decodedData = this.decode(responseString);
		this.execute(decodedData);
	}
});
};filesWrapper['core/Helpers/LadPaintHelper.js'] = function(){
	/*
Script: LadPaintHelper
	Trợ giúp việc dịch dữ liệu LAD để vẽ ra các element và HTML tương ứng với lệnh. Dữ liệu đầu vào chính là các data được decode. Thông thường, helper này có sẵn trong <HelpersFactory>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
HelpersFactory.getLadPaintHelper()
	(end)
*/
/* class */ LadPaintHelper /**/
= new Class({
	debugMode: false,

	/*
	Function: resetHtml
		Chạy lệnh resetHtml trong gói tin LAD

	Arguments:
		drawingData - (array) Dữ liệu của câu lệnh vẽ
	*/
    resetHtml: function(drawingData){
        if (!HelpersFactory.getTypeHelper().hasAllKeys(drawingData, ['elementId', 'htmlText'])){
			getErrorConsole().throwError("Invalid drawing data for command: resetHTML");
		}

        var el = $(drawingData['elementId']);
        var htmlText = drawingData['htmlText'];

		if (el){
			el.set('html', htmlText);
			HelpersFactory.getHtmlHelper().execute(htmlText);
		}
		else {
			getErrorConsole().throwError("Paint can't find element with ID: " + drawingData['elementId']);
		}

		if (this.debugMode){
			//console.log('Paint vừa vẽ lại HTML của element có ID: ', drawingData['elementId']);
		}
	},

	/*
	Function: injectHtml
		Chạy lệnh injectHtml trong gói tin LAD

	Arguments:
		drawingData - (array) Dữ liệu của câu lệnh vẽ
	*/
	injectHtml: function(drawingData){
        if (!HelpersFactory.getTypeHelper().hasAllKeys(drawingData, ['elementId', 'htmlText', 'where'])){
			getErrorConsole().throwError("Invalid drawing data for command: injectHTML");
		}

		if (!isset(drawingData['wrapperElementId'])){
			this.injectElement(
				drawingData['elementId'],
				drawingData['htmlText'],
				drawingData['where']
			);
		}
		else {
			this.injectElement(
				drawingData['elementId'],
				drawingData['htmlText'],
				drawingData['where'],
				drawingData['wrapperElementId']
			);
		}

        if (this.debugMode){
			//console.log('Paint vừa chèn thêm HTML vào element có ID: ', drawingData['elementId']);
		}
	},

	/*
	Function: destroyElement
		Chạy lệnh injectHtml trong gói tin LAD

	Arguments:
		drawingData - (array) Dữ liệu của câu lệnh vẽ
	*/
	destroyElement: function(drawingData){
        if (!drawingData['elementId']){
			getErrorConsole().throwError("Invalid drawing data for command: destroyElement");
		}

        var el = $(drawingData['elementId']);
		if (el){
			el.destroy();
		}
		else {
			getErrorConsole().throwError("Paint can't find element with ID: " + elementId);
		}

        if (this.debugMode){
			//console.log('Paint vừa xóa element có ID: ', drawingData['elementId']);
		}
	},

	/*
	Function: executeHtml
		Chạy lệnh executeHtml trong gói tin LAD

	Arguments:
		drawingData - (array) Dữ liệu của câu lệnh vẽ
	*/
	executeHtml: function(drawingData){
        if (!drawingData['htmlText']){
			getErrorConsole().throwError("Invalid drawing data for command: executeHtml");
		}

		var htmlText = drawingData['htmlText'];
		var tempSpace = $('tempSpace');
		if (!isset(tempSpace)){
			tempSpace = new Element('div', {
				'id': 'tempSpace',
				'styles': {
					'display': 'none'
				}
			}).inject(document.body, 'bottom');
		}

		tempSpace.set('html', tempSpace.get('html') + htmlText);
		HelpersFactory.getHtmlHelper().execute(htmlText);

        if (this.debugMode){
			//console.log('Paint vừa execute HTML');
		}
	},

	injectElement: /* private */ function(elementId, htmlText, where, wrapperElementId){
        if (!isset(where)) where = 'bottom';
        where = HelpersFactory.getTypeHelper().getValueWithLimited(where, ['top', 'bottom', 'after', 'before']);

        var el = $(elementId);
		if (el){
			var newEl;
			if (wrapperElementId){
				newEl = new Element('div',{
					'id': wrapperElementId
				});
                newEl.set('html', htmlText);
				newEl.inject(el, where);
			}
			else {
				if (where == 'after' || where == 'before'){
					newEl = new Element('div');
                    newEl.set('html', htmlText);
					newEl.inject(el, where);
				}
				else {
					var oldHTML = $(elementId).get('html');
                    if (where == 'top'){
					    el.set('html', htmlText + oldHTML);
					}
					else if (where == 'bottom'){
					    el.set('html', oldHTML + htmlText);
					}
				}
			}
		}
		else {
			getErrorConsole().throwError("Paint can't find element with ID: " + elementId);
		}
	}
});
};filesWrapper['core/Helpers/TypeHelper.js'] = function(){
	/*
Class: TypeHelper
	Helper hỗ trợ việc kiểm tra dữ liệu đầu vào. Thông thường, helper này có sẵn trong <HelpersFactory>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
HelpersFactory.getTypeHelper()
	(end)
*/
/* class */ TypeHelper /* */
= new Class({
	instances: new Array(),

    /*
	Function: getValueWithDefault
		Kiểu tra xem biến yêu cầu có giá trị không, nếu không thì lấy giá trị mặc định

	Arguments:
		value - (mixed) Giá trị cần kiểm tra
		defaultValue - (mixed) Giá trị mặc định trả về
	*/
    getValueWithDefault: function(value, defaultValue){
    	if(!isset(value)){
    		return defaultValue;
    	}

    	return value;
    },

    /*
    Function: getValueWithLimited
    	Kiểm tra xem biến yêu cầu có trong mảng đầu vào không

    Arguments:
    	value - (mixed) Giá trị cần kiểm tra
    	limitedValues - (array) Mảng dữ liệu được phép
    	defaultValue - (mixed) Giá trị mặc định trả về khi giá trị kiểm tra nằm ngoài mảng được phép

    Returns:
    	- (mixed) Giá trị mặc định nếu có lỗi, quăng exception nếu không có giá trị mặc định
    */
    getValueWithLimited: function(value, limitedValues, defaultValue){
    	if (!limitedValues.contains(value)){
    		if (isset(defaultValue)){
    			return defaultValue;
    		}
    		else {
    			getErrorConsole().throwError(value + "is not a valid value we can use");
    			return false;
			}
    	}
    	else {
    		return value;
    	}
    },

    /*
    Function: getFlagString
    	Trả về xâu cờ của mảng dữ liệu đầu vào

    Arguments:
    	mainData - (array) Mảng dữ liệu đầu vào, thường là chỉ có true và false

    Returns:
    	- (string) Xâu cờ trả về, có các dạng 01100 tương ứng với các giá trị đầu vào true hay false

    */
    getFlagString: function(mainData){
        var flagString = "";
        mainData.each(function(value){
        	if (value) flagString += "1"; else flagString += "0";
        });

        return flagString;
    },

    /*
    Function: hasAllKeys
    	Kiểm tra xem mảng có đầy đủ tất cả các key yêu cầu không

    Arguments:
    	data - (array) Mảng đầu vào cần kiểm tra
    	keys - (array) Danh sách các key bắt buộc phải có

    Returns:
    	- (boolean) Có đầy đủ các key hay không

    */
    hasAllKeys: function(data, keys){
    	keys.each(function(key){
    		if (!isset(data[key])){
    			return false;
    		}
    	});

    	return true;
    },

    loadVerifierObj: function(ruleName){
    	if (isset(this.instances[ruleName])){
    		return this.instances[ruleName];
		}

		var ourInst;
        switch(ruleName.toLowerCase()){
    		case 'integer':
    			loadFile('core/Helpers/Verifiers/' + ruleName.capitalize() + 'Verifier.js');
    	  		ourInst = new IntegerVerifier();
				break;
			case 'regex':
				loadFile('core/Helpers/Verifiers/' + ruleName.capitalize() + 'Verifier.js');
				ourInst = new RegexVerifier();
				break;
			case 'string':
				loadFile('core/Helpers/Verifiers/' + ruleName.capitalize() + 'Verifier.js');
				ourInst = new StringVerifier();
				break;
			case 'remote':
				loadFile('core/Helpers/Verifiers/' + ruleName.capitalize() + 'Verifier.js');
				ourInst = new RemoteVerifier();
				break;
    		default:
    			getErrorConsole().throwError('Không tìm thấy luật nào như yêu cầu: ' + ruleName);
    	  		break;
    	}

    	this.instances[ruleName] = ourInst;
    	return ourInst;
    },

    /*
    Function: verifyDataByRule
    	Kiểm tra xem dữ liệu có hợp lệ không

    Arguments:
    	data - (mixed) Dữ liệu cần kiểm tra
    	ruleName - (string) Tên rule
    	ruleData - (mixed, optional) Options tương ứng với rule verifier

    Returns:
    	- (boolean) Dữ liệu có hợp lệ hay không
    */
    verifyDataByRule: function(data, ruleName, ruleData){
    	var objVerifier = this.loadVerifierObj(ruleName);
    	return objVerifier.verify(data, ruleData);
    },

    /*
    Function: verifyDataByRules
    	Kiểm tra dữ liệu có hợp lệ các rule không

    Arguments:
    	data - (mixed) Dữ liệu cần kiểm tra
    	rules - (Array) Mảng dữ liệu có key là tên rule, data là options của rule

    Returns:
    	- (boolean) Dữ liệu có hợp lệ hay không

    See Also:
    	- <IntegerVerifier>, <RegexVerifier>, <StringVerifier>
    */
    verifyDataByRules: function(data, rules){
    	rules = $H(rules);
    	return rules.every(
    		function(ruleData, ruleName){
    			var result = this.verifyDataByRule(data, ruleName, ruleData);
    			return result;
    		}.bind(this)
    	);
    },

    /*
    Function: getDataByRule
    	Láy dữ liệu đã được kiểm tra

    Arguments:
    	data - (mixed) Dữ liệu cần kiểm tra
    	ruleName - (string) Tên rule
    	ruleData - (mixed, optional) Options tương ứng với rule verifier

    Returns:
    	- (mixed) Dữ liệu đã được kiểm tra
    */
    getDataByRule: function(data, ruleName, ruleData){
        var objVerifier = this.loadVerifierObj(ruleName);
    	if (objVerifier.verify(data, ruleData)){
    		return objVerifier.cleanup(data);
		}
		else {
			return objVerifier.refine(data);
		}
    }
});
};filesWrapper['core/Helpers/Verifiers/AbstractVerifier.js'] = function(){
	/*
Class: AbstractVerifier
	Lớp abstract dành cho các verifier thừa kế

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ AbstractVerifier /* */
= new Class({
	Implements: [Options],

	/*
	Function: verify
		Verify dữ liệu

	Arguments:
		data - (mixed) Dữ liệu cần kiểm tra
		options - (mixed) Options cho verifier

	Returns:
		- (boolean) Có phù hợp luật hay không
	*/
	verify: /* abstract */ function(data, options){
		getErrorConsole().throwError('Phải thừa kế lại hàm verify của Verifier');
	},

	/*
	Function: cleanup
		Dùng để chuẩn hóa dữ liệu sau khi đã xác nhận là verify thành công

	Arguments:
		data - (mixed) Dữ liệu đầu vào nguyên vẹn sau khi đã verify
	*/
    cleanup: /* abstract */ function(data){
		getErrorConsole().throwError('Phải thừa kế lại hàm cleanup của Verifier');
	},

	/*
	Function: refine
		Dùng để sửa đổi lại dữ liệu nếu không verify thành công

	Arguments:
		data - (mixed) Dữ liệu đầu vào nguyên vẹn sau khi đã verify
	*/
	refine: /* abstract */ function(data){
		getErrorConsole().throwError('Phải thừa kế lại hàm refine của Verifier');
	}
});
};filesWrapper['core/Helpers/Verifiers/IntegerVerifier.js'] = function(){
	loadFile('core/Helpers/Verifiers/AbstractVerifier.js');

/*
Class: IntegerVerifier
	Verfier kiểm tra dữ liệu kiểu số nguyên

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractVerifier>

Syntax:
	- Sử dụng thông qua <TypeHelper>
	(start code)
HelpersFactory.getTypeHelper().verifyDataByRule(data, 'integer', [options]);
	(end)
	- Tự new ra và sử dụng
	(start code)
loadFile('core/Helpers/Verifiers/IntegerVerifier.js');
var vrf = new IntegerVerifier();
vrf.verify(data, [options]);
	(end)

Options:
	min - (integer, default là null) Nhỏ nhất cho phép, null để không kiểm tra
	max - (integer, default là null) Lớn nhất cho phép, null để không kiểm tra
*/
/* class */ IntegerVerifier /* extends AbstractVerifier */
= new Class({
	Extends: AbstractVerifier,
	options: {
		min: null,
		max: null
	},

	verify: function(data, options){
		if (data === '') return true;
		this.setOptions(options);
		data = data.toString();
		var result = data.test(/^[-+]?[0-9]+$/);
		if (result === true){
			/* nếu qua được vòng regExp, check min, max */
			var dataInt = data.toInt();
			if (isset(this.options.min)){
				if (dataInt < this.options.min){
					return false;
				}
			}

			if (isset(this.options.max)){
				if (dataInt > this.options.max){
					return false;
				}
			}

			return true;
		}
		else {
			return false;
		}
	},

	cleanup: function(data){
		return data;
	},

    refine: function(data){
		return null;
	}
});
};filesWrapper['core/Helpers/Verifiers/RegexVerifier.js'] = function(){
	loadFile('core/Helpers/Verifiers/StringVerifier.js');

/*
Class: RegexVerifier
	Verifier dùng để kiểm tra có tuân theo một regular expression yêu cầu không

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<StringVerifier>

Syntax:
	(start code)
HelpersFactory.getTypeHelper().verifyDataByRule(data, 'regex', options);
	(end)

Options:
	regexRule - (regex value, string) Điền các giá trị regular expression vào hoặc sử dụng string nằm trong các luật có sẵn

Default Rules:
	alpha - Chỉ được phép sử dụng các ký tự alphabet thông thường
	alphanum - Chỉ được phép sử dụng các ký tự alphabet và các ký tự số
	nodigit - Không có ký tự số
	email - Đúng định dạng email
	url - Đúng định dạng url
*/
/* class */ RegexVerifier /* extends StringVerifier */
= new Class({
	Extends: StringVerifier,

	options: {
		regexRule: null
	},

	defaultRules: {
		alpha : /^[a-z ._-]+$/i,
		alphanum : /^[a-z0-9 ._-]+$/i,
		nodigit : /^[^0-9]+$/,
		email : /^[a-z0-9._%-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i,
		url : /^(http|https|ftp)\:\/\/[a-z0-9\-\.]+\.[a-z]{2,3}(:[a-z0-9]*)?\/?([a-z0-9\-\._\?\,\'\/\\\+&amp;%\$#\=~])*$/i
	},

	verify: function(data, options){
		var result = this.parent(data, options);
		if (result === false){
			return false;
		}

		if (!isset(this.options.regexRule)){
			getErrorConsole().throwError('Luật regex không thể là null. Xin hãy truyền regexRule vào options');
		}

		if ($type(this.options.regexRule) == 'string'){
			return data.toString().test(
				this.defaultRules[this.options.regexRule]
			);
		}
		else {
			return data.toString().test(
				this.options.regexRule
			);
		}
	}
});
};filesWrapper['core/Helpers/Verifiers/RemoteVerifier.js'] = function(){
	loadFile('core/Helpers/Verifiers/AbstractVerifier.js');

/*
Class: RemoteVerifier
	Verifier tạo ra bằng cách gửi một request đi và hỏi server xem có đúng hay không

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ RemoteVerifier /* extends AbstractVerifier */
= new Class({
	Extends: AbstractVerifier,

	options: {
		url: null
	},

	verify: function(data, options){
		if (data === '') return true;
		this.setOptions(options);
		if (!isset(this.options.url)) getErrorConsole().throwError('[from RemoteVerifier] Không thể verify nếu không có url');

		loadFile('light.Ajax/json/Request.Light.Json.js');
		var request = new Request.Light.Json({
			url: this.options.url,
			data: {
				'key': data
			}
		});
		request.send();
		if ($type(request.getResult()) != 'boolean') return false;
		return request.getResult();
	},

	cleanup: function(data){
		return data;
	},

    refine: function(data){
		return null;
	}
});
};filesWrapper['core/Helpers/Verifiers/StringVerifier.js'] = function(){
	loadFile('core/Helpers/Verifiers/AbstractVerifier.js');

/*
Class: StringVerifier
	Verifier dùng để kiểm tra có đúng định dạng xâu hay không

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractVerifier>

Syntax:
	(start code)
HelpersFactory.getTypeHelper().verifyDataByRule(data, 'string', [options]);
	(end)

Options:
	required - (boolean, default là false) Có bắt buộc phải có giá trị không
	minLength - (integer, default là null) Độ dài xâu tối thiểu, null để không kiểm tra
	maxLength - (integer, default là null) Độ dài xâu tối đa, null để không kiểm tra
*/
/* class */ StringVerifier /* extends AbstractVerifier */
= new Class({
	Extends: AbstractVerifier,
	options: {
		required: false,
		minLength: null,
		maxLength: null,
		sameAs: null
	},

    verify: function(data, options){
    	this.options = {
			required: false,
			minLength: null,
			maxLength: null
		};

    	this.setOptions(options);
    	data = data.toString();
    	if (this.options.required && data.trim().length === 0) return false;
    	if (isset(this.options.minLength) && data.trim().length < this.options.minLength) return false;
    	if (isset(this.options.maxLength) && data.trim().length > this.options.maxLength) return false;
    	if (isset(this.options.sameAs)) return $(this.options.sameAs).get('value') == data;
    	return true;
	},

    cleanup: function(data){
		return data;
	},

	refine: function(data){
		return null;
	}
});
};filesWrapper['core/HelpersFactory.js'] = function(){
	/*
Class: HelpersFactory
	Factory chứa các helper phổ biến trong hệ thống để tận dụng xử lý các quá trình lặp đi lặp lại nhiều lần

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ HelpersFactory /* */
= new Hash({
    /*
	Function: getHtmlHelper
		Gọi Helper hỗ trợ xử lý HTML

	Returns:
		- <HtmlHelper>
	*/
	getHtmlHelper: function(){
		loadFile('core/Helpers/HtmlHelper.js');
        var inst = window.retrieve('HtmlHelper');
		if (!isset(inst)){
			inst = new HtmlHelper();
			window.store('HtmlHelper', inst);
		}

		return inst;
	},

    /*
	Function: getLadHelper
		Gọi Helper hỗ trợ xử lý decode Lad

	Returns:
		- <LadHelper>
	*/
	getLadHelper: function(){
		loadFile('core/Helpers/LadHelper.js');
        var inst = window.retrieve('LadHelper');
		if (!isset(inst)){
			inst = new LadHelper();
			window.store('LadHelper', inst);
		}

		return inst;
	},

	/*
	Function: getLadPaintHelper
		Gọi helper hỗ trợ việc vẽ các câu lệnh trong gói tin được đóng gói kiểu LAD

	Returns:
		- <LadPaintHelper>
	*/
	getLadPaintHelper: function(){
		loadFile('core/Helpers/LadPaintHelper.js');
        var inst = window.retrieve('LadPaintHelper');
		if (!isset(inst)){
			inst = new LadPaintHelper();
			window.store('LadPaintHelper', inst);
		}

		return inst;
	},

	/*
	Function: getBase64Helper
		Gọi helper hỗ trợ việc encode và decode theo chuẩn base64

	Returns:
		- <Base64Helper>
	*/
	getBase64Helper: function(){
		loadFile('core/Helpers/Base64Helper.js');
        var inst = window.retrieve('Base64Helper');
		if (!isset(inst)){
			inst = new Base64Helper();
			window.store('Base64Helper', inst);
		}

		return inst;
	},

	/*
	Function: getCookiesHelper
		Gọi helper hỗ trợ việc xử lý cookies

	Returns:
		- <CookiesHelper>
	*/
    getCookiesHelper: function(){
    	loadFile('core/Helpers/CookiesHelper.js');
        var inst = window.retrieve('CookiesHelper');
		if (!isset(inst)){
			inst = new CookiesHelper();
			window.store('CookiesHelper', inst);
		}

		return inst;
	},

    /*
	Function: getTypeHelper
		Gọi Helper hỗ trợ xử lý dữ liệu và kiểu dữ liệu

	Returns:
		- <TypeHelper>
	*/
	getTypeHelper: function(){
		loadFile('core/Helpers/TypeHelper.js');
        var inst = window.retrieve('TypeHelper');
		if (!isset(inst)){
			inst = new TypeHelper();
			window.store('TypeHelper', inst);
		}

		return inst;
	},

	/*
	Function: getFileHelper
		Gọi Helper hỗ trợ xử lý các thông tin của file

	Returns:
		- <FileHelper>
	*/
	getFileHelper: function(){
		loadFile('core/Helpers/FileHelper.js');
        var inst = window.retrieve('FileHelper');
		if (!isset(inst)){
			inst = new FileHelper();
			window.store('FileHelper', inst);
		}

		return inst;
	}
});
};filesWrapper['core/IdleTimer.js'] = function(){
	/*
Class: IdleTimer
	Hỗ trợ việc bắt đầu chạy một danh sách các hàm sau một khoảng thời gian nhất định, có thể stop trước khi thời gian này xảy ra

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
var timer = new IdleTimer(startQueueTime);
	(end)

Example:
	(start code)
var timer = new IdleTimer(400); // hẹn giờ 400ms sau thì mới chạy
timer.addEvent('complete', function(){
	alert('time reached');
});
timer.start(); // bắt đầu tính giờ
...
timer.idle(); // bắt đầu cho phép chạy queue
...
if (something == 'failed'){
	timer.stop(); // ngừng chạy queue nếu failed
}
	(end)
*/
/* class */ IdleTimer /* */
= new Class({
	Implements: [Events],

	time: null,
	startQueueTime: null,
	stopped: false,

    /*
	Function: constructor
		Constructor

	Arguments:
		startQueueTime - Định nghĩa bao nhiêu lâu kể từ khi đếm thời gian thì chạy function queue, tính bằng ms
	*/
	initialize: function(startQueueTime){
		this.startQueueTime = startQueueTime;
	},

    /*
	Function: start
		Bắt đầu đếm thời gian. Hàm này tách biệt khỏi <idle> để có thể xảy ra việc bắt đầu đếm và bắt đầu cho phép chạy function queue là độc lập với nhau
	*/
	start: function(){
		this.stopped = false;
		this.time = $time();
	},

    /*
	Function: idle
		Bắt đầu cho phép chạy function queue
	*/
	idle: function(){
		var time = $time();
		var newArguments = [this.time].extend(arguments);
		if (time > this.time + this.startQueueTime){
			this.complete.run(newArguments);
		}
		else {
			this.complete.delay(
				this.time + this.startQueueTime - time,
				this,
				newArguments
			);
		}
	},

    /*
	Function: stop
		Ngừng cho phép chạy function queue
	*/
	stop: function(willFireEvent){
		if (!isset(willFireEvent)) willFireEvent = true;
		this.stopped = true;
		if (willFireEvent)
			this.fireEvent('stop');
	},

	complete: /* private */ function(){
		if (this.stopped){
			return;
		}

		var lastTime = arguments[0];
		if (this.time != lastTime) return;

		var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);
		this.fireEvent('complete', realArguments);
	},

	reset: function(){
		this.stop(false);
		this.start();
		this.idle();
		this.fireEvent('reset');
	}
});
};filesWrapper['core/LightException.js'] = function(){
	/*
Class: LightException
	Định nghĩa exception sẽ được quăng ra khi có lỗi

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ LightException /* */
= new Class({
	message: null,
	errorCode: null,

	initialize: function(message, errorCode){
		this.message = message;
		this.errorCode = errorCode;
	},

	getMessage: function(){
		return this.message;
	},

	getCode: function(){
		return this.errorCode;
	}
});
};filesWrapper['core/Resources/IconResource.js'] = function(){
	/*
Class: IconResource
	Định nghĩa cho việc lưu trữ một resource icon

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Options:
	url - (string) URL chứa resource
	maps - (array) Mảng map kích thước icon cần lấy thành tọa độ y tương ứng
	defaultSize - (integer) Kích thước mặc định cần lấy nếu khi get không yêu cầu
*/
/* class */ IconResource /**/
= new Class({
	Implements: [Options],

	options: {
		url: null,
		maps: null,
		defaultSize: null
	},

	initialize: function(options){
		this.setOptions(options);
	},

	/*
	Function: get
		Trả về một cấu trúc hoặc element tương ứng với icon yêu cầu

	Arguments:
		index - (integer) Vị trí của icon cần lấy
		size - (integer) Kích thước loại icon cần lấy
		returnElement - (boolean) Trả về element hay trả về cấu trúc, mặc định là true, trả về element
	*/
	get: function(index, size, returnElement){
		if (!isset(size)) size = this.options.defaultSize;
		if (!isset(size)) getErrorConsole().throwError('Không tính được kích thước icon');

		var offsetX = -(index - 1) * size;
		var offsetY = this.options.maps[size];

		if (!isset(returnElement) || returnElement === true){
	        return new Element('div', {
	            'styles': {
					'background-image': "url('" + this.options.url + "')",
					'background-position': offsetX + 'px ' + offsetY + 'px',
					'background-repeat': 'no-repeat',
					'width': size,
					'height': size
				}
			});
		}
		else {
			return {
				url: this.options.url,
				offsetX: offsetX,
				offsetY: offsetY,
				size: size
			};
		}
	}
});
};filesWrapper['core/StaticFunctions.js'] = function(){
	/*
Script: StaticFunctions.js
	File chứa các hàm tĩnh được sử dụng trong hệ thống LightJS

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/*
Function: getErrorConsole
	Hàm định nghĩa một Global Error Console để thông báo lỗi code. Sửa hàm này để thay thế <ErrorConsole> mặc định bằng một console khác

Returns:
	<ErrorConsole>
*/
getErrorConsole = function(){
	loadFile('core/ErrorConsole.js');
    var inst = window.retrieve('ErrorConsole');
	if (!isset(inst)){
		inst = new ErrorConsole();
		window.store('ErrorConsole', inst);
	}
	return inst;
};

/*
Function: getClientStorage
	Hàm định nghĩa và gọi một nơi lưu trữ dữ liệu Client tồn tại trong quá trình window của Browser tồn tại

Returns:
	<GlobalStorage>
*/
getClientStorage = function(){
	loadFile('core/Storages/GlobalStorage.js');
    var inst = window.retrieve('ClientStorage');
	if (!isset(inst)){
		inst = new GlobalStorage();
		window.store('ClientStorage', inst);
	}

	return inst;
};

/*
Function: getTaskManager
	Định nghĩa và gọi một Object quản lý các Process trong hệ thống

Returns:
	<TaskManager>
*/
getTaskManager = function(){
	loadFile('core/TaskManager.js');
    var inst = window.retrieve('TaskManager');
	if (!isset(inst)){
		inst = new TaskManager();
		window.store('TaskManager', inst);
	}

	return inst;
};

/*
Function: getSystemConfig
	Định nghĩa và gọi một Object quản lý các tham số config trong hệ thống

Returns:
	<Registry>
*/
getSystemConfig = function(){
	loadFile('core/Storages/Registry.js');
    var inst = window.retrieve('SystemConfig');
	if (!isset(inst)){
        inst = new Registry();
		window.store('SystemConfig', inst);
	}

	return inst;
};
};filesWrapper['core/Storages/AbstractStorage.js'] = function(){
	/*
Class: AbstractStorage
	Abstract cho một storage là một nơi có thể chứa dữ liệu, chỉ bao gồm hai hàm cơ bản là get và set

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* abstract class */ AbstractStorage /* */
= new Class({
	/*
	Function: set
		Set dữ liệu của một key trong storage

	Arguments:
		path - (string) Key cần set
		value - (mixed) Giá trị cần set cho key
	*/
	set: /*abstract*/ function(path, value){},

	/*
	Function: get
		Lấy dữ liệu của một key trong storage

	Arguments:
		path - (string) Key cần lấy dữ liệu
	*/
	get: /*abstract*/ function(path){},

	/*
	Function: readFromFile
		Lấy dữ liệu config cho một key từ một file có đường dẫn biết trước. Quy định là trong file này phải có một biến ConfigData chứa dữ liệu cần lưu và được set là global

	Arguments:
		key - (string) Key dùng để lưu
		path - (string) Đường dẫn đến file lưu config
	*/
	readFromFile: function(key, path){
		loadFile(path);
		this.set(key, ConfigData);
	}
});
};filesWrapper['core/Storages/ElementStorage.js'] = function(){
	/*
Class: ElementStorage
	Cung cấp phương thức để có thể lưu dữ liệu vào một Element (thường là một form) để dữ liệu này có thể được gửi đi cùng HTTP Request thông thường

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractStorage>

Syntax:
	(start code)
new ElementStorage(element)
	(end)
*/
/* class */ ElementStorage /* extends AbstractStorage */
= new Class({

	Extends: AbstractStorage,
	element: null,

	/*
	Function: constructor

	Arguments:
		el - (element) Đối tượng form element cần dùng để lưu trữ storage
	*/
	initialize: function(el){
		if (!isset(el)){
			getErrorConsole().throwError('Cant create ElementStorage without an element pass into constructor');
		}

		this.element = $(el);
	},

    /*
	Function: set
		Gán một giá trị vào element

	Arguments:
		inputName - (string) Tên của key cần gán
		inputValue - (string) Giá trị cần gán
	*/
    set: function(inputName, inputValue){
    	var inputEl = this.element.getElement('input[name=' + inputName + ']');
        if (!inputEl){
			new Element(
				"input", {
				'type': 'hidden',
				'name': inputName,
				'value': inputValue
			}).injectInside(this.element);
		}
		else {
			inputEl.value = inputValue;
		}
	},

    /*
	Function: get
		Lấy giá trị trong element

	Arguments:
		inputName - (string) Tên của key muốn lấy

	Returns
		- (mixed) Giá trị đang được lưu giữ trong storage của key
	*/
	get: function(inputName){
		var inputEl = this.element.getElement('input[name=' + inputName + ']');
		if (!inputEl){
			return null;
		}
		else {
			return inputEl.value;
		}
	}
});
};filesWrapper['core/Storages/GlobalStorage.js'] = function(){
	/*
Class: GlobalStorage
	Cung cấp nơi chứa dữ liệu mà có thể đọc được trên toàn hệ thống từ lúc bắt đầu khởi động cho đến khi Browser Window được hủy

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractStorage>

Syntax:
	(start code)
new GlobalStorage(prefix)
	(end)
*/
/* class */ GlobalStorage /* extends AbstractStorage */
= new Class({
	Extends: AbstractStorage,
	prefix: 'globalVar',

    /*
	Function: constructor

	Arguments:
		prefix - (string) Key khởi đầu để tránh trùng, có thể dùng để đặt tên cho Storage
	*/
	initialize: function(prefix){
		if (isset(prefix)){
			this.prefix = prefix;
		}
	},

    /*
	Function: set
		Gán giá trị cho key trong storage

	Arguments:
		varName - (string) Tên key
		value - (mixed) Giá trị cần gán
	*/
	set: function(varName, value){
		window.store(this.prefix + varName, value);
	},

    /*
	Function: get
		Trả về giá trị trong storage

	Arguments:
		varName - (string) Tên key
	*/
	get: function(varName){
		return window.retrieve(this.prefix + varName);
	}

});
};filesWrapper['core/Storages/Registry.js'] = function(){
	loadFile('core/Storages/AbstractStorage.js');

/*
Class: Registry
	Registry là một nơi lưu dữ liệu cho phép có thể đọc dữ liệu theo kiểu /Root/Options/ từ một Hash

	Copyright -	nwhite.net

Extends:
	<AbstractStorage>

Syntax:
	(start code)
var registry = new Registry(data);
	(end)

See Also:
	- http://www.nwhite.net/2008/12/04/registry-class-for-mootools/
*/
/* class */ Registry /* extends AbstractStorage imports Events */
= new Class({

	Extends: AbstractStorage,
	Implements : [Events],
	conf : {},

    /*
	Function: constructor

	Arguments:
		data - (Hash) Mảng dữ liệu đầu vào mặc định
	*/
    initialize: function(data){
		if (isset(data)){
			this.conf = data;
		}
	},

    /*
	Function: set
		Gán dữ liệu trong storage

	Arguments:
		path - (string) Có thể gán dữ liệu theo dạng đường dẫn. Ví dụ: /Root/Options/
		value - (mixed) Giá trị cần gán
	*/
	set: function(path, value){
		var fragments = path.split('/');

		if( fragments.shift() !== '') return; // remove empty, first component
		if(fragments.length > 0 && fragments[fragments.length - 1] === '') fragments.pop();

		var obj = {}; var ref = obj; var len = fragments.length;
		if( len > 0){
			for(var i = 0; i < len-1; i++){
				ref[fragments[i]] = {};
				ref = ref[fragments[i]];
			}
			ref[fragments[len-1]] = value;
			this.conf = $merge(this.conf,obj);
		} else {
			this.conf = value;
		}
	},

    /*
	Function: get
		Lấy dữ liệu theo đường dẫn

	Arguments:
		path - (string) Dữ liệu dạng đường dẫn. Ví dụ: /Root/Options
	*/
	get: function(path){
		var fragments = path.split('/');

		if( fragments.shift() !== '') return null;
		if(fragments.length > 0 && fragments[fragments.length -1] === '') fragments.pop();

		var ref = this.conf; var path_exists = true; var i = 0; var len = fragments.length;
		while(path_exists && i < len){
			path_exists = path_exists && (ref[fragments[i]] !== undefined);
			ref = ref[fragments[i]]; i++;
		}

		return ref;
	}
});
};filesWrapper['core/TaskManager.js'] = function(){
	/*
Class: TaskManager
	Chịu trách nhiệm quản lý các tiến trình chạy bên trong framework bằng cách sử dụng các hàng đợi (queue) mà sẽ được chạy khi được yêu cầu. Đặc biệt là được sử dụng nhiều trong AJAX request.

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ TaskManager /* */
= new Class({
	getQueue: function(queueName){
		if (!isset(queueName)){
			queueName = 'afterDomReady';
		}

        var queueArrayName = queueName + 'Processes';
		var lbpEvents = window.retrieve(queueArrayName);
		if (!isset(lbpEvents)){
			lbpEvents = new Array();
		}

		return lbpEvents;
	},

	saveQueue: function(queueName, lbpEvents){
		if (!isset(queueName)){
			queueName = 'afterDomReady';
		}

        var queueArrayName = queueName + 'Processes';
		window.store(queueArrayName, lbpEvents);
	},

    /*
	Function: addProcess
		Thêm một process vào queue có tên yêu cầu

	Arguments:
		process - (function) Process cần được thêm vào
		queueName - (string) Tên của queue mà process cần được add vào
		destroyAfterRun - (boolean) Hủy sau khi chạy một lần
	*/
	addProcess: function(process, queueName, destroyAfterRun){
		var lbpEvents = this.getQueue(queueName);
		lbpEvents.include(process);
		this.saveQueue(queueName, lbpEvents);

		if (destroyAfterRun){
			var trash = this.getQueue(queueName + 'Trash');
			trash.include(process);
			this.saveQueue(queueName + 'Trash', trash);
		}
	},

    /*
	Function: removeProcess
		Xóa một process ra khỏi queue

	Arguments:
		process - (function) Process được yêu cầu remove
		queueName - (string) Tên của queue mà process cần được gỡ khỏi
	*/
	removeProcess: function(process, queueName){
		var lbpEvents = this.getQueue(queueName);
		lbpEvents.erase(process);
		this.saveQueue(queueName, lbpEvents);
	},

    /*
	Function: runProcesses
		Chạy toàn bộ các process đã được add vào queue

	Arguments:
		queueName - (string) Tên của queue cần được chạy
	*/
	runProcesses: function(queueName){
        if (!isset(queueName)){
			queueName = 'afterDomReady';
		}

        var queueArrayName = queueName + 'Processes';
		var lbpEvents = window.retrieve(queueArrayName);
		var trash = this.getQueue(queueName + 'Trash');
		if (isset(lbpEvents)){
			lbpEvents = $A(lbpEvents);
			$each(lbpEvents, function(fn){
				fn.run();
				if (trash.contains(fn)) {
					this.removeProcess(fn, queueName);
					trash.erase(fn);
				}
			}.bind(this));
		}

		this.saveQueue('trash', trash);
	}
});

};filesWrapper['light.Ajax/AjaxFactory.js'] = function(){
	/*
Class: AjaxFactory
	Factory chứa các Object Pool liên quan đến Ajax có thể gọi trong hệ thống. Thông thường AjaxFactory được load vào ngay khi boot nên ở bất cứ đâu ta chỉ cần gọi luôn là được. Các hàm cơ bản của AjaxFactory dưới đây chỉ có ý nghĩa đặt chỗ, sửa đổi nó nếu muốn sử dụng chúng để thực thi các đoạn lệnh, ví dụ như hiển thị dialog báo lỗi...

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	- <AjaxFactory.Lad>, các hàm của AjaxFactory được sử dụng khi gói LAD đã được boot
*/
/* static class */ AjaxFactory /* */
= new Hash({
	/*
	Function: showLoadingDialog
		Hàm đặt chỗ cho việc hiển thị dialog thông báo đang có request loading. Khuyến cáo nên được gọi trong tất cả các hàm nạp chồng hàm onRequest của <Request.Light> để hiển thị dialog mỗi khi gửi request đi
	*/
	showLoadingDialog: $empty,

	/*
	Function: hideLoadingDialog
		Hàm đặt chỗ cho việc tắt dialog thông báo đang có request loading. Khuyến cáo nên được gọi trong tất cả các hàm nạp chồng hàm onSuccess hoặc hàm onFailure của <Request> hoặc các hàm có chức năng tương tự như hai hàm đó
	*/
	hideLoadingDialog: $empty,

	/*
	Function: showRequestBusyDialog
		Hàm đặt chỗ cho việc hiển thị dialog thông báo đang có một request khác thực hiện, không thể gửi thêm một request nữa. Khuyến cáo các Request thừa kế <Request.Light> thực hiện kiểm tra busy và gọi hàm này
	*/
	showRequestBusyDialog: $empty,

	/*
	Function: showRequestFailureDialog
		Hàm đặt chỗ cho việc hiển thị dialog thông báo có lỗi HTTP khi request thực hiện. Khuyến cáp các Request thừa kế <Request.Light> gọi hàm này trong hàm onFailure
	*/
	showRequestFailureDialog: $empty
});
};filesWrapper['light.Ajax/bridge.js'] = function(){
	/*
File: bridge.js
	File khởi động hệ thống của gói LightJS Ajax. Chỉ cần load file này vào, không cần gọi hàm gì cả.

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

loadFile('light.Ajax/AjaxFactory.js');
};filesWrapper['light.Ajax/ButtonPool.js'] = function(){
	loadFile('light.Ajax/ObjectPool.js');

/*
Class: ButtonPool
	Pool chứa các button tham gia vào quá trình gửi request kiểu Light

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<ObjectPool>
*/
/* class */ ButtonPool /* extends ObjectPool */
= new Class({
	Extends: ObjectPool,

	/*
	Function: getRequestCaller
		Trả về caller thực hiện request. Hàm này được nạp chồng của <ObjectPool>

	Arguments:
		button - (element) Button element thực hiện request

	Returns:
		(string) Request caller
	*/
    getRequestCaller: function(button){
    	getErrorConsole().throwError('Phải nạp chồng hàm getRequestCaller của ButtonPool');
	},
	
	pull: function(button){
		button.removeEvents('click');
		this.parent(button);
	}
});
};filesWrapper['light.Ajax/FormPool.js'] = function(){
	loadFile('light.Ajax/ObjectPool.js');

/*
Script: FormPool
	Pool quản lý các form có thể gửi request kiểu Light

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Todo:
	Sửa lại hàm pull để khi uninstall không xóa toàn bộ sự kiện click của các submit button

Extends:
	<ObjectPool>
*/
/* abstract class */ FormPool /* extends ObjectPool */
= new Class({
	Extends: ObjectPool,

    /*
	Function: onSubmitButtonClick
		Hàm thực hiện khi submit button được ấn. Nạp chồng hàm này để thể hiện đặc trưng của Request

	Arguments:
		e - (event) Sự kiện click
		button - (element) Button thực hiện submit
	*/
	onSubmitButtonClick: /* abstract */ function(e, button){
		getErrorConsole().throwError('Phải nạp chồng hàm onSubmitButtonClick của FormPool');
	},

	/*
	Function: getRequestCaller
		Trả về request caller tương ứng với form. Với FormPool, mọi dữ liệu được lưu trong ElementStorage

	Arguments:
		el - (element) Element gửi request

	Returns:
		(string) Caller của request

	See Also:
		<ElementStorage>
	*/
    getRequestCaller: function(form){
        loadFile('core/Storages/ElementStorage.js');
        var formData = new ElementStorage(form);
	    var requestCaller = formData.get('requestcaller');
        requestCaller = HelpersFactory.getTypeHelper().getValueWithDefault(
			requestCaller,
			'ladDefaultCaller'
		);

		return requestCaller;
	},

	push: function(form){
		if (!this.inPool(form)){
			this.parent(form);
			form.getElements('input[type=submit], button[type=submit]').each(function(thisButton){
				thisButton.addEvent('click', function(e){
					this.onSubmitButtonClick(e, thisButton);
				}.bind(this));
			}.bind(this));
		}
	},

	pull: function(form){
        form.getElements('input[type=submit], button[type=submit]').each(function(thisButton){
			thisButton.removeEvents('click');
		}.bind(this));
		this.parent(form);
	}

});
};filesWrapper['light.Ajax/json/Request.Light.Json.js'] = function(){
	loadFile('light.Ajax/Request.Light.js');

/*
Class: Request.Light.Json
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ Request.Light.Json /* extends Request.Light */
= new Class({
	Extends: Request.Light,
	result: null,

	/*
	Function: success
		Hàm chạy khi request thành công, không hề có lỗi
	*/
    success: function(text){
    	try {
    		this.result = JSON.decode(text);
    		this.fireEvent('success', [text]);
		}
		catch(e){
			//console.log(e);
			//this.result = null;
			//getErrorConsole().throwError('Có lỗi trong quá trình giải mã dữ liệu của Request.Light.Json');
		}
	},

	getResult: function(){
		return this.result;
	}
});
};filesWrapper['light.Ajax/lad/AjaxFactory.Lad.js'] = function(){
	loadFile('light.Ajax/AjaxFactory.js');

/*
Class: AjaxFactory.Lad
	Bổ sung các hàm để tương tác với các pool dạng LAD vào AjaxFactory

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	<AjaxFactory>
*/
AjaxFactory.extend({
	/*
	Function: getLadFormPool
		Định nghĩa và gọi một Pool hệ thống quản lý các Form gửi Request kiểu LAD

	Returns:
		- <LadFormPool>

	See Also:
		<Request.Light.Lad>
	*/
	getLadFormPool: function(){
		loadFile('light.Ajax/lad/LadFormPool.js');
	    var inst = window.retrieve('LadFormPool');
		if (!isset(inst)){
			inst = new LadFormPool();
			window.store('LadFormPool', inst);
		}

		return inst;
	},

	/*
	Function: getLadLinkPool
		Định nghĩa và gọi một Pool hệ thống quản lý các Link gửi Request kiểu LAD

	Returns:
		- <LadLinkPool>

	See Also:
		<Request.Light.Lad>
	*/
	getLadLinkPool: function(){
		loadFile('light.Ajax/lad/LadLinkPool.js');
	    var inst = window.retrieve('LadLinkPool');
		if (!isset(inst)){
			inst = new LadLinkPool();
			window.store('LadLinkPool', inst);
		}

		return inst;
	},

	/*
	Function: getLadButtonPool
		Định nghĩa và gọi một Pool hệ thống quản lý các Button gửi Request kiểu LAD

	Returns:
		- <LadButtonPool>

	See Also:
		<Request.Light.Lad>
	*/
	getLadButtonPool: function(){
		loadFile('light.Ajax/lad/LadButtonPool.js');
	    var inst = window.retrieve('LadButtonPool');
		if (!isset(inst)){
			inst = new LadButtonPool();
			window.store('LadButtonPool', inst);
		}

		return inst;
	}
})
};filesWrapper['light.Ajax/lad/bridge.js'] = function(){
	/*
File: bridge.js
	File khởi động hệ thống của gói con LAD trong gói LightJS Ajax. Chỉ cần load file này vào, không cần gọi hàm gì cả.

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/* gói LAD yêu cầu gói ajax đã được boot */
loadFile('light.Ajax/bridge.js');

loadFile('light.Ajax/lad/Element.Light.Ajax.Lad.js');
loadFile('light.Ajax/lad/AjaxFactory.Lad.js');
};filesWrapper['light.Ajax/lad/Element.Light.Ajax.Lad.js'] = function(){
	/*
Class: Element.Light.Ajax.lad
	Kết nối Light và Mootools bằng cách bổ sung hàm vào native class Element

	Author - hitori_vodanh <nhanvc@vsmc.vn>
	Copyright -	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	http://mootools.net/docs/Element/Element.Event
*/
Element.implement({
	/*
	Function: submitLad
		Hàm giả toàn bộ hoạt động submit của một form, nhưng gửi Request.Light.Lad

	See Also:
		<Request.Light.Lad>
	*/
	submitLad: function(){
		if (getClientStorage().get('busyLad')) {
			AjaxFactory.showRequestBusyDialog();
			return;
		}

		if (!AjaxFactory.getLadFormPool().inPool(this)) return this;
		var result = this.tryEvent('submit');
        if (!result) return this;
		else {
			var refreshRate = getSystemConfig().get('/System/G/refreshRate/');
	        var formSubmitDelay = getSystemConfig().get('/System/G/formSubmitDelay');
	        if (isset(refreshRate) && isset(formSubmitDelay)) {
				this.doSubmitLad.delay(
					refreshRate + formSubmitDelay,
					this
				);
				// submit delay nhiều hơn refresh rate để đảm bảo mọi lệnh vẽ
				// trong các event submit được vẽ trước khi submit gửi đi
			}
			else {
				this.doSubmitLad();
			}

			return this;
		}
	},

	doSubmitLad: /* private */ function(){
		var url;
		if (!isset(this.get('action')) || this.get('action') === ''){
			url = window.location;
		}
		else {
			url = this.get('action');
		}

		var requestCaller = AjaxFactory.getLadFormPool().getRequestCaller(this);
		var idleElements = AjaxFactory.getLadFormPool().getIdleElements(this);

		var requestOptions = {
			method: 'post',
			url: url,
			data: this,
			caller: requestCaller,
			idleElements: idleElements
		};

		loadFile('light.Ajax/lad/Request.Light.Lad.js');
		new Request.Light.Lad(requestOptions).send();
		return this;
	},

	/*
	Function: clickSimulate
		Giả hoạt động click của một button hoặc link, nạp chồng lên hàm của <Element.Light>
	*/
	clickSimulate: function(){
		/* hàm này chạy đúng với button[type=submit] cho LadForm
		và với link trong LadLink, vì các sự kiện gửi Request đều đã được bind vào click */
		this.fireEvent('click');

		/* sau đây chúng ta chỉ kiểm tra button[type=submit] không thuộc về LAD */
		if (
			this.get('tag') == 'button' &&
			this.get('type') == 'submit'
		){
			var form = this.getParent('form');
	        if (!isset(form)){
	        	if (isset(this.get('attachform')) && this.get('atachform') !== ''){
					form = $(this.get('attachform'));
				}
			}

			if (isset(form)){
				if (!AjaxFactory.getLadFormPool().inPool(form)){
					form.submitHttp();
				}
			}
		}

		if (this.get('tag') == 'a'){
			if (!AjaxFactory.getLadLinkPool().inPool(this)){
				this.goToHref();
			}
		}
	},

	/*
	Function: goToHrefLad
		Hàm giả toàn bộ hoạt động chạy đến một href của link, nhưng gửi link Light.Lad

	See Also:
		<Request.Light.Lad>
	*/
	goToHrefLad: function(){
		if (getClientStorage().get('busyLad')) {
			AjaxFactory.showRequestBusyDialog();
			return;
		}

		var pool;
		if (this.get('tag') == 'a'){
			pool = AjaxFactory.getLadLinkPool();
		}
		else if (this.get('tag') == 'button'){
			pool = AjaxFactory.getLadButtonPool();
		}

		if (!pool.inPool(this)){
			return this;
		}

		var linkUrl = this.get('href');
		if (!isset(linkUrl) || linkUrl === ''){
			linkUrl = window.location;
		}

		var requestCaller = pool.getRequestCaller(this);
		var idleElements = pool.getIdleElements(this);

		getClientStorage().set('lastLadRequestObject', this);

		var requestOptions = {
			method: 'post',
			url: linkUrl,
			caller: requestCaller,
			idleElements: idleElements
		};

		loadFile('light.Ajax/lad/Request.Light.Lad.js');
	    new Request.Light.Lad(requestOptions).send();
	    return this;
	}
});
};filesWrapper['light.Ajax/lad/LadButtonPool.js'] = function(){
	loadFile('light.Ajax/ButtonPool.js');

/*
Class: LadButtonPool
	Môt tả rõ một pool chứa các button gửi request kiểu Light.Lad. Các element sẽ được đưa về trạng thái chờ khi request gửi đi được lưu trong thuộc tính 'idles' của button, mỗi element ID cách nhau bởi dấu phẩy

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<ButtonPool>

Syntax:
	Một button dạng sau có thể được đưa vào pool
	(start code)
<button href='http://lightjs.vn/test/go/' rev='lightjscaller' idles='alpha,beta' id='simpleButton'>Very Simple</button>
	(end)
*/
/* class */ LadButtonPool /* extends ButtonPool */
= new Class({
	Extends: ButtonPool,

	/*
	Function: getIdleElements
		Hàm trả về các elements sẽ idle khi request gửi đi

	Arguments:
		buttonEl - (element) Element sẽ thực hiện gửi request

	Returns:
		(string) Danh sách các elements sẽ idle, ngăn cách nhau bởi dấu phẩy
	*/
	getIdleElements: function(buttonEl){
		return buttonEl.get('idles');
	},

	/*
	Function: getRequestCaller
		Trả về caller thực hiện request, trong trường hợp này, lấy 'rev' của button

	Arguments:
		button - (element) Button element thực hiện request

	Returns:
		(string) Request caller
	*/
    getRequestCaller: function(button){
    	var requestCaller = button.get('rev');
        requestCaller = HelpersFactory.getTypeHelper().getValueWithDefault(
			requestCaller,
			'ladDefaultCaller'
		);

		return requestCaller;
	},

	/*
	Function: push
		Đưa button vào pool

	Arguments:
		button - (element) Button cần đưa vào pool

	See Also:
		<LightMooConnector.Ajax::goToHrefLad>
	*/
	push: function(button){
		if (!this.inPool(button)){
			this.parent(button);
	        button.addEvent('click', function(e){
	        	if (isset(e)){
					e.preventDefault();
				}

				button.goToHrefLad();
			}.bind(this));
		}
	}
});
};filesWrapper['light.Ajax/lad/LadFormPool.js'] = function(){
	loadFile('light.Ajax/FormPool.js');

/*
Class: LadFormPool
	Quản lý các form gửi request kiểu LAD. Bởi vì form element không biết cách thức lưu trữ dữ liệu đặc biệt của pool nên tất cả các hàm lấy dữ liệu đều phải có ở pool để form element hỏi. Các element sẽ được đưa về trạng thái chờ khi request gửi đi được lưu trong thuộc tính 'idles' của form (Xem <ElementStorage>), mỗi element ID cách nhau bởi dấu phẩy

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	<Request.Light.Lad>

Extends:
	<FormPool>

Syntax:
	Một form dạng như sau có thể được đưa vào Pool
	(start code)
<form class='lbp' action='http://lightjs.vn/test/do/'>
	<input type='hidden' name='idles' value='alpha,beta'>
	<button type='submit'>Submit</button>
</form>
	(end)
*/
/* class */ LadFormPool /* extends FormPool */
= new Class({
	Extends: FormPool,

	/*
	Function: onSubmitButtonClick
		Hàm thực hiện khi submit button được ấn. Sẽ cố gắng lấy form là parent của button hoặc lấy thuộc tính 'attachform' của button là id của form

	Arguments:
		e - (event) Sự kiện click
		button - (element) Button thực hiện submit

	See Also:
		<LightMooConnector.Ajax>, <Element::submitLad>
	*/
    onSubmitButtonClick: /* protected */ function(e, button){
    	if (isset(e)) e.preventDefault();
		var form = button.getParent('form');
        if (!isset(form)) form = $(button.get('attachform'));

        loadFile('core/Storages/ElementStorage.js');
		var formData = new ElementStorage(form);
		formData.set('clickedname', button.name);
		formData.set('clickedid', button.id);

        /*
		*	lưu lại object gửi lad request cuối cùng
		*/
		getClientStorage().set('lastLadRequestObject', button);
		form.submitLad();
	},

	getIdleElements: function(formEl){
		var formData = new ElementStorage(formEl);
		var idleElements = formData.get('idles');
		return idleElements;
	}
});
};filesWrapper['light.Ajax/lad/LadLinkPool.js'] = function(){
	loadFile('light.Ajax/LinkPool.js');

/*
Script: LadLinkPool
	Mô tả rõ một pool tái quản lý các đối tượng link (có thẻ a), gửi request kiểu Light.LAD chứ không phải request kiểu HTTP. Các element sẽ được đưa về trạng thái chờ khi request gửi đi được lưu trong thuộc tính 'idles' của link, mỗi element ID cách nhau bởi dấu phẩy

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	<Request.Light.Lad>

Extends:
	<LinkPool>

Syntax:
	Một link dạng như sau có thể được đưa vào Pool
	(start code)
<a href='http://lightjs.vn/test/go/' rev='lightjscaller' idles='alpha,beta' id='simpleLink'>Very Simple Link</a>
	(end)
*/
/* class */ LadLinkPool /* extends LinkPool */
= new Class({
	Extends: LinkPool,

	/*
	Function: getIdleElements
		Hàm trả về các elements sẽ idle khi request gửi đi

	Arguments:
		linkEl - (element) Element sẽ thực hiện gửi request

	Returns:
		(string) Danh sách các elements sẽ idle, ngăn cách nhau bởi dấu phẩy
	*/
	getIdleElements: function(linkEl){
		return linkEl.get('idles');
	},

	/*
	Function: getRequestCaller
		Trả về caller thực hiện request, trong trường hợp này, ta lấy từ giá trị 'rev' của link

	Arguments:
		link - (element) Link element thực hiện request

	Returns:
		(string) Request caller
	*/
    getRequestCaller: function(link){
    	var requestCaller = link.get('rev');
        requestCaller = HelpersFactory.getTypeHelper().getValueWithDefault(
			requestCaller,
			'ladDefaultCaller'
		);

		return requestCaller;
	},

	/*
	Function: push
		Đưa link vào pool

	Arguments:
		link - (element) Link cần đưa vào pool

	See Also:
		<LightMooConnector.Ajax::goToHrefLad>
	*/
	push: function(link){
		if (!this.inPool(link)){
			this.parent(link);
	        link.addEvent('click', function(e){
	        	if (isset(e)) e.preventDefault();
				link.goToHrefLad();
			}.bind(this));
		}
	}
});
};filesWrapper['light.Ajax/lad/Request.Light.Lad.js'] = function(){
	loadFile('light.Ajax/Request.Light.js');

/*
Class: Request.Light.Lad
	Định nghĩa cách thức gửi và nhận dữ liệu trả về của một Request kiểu Light.Lad. Đặc trưng của request này bao gồm việc nhận dữ liệu ở dạng LAD và decode, đồng thời, ngay trước khi gửi request đi, các element được tính là idles (được truyền vào khi khởi tạo Request), sẽ bị đưa về trạng thái chờ, sử dụng hàm <setElementWaiting>. Sau khi request hoàn thành (success hoặc fail), các element này lại bị đưa về như cũ, sử dụng hàm <unsetElementWaiting>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<Request.Light>

Syntax:
	(start code)
var myRequest = new Request.Light.Lad([options]);
	(end)

Options:
	caller - (string) Lưu giữ tên định nghĩa cho trang sẽ gửi request đi
	idleElements - (string) Xâu lưu trữ các ID của các element sẽ bị đưa về chế độ chờ
*/
/* class */ Request.Light.Lad /* extends Request.Light */
= new Class({
	Extends: Request.Light,
	options: {
		data: new Hash({
			'requesttype': 'lad'
		}),
		duration: 500
	},
	timer: null,
	htmlBackup: new Hash(),

	/*
	Function: setBackupData
		Lưu trữ dữ liệu cũ của các element được set là idle khi ajax loading

	Arguments:
		id - (string) ID của element bị set ở chế độ chờ
		backupData - (mixed) Dữ liệu cũ cần lưu
	*/
	setBackupData: function(id, backupData){
		this.htmlBackup[id] = backupData;
	},

	/*
	Function: setElementWaiting
		Đưa một element về chế độ chờ

	Arguments:
		el - (element) Element cần set về chế độ idle
	*/
	setElementWaiting: function(el){
		var id = el.get('id');
		this.setBackupData(id, el.get('html'));
		var elHeight = el.getSize().y
		el.setStyle('height', elHeight);
		el.set('html', '');
		var loadingEl = new Element('div', {
			'class': 'ajax-loading'
		});
		if (elHeight < 300)
			loadingEl.setStyle('margin-top', Math.round(elHeight / 4));
		else
			loadingEl.setStyle('margin-top', 100);

		el.grab(loadingEl);
	},

	/*
	Function: unsetElementWaiting
		Ngừng chế độ chờ của một element

	Arguments:
		el - (element) Element cần bỏ chế độ chờ
		backupData - (mixed) Dữ liệu đã lưu trữ backup của element đó
		isModified - (boolean) Dữ liệu đánh dấu xem element có bị sửa chữa trong quá trình decode LAD không
	*/
	unsetElementWaiting: function(el, backupData, isModified){
		var html = backupData;
		el.getElement('.ajax-loading').destroy();
		el.setStyle('height', null);
		if (!isModified) el.set('html', html);
	},

	/*
	Function: onRequest
		Hàm nạp chồng của <Request.Light>. Chạy khi request bắt đầu được thực hiện
	*/
	onRequest: function(){
		getClientStorage().set('busyLad', true); // sử dụng busy
		AjaxFactory.showLoadingDialog();

		var idleElements = this.options.idleElements;
		if (isset(idleElements)){
			var ids = idleElements.split(',');
			ids.each(function(id){
				var el = $(id);
				if (isset(el)) this.setElementWaiting(el);
			}.bind(this));

			loadFile('core/IdleTimer.js');
			this.timer = new IdleTimer(this.options.duration);
			this.timer.start();
		}

		this.parent();
	},

	/*
	Function: finishRequest
		Hàm được chạy khi request thực sự kết thúc, tức là sau khi đã chạy toàn bộ dữ liệu LAD
	*/
	finishRequest: function(){
		if (typeof pageTracker != 'undefined') {
			pageTracker._setAllowLinker(true);
			pageTracker._setDomainName(getSystemConfig().get('/System/cookieDomain'));
			pageTracker._trackPageview(window.location.pathname + '?ajaxto=' + this.options.url);
			//console.log('notified GA as ', window.location.pathname + '?ajaxto=' + this.options.url);
		}

		/*
    	*	bổ sung các hàm gọi TaskManager ở đây
    	*/
    	getTaskManager().runProcesses('afterLadExecute');
    	getTaskManager().runProcesses('finishLadExecute');
    	getTaskManager().runProcesses('domModified');
	},

	/*
	Function: completeRequest
		Hàm nạp chồng của lớp Request mặc định của mootools
	*/
	completeRequest: function(text, xml){
        var decodedData = HelpersFactory.getLadHelper().decode(text);
        var modifiedElementIds = HelpersFactory.getLadHelper().getModifiedElementIds(decodedData);
        /* ở đây, chúng ta chỉ unsetWaiting với các element sẽ không bị modified mà thôi */
        this.htmlBackup.each(function(backupData, id){
        	var isModified = true;
        	if (modifiedElementIds.indexOf(id) == -1) isModified = false;
    		var el = $(id);
    		if (isset(el)) this.unsetElementWaiting(el, backupData, isModified);
    	}.bind(this));

    	HelpersFactory.getLadHelper().execute(decodedData);
		this.finishRequest();

		AjaxFactory.hideLoadingDialog();
		getClientStorage().set('busyLad', false); // chỉ tắt khi thực sự kết thúc hoặc fail
	},

	onFailure: function(xhr){
		this.htmlBackup.each(function(backupData, id){
    		var el = $(id);
    		if (isset(el)) this.unsetElementWaiting(el, backupData, false);
    	}.bind(this));

    	AjaxFactory.hideLoadingDialog();
    	AjaxFactory.showRequestFailureDialog();
		getClientStorage().set('busyLad', false); // chỉ tắt khi thực sự kết thúc hoặc fail
	},

    /*
	Function: send
		Hàm nạp chồng của <Request.Light> để bổ sung request caller vào dữ liệu gửi đi
	*/
	send: function(options){
		if ($type(this.options.data) == 'element'){
			var formData = new ElementStorage(this.options.data);
			formData.set('requesttype', 'lad');
			formData.set('requestcaller', this.options.caller);
		}
		else {
			this.options.data['requestcaller'] = this.options.caller;
			this.options.data['requesttype'] = 'lad';
		}

		this.parent(options);
	},

    /*
	Function: success
		Hàm chạy khi request thành công, không hề có lỗi
	*/
    success: function(text, xml){
    	if (isset(this.timer)){
    		this.timer.addEvent('complete', function(){
    			this.completeRequest.run(arguments, this);
    		}.bind(this));

    		this.timer.idle(text,xml);
		}
		else {
			this.completeRequest(text, xml);
		}

		this.parent(text, xml);
	}
});
};filesWrapper['light.Ajax/LinkPool.js'] = function(){
	/*
Script: LinkPool
	Định nghĩa một pool chuyên quản lý các đối tượng kiểu link (có thẻ a) và gửi request kiểu Light

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<ObjectPool>
*/
loadFile('light.Ajax/ObjectPool.js');
/* abstract class */ LinkPool /* extends ObjectPool */
= new Class({
	Extends: ObjectPool,

	/*
	Function: getRequestCaller
		trả về caller thực hiện request

	Arguments:
		link - (element) Link element thực hiện request

	Returns:
		(string) Request caller
	*/
    getRequestCaller: function(link){
    	getErrorConsole().throwError('Phải nạp chồng hàm getRequestCaller của LinkPool');
	},

	pull: function(link){
		link.removeEvents('click');
		this.parent(link);
	}
});
};filesWrapper['light.Ajax/ObjectPool.js'] = function(){
	/*
Class: ObjectPool
	Định nghĩa một pool dùng để lưu trữ các element có khả năng gửi request kiểu Light. Cung cấp các hàm đưa một element vào pool và gỡ nó ra khỏi pool. Việc element gửi request như thế nào được hỗ trợ trong hàm <push>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ ObjectPool /**/
= new Class({
    /*
	Function: inPool
		Trả về xem element yêu cầu có phải là nằm trong Pool hay không

	Arguments:
		el - (element,string) Element được yêu cầu kiểm tra

	Returns:
		(boolean) Element nằm trong Pool hay không
	*/
	inPool: function(el){
		el = $(el);
        var bl = el.retrieve('managedByLight');
        if (!isset(bl)){
			return false;
		}
		return bl;
	},

	/*
	Function: getRequestCaller
		Trả về caller tương ứng với request

	Arguments:
		el - (element) Element gửi request

	Returns:
		(string) Caller của request
	*/
	getRequestCaller: /* abstract */ function(el){
		getErrorConsole().throwError('Pool phải nạp chồng hàm getRequestCaller này');
	},

    /*
	Function: push
		Đưa một element vào trong Pool

	Arguments:
		el - (element,string) Element được yêu cầu vào Pool
	*/
	push: function(el){
		el = $(el);
		el.store('managedByLight', true);
	},

    /*
	Function: pull
		Xóa một đối tượng ra khỏi Pool

	Arguments:
		el - (element,string) Đối tượng cần xóa
	*/
	pull: function(el){
		el = $(el);
        el.store('managedByLight', false);
	}

});
};filesWrapper['light.Ajax/Request.Light.js'] = function(){
	/*
Class: Request.Light
	Class định nghĩa cách thức gửi và nhận dữ liệu trả về của một Request kiểu Light. Nạp chồng Request mặc định của mootools

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	- http://mootools.net/docs/core/Request/Request#Request

Syntax:
	(start code)
new Request.Light([options]);
	(end)

Options:
	- http://mootools.net/docs/core/Request/Request#Request
	async - Giá trị mặc định được nạp chồng để thành false
	autoCancel - Giá trị mặc định được nạp chồng để thành true
*/
/* class */ Request.Light /* extends Request */
= new Class({
	Extends: Request,
	options: {
        async: false,
		autoCancel: true
	},

    /*
	Function: onRequest
		Hàm này được Light thêm vào để chạy ngay trước khi request được gửi đi. Nạp chồng hàm này để tạo đặc trưng cho Request
	*/
	onRequest: function(){
		this.fireEvent('request');
	},

    /*
	Function: send
		Light nạp chồng hàm này của Request (Moo Class) để có thể có thêm hàm onRequest
	*/
    send: function(options){
		if (!this.check(arguments.callee, options)) return this;
		this.running = true;

		var type = $type(options);
		if (type == 'string' || type == 'element') options = {data: options};

		var old = this.options;
		options = $extend({data: old.data, url: old.url, method: old.method}, options);
		var data = options.data, url = options.url, method = options.method;

		switch ($type(data)){
			case 'element': data = $(data).toQueryString(); break;
			case 'object': case 'hash': default: data = Hash.toQueryString(data); break;
		}

		if (this.options.format){
			var format = 'format=' + this.options.format;
			data = (data) ? format + '&' + data : format;
		}

		if (this.options.emulation && ['put', 'delete'].contains(method)){
			var _method = '_method=' + method;
			data = (data) ? _method + '&' + data : _method;
			method = 'post';
		}

		if (this.options.urlEncoded && method == 'post'){
			var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
			this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding);
		}

		if (data && method == 'get'){
			url = url + (url.contains('?') ? '&' : '?') + data;
			data = null;
		}

		this.xhr.open(method.toUpperCase(), url, this.options.async);

		this.xhr.onreadystatechange = this.onStateChange.bind(this);

		this.headers.each(function(value, key){
			try {
				this.xhr.setRequestHeader(key, value);
			} catch (e){
				this.fireEvent('exception', [key, value]);
			}
		}, this);

        /**
		*	modify this so that we can have a function that is implementable
		*/
		this.onRequest();

		this.xhr.send(data);
		if (!this.options.async) this.onStateChange();
		return this;
	}
});
};filesWrapper['light.G/bridge.js'] = function(){
	loadFile('light.G/Element.Light.G.js');
loadFile('light.G/GFactory.js');

/*
Function: installGraphics
	Cài đặt hệ thống graphics cho bộ Light.G
*/
installGraphics = function(){
	loadFile('light.G/WindowX.js');
	var windowX = new WindowX();
	getClientStorage().set('windowX', windowX);

	var wdFunctions = new Hash({
		'blur': function(e){
			windowX.fireEvent('blur', [e]);
		}.bind(this),
		'focus': function(e){
			windowX.fireEvent('focus', [e]);
		}.bind(this),
        'load': function(e){
            windowX.fireEvent('load', [e]);
		}.bind(this),
        'resize': function(e){
        	var lastWidth = getClientStorage().get('lastWidth');
			var lastHeight = getClientStorage().get('lastHeight');
			var docSize = document.getSize();
			var docWidth = docSize.x;
			var docHeight = docSize.y;
			if (lastWidth != docWidth || lastHeight != docHeight){
				/* bổ sung để quản lý kích thước màn hình và vị trí chuột */
				GFactory.getScreen().saveResolution(); // để nhờ vào đây

            	windowX.fireEvent('resize', [e]);
            	getClientStorage().set('lastWidth', docWidth);
				getClientStorage().set('lastHeight', docHeight);
			}
		}.bind(this),
        'scroll': function(e){
            windowX.fireEvent('scroll', [e]);
		}.bind(this),
        'beforeunload': function(e){
            windowX.fireEvent('beforeunload', [e]);
		}.bind(this),
	    'unload': function(e){
	        windowX.fireEvent('unload', [e]);
		}.bind(this)
	});

	wdFunctions.each(function(value, key){
		window.addEvent(key, value);
	});

	/*document.addEvent('mousemove', function(e){
		GFactory.getScreen().saveMousePosition(e);
	});*/
}


GFactory.getResourceManager().installTheme('Basic', 'light.G/resources/themes/Basic.js');
getSystemConfig().readFromFile('/System/G', 'light.G/DefaultConfig.js');
installGraphics();
};filesWrapper['light.G/Comm/DefaultComboBoxListCellRenderer.js'] = function(){
	/*
Class: DefaultComboBoxListCellRenderer
	Có nhiệm vụ tạo dựng một component trong một list

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	<GList>
*/
/* static class */ DefaultComboBoxListCellRenderer /* implements ListCellRenderer */
= new Hash({
	getComponent: function(/*AbstractList*/ list, item, index, isSelected, cellHasFocus){
		loadFile('light.G/Components/GLabel.js');
		if ($type(item) == 'string'){
			var cell = new GLabel({
				text: item,
				themePath: 	'/Basic/List/ListRow/'
			});
		}
		else if ($type(item) == 'object'){
            var cell = new GLabel({
				text: item.text,
				themePath: 	'/Basic/List/ListRow/',
				baseCss: item.baseCss
			});
		}

		loadFile('light.G/Skin/Basic/BasicLabelView.js');
		cell.setView(new BasicLabelView.FullState());
		cell.setIndex(index);
		cell.setSelected(isSelected);
		return cell;
	}
});
};filesWrapper['light.G/Comm/DefaultComboBoxPopupRenderer.js'] = function(){
	/*
Class: DefaultComboBoxPopupRenderer
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ DefaultComboBoxPopupRenderer /* implements LayoutRenderer */
= new Hash({
	getComponent: function(c){
		loadFile('light.G/Components/GPopupMenu.js');
		if (isset(c.getOption('baseCss')))
			return new GPopupMenu({
				baseCss: c.getOption('baseCss') + '-popup'
			});
		else
			return new GPopupMenu();
	}
});
};filesWrapper['light.G/Comm/DefaultListCellRenderer.js'] = function(){
	/*
Class: DefaultListCellRenderer
	Có nhiệm vụ tạo dựng một component trong một list

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	<GList>

Todo:
	Làm hiệu ứng click ở item này rồi nhả ra ở item khác thì vẫn select
*/
/* static class */ DefaultListCellRenderer /* implements ListCellRenderer */
= new Hash({
	getComponent: function(/*AbstractList*/ list, item, index, isSelected, cellHasFocus){
		loadFile('light.G/Components/GLabel.js');
		if ($type(item) == 'string'){
			//console.log(item);
			var cell = new GLabel({
				text: item,
				themePath: 	'/Basic/List/ListRow/'
			});
		}
		else if ($type(item) == 'object'){
            var cell = new GLabel({
				text: item.text,
				themePath: 	'/Basic/List/ListRow/',
				baseCss: item.baseCss
			});
		}

		cell.setIndex(index);
		cell.setSelected(isSelected);
		loadFile('light.G/Skin/Basic/BasicLabelView.js');
		cell.setView(new BasicLabelView.FullState());
		return cell;
	}
});
};filesWrapper['light.G/Comm/DefaultTableCellRenderer.js'] = function(){
	/*
Class: DefaultTableCellRenderer
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ DefaultTableCellRenderer /* implements TableCellRenderer */
= new Hash({
	getComponent: function(row, data, index){
		var cell = new DefaultTableCell({
			text: data
		});

		cell.setIndex(index);

		return cell;
	}
});

/*
Class: DefaultTableCell
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ DefaultTableCell /* extends AbstractSelectable */
= new Class({
	Extends: AbstractSelectable,
	initialize: function(options){
		this.setModel(new DefaultTableCell.Model);
		this.setOptions(options);
	},

	createDefaultView: function(){
		return new DefaultTableCell.View();
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	}
});

loadFile('light.G/Model/AbstractSelectableModel.js');
/* class */ DefaultTableCell.Model /* extends AbstractSelectableModel */
= new Class({
	Extends: AbstractSelectableModel
});

loadFile('light.G/Skin/ComponentView.js');
/* class */ DefaultTableCell.View /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: 	'/Basic/Table/Cell/',

	paint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), ['inject']);
		this.paintBorder();
		this.paintInside();
		GFactory.getPaint().draw(this.getElement(),this.getComponent().getGraphicsContext(),null,['inject']);
		this.saveState();
	},

	repaint: function(){
		this.paintBorder();
		GFactory.getPaint().draw(this.getElement(),this.getComponent().getGraphicsContext(),null,['inject']);
		this.saveState();
	},

	paintBorder: function(){
		var c = this.getComponent();
        this.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));
    	this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());
	},

	paintInside: function(){
		var c = this.getComponent();
		var text = c.getOption('text');
		loadFile('light.G/Components/GLabel.js');
		var label = new GLabel({
			text: text
		});
		c.add(label);
	},

	createDomElement: function(){
		this.domElement = new Element('td');
		this.getComponent().attachWithElement(this.domElement);
	},

	getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement(),
				'position': 'bottom'
			}
		});
	}
});

};filesWrapper['light.G/Comm/DefaultTableRowRenderer.js'] = function(){
	/*
Class: DefaultTableRowRenderer
	Description cho class

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ DefaultTableRowRenderer /* implements TableRowRenderer */
= new Hash({
	getComponent: function(table, data, index, isSelected){
		var row = new DefaultTableRow(null, data);
		row.setIndex(index);
		row.setSelected(isSelected);
		return row;
	}
});

loadFile('light.G/Components/AbstractSelectable.js');
/*
Class: DefaultTableRow
	Table row được tạo ra khi <GTable> có nhu cầu vẽ một dòng trong bảng, dữ liệu truyền vào cho table row để vẽ chính là dữ liệu của dòng đó trong dữ liệu của bảng

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Todo:
	Suy nghĩ thêm về việc một row có phải một list không? Khi cell được select, ta thông báo gì cho row?? Có cần không? Hay là vì row đã thông báo cho table rồi và ta chỉ dừng ở cấp này

Rules:
	Model phải implements ListModel và SelectableModel
*/
/* class */ DefaultTableRow /* extends AbstractSelectable */
= new Class({
	Extends: AbstractSelectable,
	initialize: function(options, input){
		if ($type(input) == 'array'){
			this.setModel(new DefaultTableRow.Model(input));
		}
		else if ($type(input) == 'object'){
			this.setModel(input);
		}
		else if (!isset(input)){
			getErrorConsole().throwError('Không thể tạo được một table row nếu không có dữ liệu đầu vào');
		}

		this.setOptions(options);
	},

	createDefaultView: function(){
		return new DefaultTableRow.View();
	},

	getCellRenderer: function(){
		return this.getOption('cellRenderer');
	},

	setCellRenderer: function(renderer){
		this.setOption('cellRenderer', renderer);
	},

	getAllData: function(){
		return this.getModel().getAllData();
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	},

	getHandler: function(){
		return this.getView().getHandler();
	}
});

loadFile('light.G/Model/AbstractSelectableModel.js');
/* class */ DefaultTableRow.Model /* extends AbstractSelectableModel implements ListModel, SelectableModel */
= new Class({
	Extends: AbstractSelectableModel,
	data: null,

	options: {
		createHandler: true
	},

	initialize: function(data){
		this.data = data;
	},

	getAllData: function(){
		return this.data;
	}
});

loadFile('light.G/Skin/ComponentView.js');
/* class */ DefaultTableRow.View /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: 	'/Basic/Table/Row/',
	handler: null,

	paint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), ['inject']);
    	this.paintBorder();
    	this.paintInside();
        if (this.getComponent().isEnabled()){
    		this.paintState();
		}
		GFactory.getPaint().draw(this.getElement(),this.getComponent().getGraphicsContext(),null,['inject']);
		this.saveState();
	},

	repaint: function(){
        this.paintBorder();
        if (this.getComponent().isEnabled()){
    		this.paintState();
		}

		GFactory.getPaint().draw(this.getElement(),this.getComponent().getGraphicsContext(),null,['inject']);
    	this.saveState();
	},

	paintBorder: function(){
		var c = this.getComponent();
        this.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));
    	this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());
	},

	paintInside: function(){
		var c = this.getComponent();

		if (c.getOption('createHandler')) {
			loadFile('light.G/Components/GDomElement.js');
			this.handler = new GDomElement(null, new Element('div', {
				'class': 'slash-dot'
			}));
			var cell = new GDomElement(null, new Element('td'));
			cell.add(this.handler);
			c.add(cell);
		}

    	var data = c.getAllData();
    	data.each(function(item, index){
    		this.paintCell(item, index);
    	}.bind(this));
	},

	paintCell: function(item, index){
		var c = this.getComponent();
		var renderer = c.getCellRenderer();
		if (!isset(renderer)){
			loadFile('light.G/Comm/DefaultTableCellRenderer.js');
			renderer = DefaultTableCellRenderer;
		}

		cell = renderer.getComponent(c, item, index);
		c.add(cell);
	},

	paintState: function(){
		var c = this.getComponent();
        var classFlag = HelpersFactory.getTypeHelper().getFlagString([
        	c.isSelected(),
        	c.isPressed(),
        	c.isArmed()
        ]);

        var classesConfig = new Hash({
    		'011':	this.getTheme('armedPressed'),
    		'010':	'',
    		'001':	this.getTheme('armed'),
    		'000':	'',
    		'111':	this.getTheme('selectedArmedPressed'),
    		'110':	'',
    		'101':	this.getTheme('selectedArmed'),
    		'100':	this.getTheme('selected')
		});

		classesConfig.each(function(value){
			c.getElement().removeClass(value);
		}.bind(this));

		c.getElement().addClass(classesConfig[classFlag]);
	},

	createDomElement: function(){
		this.domElement = new Element('tr');
		this.getComponent().attachWithElement(this.domElement);
	},

	getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement(),
				'position': 'bottom'
			}
		});
	},

	install: function(){
		this.parent();
        var c = this.getComponent();
		this.returnFncs['mouse'] = c.addMouseListener(DefaultTableRow.View.Listener);
		this.returnFncs['mouseMotion'] = c.addMouseMotionListener(DefaultTableRow.View.Listener);
		this.returnFncs['change'] = c.addChangeListener(DefaultTableRow.View.Listener);
	},

	uninstall: function(){
        var c = this.getComponent();
        c.removeMouseListener(this.returnFncs['mouse']);
        c.removeMouseMotionListener(this.returnFncs['mouseMotion']);
		c.removeChangeListener(this.returnFncs['change']);
		this.parent();
	},

	getHandler: function(){
		return this.handler;
	}
});

/* class */ DefaultTableRow.View.Listener /* implements ChangeListener, MouseListener, MouseMotionListener */
= new Hash({
    stateChanged: function(row){
    	row.repaint();
	},

    mouseDown: function(e, row){
    	if (row.isEnabled()){
    		row.setPressed(true);
		}
	},

	mouseUp: function(e, row){
		if (row.isEnabled()){
			row.setPressed(false);
		}
	},

	singleClick: $empty,
    doubleClick: $empty,

    mouseEnter: function(e, row){
    	if (row.isEnabled()){
    		row.setArmed(true);
		}
	},

	mouseLeave: function(e, row){
		if (row.isEnabled()){
			row.setArmed(false);
		}
	},

	mouseOver: $empty,
	mouseOut: $empty
});
};filesWrapper['light.G/Comm/DefaultTextFieldOverTextRenderer.js'] = function(){
	/*
Class: DefaultTextFieldOverTextRenderer
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/* static class */ DefaultTextFieldOverTextRenderer/* implements TextFieldOverTextRenderer */
= new Hash({
	getComponent: function(textField, overText, graphicsContext){
		var overText = new DefaultTextFieldOverText({
			text: overText
		});
		overText.setGraphicsContext(graphicsContext);
		overText.paint();
		overText.addMouseListener(DefaultTextFieldOverText.Listener, textField);
		return overText;
	}
});

loadFile('light.G/Components/AbstractLayer.js');
/*
Class: DefaultTextFieldOverText
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ DefaultTextFieldOverText /* extends AbstractLayer */
= new Class({
	Extends: AbstractLayer,

	initialize: function(options){
    	loadFile('light.G/Model/DefaultLayerModel.js');
		this.setModel(new DefaultLayerModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new DefaultTextFieldOverText.View();
	},

	show: function(){
		this.getElement().show();
	},

	hide: function(){
		this.getElement().hide();
	}
});

loadFile('light.G/Skin/Basic/BasicTooltipView.js');
/* class */ DefaultTextFieldOverText.View /* */
= new Class({
	Extends: BasicTooltipView,
	themePath: '/Basic/OverText/',
	paintLayer: $empty
});

/* class */ DefaultTextFieldOverText.Listener /* implements MouseListener */
= new Hash({
	mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, overText, textField){
    	overText.hide();
    	textField.grabFocus();
	},

    doubleClick: $empty
});
};filesWrapper['light.G/ComponentManager.js'] = function(){
	/*
Class: ComponentManager
	Quản lý các component có trong hệ thống Light.G, như component nào đang được focus, component nào đang được press

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ ComponentManager /* */
= new Class({
	lastFocusComponent: null,
	lastPressedComponent: null,
	lastActivatedComponent: null,
	lastActivatedWindow: null,

	getLastActivatedWindow: function(){
		return this.lastActivatedWindow;
	},

	setLastActivatedWindow: function(c){
		this.lastActivatedWindow = c;
	},

	getLastFocusComponent: function(){
		return this.lastFocusComponent;
	},

	setLastFocusComponent: function(c){
		this.lastFocusComponent = c;
	},

	getLastPressedComponent: function(){
		return this.lastPressedComponent;
	},

	setLastPressedComponent: function(c){
		this.lastPressedComponent = c;
	},

	resetFocus: function(c){
		c.setFocus(false);
		this.setLastFocusComponent(null);
	},

	makeFocus: function(c){
		var lastFocusComponent = this.getLastFocusComponent();
		if (lastFocusComponent == c) return;
		if (isset(lastFocusComponent)){
			var exceptionsList = $A(['GTextField']);
			var className = lastFocusComponent.getClassName();
			if (exceptionsList.indexOf(className) == -1){
				lastFocusComponent.setFocus(false);
			}
		}

		c.setFocus(true);
		this.setLastFocusComponent(c);

		var pc;

		if (c.isWindow()) {
			this.deActivateLastWindow();
			c.setActivated(true);
			this.setLastActivatedWindow(c);
			return;
		}

		/* nếu không phải là window thì travel lên đến khi tìm thấy window hoặc null thì thôi */
		while(true){
			pc = c.getParentComponent();
			if (!isset(pc) || pc.isWindow()) break;
			c = pc;
		}

		if (isset(pc)) {
			// nếu tìm thấy window trong quá trình travel
			pc.setActivated(true);
			this.setLastActivatedWindow(pc);
		}

		// không tìm thấy thì không cần làm gì cả
	},

	deActivateLastWindow: function(){
		var lastActivatedWindow = this.getLastActivatedWindow();
		if (isset(lastActivatedWindow))
			lastActivatedWindow.setActivated(false);
	}
});
};filesWrapper['light.G/Components/AbstractButton.js'] = function(){
	loadFile('light.G/Components/AbstractSelectable.js');

/*
Class: AbstractButton
	Lớp mô tả sơ bộ cho một button

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractSelectable>

Direct Known Subclasses:
	<GButton>, <GToggleButton>

See Also:
	<DefaultButtonModel>
*/
/* class */ AbstractButton /* extends AbstractSelectable */
= new Class({
	Extends: AbstractSelectable,

    initialize: function(options){
    	loadFile('light.G/Model/DefaultButtonModel.js');
		this.setModel(new DefaultButtonModel());
		this.setOptions(options);
	},

	/*
	Function: setButtonGroup
		Đặt button gia nhập một button group, chỉ có tác dụng với các button có khả năng toggle

	Arguments:
		buttonGroup - (<ButtonGroup>) Instance của một button group
	*/
    setButtonGroup: function(buttonGroup){
    	this.getModel().setButtonGroup(buttonGroup);
    },

    /*
    Function: getButtonGroup
    	Trả về button group mà button thuộc về

    Returns:
    	(<ButtonGroup>) Button group mà button thuộc về, null nếu không có
    */
    getButtonGroup: function(){
    	return this.getModel().getButtonGroup();
    },

	/*
	Function: getText
		Trả về text của button

	Returns:
		(string) Text trên button
	*/
    getText: function(){
		return this.getModel().getOption('text');
	},

	/*
	Function: setText
		Đặt text cho button

	Arguments:
		newValue - (string) Text cần đặt mới cho button
	*/
	setText: function(newValue){
		this.getModel().setOption('text', newValue);
	}
});
};filesWrapper['light.G/Components/AbstractColorPicker.js'] = function(){
	loadFile('light.G/Components/AbstractButton.js');
/*
Class: AbstractColorPicker
	Lớp mô tả của một component có khả năng lưu trữ mầu sắc và thông báo sự thay đổi của nó

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractButton>
*/
//TODO:	Xem lại kiến trúc của cái này và tất cả những component liên quan
/* class */ AbstractColorPicker /* extends AbstractButton */
= new Class({
	Extends: AbstractButton,

    getColor: function(){
		return this.getModel().getColor();
	},

	setColor: function(color){
		this.getModel().setColor(color);
	},

	addColorChangeListener: function(colorChangeListenerHash, rootComponent){
		this.getModel().addColorChangeListener(colorChangeListenerHash, rootComponent);
	},

	removeColorChangeListener: function(returnFncs){
		this.getModel().removeColorChangeListener(returnFncs);
	}
});
};filesWrapper['light.G/Components/AbstractLayer.js'] = function(){
	/*
Class: AbstractLayer
	Lớp abstract thể hiện mô tả cho tất cả các component có khả năng xuất hiện 3D, như popup menu, window, tooltip, balloon...

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<GComponent>

Direct Known Subclasses:
	<GWindow>, <GPopupMenu>

See Also:
	<DefaultLayerModel>, <LayerView>
*/
loadFile("light.G/Components/GComponent.js");
/* class */ AbstractLayer /* extends GComponent */
= new Class({
	Extends: GComponent,
	relatedLayers: new Array(),

	/*
	Function: setIndex
		Đặt index cho component theo trục z

	Arguments:
		zIndex - (integer) Index trên trục z cần đặt
	*/
	setIndex: function(zIndex){
		this.getModel().setIndex(zIndex);
		this.getView().setIndex(zIndex);
	},

	/*
	Function: getIndex
		Trả về index của component trên trục z

	Returns:
		index của component trên trục z
	*/
	getIndex: function(){
		return this.getModel().getIndex();
	},

	/*
	Function: setLaunchedComponent
		Đặt một component làm component kích hoạt window. Sẽ có tác dụng thiết lập vị trí cho window khi được paint

	Arguments:
		c - (<GComponent>) Instance của một component
	*/
	setLaunchedComponent: function(c){
		this.getModel().setLaunchedElement(c.getElement());
	},

	/*
	Function: setLaunchedElement
		Đặt một DOM element làm element kích hoạt window. Có tác dụng thiết lập vị trí cho window khi được paint

	Arguments:
		e - (element) Element trong cây DOM
	*/
	setLaunchedElement: function(e){
		this.getModel().setLaunchedElement(e);
	},

	/*
	Function: hasLaunchedElement
		Trả về xem window hiện tại có được launched ra từ một element nào đó không

	Returns:
		(boolean) True nếu có, false là không có element nào
	*/
	hasLaunchedElement: function(){
		return this.getModel().hasLaunchedElement();
	},

	/*
	Function: getLaunchedElement
		Lấy element sẽ launched window

	Returns:
		(element) Element được thiết lập là vẽ ra window, null nếu không có
	*/
	getLaunchedElement: function(){
		return this.getModel().getLaunchedElement();
	},

	/*
	Function: addRelatedLayer
		Thêm một layer vào danh sách lệ thuộc vào layer hiện tại, sẽ được đưa lên trên khi layer này được đưa lên trên

	Arguments:
		cpn - (<AbstractLayer>) Layer lệ thuộc vào layer hiện tại
	*/
	addRelatedLayer: function(cpn){
		this.relatedLayers.include(cpn);
	},

	/*
	Function: getAllRelatedLayers
		Cung cấp toàn bộ danh sách các layer lệ thuộc vào layer hiện tại

	Returns:
		(Array) Tất cả các layer lệ thuộc vào layer hiện tại
	*/
	getAllRelatedLayers: function(){
		return this.relatedLayers;
	},

	/*
	Function: setRelatedTo
		Làm cho layer hiện tại phụ thuộc vào một layer khác

	Arguments:
		cpn - (<AbstractLayer>) Layer mà layer hiện tại sẽ phụ thuộc vào
	*/
	setRelatedTo: function(cpn){
		cpn.addRelatedLayer(this);
	}
});

};filesWrapper['light.G/Components/AbstractList.js'] = function(){
	loadFile('light.G/Components/GComponent.js');

/*
Class: AbstractList
	Abstract class định nghĩa tất cả các Component dạng List. List được hiểu là một component có chứa một danh sách các component khác, mỗi khi một component con này nhận tương tác (ấn chuột, bàn phím...), list sẽ được thông báo và thay đổi trạng thái của một hoặc nhiều component con cho phù hợp với trạng thái mới của list. List có 2 model độc lập dùng để lưu trữ 2 thành phần dữ liệu:
	- Dữ liệu của list bao gồm dữ liệu gốc dùng để xây dựng các thành phần component con
	- Các index đang được select

	Các dạng thể hiện cơ bản của list bao gồm:
	- single-selection list
	- standard multiple-selection list
	- check box list

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<GComponent>
*/
/* class */ AbstractList /* extends GComponent */
= new Class({
	Extends: GComponent,

	createDefaultView: /* abstract */ function(){
    	getErrorConsole().throwError('Phải nạp chồng hàm này của AbstractList');
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	},

	setSelectionModel: function(selectionModel){
		if (this.selectionModel != null){
			/* đây là cho trường hợp ta thay đổi selection model thì ta chuyển nguyên vẹn danh sách selected sang */
			selectionModel.setSelectionIndices(this.selectionModel.getSelectionIndices());
		}

        this.selectionModel = selectionModel;
		this.selectionModel.setComponent(this);
	},

	getAllData: function(){
		return this.getModel().getAllData();
	},

	getDataElementAt: function(index){
		return this.getModel().getElementAt(index);
	},

	getDataSize: function(){
		return this.getModel().getSize();
	},

	getSelectionSize: function(){
		return this.getSelectionModel().getSize();
	},

	setCellRenderer: function(renderer){
		this.setOption('cellRenderer', renderer);
	},

	getCellRenderer: function(){
		return this.getOption('cellRenderer');
	},

	getSelectionModel: function(){
		return this.selectionModel;
	},

	addListSelectionListener: function() {
		var listSelectionListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(arguments[0]);
    	var newArguments = [listSelectionListenerHash, this].extend(realArguments);
		return this.getSelectionModel().addListSelectionListener.run(newArguments, this.getSelectionModel());
	},

	removeListSelectionListener: function(returnFncs){
		this.getSelectionModel().removeListSelectionListener(returnFncs);
	},

	/*
	Function: setSelectionMode
		Đặt lại mode select

	Arguments:
		selectionMode - (string) Cách thức chọn danh sách, 'single' hay 'multiple'
	*/
	setSelectionMode: function(selectionMode){
		this.getSelectionModel().setSelectionMode(selectionMode);
	},

	/*
	Function: getSelectionMode
		Trả về mode select đang dùng

	Returns:
		(string) Mode select đang dùng, 'single' hay 'multiple'
	*/
	getSelectionMode: function(){
		return this.getSelectionModel().getSelectionMode();
	},

	/*
	Function: removeSelectionIndex
		Bỏ một index ra khỏi trạng thái đã select

	Arguments:
		index - (string,integer) Index nằm trong danh sách dữ liệu
	*/
	removeSelectionIndex: function(index){
		this.getSelectionModel().removeSelectionIndex(index);
	},

	/*
	Function: addSelectionIndex
		Đưa một index vào trạng thái đã select

	Arguments:
		index - (string,integer) Index nằm trong danh sách dữ liệu
	*/
	addSelectionIndex: function(index){
		this.getSelectionModel().addSelectionIndex(index);
	},

	/*
	Function: setSelectionIndex
		Đặt lại danh sách selection thành một index mà thôi. Có tác dụng tương đương với việc việc <clearSelection> rồi <addSelectionIndex>. Chủ yếu hỗ trợ khi select trong mode single

	Arguments:
		index - (string,integer) Index nằm trong danh sách dữ liệu
	*/
	setSelectionIndex: function(index){
		this.getSelectionModel().setSelectionIndex(index);
	},

	/*
	Function: setSelectionIndices
		Đặt lại danh sách selection thành giống như danh sách index truyền vào

	Arguments:
		indices - (Array) Danh sách các index mà ta muốn đặt là trạng thái select
	*/
	setSelectionIndices: function(indices){
		this.getSelectionModel().setSelectionIndices(indices);
	},

	/*
	Function: shiftSelectionToIndex
		Di dời danh sách index từ vị trí select cuối cùng đến vị trí yêu cầu

	Arguments:
		index - (string,integer) Index nằm trong danh sách dữ liệu
	*/
	shiftSelectionToIndex: function(index){
		this.getSelectionModel().shiftSelectionToIndex(index);
	},

	/*
	Function: isSelectionIndex
		Kiểm tra xem một index đã được select hay chưa

	Arguments:
		index - (string,integer) Index nằm trong danh sách dữ liệu
	*/
	isSelectionIndex: function(index){
		return this.getSelectionModel().isSelectionIndex(index);
	},

	/*
	Function: getSelectionIndices
		Trả về toàn bộ các index đã được select

	Returns:
		(Array) Danh sách index đang được select
	*/
	getSelectionIndices: function(){
		return this.getSelectionModel().getSelectionIndices();
	},

	/*
	Function: clearSelection
		Xóa toàn bộ danh sách đã được select
	*/
	clearSelection: function(){
		this.getSelectionModel().clearSelection();
	},

	/*
	Function: toggleSelectionIndex
		Đảo ngược trạng thái select của một index

	Arguments:
		index - (string,integer) Index nằm rong danh sách dữ liệu
	*/
	toggleSelectionIndex: function(index){
		this.getSelectionModel().toggleSelectionIndex(index);
	},

	/*
	Function: getLastSelectionIndex
		Lấy index được select cuối cùng. Cái này chủ yếu dùng khi cần lấy một dữ liệu đặc trưng cho list

	Returns:
		(string,integer) Index được select cuối cùng
	*/
	getLastSelectionIndex: function(){
		return this.getSelectionModel().getLastSelectionIndex();
	},

	selectAll: function(aFlag){
		if (aFlag) this.getSelectionModel().addSelectionRange(0, this.getDataSize() - 1);
		else this.getSelectionModel().clearSelection();
	},

	/*hoverNext: function(){
        this.getSelectionModel().hoverNext();
	},

	hoverPrevious: function(){
		this.getSelectionModel().hoverPrevious();
	},

	setHover: function(index){
		this.getSelectionModel().setHover(index);
	},

	removeHover: function(index){
		this.getSelectionModel().removeHover(index);
	},*/

	selectNext: function(){
		this.getSelectionModel().setNextToIndex();
	},

	selectPrevious: function(){
		this.getSelectionModel().setPreviousToIndex();
	}
});
};filesWrapper['light.G/Components/AbstractSelectable.js'] = function(){
	loadFile('light.G/Components/GComponent.js');

/*
Class: AbstractSelectable
	Lớp miêu tả cho tất cả các component có khả năng nhận các sự kiện của chuột

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<GComponent>

Direct Known Subclasses:
	<AbstractButton>, <AbstractColorPicker>
*/
/* class */ AbstractSelectable /* extends GComponent */
= new Class({
	Extends: GComponent,

	/*
    Function: isPressed
    	Trả về trạng thái của button có đang được ấn chuột vào hay không

    Returns:
    	(boolean) True là đang được ấn chuột vào, false là không
    */
	isPressed: function(){
		return this.getModel().isPressed();
	},

	/*
	Function: setPressed
		Đặt trạng thái cho button về việc được ấn chuột vào

	Arguments:
		aFlag - (boolean) True là đang được ấn, false là đã thả ra
	*/
	setPressed: function(aFlag){
		this.getModel().setPressed(aFlag);
	},

	/*
	Function: isArmed
		Trả về trạng thái của button có đang được di chuột qua hay không

	Returns:
		(boolean) True là đang được di chuột qua, false là không
	*/
	isArmed: function(){
		return this.getModel().isArmed();
	},

	/*
	Function: setArmed
		Đặt trạng thái của button về việc di chuột qua

	Arguments:
		aFlag - (boolean) True là đang di chuột qua, false là đã ra ngoài
	*/
	setArmed: function(aFlag){
		this.getModel().setArmed(aFlag);
	},

	/*
	Function: isSelected
		Trả về trạng thái có được select hay không, chỉ hữu dụng cho các button có khả năng toggle

	Returns:
		(boolean) True là đang được select, false là không
	*/
	isSelected: function(){
		return this.getModel().isSelected();
	},

	/*
	Function: setSelected
		Đặt trạng thái của button cho việc được select

	Arguments:
		aFlag - (boolean) True là đang được select, false là không
	*/
	setSelected: function(aFlag){
		this.getModel().setSelected(aFlag);
	},

	/*
	Function: toggleSelected
		Đảo ngược trạng thái selected của button
	*/
	toggleSelected: function(){
		this.getModel().toggleSelected();
	}
});
};filesWrapper['light.G/Components/GButton.js'] = function(){
	loadFile('light.G/Components/AbstractButton.js');

/*
Class: GButton
	Định nghĩa một button component trong Light.G

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractButton>

Syntax:
	(start code)
var btnObj = new GButton([options]);
	(end)

See Also:
	- <DefaultButtonModel>, <BasicButtonView.WithFocus>
	- <GToggleButton>

Example:
	(start code)
var testBtn = new GButton({
	text: 'Button Text'
});
testWnd = new GWindow();
testWnd.add(testBtn);
	(end)
*/
/* class */ GButton /* extends AbstractButton */
= new Class({
	Extends: AbstractButton,

    createDefaultView: function(){
    	var skinView = GFactory.getResourceManager().getComponentView('GButton')
    	if (!isset(skinView)) {
    		loadFile('light.G/Skin/Basic/BasicButtonView.js');
			skinView = new BasicButtonView();
    	}

    	return skinView;
	}
});
};filesWrapper['light.G/Components/GCheckbox.js'] = function(){
	loadFile('light.G/Components/GToggleButton.js');

/*
Class: GCheckbox
	Là thể hiện của button có khả năng bật, tắt trạng thái selected khi được ấn vào

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<GToggleButton>
*/
/* class */ GCheckbox /* extends GToggleButton */
= new Class({
	Extends: GToggleButton,

    createDefaultView: function(){
    	var skinView = GFactory.getResourceManager().getComponentView('GCheckbox')
    	if (!isset(skinView)) {
    		loadFile('light.G/Skin/Basic/BasicCheckboxView.js');
			skinView = new BasicCheckboxView();
    	}

    	return skinView;
	}
});
};filesWrapper['light.G/Components/GColorBlock.js'] = function(){
	loadFile('light.G/Components/AbstractColorPicker.js');

/* class */ GColorBlock /* extends AbstractColorPicker */
= new Class({
	Extends: AbstractColorPicker,
    initialize: function(options, color){
    	loadFile('light.G/Model/DefaultColorPickerModel.js');
		this.setModel(new DefaultColorPickerModel(color));
		this.setOptions(options);
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicColorBlockView.js');
    	return new BasicColorBlockView();
	}
});
};filesWrapper['light.G/Components/GComboBox.js'] = function(){
	loadFile('light.G/Components/AbstractButton.js');

/*
Class: GComboBox
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ GComboBox /* extends AbstractButton */
= new Class({
	Extends: AbstractButton,
	tempList: null,

	initialize: function(options, list){
		if (!isset(list)){
			getErrorConsole().throwError('List cho combo box không thể null');
		}

		loadFile('light.G/Model/DefaultComboBoxModel.js');
		this.setModel(new DefaultComboBoxModel());
		this.setOptions(options);
		this.tempList = list;
	},

	setView: function(view){
		this.parent(view);
		this.setList(this.tempList);
	},

	createDefaultView: function(){
		var skinView = GFactory.getResourceManager().getComponentView('GComboBox')
    	if (!isset(skinView)) {
    		loadFile('light.G/Skin/Basic/BasicComboBoxView.js');
    		skinView = new BasicComboBoxView();
    	}

    	return skinView;
	},

	getGraphicsContext: function(){
		var parentResult = this.parent();
		if (!isset(parentResult)){
			return this.getView().getDefaultGraphicsContext();
		}

		return parentResult;
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	},

	setList: function(list){
		this.getView().setList(list);
	},

	getList: function(){
		return this.getView().getList();
	},

    paintText: function(text){
		this.getView().paintText(text);
	},

	setPopupRenderer: function(renderer){
		this.setOption('popupRenderer', renderer);
	},

	getPopupRenderer: function(){
		return this.getOption('popupRenderer');
	},

	getListCellRenderer: function(renderer){
		this.setOption('listCellRenderer', renderer);
	},

	setListCellRenderer: function(){
		return this.getOption('listCellRenderer');
	},

	getPopup: function(){
		return this.getView().getPopup();
	}
});
};filesWrapper['light.G/Components/GComponent.js'] = function(){
	/*
Class: GComponent
	Abstract cho một GUI Component trong hệ thống Light. GUI Component được xây dựng theo mô hình MVC, nhưng do đặc thù về quản lý sự kiện trên HTML nên ta kết hợp View và Controller lại với nhau và chỉ còn là View mà thôi

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	<AbstractModel>
*/
/* class */ GComponent /* */
= new Class({
	model: null,
	view: null,

	/* private */ attachedDomElement: null,
	/* private */ parentComponent: null,
	/* private */ componentsList: new Array(),
	/* private */ graphicsContext: null,
	/* private */ defaultChildGraphicsContext: null,
	/* private */ index: null,

	initialize: function(options){
		this.setOptions(options);
	},

	/*
	Function: setOptions
		Đặt thuộc tính cho component, không fire sự kiện change (các ChangeListener không được thông báo)

	Arguments:
		options - (array) Các thuộc tính của component

	Example:
		Gán thuộc tính khi construct
		(start code)
initialize: function(options){
	this.setOptions(options);
}
		(end)

	*/
	setOptions: function(options){
		this.getModel().setOptions(options);
	},

	/*
	Function: setNewOptions
		Đặt thuộc tính mới cho component, thông báo cho các ChangeListener

	Arguments:
		options - (array) Các thuộc tính mới cho component

	Example:
		Gán lại thuộc tính sau khi vẽ
		(start code)
var cpnt = new GButton({text: 'Button'});
cpnt.paint();
cpnt.setNewOptions({
	width: 500,
	height: 200
});
		(end)
	*/
	setNewOptions: function(options){
        this.getModel().setOptions(options);
		this.getModel().fireEvent('change');
	},

	/*
	Function: setOption
		Đặt thuộc tính cho component, sẽ thông báo cho các ChangeListener

	Arguments:
		key - (string) Tên thuộc tính
		value - (mixed) Giá trị của thuộc tính
		willFireEvent - (boolean) Có báo sự kiện change hay không

	Example:
		Đặt một thuộc tính
		(start code)
var cpnt = new GButton({text: 'Button'});
cpnt.paint();
cpnt.setOption('width', 500);
		(end)
	*/
	setOption: function(key, value, willFireEvent){
		this.getModel().setOption(key, value, willFireEvent);
	},

	/*
	Function: getOption
		Lấy các thuộc tính đã được set

	Arguments:
		key - (string) Tên thuộc tính

	Returns:
		(mixed) Giá trị của thuộc tính
	*/
	getOption: function(key){
		return this.getModel().getOption(key);
	},

	/*
	Function: getOptions
		Lấy toàn bộ tất cả các thuộc tính của component

	Returns:
		(array) Các thuộc tính của component
	*/
	getOptions: function(){
		return this.getModel().getOptions();
	},

	/*
	Function: add
		Đưa một component khác vào trong component

	Arguments:
		childComponent - (component) Component con cần đưa vào trong
		graphicsContext - (array) GraphicsContext để vẽ vào trong, xem <GraphicsContext>

	See Also:
		<GraphicsContext>, <GComponent::getDefaultChildGraphicsContext>
	*/
	add: function(childComponent, graphicsContext){
		childComponent.setParentComponent(this);
		if (isset(graphicsContext)){
			childComponent.setGraphicsContext(graphicsContext);
		}
		else {
			childComponent.setGraphicsContext(
				this.getDefaultChildGraphicsContext()
			);
		}

		childComponent.paint();
	},

	/*
	Function: getDefaultChildGraphicsContext
		Trả về graphics context mặc định khi vẽ một component vào bên trong

	Returns:
		<GraphicsContext>
	*/
	getDefaultChildGraphicsContext: /* abstract */ function(){
		getErrorConsole().throwError(
			'Phải nạp chồng hàm getDefaultChildGraphicsContext của GComponent để trả về GraphicsContext khi add vào bên trong component');
	},

	/*
	Function: setGraphicsContext
		Đặt graphics context cho component khi paint sẽ vẽ theo

	Arguments:
		graphicsContext - (array) Xem <GraphicsContext>
	*/
	setGraphicsContext: function(graphicsContext){
		this.graphicsContext = graphicsContext;
	},

	/*
	Function: paint
		Yêu cầu thực hiện lệnh vẽ component
	Example:
		Vẽ một button vu vơ
		(start code)
var btn = new GButton({text: 'Button'});
btn.setGraphicsContext({
	'inject': {
		'target': document.body,
		'position': 'bottom'
	}
});
btn.paint();
		(end)
	*/
    paint: function(){
		this.getView().paint();
	},

	/*
	Function: repaint
		Yêu cầu vẽ lại component đã được vẽ trước đó
	*/
	repaint: function(){
		GFactory.getGraphicsDriver().addRepaintObj(this);
	},

    /*
    Function: setIndex
    	Đặt index cho component, việc này giúp dễ theo dõi các component nằm trong một component khác hơn

    Arguments:
    	index - (string,integer) Index của component
    */
	setIndex: function(index){
		this.index = index;
	},

	/*
	Function: getIndex
		Trả về index của component

	Returns:
		(string,integer) Index của component
	*/
	getIndex: function(){
		return this.index;
	},

	/*
	Function: setModel
		Đặt model cho component

	Arguments:
		model - (object) Object thể hiện model của component
	*/
	setModel: function(model){
		if (isset(this.model)){
			model.setOptions(this.model.getOptions());
		}

      	this.model = model;
      	this.model.setComponent(this);
	},

	/*
	Function: setView
		Đặt view cho component

	Arguments:
		view - (object) Object dùng để vẽ view cho component
	*/
	setView: function(view){
		if (isset(this.view)){
            /*
			*	uninstall
			*/
			this.view.uninstall();
		}

		this.view = view;
		this.view.setComponent(this);

		if (isset(this.view)){
			this.view.install(this);
		}
	},

	/*
	Function: setParentComponent
		Đặt một component khác có liên hệ bao chứa với component này

	Arguments:
		parentComponent - (object) Component cha trong quan hệ bao chứa với component này
	*/
	setParentComponent: function(parentComponent){
		this.parentComponent = parentComponent;
		if (isset(this.parentComponent)){
			this.parentComponent.addChildComponent(this);
		}
	},

	/*
	Function: getModel
		Trả về model của component

	Returns:
		(object) Model của component
	*/
	getModel: function(){
		return this.model;
	},

	/*
	Function: createDefaultView
		Tạo view mặc định khi paint nếu không có view nào được tạo

	Returns:
		(object) View mặc định nếu không có setView
	*/
	createDefaultView: /* abstract */ function(){
		getErrorConsole().throwError('Phải nạp chồng hàm createDefaultView của component để có thể vẽ mà không cần setView');
	},

	/*
	Function: getView
		Trả về instance của view tương ứng với component, nếu chưa được set sẽ trả về default view

	Returns:
		(object) View tương ứng với component

	See Also:
		<createDefaultView>
	*/
	getView: function(){
		if (!isset(this.view)){
			this.setView(this.createDefaultView());
		}

		return this.view;
	},

	/*
	Function: getParentComponent
		Trả về component cha của component hiện tại

	Returns:
		(object) Trả về component được set là cha trong quan hệ bao chứa component, null nếu không có
	*/
    getParentComponent: function(){
    	return this.parentComponent;
	},

	/*
	Function: getGraphicsContext
		Lấy graphics context tương ứng với component

	Returns:
		(array) Graphics context đã được set lúc trước
	*/
	getGraphicsContext: function(){
		return this.graphicsContext;
	},

	/*
	Function: addChildComponent
		Đưa một component khác vào danh sách là con, trong quan hệ bao chứa

	Arguments:
		childComponent - (component) Component ở bên trong
		index - (string,integer) Index xác định component là duy nhất trong danh sách con
	*/
	addChildComponent: function(childComponent, index){
		if (index){
			this.componentsList[index] = childComponent;
		}
		else {
			this.componentsList.include(childComponent);
		}
	},

	/*
	Function: isEnabled
		Trả về property có đang enabled không

	Returns:
		(boolean)
	*/
	isEnabled: function(){
		return this.getModel().isEnabled();
	},

	/*
	Function: isVisible
		Trả về property có đang visible không

	Returns:
		(boolean)
	*/
	isVisible: function(){
		return this.getModel().isVisible();
	},

	/*
	Function: isFocus
		Trả về property có đang focus không

	Returns:
		(boolean)
	*/
	isFocus: function(){
		return this.getModel().isFocus();
	},

	/*
	Function: isActivated
		Trả về property có đang được activate không

	Returns:
		(boolean)
	*/
    isActivated: function(){
		return this.getModel().isActivated();
	},

	/*
	Function: setEnabled
		Đặt component thành enabled hoặc disabled

	Arguments:
		aFlag - (boolean) true để set thành enabled, false để disabled
	*/
	setEnabled: function(aFlag){
		this.getModel().setEnabled(aFlag);
	},

	/*
	Function: setVisible
		Đặt component thành visible hay invisible

	Arguments:
		aFlag - (boolean) true để visible, false để invisible
	*/
	setVisible: function(aFlag){
		this.getModel().setVisible(aFlag);
	},

	/*
	Function: setFocus
		Đặt property cho component. Property này chỉ có tác dụng cho view

	Arguments:
		aFlag - (boolean) true là có focus, false là bỏ focus
	*/
    setFocus: function(aFlag){
		this.getModel().setFocus(aFlag);
	},

	/*
	Function: grabFocus
		Lấy focus trong hệ thống, có thông báo cho Component Manager để sync với những đối tượng khác
	*/
	grabFocus: function(){
		GFactory.getComponentManager().makeFocus(this);
        /*var lastFocusComponent = GFactory.getComponentManager().getFocusComponent();
    	if (lastFocusComponent == this){
    		return;
    	}

    	if (lastFocusComponent){
    		lastFocusComponent.setFocus(false);
		}

    	GFactory.getComponentManager().setFocusComponent(this);
    	this.setFocus(true);*/
	},

	/*
	Function: setActivated
		Đặt trạng thái của component thành activate

	Arguments:
		aFlag - (boolean) true để activate, false để deactivate
	*/
    setActivated: function(aFlag){
		this.getModel().setActivated(aFlag);
	},

	/*
	Function: addEvent
		Bổ sung các sự kiện mặc định vào component, bằng cách thông qua element trong dom tương ứng với component

	See Also:
		http://mootools.net/docs/Element/Element.Event#Element:addEvent
	*/
    addEvent: function(type, fn){
    	this.getElement().addEvent(type, fn);
    },

    /*
    Function: removeEvent
    	Cố gắng xóa một sự kiện ra khỏi component, chỉ áp dụng với các sự kiện được gắn vào element của component

    See Also:
    	http://mootools.net/docs/Element/Element.Event#Element:removeEvent
    */
    removeEvent: function(type, fn){
    	this.getElement().removeEvent(type, fn);
    },

    /*
    Function: fireEvent
    	Function description

    See Also:
    	http://mootools.net/docs/Element/Element.Event#Element:fireEvent
    */
    fireEvent: function(type, e){
    	this.getElement().fireEvent(type, e);
    },

    /*
    Function: addMouseListener
    	Thêm vào một listener để lắng nghe sự kiện của chuột, listener phải tuân theo chuẩn <MouseListener>. Tham số đầu tiên là listener, các tham số tiếp theo sẽ được truyền vào các function của listener

    Arguments:
    	listener - (object) Listener lắng nghe sự kiện của chuột, tuân theo interface <MouseListener>

    Returns:
    	(array) Tham chiếu đến các function dùng để remove listener
    */
    addMouseListener: function(){
        var mouseListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);
    	var newArguments = [mouseListenerHash, this].extend(realArguments);
        return this.getElement().addMouseListener.run(newArguments, this.getElement());
	},

	/*
	Function: removeMouseListener
		Xóa một listener ra khỏi danh sách lắng nghe sự kiện của chuột

	Arguments:
		returnFncs - (array) Danh sách các tham chiếu đến function đã được add

	See Also:
		<addMouseListener>
	*/
	removeMouseListener: function(returnFncs){
        this.getElement().removeMouseListener(returnFncs);
	},

	/*
    Function: addMouseMotionListener
    	Thêm vào một listener để lắng nghe sự kiện di động của chuột, listener phải tuân theo chuẩn <MouseMotionListener>. Tham số đầu tiên là listener, các tham số tiếp theo sẽ được truyền vào các function của listener

    Arguments:
    	listener - (object) Listener lắng nghe sự kiện di động của chuột, tuân theo interface <MouseMotionListener>

    Returns:
    	(array) Tham chiếu đến các function dùng để remove listener
    */
    addMouseMotionListener: function(){
        var mouseMotionListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);
    	var newArguments = [mouseMotionListenerHash, this].extend(realArguments);
		return this.getElement().addMouseMotionListener.run(newArguments, this.getElement());
	},

	/*
	Function: removeMouseMotionListener
		Xóa một listener ra khỏi danh sách lắng nghe sự kiện di động của chuột

	Arguments:
		returnFncs - (array) Danh sách các tham chiếu đến function đã được add

	See Also:
		<addMouseListener>
	*/
    removeMouseMotionListener: function(returnFncs){
    	this.getElement().removeMouseMotionListener(returnFncs);
	},

    /*
	Function: addWindowListener
		Thêm một listener lắng nghe sự thay đổi của window dẫn đến thay đổi tương tác lên component

	Arguments:
		windowListenerHash - Static class chứa các hàm lắng nghe sự kiện window

	Returns:
		(array) Tham chiếu đến các function dùng để bind sự kiện, dùng khi remove listener
	*/
    addWindowListener: function(){
    	var windowListenerHash = arguments[0];
    	var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);

		var returnFncs = new Hash({
			'blur': 	function(e){
				var newArguments = [e, this].extend(realArguments);
				windowListenerHash.wndBlur.run(newArguments);
			}.bind(this),
			'focus':	function(e){
				var newArguments = [e, this].extend(realArguments);
				windowListenerHash.wndFocus.run(newArguments);
			}.bind(this),
            'load':		function(e){
            	var newArguments = [e, this].extend(realArguments);
				windowListenerHash.wndLoad.run(newArguments);
			}.bind(this),
            'resize':	function(e){
            	var newArguments = [e, this].extend(realArguments);
				windowListenerHash.wndResize.run(newArguments);
			}.bind(this),
            'scroll':	function(e){
            	var newArguments = [e, this].extend(realArguments);
				windowListenerHash.wndScroll.run(newArguments);
			}.bind(this),
            'beforeunload':	function(e){
            	var newArguments = [e, this].extend(realArguments);
				windowListenerHash.wndBeforeUnload.run(newArguments);
			}.bind(this),
	        'unload':		function(e){
	        	var newArguments = [e, this].extend(realArguments);
				windowListenerHash.wndUnload.run(newArguments);
			}.bind(this)
		});

		var windowX = getClientStorage().get('windowX');
		returnFncs.each(function(value, key){
			windowX.addEvent(key, value);
		});

		return returnFncs;
	},

	/*
	Function: removeWindowListener
		Xóa listener liên quan đến thay đổi window

	Arguments:
		returnFncs - (array) Tham chiếu đến function tạo ra khi add
	*/
	removeWindowListener: function(returnFncs){
		var windowX = getClientStorage().get('windowX');
		returnFncs.each(function(value, key){
			windowX.removeEvent(key, value);
		});
	},

	/*
	Function: addKeyboardListener
		Thêm một listener lắng nghe tương tác của bàn phím lên component, tham số đầu tiên dùng để truyền listener, các tham số sau sẽ được truyền vào các hàm của listener

	Arguments:
		listener - (object) Tuân theo interface <KeyboardListener>

	Returns:
		(array) Tham chiếu đến các function dùng để remove
	*/
    addKeyboardListener: function(){
        var keyboardListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(arguments[0]);
    	var newArguments = [keyboardListenerHash, this].extend(realArguments);

    	return this.getElement().addKeyboardListener.run(newArguments, this.getElement());
	},

	/*
	Function: removeKeyboardListener
		Xóa một listener khỏi danh sách lắng nghe sự kiện bàn phím

	Arguments:
		returnFncs - (array) Danh sách tham chiếu đến các function được tạo ra khi add
	*/
	removeKeyboardListener: function(returnFncs){
		this.getElement().removeKeyboardListener(returnFncs);
	},

	/*
	Function: addChangeListener
		Thêm một listener lắng nghe thay đổi property của component. Tham số đầu tiên được truyền vào là listener, các tham số sau được truyền vào các hàm của listener

	Arguments:
		listener - (object) Tuân theo interface của <ChangeListener>

	Returns:
		(array) Tham chiếu đến các function dùng để remove
	*/
    addChangeListener: function(){
    	return this.getModel().addChangeListener.run(arguments, this.getModel());
	},

	/*
	Function: removeChangeListener
		Hủy bỏ việc lắng nghe thay đổi property của một listener

	Arguments:
		returnFncs - (array) Tham chiếu đến các function đã add
	*/
	removeChangeListener: function(returnFncs){
		this.getModel().removeChangeListener(returnFncs);
	},

	/*
	Function: getElement
		Trả về element được select theo tag bắt đầu từ element bao ngoài, được gắn kết với component

	Arguments:
		tag - (string) Tag thể hiện CSS selector, null trả về element ngoài cùng

	Returns:
		(element) Element được select ra

	See Also:
		http://mootools.net/docs/Element/Element#Element:getElement
	*/
	getElement: function(tag){
		if (!tag){
			return this.attachedDomElement;
		}

		return this.attachedDomElement.getElement(tag);
	},

	/*
	Function: getElements
		Trả về các elements được select theo tag bắt đầu từ element bao ngoài

	Arguments:
		tag - (string) Tag thể hiện của CSS selector

	Returns:
		(array) Danh sách các element phù hợp selector nằm trong một array

	See Also:
		http://mootools.net/docs/Element/Element#Element:getElements
	*/
	getElements: function(tag){
		return this.attachedDomElement.getElements(tag);
	},

	/*
	Function: attachWithElement
		Gắn kết một element với một component

	Arguments:
		domElement - (element) Element cần gắn kết với component
	*/
	attachWithElement: function(domElement){
		this.attachedDomElement = domElement;
		domElement.setComponent(this);
	},

	/*
	Function: destroy
		Hủy hoàn toàn component hiện tại, sẽ hủy luôn các component con
	*/
	destroy: function(){
		this.componentsList.each(function(subComponent){
			subComponent.destroy();
		});
		this.getView().uninstall();
		GFactory.getGraphicsDriver().removeRepaintObj(this);
		this.getModel().fireDestroyComponent();
	},

	/*
	Function: setTooltip
		Set một đoạn text (có thể là html) làm tooltip của component, chỉ áp dụng với các component có view chấp nhận tooltip

	Arguments:
		tooltipHtml - (string) Đoạn text sẽ làm tooltip của component
	*/
	setTooltip: function(tooltipHtml){
		this.getModel().setTooltip(tooltipHtml);
	},

	/*
	Function: getTooltip
		Lấy đoạn text làm tooltip của component
	*/
	getTooltip: function(){
		return this.getModel().getTooltip();
	},

	/*
	Function: empty
		Empty ruột của component bằng cách xóa các component con và gọi empty của view
	*/
	empty: function(){
		this.componentsList.each(function(subComponent){
			subComponent.destroy();
		});
		this.getView().empty();
	},

	/*
	Function: getTooltipTimer
		Trả về timer sẽ idle để vẽ ra tooltip

	Returns:
		<IdleTimer>
	*/
	getTooltipTimer: function(){
		return this.getView().getTooltipTimer();
	},

	/*
	Function: getTooltipComponent
		Trả về component sẽ vẽ ra tooltip

	Returns:
		<GTooltip>
	*/
	getTooltipComponent: function(){
		return this.getView().tooltip;
	},

	/*
	Function: setTooltipTimer
		Đặt timer sẽ idle để vẽ ra tooltip

	Arguments:
		inst - (<IdleTimer>) Object của IdleTimer dùng để idle trước khi vẽ
	*/
	setTooltipTimer: function(inst){
		this.getView().tooltipTimer = inst;
	},

	/*
	Function: setTooltipComponent
		Đặt một component làm component vẽ ra tooltip

	Arguments:
		inst - (<GTooltip>) Object của GTooltip dùng để vẽ ra tooltip
	*/
	setTooltipComponent: function(inst){
		this.getView().tooltip = inst;
	},

	/*
	Function: getClassName
		Trả về tên của class tương ứng với component hiện tại. Rất hữu dụng trong trường hợp ta chỉ có instance của component mà không thể biết được component là loại gì

	Returns:
		(string) Tên của class
	*/
	getClassName: function(){
		return 'GComponent';
	},

	/*
	Function: addSubComponent
		Đưa một component vào danh sách liên kết phụ cho component hiện tại, khác với <add> là chỉ quan hệ bao chứa, cha con

	Arguments:
		component - (<GComponent>) Component phụ cần đưa vào danh sách
		index - (string,integer) Index của component phụ trong danh sách

	Returns:
		- (string,integer) index vừa được sử dụng để chèn
	*/
	addSubComponent: function(component, index){
		//console.log(this.getView(), index, component);
		return this.getView().addSubComponent(component, index);
	},

	/*
	Function: getSubComponent
		Lấy một component phụ trong danh sách

	Arguments:
		index - (string,integer) Index của component phụ cần lấy

	Returns:
		- (<GComponent>) Trả về component nếu có
		- null nếu không có
	*/
	getSubComponent: function(index){
		return this.getView().getSubComponent(index);
	},

	getAllSubComponents: function(){
		return this.getView().getAllSubComponents();
	},

	addDestroyListener: function(){
		return this.getModel().addDestroyListener.run(arguments, this.getModel());
	},

	removeDestroyListener: function(returnFncs){
		this.getModel().removeDestroyListener(returnFncs);
	},

	clearJumpingListeners: function(){
		this.getElement().clearJumpingListeners();
	},

	/*
	Argument
	1. jumpingListenerHash
	2. droppables
	(next)
	*/
	addJumpingListener: function(){
		var jumpingListenerHash = arguments[0];
		var droppables = arguments[1];

        var realArguments = $A(arguments);
    	realArguments.erase(arguments[0]);
    	realArguments.erase(arguments[1]);

    	var newArguments = [jumpingListenerHash, droppables, this].extend(realArguments);
    	return this.getElement().addJumpingListener.run(newArguments, this.getElement());
	},

	isWindow: function(){
		return false;
	},

	isPopupVisible: function(){
    	return this.getModel().getOption('popupVisible');
    },

    setPopupVisible: function(aFlag){
    	this.getModel().setOption('popupVisible', aFlag);
    }
});
};filesWrapper['light.G/Components/GDesktop.js'] = function(){
	loadFile('light.G/Components/GComponent.js');

/* class */ GDesktop /* */
= new Class({

	Extends: GComponent,

    getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	},

    initialize: function(options){
    	loadFile('light.G/Model/DefaultDesktopModel.js');
    	this.setModel(new DefaultDesktopModel());
    	this.setOptions(options);
		if (options.baseElement != null){
			this.paint();
		}
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicDesktopView.js');
    	return new BasicDesktopView();
	},

    repaint: function(){
		GFactory.getGraphicsDriver().addRepaintObj(this);
	},

	isWindow: function(){
		return true;
	}
});

};filesWrapper['light.G/Components/GDomButton.js'] = function(){
	loadFile('light.G/Components/AbstractButton.js');

/*
Class: GDomButton
	Khác với <GButton> là tạo ra một bộ element có khả năng hoạt động như một button, GDomButton sử dụng chính button và các trạng thái có sẵn được trình duyệt hỗ trợ để tạo ra một button component có khả năng liên hệ với các component khác

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractButton>
*/
/* class */ GDomButton /* extends AbstractButton */
= new Class({
	Extends: AbstractButton,
	buttonEl: null,

	initialize: function(options, buttonEl){
		this.parent(options);
		if (isset(buttonEl)) this.buttonEl = buttonEl;
	},

	createDefaultView: function(){
    	loadFile('light.G/Skin/DomButtonView.js');
		var skinView = new DomButtonView(this.buttonEl);
    	return skinView;
	}
});
};filesWrapper['light.G/Components/GDomCheckbox.js'] = function(){
	loadFile('light.G/Components/GToggleButton.js');
/*
Class: GDomCheckbox


	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ GDomCheckbox /* extends GToggleButton */
= new Class({
	Extends: GToggleButton,
	checkboxEl: null,

	initialize: function(options, checkboxEl){
		this.parent(options);
		if (isset(checkboxEl)) this.checkboxEl = checkboxEl;
	},

	createDefaultView: function(){
    	loadFile('light.G/Skin/DomCheckboxView.js');
		var skinView = new DomCheckboxView(this.checkboxEl);
		return skinView;
	}
});
};filesWrapper['light.G/Components/GDomElement.js'] = function(){
	loadFile('light.G/Components/GComponent.js');
/*
Class: GDomElement
	Nhiệm vụ của Component này là biến một DomElement bất kỳ thành một GComponent, tức là có thể tiệp nhận các sự kiện, đóng gói và truyền dữ liệu qua lại

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Example:
	Đưa một div element có id là 'contentElement' vào trong một window
	(start code)
	var testWnd = new GWindow();
	var domCpnt = new GDomElement(null, $('contentElement')); // đến đây thì element đã trở thành component
	testWnd.add(domCpnt);
	(end)
*/
/* class */ GDomElement /* extends GComponent */
= new Class({
	Extends: GComponent,

	initialize: function(options, baseDomElement){
		loadFile('light.G/Model/DefaultDomElementModel.js');
        this.setModel(new DefaultDomElementModel());
		this.setOptions(options);
		this.attachWithElement(baseDomElement);
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/DomElementView.js');
    	return new DomElementView();
	},

	getDefaultChildGraphicsContext: function(){
		if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	}
});
};filesWrapper['light.G/Components/GDomLayer.js'] = function(){
	loadFile('light.G/Components/AbstractLayer.js');
/*
Class: GDomLayer


	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ GDomLayer /* extends AbstractLayer */
= new Class({
	Extends: AbstractLayer,

	initialize: function(options, baseDomElement){
		loadFile('light.G/Model/DefaultLayerModel.js');
		this.setModel(new DefaultLayerModel());
		this.setOptions(options);
		this.attachWithElement(baseDomElement);
	},

	createDefaultView: function(){
    	loadFile('light.G/Skin/DomLayerView.js');
    	return new DomLayerView();
	}
});
};filesWrapper['light.G/Components/GHtmlDocument.js'] = function(){
	loadFile('light.G/Components/GComponent.js');
/*
Class: GHtmlDocument
	Component cho phép tạo một HTML Document trên màn hình, có khả năng edit được

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	<DefaultHtmlDocumentModel>
*/
/* class */ GHtmlDocument /* extends GComponent */
= new Class({

	Extends: GComponent,

    initialize: function(options){
    	loadFile('light.G/Model/DefaultHtmlDocumentModel.js');
    	this.setModel(new DefaultHtmlDocumentModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicHtmlDocumentView.js');
    	return new BasicHtmlDocumentView();
	},

    /*
	Function: addKeyboardListener
		Hàm này được nạp chồng lại của <GComponent> vì keyboard listener được gắn vào doc của View chứ không phải Component HTML element (là iframe)

	Arguments:
		keyboardListenerHash - (<KeyboardListener>) Một listener để lắng nghe keyboard
	*/
	addKeyboardListener: function(keyboardListenerHash){
		return this.getView().addKeyboardListener.run(arguments, this.getView());
	},

	removeKeyboardListener: function(returnFncs){
		this.getView().removeKeyboardListener(returnFncs, this);
	},

    /*
    Function: execute
    	Chạy một câu lệnh lên HTML Document, hàm bao lại của hàm hệ thống hỗ trợ bởi trình duyệt

    Arguments:
    	command - (string) Tên của câu lệnh cần chạy
    	value - (mixed) Giá trị cần chạy

    See Also:
    	http://msdn.microsoft.com/en-us/library/ms536419(VS.85).aspx
    	http://www.quirksmode.org/dom/execCommand.html
    	https://developer.mozilla.org/en/Rich-Text_Editing_in_Mozilla#
    */
	execute: function(command, value){
		this.getView().execute(command, value);
	},

	/*
	Function: getContent
		Lấy toàn bộ nội dung HTML của Document

	Returns:
		(string) Nội dung HTML của Document
	*/
	getContent: function(){
		return this.getView().getContent();
	},

	/*
	Function: setContent
		Thiết đặt lại nội dung HTML của Document

	Arguments:
		content - (string) Nội dung mới của Document
	*/
	setContent: function(content){
		this.getView().setContent(content);
	},

	/*
	Function: insertContent
		Chèn một nội dung vào vị trí hiện tại của con trỏ bàn phím

	Arguments:
		content - (string) Nội dung cần chèn
	*/
    insertContent: function(content){
    	this.getView().insertContent(content);
	},

	/*
	Function: getSelectedContent
		Lấy nội dung dạng HTML đang được đánh dấu ở trong Document

	Returns:
		(string) Nội dung HTML đang được đánh dấu
	*/
    getSelectedContent: function(){
		return this.getView().getSelectedContent();
	},

	/*
	Function: getSelectedText
		Lấy nội dung dạng text đang được đánh dấu trong Document

	Returns:
		(string) Nội dung text đang được đánh dấu
	*/
	getSelectedText: function(){
		return this.getView().getSelectedText();
	},

	/*
	Function: getSelectedNode
		Trả về node hiện tại mà con trỏ document đang trỏ vào trong cây DOM của Document

	Returns:
		(textnode) Node đang được trỏ vào
	*/
	getSelectedNode: function(){
		return this.getView().getSelectedNode();
	},

	/*
	Function: selectCurrentNode
		Select (bôi đen) toàn bộ node mà con trỏ document đang trỏ vào
	*/
	selectCurrentNode: function(){
		this.getView().selectNode(this.getView().getSelectedNode());
	},

	getRange: function(){
		return this.getView().getRange();
	},

	collapse: function(){
		this.getView().collapse();
	},

	repaint: function(){
		/* chúng ta nạp chồng vì không muốn sử dụng graphics driver */
		this.getView().repaint();
	},

	saveSelection: function(){
		this.getView().saveSelection();
	},

	restoreSelection: function(){
		this.getView().restoreSelection();
	}
});
};filesWrapper['light.G/Components/GLabel.js'] = function(){
	loadFile('light.G/Components/AbstractSelectable.js');

/*
Class: GLabel
	Description cho class

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ GLabel /* extends AbstractSelectable */
= new Class({
	Extends: AbstractSelectable,

	initialize: function(options){
		loadFile('light.G/Model/DefaultLabelModel.js');
        this.setModel(new DefaultLabelModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicLabelView.js');
    	return new BasicLabelView.Selectable();
	}
});
};filesWrapper['light.G/Components/GList.js'] = function(){
	loadFile('light.G/Components/AbstractList.js');

/*
Class: GList
	Thể hiện cụ thể của một AbstractList, đã nạp chồng các hàm cần thiết để tạo ra DefaultView và DefaultRenderer

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractList>
*/
/* class */ GList /* extends AbstractList */
= new Class({
	Extends: AbstractList,

	/*
	Function: constructor
		Constructor

	Arguments:
		options - (mixed) Options đầu vào của component
		input - (mixed) Đầu vào của list, nếu là object thì phải là một Model tuân theo chuẩn <ListModel>, nếu không thì phải là một array chứa danh sách các giá trị dữ liệu của list. Không được phép null
		defaultIndices - (midex) Các giá trị được "select" mặc định
		selectionMode - (string) Chế độ select, có thể là: 'single', 'multiple'
	*/
	initialize: function(options, input, defaultIndices, selectionMode){
		if ($type(input) == 'array'){
			loadFile('light.G/Model/DefaultListModel.js');
			this.setModel(new DefaultListModel(input));
		}
		else if ($type(input) == 'object'){
			this.setModel(input);
		}
		else if (!isset(input)){
			getErrorConsole().throwError('Không thể tạo được một List nếu không có dữ liệu đầu vào');
		}

		this.setOptions(options);

		loadFile('light.G/Model/DefaultListSelectionModel.js');
		this.setSelectionModel(new DefaultListSelectionModel());
		this.setSelectionMode(selectionMode);
		if (defaultIndices != null){
			if ($type(defaultIndices) == 'array'){
				this.getSelectionModel().setSelectionIndices(defaultIndices);
			}
			else if ($type(defaultIndices) == 'number'){
				this.getSelectionModel().setSelectionIndices(new Array().include(defaultIndices));
			}
			else {
				getErrorConsole().throwError('Giá trị index mặc định của List không đúng');
			}
		}
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicListView.js');
    	return new BasicListView();
	}
});
};filesWrapper['light.G/Components/GMenuItem.js'] = function(){
	loadFile('light.G/Components/AbstractButton.js');

/*
Class: GMenuItem
	Menu Item là một dạng button đặc biệt, có trạng thái selected nhưng không có khả năng nhận focus và không bị selected khi bị click. Trạng thái selected này sẽ được GList bao ngoài quản lý

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ GMenuItem /* extends AbstractButton */
= new Class({
	Extends: AbstractButton,

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicMenuItemView.js');
    	return new BasicMenuItemView();
	}
});
};filesWrapper['light.G/Components/GPopupMenu.js'] = function(){
	loadFile('light.G/Components/AbstractLayer.js');
/*
Class: GPopupMenu
	Một component có khả năng popup và hiển thị một danh sách đối tượng (thường là thế). Component này thường được sử dụng trong menu, khi người dùng yêu cầu một đối tượng trên thanh bar. Hoặc sử dụng cho dropdown list.

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ GPopupMenu /* extends AbstractLayer */
= new Class({
	Extends: AbstractLayer,

    initialize: function(options){
    	loadFile('light.G/Model/DefaultPopupMenuModel.js');
		this.setModel(new DefaultPopupMenuModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/PopupMenuView.js');
    	return new PopupMenuView();
	},

    getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	}
});
};filesWrapper['light.G/Components/GRadioButton.js'] = function(){
	loadFile('light.G/Components/GToggleButton.js');
/*
Class: GRadioButton
	Là thể hiện của một button có khả năng toggle selected khi được ấn vào, hoạt động chung với các component khác cùng loại trong một button group

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<GToggleButton>

See Also:
	<ButtonGroup>
*/
/* class */ GRadioButton /* extends GToggleButton */
= new Class({
    Extends: GToggleButton,

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicRadioButtonView.js');
    	return new BasicRadioButtonView();
	}
});
};filesWrapper['light.G/Components/GTable.js'] = function(){
	loadFile('light.G/Components/AbstractList.js');
/*
Class: GTable
	Component này sẽ vẽ ra một table và quản lý các thành phần nhỏ trong đó (là các row). Các row trong table được BasicTableView vẽ mặc định thông qua <DefaultTableRowRenderer>. Muốn thay đổi renderer, gọi hàm <setRowRenderer>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Todo:
	Kiểm tra lại tương thích với selectionMode
*/
/* class */ GTable /* extends AbstractList */
= new Class({
	Extends: AbstractList,

	/*
	Function: constructor
		Constructor

	Arguments:
		options - (mixed) Options đầu vào của component
		input - (mixed) Đầu vào của list, nếu là object thì phải là một Model tuân theo chuẩn <ListModel>, nếu không thì phải là một array chứa danh sách các giá trị dữ liệu của list. Không được phép null
		defaultIndices - (midex) Các giá trị được "select" mặc định
		selectionMode - (string) Chế độ select, có thể là: 'single', 'multiple'
	*/
	initialize: function(options, input, defaultIndices, selectionMode){
		if ($type(input) == 'array'){
			loadFile('light.G/Model/DefaultListModel.js');
			this.setModel(new DefaultListModel(input));
		}
		else if ($type(input) == 'object'){
			this.setModel(input);
		}
		else if (!isset(input)){
			getErrorConsole().throwError('Không thể tạo được một List nếu không có dữ liệu đầu vào');
		}

		loadFile('light.G/Model/DefaultListSelectionModel.js');
		this.setSelectionModel(new DefaultListSelectionModel());
		this.setSelectionMode(selectionMode);
		if (defaultIndices != null){
			if ($type(defaultIndices) == 'array'){
				this.getSelectionModel().setSelectionIndices(defaultIndices);
			}
			else if ($type(defaultIndices) == 'number'){
				this.getSelectionModel().setSelectionIndices(new Array().include(defaultIndices));
			}
			else {
				getErrorConsole().throwError('Giá trị index mặc định của List không đúng');
			}
		}
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicTableView.js');
    	return new BasicTableView();
	},

	getRowRenderer: function(){
		return this.getOption('rowRenderer');
	},

	setRowRenderer: function(renderer){
		this.setOption('rowRenderer', renderer);
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	}
});
};filesWrapper['light.G/Components/GTextArea.js'] = function(){
	loadFile('light.G/Components/GComponent.js');

/* class */ GTextArea /* extends GComponent */
= new Class({
	Extends: GComponent,
	textAreaEl: null,

	initialize: function(options, textAreaEl){
		loadFile('light.G/Model/DefaultTextAreaModel.js');
        this.setModel(new DefaultTextAreaModel());
		this.setOptions(options);
		if (isset(textAreaEl)) this.textAreaEl = textAreaEl;
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicTextAreaView.js');
    	return new BasicTextAreaView(this.textAreaEl);
	},

    getText: function(){
		return this.getView().getText();
	},

	setText: function(newValue){
		this.getModel().setOption('text', newValue);
	},

	isArmed: function(){
		return this.getModel().isArmed();
	},

	setArmed: function(aFlag){
		this.getModel().setArmed(aFlag);
	},

	getClassName: function(){
		return 'GTextArea';
	},

	setOverTextRenderer: function(renderer){
		this.setOption('overTextRenderer', renderer);
	},

	getOverTextRenderer: function(){
		return this.getOption('overTextRenderer');
	}
});
};filesWrapper['light.G/Components/GTextField.js'] = function(){
	loadFile('light.G/Components/GComponent.js');

/* class */ GTextField /* extends GComponent */
= new Class({
	Extends: GComponent,

    initialize: function(options, builtTextField){
    	if (isset(builtTextField)) this.builtTextField = builtTextField;
    	loadFile('light.G/Model/DefaultTextFieldModel.js');
		this.setModel(new DefaultTextFieldModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicTextFieldView.js');
    	return new BasicTextFieldView.WithTooltip(this.builtTextField);
	},

    getText: function(){
		return this.getView().getText();
	},

	setText: function(newValue){
		this.getModel().setOption('text', newValue, false);
		this.getView().setText(newValue);
	},

	isArmed: function(){
		return this.getModel().isArmed();
	},

	setArmed: function(aFlag){
		this.getModel().setArmed(aFlag);
	},

    repaint: function(){
		GFactory.getGraphicsDriver().addRepaintObj(this);
	},

	getClassName: function(){
		return 'GTextField';
	},

	setOverTextRenderer: function(renderer){
		this.setOption('overTextRenderer', renderer);
	},

	getOverTextRenderer: function(){
		return this.getOption('overTextRenderer');
	},

	addKeyboardListener: function(){
		var keyboardListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(arguments[0]);
    	var newArguments = [keyboardListenerHash, this].extend(realArguments);
    	var inputObj = this.getElement('input[type=text]')

    	return inputObj.addKeyboardListener.run(newArguments, inputObj);
	}
});
};filesWrapper['light.G/Components/GToggleButton.js'] = function(){
	loadFile('light.G/Components/AbstractButton.js');

/*
Class: GToggleButton
	Là một button có thể hiện trạng thái selected

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractButton>

Direct Known Subclasses:
	<GCheckbox>, <GRadioButton>

See Also:
	<ButtonGroup>
*/
/* class */ GToggleButton /* extends AbstractButton */
= new Class({
    Extends: AbstractButton,

    createDefaultView: function(){
    	loadFile('light.G/Skin/Basic/BasicToggleButtonView.js');
    	return new BasicToggleButtonView();
	},

	setSelected: function(aFlag){
		if (aFlag){
        	if (this.getButtonGroup() != null){
				this.getButtonGroup().saveSelectionState(this);
			}
		}

		this.parent(aFlag);
	}
});
};filesWrapper['light.G/Components/GToolbar.js'] = function(){
	loadFile('light.G/Components/GComponent.js');

/* class */ GToolbar /* extends GComponent */
= new Class({
	Extends: GComponent,
	builtToolbar: null,
	componentItems: new Array(),

    getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	},

    initialize: function(options, builtToolbar){
    	loadFile('light.G/Model/DefaultToolbarModel.js');
		this.setModel(new DefaultToolbarModel());
		this.setOptions(options);
		this.builtToolbar = builtToolbar;
	},

    createDefaultView: function(){
    	loadFile('light.G/Skin/ToolbarView.js');
    	return new ToolbarView(this.builtToolbar);
	},

	disableAll: function(){
		this.getAllSubComponents().each(function(component){
			component.setEnabled(false);
		});
	},

	enableAll: function(){
		this.getAllSubComponents().each(function(component){
			component.setEnabled(true);
		});
	},

	disableComponent: function(index){
		this.getSubComponent(index).setEnabled(false);
	},

	enableComponent: function(index){
		this.getSubComponent(index).setEnabled(true);
	}
});
};filesWrapper['light.G/Components/GTooltip.js'] = function(){
	loadFile('light.G/Components/AbstractLayer.js');

/*
Class: GTooltip
	Tooltip là một component đơn giản dùng để hiển thị một khối text nhỏ nhỏ ở vị trí xuất hiện của chuột, mỗi khi mà chúng ta di chuột qua component đó và để lên đó trong một khoảng thời gian nhất định (có thể config được)

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	<TooltipListener>, <ComponentView::installTooltip>
*/
/* class */ GTooltip /* extends AbstractLayer */
= new Class({
	Extends: AbstractLayer,

    initialize: function(options){
    	loadFile('light.G/Model/DefaultTooltipModel.js');
		this.setModel(new DefaultTooltipModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	var skinView = GFactory.getResourceManager().getComponentView('GTooltip')
    	if (!isset(skinView)) {
    		loadFile('light.G/Skin/Basic/BasicTooltipView.js');
			skinView = new BasicTooltipView();
    	}

    	return skinView;
	}
});
};filesWrapper['light.G/Components/GWindow.js'] = function(){
	loadFile('light.G/Components/AbstractLayer.js');
/*
Class: GWindow
	Một thể hiện của layer cho phép vẽ một cửa sổ (giống một dialog trong Microsoft Windows), cửa sổ vẽ ra sẽ tự động được activated và đưa lên layer trên cùng.

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractLayer>

Syntax:
	(start code)
var wndObj = new GWindow([options]);
	(end)

Options:
	top - (integer) Vị trí xuất hiện top của window. Mặc định là 0
	left - (integer) Vị trí xuất hiện left của window. Mặc định là 0
	stayOnTop - (boolean) vẽ một layer ở bên trên để chặn mọi hoạt động xuống lớp dưới
	activated - (boolean) activate window sau khi vẽ hay không, mặc định là có
	contentHeightDiff - (integer) Độ chênh lệch giữa content và window về chiều cao

Vị trí của window:
	Mặc định, window sẽ kiểm tra xem có launchedElement không (Xem <AbstractLayer::setLaunchedElement>). Nếu không có thì mới vẽ theo tọa độ top và left
*/
/* class */ GWindow /* extends AbstractLayer */
= new Class({
	Extends: AbstractLayer,

	initialize: function(options){
    	loadFile('light.G/Model/DefaultWindowModel.js');
		this.setModel(new DefaultWindowModel());
		this.setOptions(options);
	},

	createDefaultView: function(){
		var skinView = GFactory.getResourceManager().getComponentView('GWindow')
    	if (!isset(skinView)) {
    		loadFile('light.G/Skin/Basic/BasicWindowView.js');
			skinView = new BasicWindowView();
    	}

    	return skinView;
	},

    getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	},

	isWindow: function(){
		return true;
	}
});
};filesWrapper['light.G/DefaultConfig.js'] = function(){
	ConfigData = {
	'refreshRate':	50,
	'formSubmitDelay': 100,
	'focusDelay': 1
};
};filesWrapper['light.G/Element.Light.G.js'] = function(){
	/*
Class: Element.Light.G
	Sửa đổi Element để trở thành Class phù hợp, có khả năng sử dụng các phương thức để gắn bó nó với một GUI Component. Các hàm ở đây bổ sung vào Element mặc định

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

See Also:
	http://mootools.net/docs/Element/Element.Event
*/
Element.implement({
	/*
	Function: stackClass
		Bật, tắt một class tương ứng với trạng thái kèm theo

	Arguments:
		className - (string) Tên của class
		stackValue - (boolean) True để bật, false để tắt

	Example:
		Bật tắt class 'big' của một element dựa vào một biến có lớn hơn 10 hay không
		(start code)
var val = 20;
$('testElement').stackClass('big', val > 10 ? true : false);
		(end)
	*/
	stackClass: function(className, stackValue){
		if (stackValue){
			this.addClass(className);
		}
		else {
			this.removeClass(className);
		}
	},

	/*
	Function: setComponent
		Lưu trữ kết nối từ element đến component

	Arguments:
		component - (<GComponent>) Instance của component
	*/
	setComponent: function(component){
		this.store('component', component);
	},

	/*
	Function: getComponent
		Trả về kết nối đến component của element

	Returns:
		(<GComponent>) Kết nối đến component tương ứng với element, null nếu không có
	*/
	getComponent: function(){
		return this.retrieve('component');
	},

	/*
	Function: hide
		Ẩn element đi

	Example:
		(start code)
$('testElement').hide();
		(end)
	*/
	hide: function(){
		this.setStyles({
			'display': 'none'
		});
	},

	/*
	Function: show
		Hiện element lên

	Example:
		(start code)
$('testElement').hide();
$('testElement').show();
		(end)
	*/
	show: function(){
        this.setStyles({
			'display': null
		});
	},

    addMouseListener: function(){
        var mouseListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);

        var returnFncs = new Hash({
			'mousedown': 	function(e){
				var newArguments = [e].extend(realArguments);
				mouseListenerHash.mouseDown.run(newArguments);
				if (isset(e)) e.stopPropagation();
			},
            'mouseup': 		function(e){
            	var newArguments = [e].extend(realArguments);
				mouseListenerHash.mouseUp.run(newArguments);
				//if (isset(e)) e.stopPropagation();
			},
            'click': 	function(e){
            	var newArguments = [e].extend(realArguments);
				mouseListenerHash.singleClick.run(newArguments);
				if (isset(e)) e.stopPropagation();
			},
            'dblclick': 	function(e){
            	var newArguments = [e].extend(realArguments);
				mouseListenerHash.doubleClick.run(newArguments);
				if (isset(e)) e.stopPropagation();
			}
		});

        returnFncs.each(function(value, key){
			this.addEvent(key, value);
		}.bind(this));

		return returnFncs;
	},

	removeMouseListener: function(returnFncs){
        returnFncs.each(function(value, key){
			this.removeEvent(key, value);
		}.bind(this));
	},

    addMouseMotionListener: function(){
        var mouseMotionListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);

        var returnFncs = new Hash({
			'mouseenter': 	function(e){
				var newArguments = [e].extend(realArguments);
				mouseMotionListenerHash.mouseEnter.run(newArguments);
			},

            'mouseleave':	function(e){
            	var newArguments = [e].extend(realArguments);
				mouseMotionListenerHash.mouseLeave.run(newArguments);
			},

            'mouseover': 	function(e){
            	var newArguments = [e].extend(realArguments);
				mouseMotionListenerHash.mouseOver.run(newArguments);
			},

            'mouseout': 	function(e){
            	var newArguments = [e].extend(realArguments);
				mouseMotionListenerHash.mouseOut.run(newArguments);
			}
		});

        returnFncs.each(function(value, key){
			this.addEvent(key, value);
		}.bind(this));

		return returnFncs;
	},

    removeMouseMotionListener: function(returnFncs){
        returnFncs.each(function(value, key){
			this.removeEvent(key, value);
		}.bind(this));
	},

	addKeyboardListener: function(){
        var keyboardListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);

		var returnFncs = new Hash({
			'keypress': function(e){
				var newArguments = [e].extend(realArguments);
				keyboardListenerHash.keyPress.run(newArguments);
			},

			'keyup': 	function(e){
				var newArguments = [e].extend(realArguments);
				keyboardListenerHash.keyUp.run(newArguments);
			},

			'keydown': function(e){
				var newArguments = [e].extend(realArguments);
				keyboardListenerHash.keyDown.run(newArguments);
			}
		});

		returnFncs.each(function(value, key){
			this.addEvent(key, value);
		}.bind(this));

		return returnFncs;
	},

	removeKeyboardListener: function(returnFncs){
		returnFncs.each(function(value, key){
			this.removeEvent(key, value);
		}.bind(this));
	},

	clearJumpingListeners: function(){
		var dragFx = this.retrieve('dragFx');
    	if (isset(dragFx)) dragFx.detach();
    	this.store('dragFx', null);
	},

	/*
	Argument
	1. jumpingListenerHash
	2. droppable
	3. component
	(next)
	*/
	addJumpingListener: function(){
		var jumpingListenerHash = arguments[0];
		var droppables = arguments[1];
		var component = arguments[2];

        var realArguments = $A(arguments);
    	realArguments.erase(arguments[0]);
    	realArguments.erase(arguments[1]);
    	realArguments.erase(arguments[2]);

    	var returnFncs = new Hash({
    		'beforeStart': function(el){
				var newArguments = [component].extend(realArguments);
				jumpingListenerHash.jumpBeforeStart.run(newArguments);
			},

			'start': function(el){
				var newArguments = [component].extend(realArguments);
				jumpingListenerHash.jumpStart.run(newArguments);
			},

			'drag': function(el){
				var newArguments = [component].extend(realArguments);
				jumpingListenerHash.jumpDrag.run(newArguments);
			},

			'complete': function(el){
				var newArguments = [component].extend(realArguments);
				jumpingListenerHash.jumpComplete.run(newArguments);
			},

			'drop': function(element, droppable, event){
				var newArguments = [event, component, droppable].extend(realArguments);
				jumpingListenerHash.jumpDrop.run(newArguments);
			},

			'leave': function(element, droppable, event){
				var newArguments = [event, component, droppable].extend(realArguments);
				jumpingListenerHash.jumpLeave.run(newArguments);
			},

			'enter': function(element, droppable, event){
				var newArguments = [event, component, droppable].extend(realArguments);
				jumpingListenerHash.jumpEnter.run(newArguments);
			}
    	});

    	var dragFx = this.retrieve('dragFx');
    	if (!isset(dragFx)){
    		dragFx = new Drag.Move(this, {
				style: false,
			    modifiers: {x: 'xleft', y: 'xtop'},
				droppables: droppables
    		});
    		this.store('dragFx', dragFx);
		}
		else {
			if(getSystemConfig().get('/System/debugMode/')){
				getErrorConsole().log('Lưu ý là đã có một dragFx khác được bind vào đây. Hãy đề phòng sự khác nhau về droppable');
			}
		}

    	returnFncs.each(function(value, key){
			dragFx.addEvent(key, value);
		});

		return returnFncs;
	}
});
};filesWrapper['light.G/Event/ChangeEvent.js'] = function(){
	/*
Class: ChangeEvent
	Định nghĩa một event thể hiện sự kiện Change, thay đổi thuộc tính của một component

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ ChangeEvent /* */
= new Class({
});
};filesWrapper['light.G/Event/ChangeListener.js'] = function(){
	/*
Script: ChangeListener
	Interface cho các listener muốn quản lý các sự kiện liên quan đến thay đổi trạng thái của một GUI Component

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ ChangeListener /**/
= new Hash({

    stateChanged: function(aComponent, property, value){}

});
};filesWrapper['light.G/Event/ColorChangeListener.js'] = function(){
	/*
Script: ColorChangeListener
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/*
Class: ColorChangeListener
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
var
/* class */ ColorChangeListener /* */
= new Hash({
	colorChanged: function(component, color, rootComponent){
	}
});
};filesWrapper['light.G/Event/DestroyListener.js'] = function(){
	/*
Script: DestroyListener.js


Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/*
Class: DestroyListener
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/

var
/* class */ DestroyListener /**/
= new Hash({
	onDestroy: function(component){
	}
});
};filesWrapper['light.G/Event/FilesListListener.js'] = function(){
	/*
Script: FilesListListener.js


Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/*
Class: FilesListListener
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/

var
/* class */ FilesListListener /**/
= new Hash({
	onEmpty: function(){}
});
};filesWrapper['light.G/Event/FuConnectorListener.js'] = function(){
	/*
Script: FuConnectorListener
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

var
/* class */ FuConnectorListener /* */
= new Hash({

	onProgress: function(obj, connector){},
	onSelect: function(obj, connector){},
	onComplete: function(obj, connector){},
	onCdata: function(obj, connector){},
	onUpload: function(obj, connector){},
	onHover: function(obj){},
	onOut: function(obj){}

});
};filesWrapper['light.G/Event/JumpingListener.js'] = function(){
	/*
Class: JumpingListener
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ JumpingListener  /* */
= new Hash({
	jumpBeforeStart: function(component){
	},

	jumpStart: function(component){
	},

	jumpDrag: function(component){
	},

	jumpComplete: function(component){
	},

	jumpDrop: function(e, component, droppable){
	},

	jumpEnter: function(e, component, droppable){
	},

	jumpLeave: function(e, component, droppable){
	}
});
};filesWrapper['light.G/Event/KeyboardListener.js'] = function(){
	/*
Script: KeyboardListener.js
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
var KeyboardListenerInterface = new Hash({
	keyPress: function(e, theComponent){
	},

	keyUp: function(e, theComponent){
	},

    keyDown: function(e, theComponent){
	}
});
};filesWrapper['light.G/Event/ListSelectionEvent.js'] = function(){
	/*
Class: ListSelectionEvent
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ ListSelectionEvent /* */
= new Class({
	removingIndices: null,
	addingIndices: null,

	initialize: function(removingIndices, addingIndices){
		this.removingIndices = removingIndices;
		this.addingIndices = addingIndices;
	},

	getAddingIndices: function(){
		return this.addingIndices;
	},

	getRemovingIndices: function(){
		return this.removingIndices;
	}
});
};filesWrapper['light.G/Event/ListSelectionListener.js'] = function(){
	/*
Interface: ListSelectionListener
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ ListSelectionListener /* */
= new Hash({
	valueChanged: function(e, list){
	}
});
};filesWrapper['light.G/Event/MouseListener.js'] = function(){
	/**
Script: MouseListener.js
	Interface cho các listener muốn quản lý các sự kiện liên quan đến mouse của một GUI Component

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
var MouseListener = new Hash({
	mouseDown: function(e, theComponent){
	},

	mouseUp: function(e, theComponent){
	},

    singleClick: function(e, theComponent){
	},

    doubleClick: function(e, theComponent){
	}
});
};filesWrapper['light.G/Event/MouseMotionListener.js'] = function(){
	/**
Script: MouseMotionListener.js
	Interface cho các listener muốn quản lý các sự kiện liên quan đến mouse của một GUI Component

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
var MouseMotionListener = new Hash({
    mouseEnter: function(e, theComponent){
	},

	mouseLeave: function(e, theComponent){
	},

	mouseOver: function(e, theComponent){
	},

	mouseOut: function(e, theComponent){
	}
});
};filesWrapper['light.G/Event/WindowListener.js'] = function(){
	/**
Script: WindowListener.js
	Interface cho các listener muốn quản lý các sự kiện liên quan đến thay đổi trạng thái của một GUI Component

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
var WindowListener = new Hash({
	wndBlur: function(e, aComponent){
	},

    wndFocus: function(e, aComponent){
	},

    wndLoad: function(e, aComponent){
	},

    wndResize: function(e, aComponent){
	},

    wndScroll: function(e, aComponent){
	},

    wndBeforeUnload: function(e, aComponent){
	},

    wndUnload: function(e, aComponent){
	}
});
};filesWrapper['light.G/GFactory.js'] = function(){
	/*
Class: GFactory
	Factory chứa các hàm cơ bản sử dụng cho hệ thống GUI. Factory này cũng thường được load ngay khi boot nên ta chỉ cần gọi luôn

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ GFactory /* */
= new Hash({
	/*
	Function: getResourceManager
		Định nghĩa và gọi Resource Manager để quản lý các resource có trong hệ thống

	Returns:
		- <ResourceManager>
	*/
	getResourceManager: function(){
		loadFile('light.G/ResourceManager.js');
		var inst = window.retrieve('ResourceManager');
		if (!isset(inst)){
	        inst = new ResourceManager();
			window.store('ResourceManager', inst);
		}

		return inst;
	},

	/*
	Function: getPaint
		Định nghĩa và gọi Paint để sử dụng các hàm vẽ đặc trưng của hệ thống Light

	Returns:
		- <Paint>
	*/
	getPaint: function(){
		loadFile('light.G/Paint.js');
	    var inst = window.retrieve('Paint');
		if (!isset(inst)){
	        inst = new Paint();
			window.store('Paint', inst);
		}

		return inst;
	},

	/*
	Function: getComponentManager
		Định nghĩa và gọi Component Manager để quản lý các component được vẽ trong hệ thống Light.G

	Returns:
		- <ComponentManager>
	*/
	getComponentManager: function(){
		loadFile('light.G/ComponentManager.js');
	    var inst = window.retrieve('ComponentManager');
		if (!isset(inst)){
	        inst = new ComponentManager();
			window.store('ComponentManager', inst);
		}

		return inst;
	},

	/*
	Function: getLayerManager
		Trả về Layer Manager quản lý các layer trong Light.G

	Returns:
		- <LayerManager>
	*/
	getLayerManager: function(){
		loadFile('light.G/LayerManager.js');
	    var inst = window.retrieve('LayerManager');
		if (!isset(inst)){
	        inst = new LayerManager();
			window.store('LayerManager', inst);
		}

		return inst;
	},

	/*
	Function: getScreen
		Trả về bộ quản lý màn hình

	Returns:
		- <LightScreen>
	*/
	getScreen: function(){
		loadFile('light.G/LightScreen.js');
	    var inst = window.retrieve('LightScreen');
		if (!isset(inst)){
	        inst = new LightScreen();
			window.store('LightScreen', inst);
		}

		return inst;
	},

	/*
	Function: getGraphicsDriver
		Trả về driver quản lý graphics

	Returns:
		- <GraphicsDriver>
	*/
	getGraphicsDriver: function(){
        loadFile('light.G/GraphicsDriver.js');
	    var inst = window.retrieve('GraphicsDriver');
		if (!isset(inst)){
	        inst = new GraphicsDriver();
			window.store('GraphicsDriver', inst);
		}

		return inst;
	}
});
};filesWrapper['light.G/GraphicsDriver.js'] = function(){
	/*
Class: GraphicsDriver
	Quản lý các component được repaint, giảm tải cho hệ thống

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ GraphicsDriver /* */
= new Class({

    objs: new Array(),
    timer: null,
    started: false,

    /*
    Function: addRepaintObj
    	Đưa một component vào danh sách chờ vẽ lại

    Arguments:
    	obj - (<GComponent>) Instance của component cần vẽ lại
    */
	addRepaintObj: function(obj){
		this.objs.include(obj);
		if (!this.started) this.start();
	},

	start: function(){
		if (!isset(this.timer)) {
			loadFile('core/IdleTimer.js');
			this.timer = new IdleTimer(getSystemConfig().get('/System/G/refreshRate'));
			this.timer.addEvent('complete', function(){
				this.repaintAll();
			}.bind(this));
		}
		this.started = true;
		this.timer.start();
		this.timer.idle();
	},

	/*
	Function: removeRepaintObj
		Đưa component ra khỏi danh sách repaint

	Arguments:
		obj - (<GComponent>) Instance của component cần bỏ khỏi danh sách repaint
	*/
	removeRepaintObj: function(obj){
		this.objs.erase(obj);
	},

	/*
	Function: repaintAll
		Thực hiện vẽ lại các component đang chờ theo một batch
	*/
	repaintAll: function(){
		var tempObjs = $A(this.objs);
	    $each(tempObjs, function(obj){
			obj.getView().repaint();
			this.objs.erase(obj);
		}.bind(this));

		if (this.objs.length == 0)
			this.started = false;
		else {
			this.timer.start();
			this.timer.idle();
		}
	}
});
};filesWrapper['light.G/Interfaces/LayoutRenderer.js'] = function(){
	/*
Script: LayoutRenderer
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ LayoutRenderer /* */
= new Hash({
	getComponent: function(){
		return new GButton();
	}
});
};filesWrapper['light.G/Interfaces/ListCellRenderer.js'] = function(){
	/*
Interface: ListCellRenderer
	Định nghĩa chuẩn mà các renderer tạo ra cell trong một <GList> cần tuân theo

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ ListCellRenderer /* extends LayoutRenderer */
= new Hash({
	getComponent: function(/*AbstractList*/ list, item, index, isSelected, cellHasFocus){
	}
});
};filesWrapper['light.G/Interfaces/ListModel.js'] = function(){
	/*
Interface: ListModel
	Interface định nghĩa cách thức mà các component như GList sử dụng để lấy giá trị của từng dòng trong danh sách hoặc độ dài danh sách. Thông thường thì danh sách dữ liệu là một mảng bắt đầu từ 0. Bất cứ sự thay đổi nào về mặt dữ liệu đều phải được thông báo cho các ListDataListeners

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ ListModel /* */
= new Class({
	getAllData: function(){
	},

	getSize: function(){
	},

	getElementAt: function(index){
	},

	addListDataListener: function(){
	},

	removeListDataListener: function(){
	}
});
};filesWrapper['light.G/Interfaces/TableRowRenderer.js'] = function(){
	/*
Interface: TableRowRenderer
	Description cho class

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ TableRowRenderer /* */
= new Hash({
	getComponent: function(){
		
	}
});
};filesWrapper['light.G/Interfaces/TextFieldOverTextRenderer.js'] = function(){
	/*
Interface: TableRowRenderer
	Description cho class

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
TextFieldOverTextRenderer
};filesWrapper['light.G/LayerManager.js'] = function(){
	/*
Class: LayerManager
	Quản lý các layer trong hệ thống

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ LayerManager /* */
= new Class({
	// stats
	layerCount: 20,
	topIndex: 20,

	getNextLayerCount: function(){
		return ++this.layerCount;
	},

	/*
	Function: getNextIndex
		Trả về z-index tiếp theo cho layer sẽ được tạo

	Returns:
		(integer) z-index cao nhất cần có
	*/
	getNextIndex: function(){
		return ++this.topIndex;
	},

	/*
	Function: bringLayerToFront
		Đưa layer được yêu cầu lên trên cùng

	Arguments:
		theLayer - (<AbstractLayer>) Instance của layer cần đưa lên trên cùng
	*/
	bringLayerToFront: function(theLayer){
		if (theLayer.getIndex() != this.topIndex){
			theLayer.setIndex(this.getNextIndex());
			var relatedLayers = theLayer.getAllRelatedLayers();
			if (isset(relatedLayers)){
				relatedLayers.each(function(relatedLayer){
					this.bringLayerToFront(relatedLayer);
				}.bind(this));
			}
		}
	},

	setAsTooltipLayer: function(theLayer){
		theLayer.setIndex(99999);
	}
});
};filesWrapper['light.G/LightScreen.js'] = function(){
	/*
Class: LightScreen
	Định nghĩa cách thức tương tác với màn hình (là phần ruột của Browser mà trang web sẽ được load lên), lấy độ rộng, độ cao, vị trí chuột

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ LightScreen /* */
= new Class({
	width: null,
	height: null,

	/*
	Function: getWidth
		Trả về độ rộng của màn hình

	Returns:
		(integer) Con số chỉ độ rộng của màn hình
	*/
	getWidth: function(){
		if (!isset(this.width)){
			this.width = document.getSize().x;
		}

		return this.width;
	},

	/*
	Function: getHeight
		Trả về độ cao của màn hình

	Returns:
		(integer) Con số chỉ độ cao của màn hình
	*/
	getHeight: function(){
		if (!isset(this.height)){
			this.height = document.getSize().y;
		}

		return this.height;
	},

	/*
	Function: getMousePosition
		Lấy tọa độ của chuột

	Returns:
		(mixed) Tọa độ x, y của chuột
	*/
	/*getMousePosition: function(){
		if (!isset(this.mousePos)) this.mousePos = {x:0,y:0};
		return this.mousePos;
	},

	saveMousePosition: function(e){
		this.mousePos = e.client;
	},*/

	saveResolution: function(){
		this.width = document.getSize().x;
		this.height = document.getSize().y;
	}
});
};filesWrapper['light.G/Model/AbstractListModel.js'] = function(){
	loadFile('light.G/Model/AbstractModel.js');

/*
Class: AbstractListModel
	Lớp abstract thể hiện mô hình dữ liệu cho một List

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Implements:
	<ListModel>
*/
/* class */ AbstractListModel /* extends AbstractModel implements ListModel */
= new Class({
	Extends: AbstractModel,
	data: null,
	options: {
		maxRow: 7,
		rowHeight: 13
	},

	initialize: function(data){
		this.data = data;
	},

	getAllData: function(){
		return this.data;
	},

	getSize: function(){
		return this.data.length;
	},

	getElementAt: function(index){
		return this.data[index];
	},

	addListDataListener: function(){
	},

	removeListDataListener: function(){
	},

	/*
	Function: fireContentsChanged
		Lớp con của AbstractListModel phải gọi hàm này sau khi có một hoặc nhiều đối tượng dữ liệu trong list bị thay đổi

	Arguments:
		var - (type) desc
	*/
	fireContentsChanged: function(){
	},

	/*
	Function: fireIndexAdded
		Lớp con của AbstractListModel phải gọi hàm này sau khi có một hoặc nhiều đối tượng dữ liệu trong list được thêm vào

	Arguments:
		var - (type) desc
	*/
	fireIndexAdded: function(){
	},

	/*
	Function: fireIndexRemoved
		Lớp con của AbstractListModel phải gọi hàm này sau khi có một hoặc nhiều đối tượng dữ liệu trong list bị xóa

	Arguments:
		var - (type) desc
	*/
	fireIndexRemoved: function(){
	}
});
};filesWrapper['light.G/Model/AbstractModel.js'] = function(){
	/*
Class: AbstractModel
	Lớp mô tả đại diện cho một model trong mô hình class dựng component của Light.G

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Imports:
	Events, Options

Options:
	id 			- 	(string,integer)	ID của component
	width 		- 	(integer) 	Chiều rộng của component
	height 		- 	(integer) 	Chiều cao của component
	top 		- 	(integer) 	Vị trí tọa độ top của component
	left		-	(integer) 	Vị trí tọa độ left của component
	text		-	(string) 	Text thể hiện cho component
	enabled		-	(boolean) 	Có đang được cho phép nhận hoạt động không
	visible		-	(boolean) 	Có hiển thị ra không
	focus		-	(boolean) 	Có đang là component được focus vào không
	activated	-	(boolaen) 	Có đang được kích hoạt không
	baseCss		-	(string)	CSS class bổ sung cho component khi được paint
	tooltipIdleTime	-	(integer)	Thời gian chờ trước khi cho hiện tooltip
	tooltip		-	(string)	Đoạn text sẽ hiện ra trong tooltip
*/
/* class */ AbstractModel /* imports Events, Options */
= new Class({
	Implements: [Events, Options],

	component: null,

    options: {
    	id:				null,
		width: 			null,
		height:			null,
		top:			null,
		left:			null,
		text:			null,

        enabled: 		true,
		visible: 		true,
		focus: 			false,
		activated: 		false,

		baseCss:			'',
		tooltipIdleTime:	500,
		tooltip:			null,
		popupVisible:		null
	},

	getOptions: function(){
		return this.options;
	},

	setOption: function(key, value, willFireEvent){
		if (!isset(willFireEvent)) willFireEvent = true;
		if (this.options[key] != value){
			this.options[key] = value;
			if (willFireEvent)
				this.fireEvent('change', [key, value]);
		}
	},

	getOption: function(key){
		return this.options[key];
	},

	setComponent: function(aComponent){
		this.component = aComponent;
	},

	isEnabled: function(){
		return this.getOption('enabled');
	},

	isVisible: function(){
		return this.getOption('visible');
	},

	isFocus: function(){
		return this.getOption('focus');
	},

	setEnabled: function(aFlag){
		this.setOption('enabled', aFlag);
	},

    setVisible: function(aFlag){
    	this.setOption('visible', aFlag);
	},

	setFocus: function(aFlag){
		this.setOption('focus', aFlag);
	},

	getComponent: function(){
		return this.component;
	},

    isActivated: function(){
		return this.getOption('activated');
	},

	setActivated: function(aFlag){
		this.setOption('activated', aFlag);
	},

    addChangeListener: function(){
        var changeListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);

		var returnFncs = new Hash({
			'change': function(property, value){
				var newArguments = [this.getComponent(), property, value].extend(realArguments);
				changeListenerHash.stateChanged.run(newArguments);
			}.bind(this)
		});

        returnFncs.each(function(value, key){
			this.addEvent(key, value);
		}.bind(this));

		return returnFncs;
	},

	removeChangeListener: function(returnFncs){
        returnFncs.each(function(value, key){
			this.removeEvent(key, value);
		}.bind(this));
	},

	addDestroyListener: function(){
        var destroyListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);

		var returnFncs = new Hash({
			'destroy': function(){
				var newArguments = [this.getComponent()].extend(realArguments);
				destroyListenerHash.onDestroy.run(newArguments);
			}.bind(this)
		});

        returnFncs.each(function(value, key){
			this.addEvent(key, value);
		}.bind(this));

		return returnFncs;
	},

    removeDestroyListener: function(returnFncs){
        returnFncs.each(function(value, key){
			this.removeEvent(key, value);
		}.bind(this));
	},

	fireDestroyComponent: function(){
		this.fireEvent('destroy');
	},

	setTooltip: function(tooltip){
		this.setOption('tooltip', tooltip);
	},

	getTooltip: function(){
		return this.getOption('tooltip');
	}
});
};filesWrapper['light.G/Model/AbstractSelectableModel.js'] = function(){
	loadFile('light.G/Model/AbstractModel.js');

/*
Class: AbstractSelectableModel
	Description cho class

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Options:
	pressed	-	(boolean)	Lưu giữ trạng thái có đang được chuột ấn lên hay không
	armed	-	(boolean)	Lưu giữ trạng thái có đang được chuột di qua hay không
	selected	-	(boolean)	Lưu giữ trạng thái có đang được selected hay không
*/
/* class */ AbstractSelectableModel /* extends AbstractModel */
= new Class({
	Extends: AbstractModel,
	options: {
    	pressed: 		false,
		armed: 			false,
		selected: 		false
	},

	isPressed: function(){
		return this.getOption('pressed');
	},

	setPressed: function(aFlag){
		this.setOption('pressed', aFlag);
	},

	isArmed: function(){
		return this.getOption('armed');
	},

	setArmed: function(aFlag){
		this.setOption('armed', aFlag);
	},

    isSelected: function(){
		return this.getOption('selected');
	},

	setSelected: function(aFlag){
		this.setOption('selected', aFlag);
	},

	toggleSelected: function(){
		if (this.getOption('selected')){
			this.setOption('selected', false);
		}
		else {
			this.setOption('selected', true);
		}
	}
});
};filesWrapper['light.G/Model/DefaultButtonModel.js'] = function(){
	loadFile('light.G/Model/AbstractSelectableModel.js');

/*
Class: DefaultButtonModel
	Model lưu trữ dữ liệu cho button

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ DefaultButtonModel /* extends AbstractSelectableModel implements ButtonModel */
= new Class({
	Extends: AbstractSelectableModel,

	buttonGroup: null,

	/*
	Function: setButtonGroup
		Đặt button gia nhập một button group, chỉ có tác dụng với các button có khả năng toggle

	Arguments:
		buttonGroup - (<ButtonGroup>) Instance của một button group
	*/
    setButtonGroup: function(buttonGroup){
    	this.buttonGroup = buttonGroup;
    },

    /*
    Function: getButtonGroup
    	Trả về button group mà button thuộc về

    Returns:
    	(<ButtonGroup>) Button group mà button thuộc về, null nếu không có
    */
    getButtonGroup: function(){
    	return this.buttonGroup;
    }
});
};filesWrapper['light.G/Model/DefaultColorPickerModel.js'] = function(){
	loadFile('light.G/Model/DefaultButtonModel.js');
/* class */ DefaultColorPickerModel /* extends DefaultButtonModel */
= new Class({
	Extends: DefaultButtonModel,
	color: null,

	initialize: function(color){
		this.color = color;
	},

	getColor: function(){
		return this.color;
	},

	setColor: function(color){
		this.color = color;
		this.fireEvent('colorChange', [color]);
	},

	addColorChangeListener: function(colorChangeListenerHash, rootComponent){
        var returnFncs = new Hash({
			'colorChange': function(color){
				colorChangeListenerHash.colorChanged(this.getComponent(), color, rootComponent);
			}.bind(this)
		});

        returnFncs.each(function(value, key){
			this.addEvent(key, value);
		}.bind(this));

		return returnFncs;
	},

	removeColorChangeListener: function(returnFncs){
        returnFncs.each(function(value, key){
			this.removeEvent(key, value);
		}.bind(this));
	}
});
};filesWrapper['light.G/Model/DefaultComboBoxModel.js'] = function(){
	/*
Script: DefaultComboBoxModel.js


Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
loadFile('light.G/Model/DefaultButtonModel.js');
/* class */ DefaultComboBoxModel /* extends DefaultButtonModel */
= new Class({
	Extends: DefaultButtonModel,

    options: {
	    popupVisible: false,
	    editable: false,
	    arrowButtonWidth: 16,
	    maxRow: 7,
		rowHeight: 13,
		redrawText: true
	},

    /*
	Function: setFocus
		nạp chồng hàm này vì khi bỏ focus thì đồng nghĩa với việc ẩn popup

	Arguments:
		aFlag - (boolean) cờ thể hiện trạng thái focus
	*/
    setFocus: function(aFlag){
    	if (this.options.focus != aFlag){
    		this.options.focus = aFlag;
    		//this.options.popupVisible = aFlag;
    		this.fireEvent('change', ['focus', aFlag]);
    		//this.fireEvent('change', ['popupVisible', aFlag]);
		}
	},

    isPopupVisible: function(){
    	return this.getOption('popupVisible');
    },

    setPopupVisible: function(aFlag){
    	this.setOption('popupVisible', aFlag);
    },

    isEditable: function(){
    	return this.getOption('editable');
    },

    setEditable: function(aFlag){
    	this.setOption('editable', aFlag);
    }

});
};filesWrapper['light.G/Model/DefaultDesktopModel.js'] = function(){
	/*
Script: DefaultDesktopModel.js
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
loadFile('light.G/Model/AbstractModel.js');
/* class */ DefaultDesktopModel /* */
= new Class({
	Extends: AbstractModel
});
};filesWrapper['light.G/Model/DefaultDomElementModel.js'] = function(){
	/*
Script: DefaultDomElementModel.js


Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/*
Class: DefaultDomElementModel
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Model/AbstractModel.js');
/* class */ DefaultDomElementModel /* extends AbstractModel */
= new Class({
	Extends: AbstractModel
});
};filesWrapper['light.G/Model/DefaultHtmlDocumentModel.js'] = function(){
	loadFile('light.G/Model/AbstractModel.js');
/*
Class: DefaultHtmlDocumentModel
	Model lưu trữ dữ liệu cho GHtmlDocument

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Options:
	cssPath		-	(string)	Đường dẫn đến file CSS sẽ áp dụng cho Document
	cssClass	-	(string)	Tên class sẽ được gắn làm body của Document
	styleWithCss	-	(boolean)	Có sử dụng CSS khi dựng style bên trong Document hay không
*/
/* class */ DefaultHtmlDocumentModel /* */
= new Class({
	Extends: AbstractModel,
	options: {
		cssPath: null,
		cssClass: null,
		styleWithCss: true
	}
});
};filesWrapper['light.G/Model/DefaultLabelModel.js'] = function(){
	loadFile('light.G/Model/AbstractSelectableModel.js');

/*
Class: DefaultLabelModel
	Description cho class

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ DefaultLabelModel /* extends AbstractSelectableModel */
= new Class({
	Extends: AbstractSelectableModel
});
};filesWrapper['light.G/Model/DefaultLayerModel.js'] = function(){
	loadFile('light.G/Model/AbstractModel.js');

/*
Class: DefaultLayerModel
	Model mặc định cho một layer, lưu trữ dữ liệu về tọa độ z của layer đó và các phương thức đặc biệt để quản lý nó trên trục z

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ DefaultLayerModel /* extends AbstractModel */
= new Class({
	Extends: AbstractModel,
	zIndex: null,
	launchedElement: null,

	setIndex: function(zIndex){
		this.zIndex = zIndex;
	},

	getIndex: function(){
		return this.zIndex;
	},

	setLaunchedElement: function(e){
		this.launchedElement = e;
	},

	hasLaunchedElement: function(){
		return !isset(this.launchedElement) ? false : true;
	},

	getLaunchedElement: function(){
		return this.launchedElement;
	}
});
};filesWrapper['light.G/Model/DefaultListModel.js'] = function(){
	loadFile('light.G/Model/AbstractListModel.js');

/*
Class: DefaultListModel
	Description cho class

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ DefaultListModel /* extends AbstractListModel */
= new Class({
	Extends: AbstractListModel
});
};filesWrapper['light.G/Model/DefaultListSelectionModel.js'] = function(){
	loadFile('light.G/Model/AbstractModel.js');
/* class */ DefaultListSelectionModel /* extends AbstractModel implements ListSelectionModel */
= new Class({

	Extends: AbstractModel,

	selectionMode: 'single', // 'single', 'multiple'
	selectionAnchor: 0,
	selectionIndices: new Array(),

	removingQueue: new Array(),
	addingQueue: new Array(),
	lastSelectionIndex: null,

	setSelectionIndices: function(indices){
		this.selectionIndices = indices;
		this.lastSelectionIndex = indices[0];

		if (this.selectionMode == 'single'){
			this.selectionIndices.empty().include(this.lastSelectionIndex);
		}
	},

	startEvent: function(){
		this.removingQueue.empty();
		this.addingQueue.empty();
	},

	saveRemoving: function(index){
		if (!this.removingQueue.contains(index)){
			this.removingQueue.include(index);
		}
	},

	saveAdding: function(index){
		if (this.removingQueue.contains(index)){
			this.removingQueue.erase(index);
		}

		if (!this.addingQueue.contains(index)){
			this.addingQueue.include(index);
		}
	},

	finishEvent: function(){
		loadFile('light.G/Event/ListSelectionEvent.js');
		var e = new ListSelectionEvent(this.removingQueue, this.addingQueue);
		this.fireEvent('valueChanged', [e]);
	},

	getSize: function(){
		return this.selectionIndices.length;
	},

	clearSelection: function(isAdjusting){
		if (!isAdjusting) this.startEvent();

		var tempIndices = $A(this.selectionIndices);
        tempIndices.each(function(index){
        	this.removeSelectionIndex(index, true);
		}.bind(this));

		if (!isAdjusting) this.finishEvent();
	},

	toggleSelectionIndex: function(index, currentValue){
		if (this.isSelectionIndex(index)){
			this.removeSelectionIndex(index);
		}
		else {
			this.addSelectionIndex(index);
		}
	},

	removeSelectionIndex: function(index, isAdjusting){
		if (this.selectionIndices.contains(index)){
			if (!isAdjusting) this.startEvent();

			this.selectionIndices.erase(index);
			this.saveRemoving(index);
			this.getComponent().getSubComponent(index).setSelected(false);

			if (!isAdjusting) this.finishEvent();
		}
	},

	addSelectionIndex: function(index, isAdjusting){
		if (!this.selectionIndices.contains(index)){
			if (!isAdjusting) this.startEvent();

			this.selectionIndices.include(index);
			this.saveAdding(index);

			this.lastSelectionIndex = index;
			this.getComponent().getSubComponent(index).setSelected(true);
			if (this.getSelectionMode() == 'multiple') this.startSelectionAnchor(index);

			if (!isAdjusting) this.finishEvent();
		}
	},

	addSelectionRange: function(index0, index1){
		this.startEvent();

		if (index0 < index1) {
			var min = index0;
			var max = index1;
		}
		else {
			var min = index1;
			var max = index0;
		}

		for (var i=min; i<=max; i++){
			if (!this.selectionIndices.contains(i)){
				this.selectionIndices.include(i);
				this.saveAdding(i);
				//console.log(this.getComponent().getSubComponent(i));
				this.getComponent().getSubComponent(i).setSelected(true);
			}
		}

		this.lastSelectionIndex = max;

		this.finishEvent();
	},

	setSelectionIndex: function(index){
		this.startEvent();
		this.clearSelection(true);
		this.addSelectionIndex(index, true);
		this.finishEvent();
	},

    startSelectionAnchor: function(index){
    	this.selectionAnchor = index;
	},

	shiftSelectionToIndex: function(index){
		this.addSelectionRange(
			this.selectionAnchor,
			index
		);
	},

    isSelectionIndex: function(index){
		return (!(this.selectionIndices.indexOf(index) == -1));
	},

	getSelectionIndices: function(){
		return this.selectionIndices;
	},

	getSelectionMode: function(){
		return this.selectionMode;
	},

	setSelectionMode: function(selectionMode){
		this.selectionMode = selectionMode;
	},

    addListSelectionListener: function(){
    	var listSelectionListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);

        var returnFncs = new Hash({
			'valueChanged': function(e){
				var newArguments = [e].extend(realArguments);
				listSelectionListenerHash.valueChanged.run(newArguments);
			}.bind(this)
		});

        returnFncs.each(function(value, key){
			this.addEvent(key, value);
		}.bind(this));

		return returnFncs;
	},

    removeListSelectionListener: function(returnFncs){
        returnFncs.each(function(value, key){
			this.removeEvent(key, value);
		}.bind(this));
	},

	getLastSelectionIndex: function(){
		/*if (!isset(this.lastSelectionIndex))
		getErrorConsole().throwError('Chưa có index nào trong list được select cả');*/
		return this.lastSelectionIndex;
	},

	setNextToIndex: function(){
		var lastSel = this.getLastSelectionIndex();
		if (!isset(lastSel)) {
			this.setSelectionIndex(0);
		}
		else {
			if (lastSel < this.getComponent().getModel().getSize() - 1)
				this.setSelectionIndex(lastSel + 1);
		}
	},

	setPreviousToIndex: function(){
		var lastSel = this.getLastSelectionIndex();
		if (!isset(lastSel)) {
			this.setSelectionIndex(0);
		}
		else {
			if (lastSel > 0)
				this.setSelectionIndex(lastSel - 1);
		}
	}

	/*getHoverIndex: function(){
		return this.lastHover;
	}

	hoverNext: function(){
        var lastHover = this.getHoverIndex();
        if (!isset(lastHover)) this.setHover(0);
        else if (lastHover < this.getComponent().getModel().getSize() - 1) this.setHover(lastHover + 1)
	},

	hoverPrevious: function(){
		var lastHover = this.getHoverIndex();
        if (!isset(lastHover)) this.setHover(0);
        else if (lastHover < this.getComponent().getModel().getSize() - 1) this.setHover(lastHover + 1)
	},

	setHover: function(index){
		this.lastHover = index;
	},

	removeHover: function(index){
		this.getSelectionModel().removeHover(index);
	},*/
});
};filesWrapper['light.G/Model/DefaultPopupMenuModel.js'] = function(){
	loadFile('light.G/Model/DefaultLayerModel.js');
/* class */ DefaultPopupMenuModel /* extends DefaultLayerModel */
= new Class({
	Extends: DefaultLayerModel,

	options: {
		visible: false
	}
});
};filesWrapper['light.G/Model/DefaultTextAreaModel.js'] = function(){
	/*
Script: DefaultTextAreaModel
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/*
Class: DefaultTextAreaModel
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Model/AbstractModel.js');
/* class */ DefaultTextAreaModel /* extends AbstractModel */
= new Class({
	Extends: AbstractModel,

	options: {
		armed: 			false
	},

	isArmed: function(){
		return this.getOption('armed');
	},

	setArmed: function(aFlag){
		this.setOption('armed', aFlag);
	}
});
};filesWrapper['light.G/Model/DefaultTextFieldModel.js'] = function(){
	/*
Script: DefaultTextFieldModel
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/*
Class: DefaultTextFieldModel
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Model/AbstractModel.js');
/* class */ DefaultTextFieldModel /* extends AbstractModel */
= new Class({
	Extends: AbstractModel,

	options: {
		name: 			'input',
		armed: 			false
	},

	isArmed: function(){
		return this.getOption('armed');
	},

	setArmed: function(aFlag){
		this.setOption('armed', aFlag);
	}
});
};filesWrapper['light.G/Model/DefaultToolbarModel.js'] = function(){
	/*
Script: DefaultToolbarModel
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/*
Class: DefaultToolbarModel
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Model/AbstractModel.js');
/* class */ DefaultToolbarModel /* extends AbstractModel */
= new Class({
	Extends: AbstractModel
});
};filesWrapper['light.G/Model/DefaultTooltipModel.js'] = function(){
	loadFile('light.G/Model/DefaultLayerModel.js');
/* class */ DefaultTooltipModel /* extends DefaultLayerModel */
= new Class({
	Extends: DefaultLayerModel
});
};filesWrapper['light.G/Model/DefaultWindowModel.js'] = function(){
	loadFile('light.G/Model/DefaultLayerModel.js');
/*
Class: DefaultWindowModel
	Model lưu trữ dữ liệu cho window

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Options:
	top - (integer) Vị trí xuất hiện top của window. Mặc định là 0
	left - (integer) Vị trí xuất hiện left của window. Mặc định là 0
	stayOnTop - (boolean) vẽ một layer ở bên trên để chặn mọi hoạt động xuống lớp dưới
	activated - (boolean) activate window sau khi vẽ hay không, mặc định là có
	contentHeightDiff - (integer) Độ chênh lệch giữa content và window về chiều cao
*/
/* class */ DefaultWindowModel /* extends DefaultLayerModel */
= new Class({
	Extends: DefaultLayerModel,
	options: {
		top: 0,
		left: 0,
		stayOnTop: true,
		activated: false,
		contentHeightDiff: 42,
		pinAfterPos: false
	}
});
};filesWrapper['light.G/Paint.js'] = function(){
	/*
Class: Paint
	Cung cấp các phương thức để hỗ trợ việc vẽ các đối tượng theo các kiểu đặc biệt đặc trưng trong Light GUI

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ Paint /**/
= new Class({

	/*
	Function: setWidth
		Gán chiều rộng cho một element, bỏ qua padding và border

	Arguments:
		element - (element) Element cần set
		targetWidth - (integer) Độ rộng cần set
	*/
	setWidth: function(element, targetWidth){
		if (!isset(targetWidth)) return;
        element = $(element);
        var elStyles = element.getStyles('padding','border-width');
		var sides = ['top','right','bottom','left'];
		for (var i = 0; i < sides.length; i++) {
			elStyles['padding-' + sides[i]] = elStyles['padding'].split(' ')[i];
			elStyles['border-' + sides[i] + '-width'] = elStyles['border-width'].split(' ')[i];
		}

        element.setStyles({
        	'width': targetWidth -
			        (elStyles['border-left-width'].toInt()
			        +elStyles['border-right-width'].toInt()
			        +elStyles['padding-left'].toInt()
			        +elStyles['padding-right'].toInt())
		});
	},

	/*
	Function: setHeight
		Gán chiều cao cho element, bỏ qua padding và border

	Arguments:
		element - (element) Element cần set
		targetHeight - (integer) Độ cao cần set
	*/
	setHeight: function(element, targetHeight){
		if (!isset(targetHeight)) return;
        element = $(element);

        var elStyles = element.getStyles('padding','border-width');
		var sides = ['top','right','bottom','left'];
		for (var i = 0; i < sides.length; i++) {
			elStyles['padding-' + sides[i]] = elStyles['padding'].split(' ')[i];
			elStyles['border-' + sides[i] + '-width'] = elStyles['border-width'].split(' ')[i];
		}

        element.setStyles({
        	'height': targetHeight -
			        (elStyles['border-top-width'].toInt()
			        +elStyles['border-bottom-width'].toInt()
			        +elStyles['padding-top'].toInt()
			        +elStyles['padding-bottom'].toInt())
		});
	},

    /*
	Function: stackWidth
		Biến một đối tượng thành có cùng chiều rộng với một đối tượng khác

	Arguments:
		element - (element,string) Đối tượng cần thay đổi chiều rộng
		targetElement - (element,string) Đối tượng làm chuẩn chiều rộng

	*/
	stackWidth: function(element, targetElement){
		element = $(element);
		targetElement = $(targetElement);

        /*
		*	bỏ hết các style width trước kia
		*/
        element.setStyle('width', null);

        var elWidth = element.getSize().x;
        var targetWidth = targetElement.getSize().x;

		if (elWidth < targetWidth) this.setWidth(element, targetWidth);
	},

    /*
	Function: stackPosition
		Cho phép một đối tượng bám vị trí của một đối tượng khác

	Arguments:
		element - (element,string) Đối tượng cần set vị trí
		targetElement - (element,string) Đối tượng làm chuẩn vị trí
		pop - (string) Nơi xuất hiện của đối tượng. Giá trị cho phép 'top','bottom','left','right'
		align - (string) Vị trí căn lề bám vào đối tượng. Giá trị cho phép 'left','right','top','bottom'

	Example:
		(start code)
GFactory.getPaint().stackPosition('Popup', 'Dropdown', 'bottom', 'left')
		(end)
		sẽ làm cho #Popup xuất hiện ở dưới #Dropdown và kéo sát về bên trái của #Dropdown

	*/
	stackPosition: function(element, targetElement, pop, align, offsetX, offsetY){
		offsetX = HelpersFactory.getTypeHelper().getValueWithDefault(offsetX, 0);
		offsetY = HelpersFactory.getTypeHelper().getValueWithDefault(offsetY, 0);
		element = $(element);
		targetElement = $(targetElement);
        var targetCo = targetElement.getCoordinates();
        var docCo = document.getCoordinates();
        docCo.height = document.getScrollHeight();
        var eCo = element.getCoordinates();
        var oldPop = pop;
		pop = this.checkEnough(pop, targetCo, eCo, docCo);

		var pos, edge;
        switch (pop){
            case 'bottom':
            case 'top':
                /*
				*	'bottom' và 'top'
				*/
				if (!isset(align)) align = 'left';
                pos = pop + '-' + align;
				edge = this.minus(pop) + '-' + align;

				break;
			case 'right':
			case 'left':
                /*
				*	'left' và 'right'
				*/
	            if (!isset(align)) align = 'top';
	            if (align == 'bottom'){
	            	pos = 'bottom' + '-' + pop;
					edge = 'top' + '-' + this.minus(pop);
				}
				else {
	            	pos = align + '-' + pop;
					edge = align + '-' + this.minus(pop);
	            }


				break;
			default:
				return null;
				break;
		}

		if (pop != oldPop){
			switch (pop){
				case 'bottom':
				case 'top':
					offsetY = -1 * offsetY;
					break;
				case 'right':
				case 'left':
					offsetX = -1 * offsetX;
					break;
				default:
					return null;
					break;
			}
		}

		pos = pos.camelCase();
		edge = edge.camelCase();

        element.position({
	        'relativeTo': targetElement,
		    'position': pos,
			'edge': edge,
			'offset': {
				x: offsetX,
				y: offsetY
			}
		});

		return {
			'pop': pop,
			'align': align
		};
	},

    minus: /* private */ function(value){
        switch (value){
            case 'bottom':
				return 'top';
			case 'top':
	            return 'bottom';
			case 'right':
	            return 'left';
			case 'left':
	            return 'right';
	        default:
	        	return null;
		}
	},

	checkEnough: /* private */ function(value, targetCo, eCo, docCo){
		var config = new Hash({
			bottom: {
				'stack': 'height',
				'way': 1,
				'docWay': 1
			},
			top: {
				'stack': 'height',
				'way': -1,
				'docWay': 0
			},
			right: {
				'stack': 'width',
				'way': 1,
				'docWay': 1
			},
			left: {
				'stack': 'width',
				'way': -1,
				'docWay': 0
			}
		});

		if (
			config[value]['way'] * (
				targetCo[value] + config[value]['way']*eCo[config[value]['stack']]
			)
				>= config[value]['docWay']*docCo[config[value]['stack']]){
			return this.minus(value);
		}
		return value;
	},

    /*
	Function: draw
		Vẽ một đối tượng theo graphicsContext của nó, giới hạn các key được phép vẽ nếu cần

	Arguments:
		element - (element,string) Đối tượng cần vẽ
		graphicsContext - (<GraphicsContext>) GraphicsContext của đối tượng
		limitedKeys - (array) Danh sách các key được phép vẽ
		excludeKeys - (array) Danh sách các key không được phép vẽ

	See Also:
		<GraphicsContext>

	*/
	draw: function(element, graphicsContext, limitedKeys, excludeKeys){
		if (!isset(limitedKeys)) limitedKeys = ['inject','replace','relative','stackwidth', 'stackpos'];
		if ($type(excludeKeys) == 'array'){
			$each(excludeKeys, function(key){
				limitedKeys = limitedKeys.erase(key);
			});
		}

		element = $(element);

		if (isset(graphicsContext)){
			$each(graphicsContext, function(value, key){
	            if (key == 'inject' && limitedKeys.contains(key)){
            		element.inject(value.target, value.position);
	            }
	            else if (key == 'replace' && limitedKeys.contains(key)){
            		element.replaces(value.target);
	            }
	            else if (key == 'stackwidth' && limitedKeys.contains(key)){
            		this.stackWidth(element, value.target);
	            }
	            else if (key == 'relative' && limitedKeys.contains(key)){
	            	if (value.returnPos){
            			var pos = element.setPosition(value);
            			var top = pos.top;
            			var left = pos.left;
            			if (element.getSize().x + pos.left > document.getSize().x){
            				left = document.getSize().x - element.getSize().x - 30;
            			}

            			if (element.getSize().y + pos.top > document.getSize().y){
            				top = document.getSize().y - element.getSize().y - 30;
            			}

            			if (top < 0 || left < 0){
            				getErrorConsole().throwError('Kích thước cửa sổ cần mở quá lớn hoặc kích thước màn hình quá nhỏ');
            			}

            			element.set('styles', {
            				'top': top,
            				'left': left
            			});
					}
					else {
						element.setPosition(value);
					}
	            }
	            else if (key == 'samepos'){
					element.position({
    					relativeTo: value.target,
    					position: 'leftTop',
    					edge: 'leftTop'
    				});
	            }
	            else if (key == 'stackpos' && limitedKeys.contains(key)){
            		this.stackPosition(element, value.target, value.pop, value.align, value.offsetX, value.offsetY);
	            }
			}.bind(this));
		}
	},

	getMiddleTop: function(height){
		return document.getScrollTop() + (GFactory.getScreen().getHeight() - height)/2;
	},

	getMiddleLeft: function(width){
		return document.getScrollLeft() + (GFactory.getScreen().getWidth() - width)/2
	}
});

};filesWrapper['light.G/ResourceManager.js'] = function(){
	/*
Class: ResourceManager
	Manager quản lý resource, bao gồm theme và icon

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ ResourceManager /* */
= new Class({
	iconResources: new Array(),
	themeDataStorage: null,
	skinData: null,

	/*
	Function: installIconResource
		Cài đặt một icon resource, phải nằm trong thư mục resources/icons/ với tên file là tên của resource

	Arguments:
		resourceName - (string) Tên của icon resource
		resourcePath - (string)	Đường dẫn đến file chứa icon resource. File này phải chứa biến tĩnh IconResourceOptions
	*/
	installIconResource: function(resourceName, resourcePath){
		loadFile('core/Resources/IconResource.js');
		loadFile(resourcePath);
		this.iconResources[resourceName] = new IconResource(IconResourceOptions);
	},

	/*
	Function: getIconResource
		Lấy instance của icon resource, báo lỗi nếu không có resource nào như vậy

	Arguments:
		resourceName - (string) Tên của icon resource

	Returns:
		(mixed) Instance tương ứng với resource
	*/
	getIconResource: function(resourceName){
		if (!isset(this.iconResources[resourceName])){
			getErrorConsole().throwError('Không có resource nào có tên như vậy: ' + resourceName);
		}

		return this.iconResources[resourceName];
	},

	/*
	Function: getThemeDataStorage
		Lấy dữ liệu về theme đã được lưu

	Returns:
		(array) Dữ liệu theme
	*/
	getThemeDataStorage: function(){
		if (!isset(this.themeDataStorage)){
			this.themeDataStorage = new Registry();
		}

		return this.themeDataStorage;
	},

	/*
	Function: installTheme
		Cài đặt một theme

	Arguments:
		themeName - (string) Tên của theme
		themeFilePath - (string) Đường dẫn đến file chứa dữ liệu của theme. File này phải chứa biến tĩnh ThemeData
	*/
	installTheme: function(themeName, themeFilePath){
        loadFile(themeFilePath);
		this.getThemeDataStorage().set('/' + themeName, $H(ThemeData));
	},

	/*
	Function: installSkin
		Cài đặt một skin

	Arguments:
		skinName - (string) Tên của skin
		skinFilePath - (string) Đường dẫn đến file chứa dữ liệu của skin. File này phải chứa biến tĩnh SkinData
	*/
	installSkin: function(skinName, skinFilePath){
		if (isset(this.skinData)){
			getErrorConsole().throwError('Một skin khác đã được install. Trong cùng một hệ thống, bạn không thể cài đặt 2 skin');
		}

		loadFile(skinFilePath);
		this.skinData = $H(SkinData);
	},

	/*
	Function: getComponentView
		Lấy instance của view dành cho một component

	Arguments:
		componentName - (string) Tên của component cần lấy view
	*/
	getComponentView: function(componentName){
		if (!isset(this.skinData) || !isset(this.skinData[componentName]) || !isset(this.skinData[componentName].createView))
			this.installSkin('Basic', 'light.G/resources/skins/Basic.js');

		return this.skinData[componentName].createView();
	}
});
};filesWrapper['light.G/resources/skins/Basic.js'] = function(){
	SkinData = {
	'GButton': {
		createView: function(){
			loadFile('light.G/Skin/Basic/BasicButtonView.js');
			return new BasicButtonView.WithFocus();
		}
	},
	'GCheckbox': {
		createView: function(){
			loadFile('light.G/Skin/Basic/BasicCheckboxView.js');
			return new BasicCheckboxView();
		}
	},
	'GToggleButton': {
		createView: function(){
			loadFile('light.G/Skin/Basic/BasicToggleButtonView.js');
			return new BasicToggleButtonView();
		}
	},
	'GComboBox': {
		createView: function(){
			loadFile('light.G/Skin/Basic/BasicComboBoxView.js');
    		return new BasicComboBoxView();
		}
	},
	'GTooltip': {
		createView: function(){
			loadFile('light.G/Skin/Basic/BasicTooltipView.js');
    		return new BasicTooltipView();
		}
	},
	'GWindow': {
		createView: function(){
    		loadFile('light.G/Skin/Basic/BasicWindowView.js');
    		return new BasicWindowView();
		}
	}
};
};filesWrapper['light.G/resources/skins/Plastic.js'] = function(){
	SkinData = {
	'GButton': {
		createView: function(){
			loadFile('light.G/Skin/Plastic/PlasticButtonView.js');
			return new PlasticButtonView();
		}
	},
	'GToggleButton': {
		createView: function(){
			loadFile('light.G/Skin/Plastic/PlasticToggleButtonView.js');
			return new PlasticToggleButtonView();
		}
	},
	'GComboBox': {
		createView: function(){
			loadFile('light.G/Skin/Plastic/PlasticComboBoxView.js');
    		return new PlasticComboBoxView();
		}
	}
};
};filesWrapper['light.G/resources/themes/Basic/Buttons.rs.js'] = function(){
	ThemeData.Button = {
	main:						'btn',
	inner:						'btn-inner',
	inside:						'btn-inside',
	'inside-text':				'btn-inside-text',
	disabled:					'btn-disabled',
	invisible:					'btn-invisible',

	armedPressed:				'btn-armed-pressed',
	focus:						'btn-focus',
	armedFocus:					'btn-armed-focus',
	armed:						'btn-armed',

	selected:					'btn-selected',
    selectedArmedPressed:		'btn-selected-armed-pressed',
	selectedFocus:				'btn-selected-focus',
	selectedArmedFocus:			'btn-selected-armed-focus',
	selectedArmed:				'btn-selected-armed'
};

ThemeData.ToggleButton = {
	main:						'tgl-btn',
	inner:						'tgl-btn-inner',
	inside:						'tgl-btn-inside',
	'inside-text':				'tgl-btn-inside-text',
	disabled:					'tgl-btn-disabled',
	invisible:					'tgl-btn-invisible',

	armedPressed:				'tgl-btn-armed-pressed',
	focus:						'tgl-btn-focus',
	armedFocus:					'tgl-btn-armed-focus',
	armed:						'tgl-btn-armed',

	selected:					'tgl-btn-selected',
    selectedArmedPressed:		'tgl-btn-selected-armed-pressed',
	selectedFocus:				'tgl-btn-selected-focus',
	selectedArmedFocus:			'tgl-btn-selected-armed-focus',
	selectedArmed:				'tgl-btn-selected-armed'
};

ThemeData.Checkbox = {
    main:						'chkbx',
	inner:						'chkbx-inner',
	inside:						'chkbx-inside',
	'inside-text':				'chkbx-inside-text',
	'inside-checkarrow':		'chkbx-inside-checkarrow',
    'inside-arrow':				'chkbx-inside-arrow',
	disabled:					'chkbx-disabled',
	invisible:					'chkbx-invisible',
	armedPressed:				'chkbx-armed-pressed',
	focus:						'chkbx-focus',
	armedFocus:					'chkbx-armed-focus',
	armed:						'chkbx-armed',

	selected:					'chkbx-selected',
    selectedArmedPressed:		'chkbx-selected-armed-pressed',
	selectedFocus:				'chkbx-selected-focus',
	selectedArmedFocus:			'chkbx-selected-armed-focus',
	selectedArmed:				'chkbx-selected-armed'
};

ThemeData.RadioButton = {
    main:						'radiobtn',
	inner:						'radiobtn-inner',
	inside:						'radiobtn-inside',
	'inside-text':				'radiobtn-inside-text',
	'inside-checkarrow':		'radiobtn-inside-checkarrow',
    'inside-arrow':				'radiobtn-inside-arrow',
	disabled:					'radiobtn-disabled',
	invisible:					'radiobtn-invisible',
	armedPressed:				'radiobtn-armed-pressed',
	focus:						'radiobtn-focus',
	armedFocus:					'radiobtn-armed-focus',
	armed:						'radiobtn-armed',

	selected:					'radiobtn-selected',
    selectedArmedPressed:		'radiobtn-selected-armed-pressed',
	selectedFocus:				'radiobtn-selected-focus',
	selectedArmedFocus:			'radiobtn-selected-armed-focus',
	selectedArmed:				'radiobtn-selected-armed'
};

ThemeData.ComboBoxButton = {
	main:						'cbb-btn pkg',
	inner:						'cbb-btn-inner',
	inside:						'cbb-btn-inside pkg',
	'inside-text':				'cbb-btn-inside-text',
	'inside-arrow':				'cbb-btn-inside-arrow',
	disabled:					'cbb-btn-disabled',
	invisible:					'cbb-btn-invisible',

	armedPressed:				'cbb-btn-armed-pressed',
	focus:						'cbb-btn-focus',
	armedFocus:					'cbb-btn-armed-focus',
	armed:						'cbb-btn-armed'
};

ThemeData.ArrowButton = {
	main:						'arrow-btn',
	inner:						'arrow-btn-inner',
	inside:						'arrow-btn-inside',
	'inside-text':				'arrow-btn-inside-text',
	disabled:					'arrow-btn-disabled',
	invisible:					'arrow-btn-invisible',

	armedPressed:				'arrow-btn-armed-pressed',
	focus:						'arrow-btn-focus',
	armedFocus:					'arrow-btn-armed-focus',
	armed:						'arrow-btn-armed',

	selected:					'arrow-btn-selected',
    selectedArmedPressed:		'arrow-btn-selected-armed-pressed',
	selectedFocus:				'arrow-btn-selected-focus',
	selectedArmedFocus:			'arrow-btn-selected-armed-focus',
	selectedArmed:				'arrow-btn-selected-armed'
};
};filesWrapper['light.G/resources/themes/Basic/Global.rs.js'] = function(){
	ThemeData = {
	'Label': {
		main: 'label',
		inner: 'label-inner',
		disabled: 'label-disabled',
		invisible: 'label-invisible',
		selected: 'label-selected',
		armed: 'label-armed',
		selectedArmed: 'label-selected-armed'
	},

	'Dropdown': {
		main:						'dd pkg',
		disabled:					'dd-disabled',
		invisible:					'dd-invisible',
		focus:						'dd-focus'
	},

	'TextArea': {
		main:						'textarea',
		disabled:					'textarea-disabled',
		invisible:					'textarea-invisible'
	},

	'HtmlDocument': {
        main:						'hdoc',
		disabled:					'hdoc-disabled',
		invisible:					'hdoc-invisible'
	},

	'PopupMenu': {
		main:						'popup',
		inner:						'popup-inner',
		disabled:					'popup-disabled',
		invisible:					'popup-invisible'
	},

	'MenuItem': {
		main:						'mi btn',
		inner:						'btn-inner',
		inside:						'btn-inside',
		'inside-text':				'btn-inside-text',
		disabled:					'btn-disabled',
		invisible:					'btn-invisible',

		armedPressed:				'btn-armed-pressed',
		armed:						'btn-armed',

		selected:					'btn-selected',
        selectedArmedPressed:		'btn-selected-armed-pressed',
		selectedArmed:				'btn-selected-armed'
	},

    'ColorPickerButton': {
		main:						'btn',
		inner:						'btn-inner',
		inside:						'btn-inside',
		image:						'btn-image',
		disabled:					'btn-disabled',
		invisible:					'btn-invisible',

		color:						'btn-pick-color',

		armedPressed:				'btn-armed-pressed',
		focus:						'btn-focus',
		armedFocus:					'btn-armed-focus',
		armed:						'btn-armed'
	},

	'FontColorBoard': {
		main:						'cboard',
		inner:						'cboard-inner',
		'theme-color-title':		'cboard-theme-color-title',
		'theme-color-content-main':	'cboard-theme-color-content-main',
		'theme-color-content-sub':	'cboard-theme-color-content-sub',
		'standard-color-title':		'cboard-standard-color-title',
		'standard-color-content':	'cboard-standard-color-content',
		'more-colors-inside':		'cboard-more-colors-inside'
	},

    'BackColorBoard': {
		main:						'back-cboard',
		inner:						'back-cboard-inner',
		inside:						'back-cboard-inside'
	},

    'ColorPickerButton': {
		main:						'cp-btn',
		inner:						'cp-btn-inner',
		inside:						'cp-btn-inside',
		'inside-text':				'cp-btn-inside-text',
		disabled:					'cp-btn-disabled',
		invisible:					'cp-btn-invisible',
		'float-color':				'cp-btn-float-color',
		armedPressed:				'cp-btn-armed-pressed',
		focus:						'cp-btn-focus',
		armedFocus:					'cp-btn-armed-focus',
		armed:						'cp-btn-armed',
		selected:					'cp-btn-selected',
        selectedArmedPressed:		'cp-btn-selected-armed-pressed',
		selectedFocus:				'cp-btn-selected-focus',
		selectedArmedFocus:			'cp-btn-selected-armed-focus',
		selectedArmed:				'cp-btn-selected-armed'
	},

	'Table': {
		main: 'table',
		disabled: 'table-disabled',
		invisible: 'table-invisible',
		'Row': {
			main: 						'trow',
			disabled: 					'trow-disabled',
			invisible: 					'trow-invisible',
			armedPressed:				'trow-armed-pressed',
			armed:						'trow-armed',
			selectedArmedPressed:		'trow-selected',
			selectedArmed:				'trow-selected',
			selected:					'trow-selected'
		},

		'Cell': {
			main: 'tcell',
			disabled: 'tcell-disabled',
			invisible: 'tcell-invisible'
		}
	},

	'TextField': {
		main:							'txtfld',
		disabled:						'txtfld-disabled',
		invisible:						'txtfld-invisible',
		armedFocus:						'txtfld-armed',
		focus:							'txtfld-focus',
		armed:							'txtfld-armed'
	},

	'ProgressBar': {
		main:		'progress',
		inner:		'progress-inner',
		bar:		'progress-bar'
	},

	'FlashUploader': {
		'FilesList': {
			main:	'files-list',
			inner:	'files-list-inner'
		},
        'FileRow': {
        	main:	'file-row',
        	inner:	'file-row-inner',
        	'file-icon':	'file-row-icon',
        	'file-name':	'file-row-name',
        	'file-size':	'file-row-size',
        	'file-delete':	'file-row-delete',
        	selected:	'file-row-selected'
        },
		main:							'fu',
		inner:							'fu-inner'
	},

	'BlackHoleLayer': {
		'main':			'black-hole',
		'disabled':		'black-hole-disabled',
		'invisible':	'black-hole-invisible'
	},

	'Tooltip': {
		main:	'tooltip',
		inner:	'tooltip-inner'
	},

	'OverText': {
		main:	'overtext',
		inner:	'overtext-inner'
	}
};

};filesWrapper['light.G/resources/themes/Basic/Lists.rs.js'] = function(){
	ThemeData.List = {
    main:						'list',
	disabled:					'list-disabled',
	invisible:					'list-invisible'
};

ThemeData.List.ListRow = {
	main:						'list-r',
	inner:						'list-r-inner',
	disabled:					'list-r-disabled',
	invisible:					'list-r-invisible',

	armed:						'list-r-armed',
	selected:					'list-r-selected',
	selectedArmed:				'list-r-selected-armed'
};
};filesWrapper['light.G/resources/themes/Basic/Windows.rs.js'] = function(){
	ThemeData.Window = {
	'Layout': {
			'main':						'wnd',
			'inner':					'wnd-inner',
			'inside':					'wnd-inside',
			'disabled':					'wnd-disabled',
			'invisible':				'wnd-invisible',
			'activated':				'wnd-activated',
			'title':					'wnd-title',
			'title-inner':				'wnd-title-inner',
			'title-text':				'wnd-title-text',
			'title-draggable':			'wnd-title-draggable',
			'content':					'wnd-content',
			'content-inner':			'wnd-content-inner'
		},

		'CloseButton': {
            main:						'wnd-closebutton',
			inner:						'',
			inside:						'',
			'inside-text':				'',
			'inside-arrow':				'',
			disabled:					'wnd-closebutton-disabled',
			invisible:					'wnd-closebutton-invisible',
			armedPressed:				'wnd-closebutton-armed-pressed',
			focus:						'',
			armedFocus:					'',
			armed:						'wnd-closebutton-armed'
		}
}
};filesWrapper['light.G/resources/themes/Basic.js'] = function(){
	var themesPath = 'light.G/resources/themes/';
loadFile(themesPath + 'Basic/Global.rs.js');
loadFile(themesPath + 'Basic/Buttons.rs.js');
loadFile(themesPath + 'Basic/Lists.rs.js');
loadFile(themesPath + 'Basic/Windows.rs.js');
};filesWrapper['light.G/resources/themes/Plastic.js'] = function(){
	/**/
};filesWrapper['light.G/Skin/Basic/BasicArrowButtonView.js'] = function(){
	loadFile('light.G/Skin/ComboBoxView.js');

/* class */ BasicArrowButtonView /* extends ComboBoxView */
= new Class({
	Extends: ComboBoxView,
	relatedComponent: null,
	themePath: '/Basic/ArrowButton/',

	initialize: function(relatedComponent){
		if (!isset(relatedComponent)){
			getErrorConsole().throwError('Component có liên quan của combo box chỉ có arrow button không thể là null');
		}

		this.relatedComponent = relatedComponent;
		this.parent();
	},

	getPopupGraphicsContext: function(){
		return {
			'inject': {
				'target': document.body,
				'position': 'bottom'
			},
			'stackwidth': {
				'target': this.relatedComponent.getElement()
			},
			'stackpos': {
				'target': this.relatedComponent.getElement(),
				'pop': 'bottom',
				'align': 'left'
			}
		}
	},

	/* bởi vì đây là combo box bình thường, nó chắc chắn phải được vẽ có graphics context */
	getDefaultGraphicsContext: function(){
		return {
			'inject': {
				'target': this.relatedComponent.getElement(),
				'position': 'bottom'
			}
		}
	},

	paintInside: $empty,

	paintText: function(text){
		this.relatedComponent.setText(text);
	}
});
};filesWrapper['light.G/Skin/Basic/BasicButtonView.js'] = function(){
	loadFile('light.G/Skin/ButtonView.js');
/*
Class: BasicButtonView
	Mẫu cơ bản cho một view để vẽ ra một button có khả năng click được

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<ButtonView>

Direct Known Subclasses:
	<BasicButtonView.WithFocus>, <BasicButtonView.WithoutFocus>

Cấu trúc HTML:
	(start code)
this.domElement = new Element('div', {
    'id': c.getOption('id'),
	'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
}).set('html',
	'<div class="' + this.getTheme('inner') + '">' +
		'<div class="' + this.getTheme('inside') + '">' +
			'<div class="' + this.getTheme('inside-text') + '">' +
			'</div>' +
		'</div>' +
	'</div>'
);
	(end)
*/
/* class */ BasicButtonView /* extends ButtonView */
= new Class({
	Extends: ButtonView,
	paintInside: function(){
		var c = this.getComponent();
        if (this.compareState('text')){
        	this.getElement().set('html', c.getOption('text'));
		}
	},

	createDomElement: function(){
		var c = this.getComponent();
        this.domElement = new Element('div', {
        	'id': c.getOption('id'),
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		});
		c.attachWithElement(this.domElement);
	},

    paintState: /* abstract */ function(){
		getErrorConsole().throwError('Bạn phải override lại hàm paintState của BasicButtonView');
	}
});

/*
Class: BasicButtonView.WithFocus
	View thể hiện một button có khả năng chiếm focus. Vì có focus nên khi thể hiện ra màn hình, view này phải vẽ cả trạng thái focus. View này sử dụng <SystemListener> bằng cách gọi <ComponentView::installSystemListener> khi install

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicButtonView.WithFocus /**/
= new Class({
	Extends: BasicButtonView,
    paintState: function(){
		var c = this.getComponent();
        var classFlag = HelpersFactory.getTypeHelper().getFlagString([
        	c.isFocus(),
        	c.isPressed(),
        	c.isArmed()
        ]);

        var classesConfig = new Hash({
            '111':	this.getTheme('armedPressed'),
    		'110':	this.getTheme('focus'),
    		'101':	this.getTheme('armedFocus'),
    		'100':	this.getTheme('focus'),
    		'011': 	this.getTheme('armedPressed'),
    		'010':	'',
    		'001': 	this.getTheme('armed'),
    		'000':	''
		});

		classesConfig.each(function(value){
			c.getElement().removeClass(value);
		}.bind(this));

		c.getElement().addClass(classesConfig[classFlag]);
	},

	install: function(){
		this.parent();
		this.installSystemListener();
	},

	uninstall: function(){
		this.uninstallSystemListener();
		this.parent();
	}
});

/*
Class: BasicButtonView.WithoutFocus
	View thể hiện một button không có khả năng chiếm focus: khi click vào vẫn có pressed nhưng nó không chiếm focus của component khác

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicButtonView.WithoutFocus /* extends BasicButtonView */
= new Class({
	Extends: BasicButtonView,
    paintState: function(){
		var c = this.getComponent();
        var classFlag = HelpersFactory.getTypeHelper().getFlagString([
        	c.isPressed(),
        	c.isArmed()
        ]);

        var classesConfig = new Hash({
            '11':	this.getTheme('armedPressed'),
    		'10':	'',
    		'01': 	this.getTheme('armed'),
    		'00':	''
		});

		classesConfig.each(function(value){
			c.getElement().removeClass(value);
		}.bind(this));

		c.getElement().addClass(classesConfig[classFlag]);
	}
});
};filesWrapper['light.G/Skin/Basic/BasicCheckboxListView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicListView.js');

/*
Class: BasicCheckboxListView
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicCheckboxListView /* extends BasicListView */
= new Class({
	Extends: BasicListView,

	paintCell: function(item, index){

		var c = this.getComponent();

		/* Gọi renderer để lấy component */
		var renderer = c.getCellRenderer();
		if (!isset(renderer)) {
			loadFile('light.G/Comm/BasicListCellRenderer.js');
			renderer = DefaultListCellRenderer;
		}

		cell = renderer.getComponent(c, item, index, c.isSelectionIndex(index));

		/* tạo row và inject checkbox vào list */
		var rowElement = new Element('div');
		loadFile('light.G/Components/GDomElement.js');
		var row = new GDomElement(null, rowElement);
		var rowInsideContext = new Hash({
			'inject': {
				'target': rowElement,
				'position': 'bottom'
			}
		});

		loadFile('light.G/Components/GCheckbox.js');
		checkbox = new GCheckbox();

		row.add(checkbox, rowInsideContext);
		row.add(cell, rowInsideContext); /* cho cell vào bên cạnh checkbox */

		c.add(row);
    	c.addSubComponent(cell, index);
    	checkbox.addChangeListener(BasicCheckboxListView.CheckboxListener, cell, c);
    	cell.addMouseListener(BasicCheckboxListView.CellListener, c, checkbox);
	}
});

/* static class */ BasicCheckboxListView.CheckboxListener /* implements ChangeListener */
= new Hash({
	stateChanged: function(checkbox, property, value, cell, list){
		if (property == 'selected'){
			list.toggleSelectionIndex(cell.getIndex());
		}
	}
});

/* static class */ BasicCheckboxListView.CellListener /* implements MouseListener */
= new Hash({
	mouseDown: $empty,
	mouseUp: $empty,

    singleClick: function(e, cell, list, checkbox){
    	checkbox.toggleSelected();
	},

    doubleClick: $empty
});
};filesWrapper['light.G/Skin/Basic/BasicCheckboxTableView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicTableView.js');

/*
Class: BasicCheckboxTableView
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicCheckboxTableView /* extends BasicTableView */
= new Class({
	Extends: BasicTableView,
	paintRow: function(rowData, index){
		var c = this.getComponent();

		/* Gọi renderer để lấy component */
		var renderer = c.getRowRenderer();
		if (!isset(renderer)) {
			loadFile('light.G/Comm/DefaultTableRowRenderer.js');
			renderer = DefaultTableRowRenderer;
		}

		row = renderer.getComponent(c, rowData, index, c.isSelectionIndex(index));
		row.setCellRenderer(c.getCellRenderer());

    	c.add(row);
    	c.addSubComponent(row, index);

    	loadFile('light.G/Components/GCheckbox.js');
		var checkbox = new GCheckbox();

		var newColumn = new Element('td');
		newColumn.inject(row.getElement(), 'top');
		checkbox.setGraphicsContext({
			'inject': {
				'target': newColumn,
				'position': 'bottom'
			}
		});
		checkbox.paint();

    	checkbox.addChangeListener(BasicCheckboxTableView.CheckboxListener, row, c);
    	row.addChangeListener(BasicCheckboxTableView.RowListener, c, checkbox);
    	row.addMouseListener(BasicCheckboxTableView.RowListener, c, checkbox);
	}
});

/* static class */ BasicCheckboxTableView.CheckboxListener /* implements ChangeListener */
= new Hash({
	stateChanged: function(checkbox, property, value, row, table){
		if (property == 'selected'){
			if (value) table.addSelectionIndex(row.getIndex());
			else table.removeSelectionIndex(row.getIndex());
		}
	}
});

/* static class */ BasicCheckboxTableView.RowListener /* implements ChangeListener, MouseListener */
= new Hash({
	stateChanged: function(row, property, value, table, checkbox){
    	if (property == 'selected') checkbox.setSelected(value);
    },

	mouseDown: $empty,
	mouseUp: $empty,

    singleClick: function(e, row, table, checkbox){
    	checkbox.toggleSelected();
	},

    doubleClick: $empty
});
};filesWrapper['light.G/Skin/Basic/BasicCheckboxView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicToggleButtonView.js');

/* class */ BasicCheckboxView /* extends BasicToggleButtonView*/
= new Class({
	Extends: BasicToggleButtonView,
	themePath: 	'/Basic/Checkbox/',

    install: function(){
    	this.parent();
		this.returnFncs['toggleMouse'] = this.getComponent().addMouseListener(BasicCheckboxView.Listener);
	},

	uninstall: function(){
		this.getComponent().removeMouseListener(this.returnFncs['toggleMouse']);
		this.parent();
	}
});

/*
Class: BasicCheckboxView.Listener
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/

/* static class */ BasicCheckboxView.Listener /* implements MouseListener */
= new Hash({
    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, checkbox){
		if (checkbox.isEnabled()){
			checkbox.toggleSelected();
		}
	},
    doubleClick: $empty
});
};filesWrapper['light.G/Skin/Basic/BasicColorBlockView.js'] = function(){
	/*
Script: BasicColorBlockView
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/*
Class: BasicColorBlockView
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Skin/Basic/BasicButtonView.js');
/* class */ BasicColorBlockView /* extends BasicButtonView */
= new Class({
    Extends: BasicButtonView.WithoutFocus,
	themePath: 	'/Basic/ColorBlock/',

    paintInside: function(){
    	var c = this.getComponent();
		this.getElementByTheme('inside-color').set('styles', {
			'background-color': c.getColor()
		});
	},

	createDomElement: function(){
		this.parent();
		this.getElementByTheme('inside').grab(
			new Element('div', {
				'class': this.getTheme('inside-color')
			})
		);
	}
});
};filesWrapper['light.G/Skin/Basic/BasicComboBoxView.js'] = function(){
	/*
Script: BasicComboBoxView.js
	Class BasicComboBoxView dùng để vẽ ra màn hình và các listener cơ bản

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Skin/ComboBoxView.js');
/* class */ BasicComboBoxView /* extends ComboBoxView */
= new Class({
	Extends: ComboBoxView,
	themePath: '/Basic/ComboBoxButton/',

	createDomElement: function(){
		var c = this.getComponent();
		this.domElement = new Element('div', {
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		}).set('html',
'<div class="' + this.getTheme('inside-text') + '">'+
'</div>'+
'<div class="' + this.getTheme('inside-arrow') + '">'+
'</div>'
		);

		c.attachWithElement(this.domElement);
	},

	paintInside: function(){
		var c = this.getComponent();
        if (this.compareState('text')){
        	this.getElementByTheme('inside-text').set('html', c.getOption('text'));
		}
	},

	getPopupGraphicsContext: function(){
		return {
			/*'inject': {
				'target': this.getComponent().getElement(),
				'position': 'after'
			},*/
			'inject': {
				'target': document.body,
				'position': 'bottom'
			},
			'stackwidth': {
				'target': this.getComponent().getElement()
			},
			'stackpos': {
				'target': this.getComponent().getElement(),
				'pop': 'bottom',
				'align': 'left'
			}
		};
	},

	/* bởi vì đây là combo box bình thường, nó chắc chắn phải được vẽ có graphics context */
	getDefaultGraphicsContext: $empty,

	paintText: function(text){
		this.getComponent().setText(text);
	}

});
};filesWrapper['light.G/Skin/Basic/BasicDesktopView.js'] = function(){
	/*
Script: BasicDesktopView.js
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/*
Class: BasicDesktopView
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/

loadFile('light.G/Skin/ComponentView.js');

/* class */ BasicDesktopView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
    getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement('.container-inner'),
				'position': 'bottom'
			}
		});
	},

    paint: function(){
		this.resizeToFitWindow();
	},

    repaint: function(){
    	var c = this.getComponent();
    	/*if (this.compareState('activated')){
			if (c.getOption('activated')){
				GFactory.getComponentManager().setActivatedComponent(c);
			}
		}*/

    	this.resizeToFitWindow();
	},

	resizeToFitWindow: function(){
        this.getElement().setStyles({
        	height: null
        });

        var elementSize = this.getElement().getSize();
        var documentSize = document.getSize();

        if (documentSize.y > elementSize.y){
        	GFactory.getPaint().setHeight(this.getElement(), documentSize.y);
        }
        var docWidth = documentSize.x;
        if (docWidth % 2 == 1) docWidth -= 1;
        GFactory.getPaint().setWidth(this.getElement(), docWidth);
	},

    createDomElement: function(){
        this.domElement = this.getComponent().getOption('baseElement');
        this.getComponent().attachWithElement(this.domElement);
	},

    install: function(){
    	this.createDomElement();
		this.installSystemListener();
		this.returnFncs['change'] = this.getComponent().addChangeListener(BasicDesktopView.Listener);
		this.returnFncs['window'] = this.getComponent().addWindowListener(BasicDesktopView.Listener);

	},

	uninstall: function(){
        this.getComponent().removeWindowListener(this.returnFncs['window']);
		this.uninstallSystemListener();
		this.destroyDomElement();
	}
});

/*
Class: BasicDesktopView.Listener
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
/* static class */ BasicDesktopView.Listener /* implements WindowListener, ChangeListener */
= new Hash ({
	stateChanged: function(desktop){
		desktop.repaint();
	},

    wndBlur: $empty,
    wndFocus: $empty,
    wndLoad: $empty,

    wndResize: function(e, desktop){
    	desktop.repaint();
	},

    wndScroll: $empty,
    wndBeforeUnload: $empty,
    wndUnload: $empty
});
};filesWrapper['light.G/Skin/Basic/BasicHtmlDocumentView.js'] = function(){
	/*
Script: HtmlDocumentView.js
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
loadFile('light.G/Skin/ComponentView.js');
/* class */ BasicHtmlDocumentView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: 	'/Basic/HtmlDocument/',

	/*
	Variable: iframe
		Lưu giữ iframe của View
	*/
	iframe: null,

	/*
	Variable: win
		Window bao ngoài của View
	*/
	win: null,

	/*
	Variable: doc
		HTML Document để View tạo dựng editable
	*/
	doc: null,
	busy: false,
	lastSelectionRange: null,

	paint: function(){
		var c = this.getComponent();
		GFactory.getPaint().draw(this.iframe, c.getGraphicsContext());

        // contentWindow and document references
		this.win = this.iframe.contentWindow;
		this.doc = this.win.document;

        // Build the content of iframe
		var documentTemplate = ''+
			'<html style="cursor: text; height: 100%">'+
				'<head>' + (c.getOption('cssPath') ? "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + c.getOption('cssPath') + "\" />" : "") + '</head>'+
				'<body id=\"editable\"' + (c.getOption('cssClass') ? " class=\"" + c.getOption('cssClass') + "\"" : "") + ' style="border: 0">'+
				c.getOption('text') +
				'</body>'+
			'</html>'+
		'';
		this.doc.open();
		this.doc.write(documentTemplate);
		this.doc.close();

        // Turn on Design Mode
		// IE fired load event twice if designMode is set
		(Browser.Engine.trident) ? this.doc.body.contentEditable = true : this.doc.designMode = 'On';

        // document.window for IE, for new Document code below
		if (Browser.Engine.trident) this.doc.window = this.win;

        // Mootoolize document and body
		if (!this.doc.$family) new Document(this.doc);
		$(this.doc.body);

        /*
        *	make images selectable and draggable in Safari
        *	cái này làm sau
        */
		/*if (Browser.Engine.webkit) this.doc.addEvent('click', function(e){
			var el = e.target;
			if (el.get('tag') == 'img') self.selectNode(el);
		});*/

		this.paintBorder();
		this.installDocEvents();
	},

	paintBorder: function(){
        var c = this.getComponent();
        this.iframe.set('class', this.getTheme('main'));
    	this.iframe.stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.iframe.stackClass(this.getTheme('invisible'), !c.isVisible());

    	GFactory.getPaint().setWidth(this.iframe, c.getOption('width'));
    	GFactory.getPaint().setHeight(this.iframe, c.getOption('height'));
	},

	repaint: function(){
        /*
		*	hàm repaint chủ yếu cần vẽ lại các yêu cầu của model
		*	liên quan đến focus và disabled, invisible
		*	tất cả các việc tương tác khác đều được thực hiện qua các hàm thành phần
		*/
		var c = this.getComponent();
		this.paintBorder();
    	if (c.isFocus()){
    		this.win.focus();
    	}
	},

	createDomElement: function(){
        var c = this.getComponent();
		this.domElement = new IFrame();
		this.iframe = this.domElement;
        c.attachWithElement(this.iframe);
	},

	install: function(){
		this.createDomElement();
		var c = this.getComponent();
		this.returnFncs['systemMouse'] = new Hash({
			'mousedown': function(e){
				SystemListener.mouseDown(e, c);
				e.stopPropagation();
			}.bind(this),
			'mouseup': function(e){
				SystemListener.mouseUp(e, c);
				e.stopPropagation();
			}.bind(this)
		});

        this.returnFncs['systemMouse'].each(function(value, key){
        	this.iframe.addEvent(key, value);
        }.bind(this));

		this.installSystemListener();
		this.returnFncs['docChange'] = c.addChangeListener(BasicHtmlDocumentView.Listener);

		if (Browser.Engine.trident) {
			this.returnFncs['saveSelectionMouse'] = new Hash({
				'mouseup': function(e){
					BasicHtmlDocumentView.SaveSelectionListener.mouseUp(e, c);
					e.stopPropagation();
				}.bind(this)
			});

			this.returnFncs['saveSelectionMouse'].each(function(value, key){
        		this.iframe.addEvent(key, value);
	        }.bind(this));
		}
	},

	installDocEvents: function(){
		/*
        *	trình duyệt coi sự kiện mouse lên iframe và lên doc bên trong
        *	là 2 sự kiện riêng biệt nên ta phải add thêm sự kiện cho doc
        */

        this.returnFncs['systemMouse'].each(function(value, key){
        	this.doc.addEvent(key, value);
        }.bind(this));

        this.returnFncs['keyboard'] = this.getComponent().addKeyboardListener(BasicHtmlDocumentView.Listener);

        if (Browser.Engine.trident) {
        	this.returnFncs['saveSelectionKeyboard'] = this.getComponent().addKeyboardListener(BasicHtmlDocumentView.SaveSelectionListener);
        	this.returnFncs['saveSelectionMouse'].each(function(value, key){
        		this.doc.addEvent(key, value);
	        }.bind(this));
		}
	},

	uninstall: function(){
		var c = this.getComponent();
        this.returnFncs['systemMouse'].each(function(value, key){
        	this.iframe.removeEvent(key, value);
        	// remove vì bên trên có add
        	this.doc.removeEvent(key, value);
        }.bind(this));

		this.uninstallSystemListener();
		c.removeChangeListener(this.returnFncs['docChange']);
		c.removeKeyboardListener(this.returnFncs['keyboard']);

		if (Browser.Engine.trident) {
			c.removeKeyboardListener(this.returnFncs['saveSelectionKeyboard']);
			this.returnFncs['saveSelectionMouse'].each(function(value, key){
        		this.iframe.removeEvent(key, value);
        		this.doc.removeEvent(key, value);
	        }.bind(this));
		}

		this.destroyDomElement();
	},

    addKeyboardListener: function(){
    	var keyboardListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);

        var returnFncs = new Hash({
			'keypress': function(e){
				var newArguments = [e, this.getComponent()].extend(realArguments);
				keyboardListenerHash.keyPress.run(newArguments);
			}.bind(this),
			'keyup': 	function(e){
				var newArguments = [e, this.getComponent()].extend(realArguments);
				keyboardListenerHash.keyUp.run(newArguments);
			}.bind(this),
			'keydown': function(e){
				var newArguments = [e, this.getComponent()].extend(realArguments);
				keyboardListenerHash.keyDown.run(newArguments);
			}.bind(this)
		});

		returnFncs.each(function(value, key){
			this.doc.addEvent(key, value);
		}.bind(this));

		return returnFncs;
	},

	removeKeyboardListener: function(returnFncs){
        returnFncs.each(function(value, key){
			this.doc.removeEvent(key, value);
		}.bind(this));
	},

    getContent: function() {
		return this.doc.getElement('#editable').get('html');
	},

    setContent: function(newContent) {
		(function() {
			this.doc.getElement('#editable').set('html', newContent);
		}).bind(this).delay(1); // dealing with Adobe AIR's webkit bug
		return this;
	},

    getSelection: function() {
		return (this.win.getSelection) ? this.win.getSelection() : this.doc.selection;
	},

	getRange: function() {
		var s = this.getSelection();

		if (!s) return null;

		try {
			return s.rangeCount > 0 ? s.getRangeAt(0) : (s.createRange ? s.createRange() : null);
		} catch (e) {
			// IE bug when used in frameset
			return this.doc.body.createTextRange();
		}
	},

	setRange: function(range) {
		if (range.select) $try(function(){
				range.select();
			});
		else {
			var s = this.getSelection();
			if (s.addRange) {
				s.removeAllRanges();
				s.addRange(range);
			}
		}
	},

	selectNode: function(node, collapse) {
		var r = this.getRange();
		var s = this.getSelection();

		if (r.moveToElementText) $try(function(){
				r.moveToElementText(node);
				r.select();
			});
		else if (s.addRange) {
			collapse ? r.selectNodeContents(node) : r.selectNode(node);
			s.removeAllRanges();
			s.addRange(r);
		} else
			s.setBaseAndExtent(node, 0, node, 1);

		return node;
	},

	isCollapsed: function() {
		var r = this.getRange();
		if (r.item) return false;
		return r.boundingWidth == 0 || this.getSelection().isCollapsed;
	},

	collapse: function(toStart) {
		var r = this.getRange();
		var s = this.getSelection();

		if (r.select) {
			r.collapse(toStart);
			r.select();
		}
		else
			toStart ? s.collapseToStart() : s.collapseToEnd();
	},

	getSelectedContent: function() {
		var r = this.getRange();
		var body = new Element('body');

		if (this.isCollapsed()) return '';

		if (r.cloneContents) body.appendChild(r.cloneContents());
		else if ($defined(r.item) || $defined(r.htmlText)) body.set('html', r.item ? r.item(0).outerHTML : r.htmlText);
		else body.set('html', r.toString());

		var content = body.get('html');
		return content;
	},

	getSelectedText: function() {
		var r = this.getRange();
		var s = this.getSelection();

		return this.isCollapsed() ? '' : r.text || s.toString();
	},

	getSelectedNode: function() {
		var r = this.getRange();

		if (!Browser.Engine.trident) {
			var el = null;

			if (r) {
				el = r.commonAncestorContainer;

				// Handle selection a image or other control like element such as anchors
				if (!r.collapsed)
					if (r.startContainer == r.endContainer)
						if (r.startOffset - r.endOffset < 2)
							if (r.startContainer.hasChildNodes())
								el = r.startContainer.childNodes[r.startOffset];

				while ($type(el) != 'element') el = el.parentNode;
			}

			return $(el);
		}

		return $(r.item ? r.item(0) : r.parentElement());
	},

	insertContent: function(content) {
		var r = this.getRange();

		if (r.insertNode) {
			r.deleteContents();
			r.insertNode(r.createContextualFragment(content));
		}
		else {
			// Handle text and control range
			if (r.pasteHTML) r.pasteHTML(content);
			else r.item(0).outerHTML = content;
		}
	},

	execute: function(command, value){
        if (!this.busy) {
        	if (Browser.Engine.trident) {
        		this.restoreSelection();
			}

			this.busy = true;
            var mustStyleWithCss = ['hilitecolor'];
            var setValue = mustStyleWithCss.contains(command) || this.getComponent().getOption('styleWithCss');

			if (!['trident', 'presto'].contains(Browser.Engine.name))
				this.doc.execCommand(
					'styleWithCSS',
					false,
					setValue
				);

			if (command == 'hilitecolor' && (Browser.Engine.trident || Browser.Engine.webkit) ){
				command = 'backcolor';
			}

			this.doc.execCommand(command, false, value);
			this.busy = false;
		}
	},

	saveSelection: function(){
		this.lastSelectionRange = this.getRange();
	},

	restoreSelection: function(){
		this.setRange(this.lastSelectionRange);
	}
});

/* static class */ BasicHtmlDocumentView.Listener /* implements ChangeListener, KeyboardListener */
= new Hash({
    stateChanged: function(theDoc){
    	theDoc.repaint();
	},

    keyPress: $empty,

	keyUp: $empty,

    keyDown: function(e, document){
        if (e.key == 'enter') {
        	var paragraphise = true;
			if (paragraphise && !e.shift) {
				if (Browser.Engine.gecko || Browser.Engine.webkit) {
					var node = document.getSelectedNode();
					var blockEls = /^(H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD)$/;
					var parentNodes = node.getParents();
					/*if (parentNodes.length == 1 ){
						var isBlock = true;
					}
					else {*/
					var isBlock = parentNodes.include(node).some(function(el){
						return el.nodeName.test(blockEls);
					});
					/*}*/

					if (!isBlock) document.execute('insertparagraph');
				}
			}
			else {
				if (Browser.Engine.trident) {
					var r = document.getRange();
					var node = document.getNode();
					if (node.get('tag') != 'li') {
						if (r) {
							document.insertContent('<br>');
							document.collapse(false);
						}
					}
					e.stop();
				}
			}
		}
	}
});

/* class */ BasicHtmlDocumentView.SaveSelectionListener /* */
= new Hash({
	mouseUp: function(e, htmlDocument){
		htmlDocument.saveSelection();
	},

	keyPress: $empty,
	keyUp: function(e, htmlDocument){
		var interestingKeys = [35,36,37,39];
		if (interestingKeys.contains(e.code)){
			htmlDocument.saveSelection();
		}
	},

    keyDown: $empty
});
};filesWrapper['light.G/Skin/Basic/BasicLabelView.js'] = function(){
	loadFile('light.G/Skin/LabelView.js');

/*
Class: BasicLabelView
	Description cho class

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicLabelView /* extends LabelView */
= new Class({
	Extends: LabelView,
	themePath: '/Basic/Label/',

	getInsideContext: function(){
		return new Hash({
			'inject': {
				'target': this.getElementByTheme('inner'),
				'position': 'bottom'
			}
		});
	},

	createDomElement: function(){
		var c = this.getComponent();
        this.domElement = new Element('div', {
        	'id': c.getOption('id'),
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		}).set('html',
'<div class="' + this.getTheme('inner') + '">' +
'</div>'
		);
		c.attachWithElement(this.domElement);
	},

	paintInside: function(){
		var c = this.getComponent();
        if (this.compareState('text')){
        	this.getElementByTheme('inner').set('html', c.getOption('text'));
		}
	},

	paintState: function(){
		getErrorConsole().throwError('Phải nạp chồng hàm paintState của BasicLabelView');
	}
});

/* class */ BasicLabelView.Selectable /* extends BasicLabelView */
= new Class({
	Extends: BasicLabelView,
	paintState: function(){
		this.getElement().stackClass(this.getTheme('selected'), this.getComponent().isSelected());
	}
});

/* class */ BasicLabelView.FullState /* */
= new Class({
	Extends: BasicLabelView,
	paintState: function(){
		var c = this.getComponent();
        var classFlag = HelpersFactory.getTypeHelper().getFlagString([
        	c.isSelected(),
        	c.isArmed()
        ]);

        var classesConfig = new Hash({
            '00':	'',
            '01':	this.getTheme('armed'),
    		'10':	this.getTheme('selected'),
    		'11':	this.getTheme('selectedArmed')
		});

		classesConfig.each(function(value){
			c.getElement().removeClass(value);
		}.bind(this));

		c.getElement().addClass(classesConfig[classFlag]);
	},

	install: function(){
		this.parent();
		this.returnFncs['mouseMotion'] = this.getComponent().addMouseMotionListener(BasicLabelView.FullState.Listener);
	},

	uninstall: function(){
		this.getComponent().removeMouseMotionListener(this.returnFncs['mouseMotion']);
		this.parent();
	}
});

/* static class */ BasicLabelView.FullState.Listener /* */
= new Hash({
	mouseEnter: $empty,
	mouseLeave: $empty,

	mouseOver: function(e, label){
		if (label.isEnabled()){
    		label.setArmed(true);
		}
	},

	mouseOut: function(e, label){
		if (label.isEnabled()){
			label.setArmed(false);
		}
	}
});
};filesWrapper['light.G/Skin/Basic/BasicListView.js'] = function(){
	loadFile('light.G/Skin/ListView.js');
/* class */ BasicListView /* extends ListView */
= new Class({
	Extends: ListView,
	themePath: '/Basic/List/',

	createDomElement: function(){
        this.domElement = new Element('div');
		this.getComponent().attachWithElement(this.domElement);
	},

    getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement(),
				'position': 'bottom'
			}
		});
	},

	paintBorder: function(){
        var c = this.getComponent();
        this.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));
    	this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());

    	GFactory.getPaint().setWidth(this.getElement(), c.getOption('width'));
    	GFactory.getPaint().setHeight(this.getElement(), c.getOption('height'));
	},

	paintChildren: function(){
        var c = this.getComponent();
    	var data = c.getAllData();
    	data.each(function(item, index){
    		this.paintCell(item, index);
    	}.bind(this));

		if (c.getModel().getSize() > c.getOption('maxRow')){
			this.getElement().setStyles({
				'height': c.getOption('maxRow') * c.getOption('rowHeight'),
				'overflow': 'auto'
			});
		}
	},

	paintCell: function(item, index){
		var c = this.getComponent();
		/* Gọi renderer để lấy component */
		var renderer = c.getCellRenderer();
		if (!isset(renderer)) {
			loadFile('light.G/Comm/DefaultListCellRenderer.js');
			renderer = DefaultListCellRenderer;
		}
		var cell = renderer.getComponent(c, item, index, c.isSelectionIndex(index));
    	c.add(cell);
    	c.addSubComponent(cell, index);
    	cell.addMouseListener(BasicListView.CellListener, c);
	}
});

/*
Class: BasicListView.CellListener
	Listener mặc định lắng nghe state của một cell trong list

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ BasicListView.CellListener /* implements MouseListener */
= new Hash({

	stateChanged: function(menuItem, property, value, theList){},

    mouseDown: $empty,

	mouseUp: $empty,

    singleClick: function(e, cell, theList){
    	if (theList.getSelectionMode() == 'multiple'){
    		if (e.control == true){
    			if (e.shift == true){
    				theList.shiftSelectionToIndex(cell.getIndex());
    			}
    			else {
    				theList.toggleSelectionIndex(cell.getIndex());
				}
    		}
    		else {
    			theList.setSelectionIndex(cell.getIndex());
			}
		}
		else {
			theList.setSelectionIndex(cell.getIndex());
		}
	},

	doubleClick: $empty
});
};filesWrapper['light.G/Skin/Basic/BasicMenuItemView.js'] = function(){
	/*
Script: BasicMenuItemView
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/*
Class: BasicMenuItemView
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Skin/Basic/BasicButtonView.js');
/* class */ BasicMenuItemView /* extends BasicButtonView */
= new Class({
	Extends: BasicButtonView,
	themePath: 	'/Basic/MenuItem/',

    paintState: function(){
        var c = this.getComponent();
        var classFlag = HelpersFactory.getTypeHelper().getFlagString([
        	c.isSelected(),
        	c.isPressed(),
        	c.isArmed()
        ]);

        var classesConfig = new Hash({
    		'011': this.getTheme('armedPressed'),
    		'010':	'',
    		'001': this.getTheme('armed'),
    		'000':	'',
    		'111': this.getTheme('selectedArmedPressed'),
    		'110':	'',
    		'101': this.getTheme('selectedArmed'),
    		'100':	this.getTheme('selected')
		});

		classesConfig.each(function(value){
			c.getElement().removeClass(value);
		}.bind(this));

		c.getElement().addClass(classesConfig[classFlag]);
	}
});
};filesWrapper['light.G/Skin/Basic/BasicRadioButtonView.js'] = function(){
	/*
Script: BasicRadioButtonView
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/*
Class: BasicRadioButtonView
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/

loadFile('light.G/Skin/Basic/BasicToggleButtonView.js');

/* class */ BasicRadioButtonView /* */
= new Class({
	Extends: BasicToggleButtonView.Selectable,
	themePath: '/Basic/RadioButton/'
});
};filesWrapper['light.G/Skin/Basic/BasicTableView.js'] = function(){
	loadFile('light.G/Skin/ListView.js');

/*
Class: BasicTableView
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicTableView /* extends ListView */
= new Class({
	Extends: ListView,
	themePath: '/Basic/Table/',

	createDomElement: function(){
        this.domElement = new Element('table');
		this.getComponent().attachWithElement(this.domElement);
	},

    getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement(),
				'position': 'bottom'
			}
		});
	},

	paintBorder: function(){
        var c = this.getComponent();
        this.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));
    	this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());
    	GFactory.getPaint().setWidth(this.getElement(), c.getOption('width'));
    	GFactory.getPaint().setHeight(this.getElement(), c.getOption('height'));
	},

	paintChildren: function(){
		//console.log('trying to paint children in table');
        var c = this.getComponent();
    	var data = c.getAllData();
    	data.each(function(rowData, index){
    		this.paintRow(rowData, index);
    	}.bind(this));
	},

	paintRow: function(rowData, index){
		var c = this.getComponent();

		/* Gọi renderer để lấy component */
		var renderer = c.getRowRenderer();
		if (!isset(renderer)) {
			loadFile('light.G/Comm/DefaultTableRowRenderer.js');
			renderer = DefaultTableRowRenderer;
		}

		row = renderer.getComponent(c, rowData, index, c.isSelectionIndex(index));
		row.setCellRenderer(c.getCellRenderer());
    	c.add(row);
    	c.addSubComponent(row, index);
    	row.addMouseListener(BasicTableView.RowListener, c);
	}
});

/* static class */ BasicTableView.RowListener /* implements MouseListener */
= new Hash({

	stateChanged: $empty,
    mouseDown: $empty,
	mouseUp: $empty,

    singleClick: function(e, row, table){
    	table.toggleSelectionIndex(row.getIndex());
	},

	doubleClick: $empty
});

};filesWrapper['light.G/Skin/Basic/BasicTextAreaView.js'] = function(){
	/*
Script: BasicTextAreaView
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/*
Class: BasicTextAreaView
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Skin/ComponentView.js');
/* class */ BasicTextAreaView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	textArea: null,
	themePath: 	'/Basic/TextArea/',

	initialize: function(textArea){
		this.textArea = textArea;
		this.parent();
	},

    paint: function(){
    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
    	this.paintBorder();
    	this.paintText();
    	this.paintOverText();
    	this.saveState();
	},

	paintBorder: function(){
        var c = this.getComponent();
        this.getElement().set('class', this.getTheme('main'));
    	this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());
        GFactory.getPaint().setWidth(this.getElement(), c.getOption('width'));
    	GFactory.getPaint().setHeight(this.getElement(), c.getOption('height'));
	},

	paintText: function(){
		var c = this.getComponent();
        if (this.compareState('text')){
			this.getElement().set('value', c.getOption('text'));
		}
	},

	getText: function(){
		return this.getElement().get('value');
	},

	repaint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
		this.paintBorder();
		this.paintText();
		this.saveState();
	},

	createDomElement: function(){
		var c = this.getComponent();

		if (!isset(this.textArea)){
			this.domElement = new Element('textarea', {
				'name': c.getOption('name'),
				'id': c.getOption('id')
			});
		}
		else {
			this.domElement = this.textArea;
		}

		this.getComponent().attachWithElement(this.domElement);
	},

	paintOverText: function(){
		var c = this.getComponent();
		if (!isset(c.getOption('overText')) || trim(c.getOption('overText')) == '') return;
		/* Gọi renderer để lấy component */
		var renderer = c.getOverTextRenderer();
		if (!isset(renderer)) {
			loadFile('light.G/Comm/DefaultTextFieldOverTextRenderer.js');
			renderer = DefaultTextFieldOverTextRenderer;
		}

		var graphicsContext = {
			'inject': {
				'target': this.getElement(),
				'position': 'after'
			},
			'samepos': {
				'target': this.getElement()
			}
		};
		this.overText = renderer.getComponent(c, c.getOption('overText'), graphicsContext);
		c.addSubComponent(this.overText, 'overText');

		if (this.getText().trim() != '') {
			this.overText.hide();
		}
	},

	install: function(){
		this.createDomElement();
		this.installSystemListener();
		var c = this.getComponent();
		this.returnFncs['change'] = c.addChangeListener(BasicTextAreaView.Listener);
		this.returnFncs['mouseMotion'] = c.addMouseMotionListener(BasicTextAreaView.Listener);
		this.textArea.addEvents({
			'mousedown': 	function(e){
				if (isset(e)) e.stopPropagation(); // chặn không cho chạy xuống dưới vì đã có sự kiện focus
			},
			'focus': function(){
				GFactory.getComponentManager().makeFocus(c);
			},
			'blur': function(){
				GFactory.getComponentManager().resetFocus(c);
			}
		});

	},

	uninstall: /* abstract */ function(){
        var c = this.getComponent();
        c.removeChangeListener(this.returnFncs['change']);
		this.uninstallSystemListener();
		this.destroyDomElement();
	}
});

/* class */ BasicTextAreaView.Listener /* implements ChangeListener */
= new Hash({
	stateChanged: function(textArea, property, value){
		if (property == 'focus'){
			if (isset(textArea.getOption('overText')) && textArea.getOption('overText') != ''){
				if (value == false){
	                if (textArea.getText().trim() == ''){
    					var overText = textArea.getSubComponent('overText');
						overText.show();
    				}
				}
				else {
					textArea.getElement().focus();
					var overText = textArea.getSubComponent('overText');
					overText.hide();
				}
			}
		}

		textArea.repaint();
	},

    mouseEnter: function(e, textArea){
        if (textArea.isEnabled()){
    		textArea.setArmed(true);
		}
	},

	mouseLeave: function(e, textArea){
        if (textArea.isEnabled()){
    		textArea.setArmed(false);
		}
	},

	mouseOver: $empty,
	mouseOut: $empty
});
};filesWrapper['light.G/Skin/Basic/BasicTextFieldView.js'] = function(){
	/*
Class: BasicTextFieldView
	Lớp thể hiện view của một textfield dưới dạng đơn giản nhất

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
loadFile('light.G/Skin/ComponentView.js');

/* class */ BasicTextFieldView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: 	'/Basic/TextField/',
	textField: null,

	initialize: function(textField){
		if (isset(textField)) this.textField = textField;
		this.parent();
	},

    paint: function(){
    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
    	this.paintBorder();
    	//this.paintText();
    	this.paintOverText();
    	this.saveState();
	},

	paintBorder: function(){
        var c = this.getComponent();
        this.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));

    	if (c.isEnabled()){
    		this.textField.set('disabled', false);
    		this.paintState();
    	}
    	else {
    		this.textField.set('disabled', true);
    	}

    	this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());

        GFactory.getPaint().setWidth(this.getElement(), c.getOption('width'));
    	GFactory.getPaint().setHeight(this.getElement(), c.getOption('height'));
        GFactory.getPaint().setWidth(this.textField, c.getOption('width'));
    	GFactory.getPaint().setHeight(this.textField, c.getOption('height'));
	},

    paintState: function(){
		var c = this.getComponent();
        var classFlag = HelpersFactory.getTypeHelper().getFlagString([
        	c.isFocus(),
        	c.isArmed()
        ]);

        var classesConfig = new Hash({
    		'11':	this.getTheme('armedFocus'),
    		'10':	this.getTheme('focus'),
    		'01': 	this.getTheme('armed'),
    		'00':	''
		});

		classesConfig.each(function(value){
			c.getElement().removeClass(value);
		}.bind(this));

		c.getElement().addClass(classesConfig[classFlag]);
	},

	paintText: function(){
        var c = this.getComponent();
        /*
        *	việc checkstate của text đảm bảo chỉ vẽ lại text khi ta thay đổi text từ option
        *	không liên quan đến việc gõ lên ô textbox
        *	làm như thế này để tránh việc mỗi lần gõ một chữ, ta lại phải set vào Model một lần
        */
        if (this.compareState('text')){
			this.textField.set('value', c.getOption('text'));
		}
	},

	setText: function(newValue){
		this.textField.set('value', newValue);
	},

	paintOverText: function(){
		var c = this.getComponent();
		if (!isset(c.getOption('overText')) || trim(c.getOption('overText')) == '') return;
		/* Gọi renderer để lấy component */
		var renderer = c.getOverTextRenderer();
		if (!isset(renderer)) {
			loadFile('light.G/Comm/DefaultTextFieldOverTextRenderer.js');
			renderer = DefaultTextFieldOverTextRenderer;
		}

		var graphicsContext = {
			'inject': {
				'target': this.getElement(),
				'position': 'after'
			},
			'samepos': {
				'target': this.getElement()
			}
		};
		this.overText = renderer.getComponent(c, c.getOption('overText'), graphicsContext);
		c.addSubComponent(this.overText, 'overText');

		if (this.getText().trim() != '') {
			this.overText.hide();
		}
	},

	getText: function(){
		return this.textField.get('value');
	},

	repaint: function(){
		var c = this.getComponent();
		GFactory.getPaint().draw(this.getElement(), c.getGraphicsContext(), null, ['inject']);
		this.paintBorder();
		//this.paintText();
		this.saveState();
	},

	createDomElement: function(){
		var c = this.getComponent();
		this.domElement = new Element('div');
		c.attachWithElement(this.domElement);
		this.createTextField();
	},

	createTextField: function(){
		if (!isset(this.textField)){
			var c = this.getComponent();
			this.textField = new Element('input', {
				'type': 'text',
				'name': c.getOption('name'),
				'id': c.getOption('id')
			});
		}
		else {
			//this.textField = this.textField.clone();
		}

		this.domElement.grab(this.textField);
	},

	install: function(){
		this.parent();
		this.installSystemListener();
        var c = this.getComponent();
		this.returnFncs['change'] = c.addChangeListener(BasicTextFieldView.Listener);
		this.returnFncs['mouseMotion'] = c.addMouseMotionListener(BasicTextFieldView.Listener);
		this.textField.addEvents({
			'mousedown': 	function(e){
				if (isset(e)) e.stopPropagation(); // chặn không cho chạy xuống dưới vì đã có sự kiện focus
			},
			'focus': function(){
				GFactory.getComponentManager().makeFocus(c);
			},
			'blur': function(){
				GFactory.getComponentManager().resetFocus(c);
			}
		});
	},

	uninstall: function(){
    	var c = this.getComponent();
        c.removeChangeListener(this.returnFncs['change']);
        c.removeMouseMotionListener(this.returnFncs['mouseMotion']);
		this.uninstallSystemListener();
		this.parent();
	}
});

/* class */ BasicTextFieldView.WithTooltip /* extends BasicTextFieldView */
= new Class({
	Extends: BasicTextFieldView,
	install: function(){
		this.parent();
		this.installTooltip();
	},

	uninstall: function(){
		this.uninstallTooltip();
		this.parent();
	}
});

/*
Class: BasicTextFieldView.Listener
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
/* static class */ BasicTextFieldView.Listener /* implements ChangeListener, MouseMotionListener */
= new Hash({

	stateChanged: function(textField, property, value){
		if (property == 'focus'){
			if (textField.getOption('overText') != null && textField.getOption('overText') != ''){
				if (value == false){
	                if (textField.getText().trim() == ''){
    					var overText = textField.getSubComponent('overText');
						overText.show();
    				}
				}
				else {
					textField.getElement('input').focus();
					var overText = textField.getSubComponent('overText');
					overText.hide();
				}
			}
		}

		textField.repaint();
	},

    mouseEnter: function(e, textField){
        if (textField.isEnabled()){
    		textField.setArmed(true);
		}
	},

	mouseLeave: function(e, textField){
        if (textField.isEnabled()){
    		textField.setArmed(false);
		}
	},

	mouseOver: $empty,
	mouseOut: $empty
});
};filesWrapper['light.G/Skin/Basic/BasicToggleButtonView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicButtonView.js');

/* class */ BasicToggleButtonView /* extends BasicButtonView */
= new Class({
	Extends: BasicButtonView,
	themePath: '/Basic/ToggleButton/',

	paintState: function(){
        var c = this.getComponent();
        var classFlag = HelpersFactory.getTypeHelper().getFlagString([
        	c.isSelected(),
        	c.isFocus(),
        	c.isPressed(),
        	c.isArmed()
        ]);

        var classesConfig = new Hash({
            '0111':	this.getTheme('armedPressed'),
    		'0110':	this.getTheme('focus'),
    		'0101':	this.getTheme('armedFocus'),
    		'0100':	this.getTheme('focus'),
    		'0011': this.getTheme('armedPressed'),
    		'0010':	'',
    		'0001': this.getTheme('armed'),
    		'0000':	'',

            '1111':	this.getTheme('selectedArmedPressed'),
    		'1110':	this.getTheme('selectedFocus'),
    		'1101':	this.getTheme('selectedArmedFocus'),
    		'1100':	this.getTheme('selectedFocus'),
    		'1011': this.getTheme('selectedArmedPressed'),
    		'1010':	'',
    		'1001': this.getTheme('selectedArmed'),
    		'1000':	this.getTheme('selected')
		});

		classesConfig.each(function(value){
			c.getElement().removeClass(value);
		}.bind(this));

		c.getElement().addClass(classesConfig[classFlag]);
	},

    install: function(){
		this.parent();
		this.installSystemListener();
	},

	uninstall: function(){
		this.uninstallSystemListener();
		this.parent();
	}
});

/* class */ BasicToggleButtonView.Selectable /* extends BasicToggleButtonView */
= new Class({
	Extends: BasicToggleButtonView,

	install: function(){
		this.parent();
		this.returnFncs['selectableMouse'] = this.getComponent().addMouseListener(BasicToggleButtonView.Selectable.Listener);
	},

	uninstall: function(){
		this.getComponent().removeMouseListener(this.returnFncs['selectableMouse']);
		this.parent();
	}
});

/* static class */ BasicToggleButtonView.Selectable.Listener /* implements MouseListener */
= new Hash({
    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button){
        if (button.isEnabled()){
			if (!button.isSelected()){
				button.setSelected(true);
			}
		}
	},

    doubleClick: $empty
});
};filesWrapper['light.G/Skin/Basic/BasicTooltipView.js'] = function(){
	loadFile('light.G/Skin/LayerView.js');
/* class */ BasicTooltipView /* extends LayerView */
= new Class({
	Extends: LayerView,
	themePath: '/Basic/Tooltip/',

    getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement('.' + this.getTheme('inner')),
				'position': 'bottom'
			}
		});
	},

    createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
			'styles': {
				'-moz-user-select': 'none'
			}
		}).grab(
			new Element('div', {
				'class': this.getTheme('inner')
			})
		);
		c.attachWithElement(this.domElement);
	},

	paintBorder: function(){
        var c = this.getComponent();
        //-----------------------------------------
    	//	đưa hết về mặc định cho khỏi lắm chuyện về sau
    	//-----------------------------------------
    	c.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));
    	c.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	c.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());

    	GFactory.getPaint().setWidth(c.getElement(), c.getOption('width'));
    	GFactory.getPaint().setHeight(c.getElement(), c.getOption('height'));
	},

	paintLayer: function(){
		GFactory.getLayerManager().setAsTooltipLayer(this.getComponent());
		var domEvent = this.getComponent().getOption('domEvent');
		this.getElement().setStyles({
			'position': 'absolute',
			'left': domEvent.client.x,
			'top': domEvent.client.y + 16
		});
	},

    paintPosition: function(){
		var c = this.getComponent();
        var defaultContext = new Hash({
            'inject': {
    			'target': document.body,
    			'position': 'bottom'
    		}
		});

		return defaultContext;
	},

    paint: function(){
        if (!isset(this.getComponent().getGraphicsContext())){
			this.getComponent().setGraphicsContext(this.paintPosition());
		}

		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
		this.paintLayer();
		this.paintBorder();
		this.paintInside();
		this.saveState();
	},

	repaint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
		this.paintBorder();
		this.paintInside();
		this.saveState();
	},

    paintInside: function(){
		var c = this.getComponent();
        if (this.compareState('text')){
    		this.getElement('.' + this.getTheme('inner')).set('html', c.getOption('text'));
		}
	},

	install: function(){
		this.parent();
		this.returnFncs['change'] = this.getComponent().addChangeListener(BasicTooltipView.Listener);
	},

	uninstall: function(){
		this.getComponent().removeChangeListener(this.returnFncs['change']);
		this.parent();
	}
});

/* static class */ BasicTooltipView.Listener /* implements ChangeListener */
= new Hash({
    stateChanged: function(popupMenu){
    	tooltip.repaint();
	}
});
};filesWrapper['light.G/Skin/Basic/BasicWindowView.js'] = function(){
	loadFile('light.G/Skin/WindowView.js');
/* class */ BasicWindowView /* extends WindowView */
= new Class({
	Extends: WindowView,

	buildTitle: function(){
		var c = this.getComponent();
		/*  vẽ thanh title */
		var titleCpnt = new GDomElement(
			null,
			new Element('div', {
        		'class': this.getTheme('title-text'),
        		'html': c.getOption('text')
        	})
        );
        titleCpnt.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('title-inner'),
				'position': 'bottom'
			}
        });
        titleCpnt.paint();

        /* vẽ nút đóng */
        loadFile('light.G/Components/GButton.js');
		this.closeButton = new GButton({
			themePath: '/Basic/Window/CloseButton/'
		});
		loadFile('light.G/Skin/Basic/BasicButtonView.js');
		this.closeButton.setView(new BasicButtonView.WithoutFocus);
		this.closeButton.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('title-inner'),
				'position': 'bottom'
			}
		});
		this.closeButton.paint();
		this.closeButton.addMouseListener(WindowView.CloseButtonListener, c);
	},

	createDomElement: function(){
		var c = this.getComponent();
        this.domElement = new Element('div', {
			'class': this.getTheme('main') + c.getOption('baseCss')
		}).set('html',
'<div class="' + this.getTheme('inner') + '">' +
	'<div class="' + this.getTheme('inside') + '">' +
		'<div class="' + this.getTheme('title') + '">' +
			'<div class="' + this.getTheme('title-inner') + '">' +
			'</div>' +
		'</div>' +
		'<div class="' + this.getTheme('content') + '">' +
			'<div class="' + this.getTheme('content-inner') + '">' +
			'</div>' +
		'</div>' +
	'</div>' +
'</div>'
		);

        c.attachWithElement(this.domElement);
	},

	paintBorder: function(){
		this.parent();
		var c = this.getComponent();
		if (c.getOption('height') != null && c.getOption('height') > c.getOption('contentHeightDiff')){
			GFactory.getPaint().setHeight(this.getElementByTheme('content-inner'), c.getOption('height') - c.getOption('contentHeightDiff'));
		}
	},

	paintLayer: function(){
		var c = this.getComponent();
		/* chỉ đưa layer lên trước khi có sự thay đổi activated và là true */
		if (this.compareState('activated')){
			if (c.getOption('activated')){
				if (isset(this.blackHoleLayer)) GFactory.getLayerManager().bringLayerToFront(this.blackHoleLayer);
				GFactory.getLayerManager().bringLayerToFront(c);
				//GFactory.getComponentManager().setLastActivatedWindow(c);
			}
		}

		/* vẽ lại vị trí, cái này dùng khi window resize */
		if (c.hasLaunchedElement()){
			var pos = GFactory.getPaint().stackPosition(
        		this.getElement(),
        		c.getLaunchedElement(),
        		'right',
        		'top',
        		30,
        		-60
        	);
		}
		else {
			if (this.compareState('top') || this.compareState('left')){
				this.getElement().set('styles', {
					'position': 'absolute',
					'top': c.getOption('top'),
					'left': c.getOption('left')
				});
			}
		}

		if (c.getOption('pinAfterPos')){
			this.getElement().set('styles', {
				'top': this.getElement().getPosition().y + window.getScroll().y,
				'left': this.getElement().getPosition().x + window.getScroll().x
			})
			this.getElement().pin();
		}
	}
});

};filesWrapper['light.G/Skin/ButtonView.js'] = function(){
	loadFile('light.G/Skin/ComponentView.js');

/*
Class: ButtonView
	Abstract class cho các view có nhiệm vụ thể hiện một button component, là các loại component thừa kế từ <AbstractButton>. Các view cụ thể cho từng component sẽ phải nạp chồng lại các hàm abstract của lớp này

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ ButtonView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: 	'/Basic/Button/',

    paintState: /* abstract */ function(){
		getErrorConsole().throwError('Bạn phải override lại hàm paintState của ButtonView');
	},

	paintInside: /* abstract */ function(){
		getErrorConsole().throwError('Bạn phải override lại hàm paintInside của ButtonView');
	},

	createDomElement: /* abstract */ function(){
		getErrorConsole().throwError('Bạn phải override lại hàm createDomElement của ButtonView');
	},

    paint: function(){
    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), ['inject']);
    	var c = this.getComponent();
    	this.paintBorder();
    	this.paintInside();
        if (c.isEnabled()) this.paintState();
        GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
		this.saveState();
	},

    repaint: function(){
    	var c = this.getComponent();
    	this.paintBorder();
    	this.paintInside();
        if (c.isEnabled()) this.paintState();
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
		this.saveState();
	},

    paintBorder: function(){
		var c = this.getComponent();
        this.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));
    	this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());
    	this.getElement().setStyles({
			'-moz-user-select': 'none'
    	});

        GFactory.getPaint().setWidth(this.getElement(), c.getOption('width'));
    	GFactory.getPaint().setHeight(this.getElement(), c.getOption('height'));
	},

    install: function(){
    	this.parent();
		this.installTooltip();
		var c = this.getComponent();
		this.returnFncs['mouse'] = c.addMouseListener(ButtonView.Listener);
		this.returnFncs['mouseMotion'] = c.addMouseMotionListener(ButtonView.Listener);
		this.returnFncs['change'] = c.addChangeListener(ButtonView.Listener);
	},

	uninstall: function(){
		var c = this.getComponent();
        c.removeMouseListener(this.returnFncs['mouse']);
        c.removeMouseMotionListener(this.returnFncs['mouseMotion']);
		c.removeChangeListener(this.returnFncs['change']);
		this.uninstallTooltip();
		this.parent();
	}

});

/*
Class: ButtonView.Listener
	Listener mặc định dành cho <ButtonView> có nhiệm vụ thay đổi 'pressed' và 'armed' của button

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ ButtonView.Listener /* implements ChangeListener, MouseListener, MouseMotionListener */
= new Hash({
    //-----------------------------------------
    //	match with ChangeListener interface
    //-----------------------------------------
    stateChanged: function(button){
    	button.repaint();
	},

    //-----------------------------------------
    //	match with MouseListener interface
    //-----------------------------------------
    mouseDown: function(e, button){
    	if (button.isEnabled()){
    		button.setPressed(true);
		}
	},

	mouseUp: function(e, button){
		if (button.isEnabled()){
			button.setPressed(false);
		}
	},

	singleClick: $empty,
    doubleClick: $empty,

    //-----------------------------------------
    //	match with MouseMotionListener interface
    //-----------------------------------------
    mouseEnter: function(e, button){
    	if (button.isEnabled()){
    		button.setArmed(true);
		}
	},

	mouseLeave: function(e, button){
		if (button.isEnabled()){
			button.setArmed(false);
		}
	},

	mouseOver: $empty,

	mouseOut: $empty
});
};filesWrapper['light.G/Skin/ComboBoxView.js'] = function(){
	loadFile('light.G/Skin/ButtonView.js');
loadFile('light.G/Components/GPopupMenu.js');
loadFile('light.G/Components/GList.js');

/*
Class: ComboBoxView
	Thể hiện view của một button có khả năng mở xuống dưới một element khác một popup

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

ComboBox gồm nhiều view, mặc định có 2 view
- single combobox:
	thừa kế từ button view
	có thêm arrow button listener để kích hoạt popup visible
	sửa lại paint và repaint để bổ sung hàm vẽ popup
	listener lắng nghe selection của list
- combo box có attach với một GInputField khác để có thể truyền dữ liệu cho inputfield
	hàm paint và repaint vẽ lại
*/
/* class */ ComboBoxView /* extends ButtonView */
= new Class({
	Extends: ButtonView,

	popup: null,
	list: null,

	setList: function(list){
		this.list = list;
	},

	getList: function(){
		return this.list;
	},

	getPopup: function(){
		return this.popup;
	},

	getPopupGraphicsContext: /* abstract */ function(){
	},

	getDefaultGraphicsContext: /* abstract */ function(){
	},

	paint: function(){
		this.parent();
		this.paintPopup();

		var item = this.list.getDataElementAt(this.list.getLastSelectionIndex());
    	if ($type(item) == 'string') text = item;
		else if ($type(item) == 'object') text = item.text;
    	this.paintText(text);
	},

	paintPopup: function(){
		var c = this.getComponent();
		var popupRenderer = c.getPopupRenderer();
		if (!isset(popupRenderer)){
			loadFile('light.G/Comm/DefaultComboBoxPopupRenderer.js');
			popupRenderer = DefaultComboBoxPopupRenderer;
		}

		this.popup = popupRenderer.getComponent(c);
    	this.popup.setParentComponent(c);
    	this.popup.setGraphicsContext(this.getPopupGraphicsContext());
    	this.popup.paint();

    	var listCellRenderer = c.getListCellRenderer();
    	if (!isset(listCellRenderer)){
			loadFile('light.G/Comm/DefaultComboBoxListCellRenderer.js');
			listCellRenderer = DefaultComboBoxListCellRenderer;
    	}

    	this.list.setCellRenderer(listCellRenderer);
    	this.list.addListSelectionListener(ComboBoxView.ListSelectionListener, c);

    	this.popup.add(this.list);
	},

	paintText: /* abstract */ function(text){
		getErrorConsole().throwError('Các view thể hiện combo box phải thừa kế lại paintText');
	},

	repaint: function(){
		this.parent();
		this.repaintPopup();
	},

	repaintPopup: function(){
		this.popup.setVisible(this.getComponent().isPopupVisible());
		this.popup.repaint();
	},

	createDomElement: function(){
		getErrorConsole().throwError('Phải nạp chồng hàm createDomElement của ComboBoxView');
	},

	paintState: function(){
		var c = this.getComponent();
        var classFlag = HelpersFactory.getTypeHelper().getFlagString([
        	c.isFocus(),
        	c.isPressed(),
        	c.isArmed()
        ]);

        var classesConfig = new Hash({
            '111':	this.getTheme('armedPressed'),
    		'110':	this.getTheme('focus'),
    		'101':	this.getTheme('armedFocus'),
    		'100':	this.getTheme('focus'),
    		'011': 	this.getTheme('armedPressed'),
    		'010':	'',
    		'001': 	this.getTheme('armed'),
    		'000':	''
		});

		classesConfig.each(function(value){
			c.getElement().removeClass(value);
		}.bind(this));

		c.getElement().addClass(classesConfig[classFlag]);
	},

    install: function(){
		this.parent();
		this.installSystemListener();
		this.installPopup();
		/* add state này sau system listener đảm bảo combo box được vẽ sau bất cứ sự thay đổi nào của system */
		//this.returnFncs['comboButtonChange'] = this.getComponent().addChangeListener(ComboBoxView.ComboButtonListener);
	},

	uninstall: function(){
		//this.getComponent().removeChangeListener(this.returnFncs['comboButtonChange']);
		this.uninstallPopup();
		this.uninstallSystemListener();
		this.parent();
	}
});

/* static class */ ComboBoxView.ListSelectionListener /* implements ListSelectionListener */
= new Hash({
    valueChanged: function(e, list, comboBox){
    	comboBox.setPopupVisible(false);
    	if (comboBox.getOption('redrawText')){
    		var item = list.getDataElementAt(list.getLastSelectionIndex());
    		if ($type(item) == 'string') text = item;
			else if ($type(item) == 'object') text = item.text;
    		comboBox.paintText(text);
		}
	}
});

};filesWrapper['light.G/Skin/ComponentView.js'] = function(){
	/*
Class: ComponentView
	Lớp abstract thể hiện vỏ ngoài cùng đặc trưng cho bất cứ View nào tương ứng với một GUI Component

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* abstract class */ ComponentView /* */
= new Class({
	/* protected */ returnFncs: null,
	/* private */ subComponents: null,
	/* private */ component: null,
	/* private */ domElement: null,
	/* private */ lastOptions: null,
	/* private */ themePath: null,
	/* private */ tooltip: null,
	/* private */ tooltipTimer: null,

	initialize: function(themePath){
		//console.log('creating new view');
		if (isset(themePath))this.themePath = themePath;
		this.subComponents = new Hash();
		this.returnFncs = new Array();
	},

	saveState: function(){
		this.lastOptions = $merge(this.getComponent().getOptions());
	},

	compareState: function(key){
		if (!isset(this.lastOptions)) return true;
		return this.lastOptions[key] != this.getComponent().getOption(key);
	},

	getInsideContext: /* abstract */ function(){
		getErrorConsole().throwError('Phải nạp chồng lại hàm getInsideContext của ComponentView');
	},

	setComponent: function(c){
		this.component = c;
	},

	getComponent: function(){
		return this.component;
	},

    getTheme: function(key){
    	var themePath = this.getComponent().getOption('themePath');
    	if (!isset(themePath)){
    		if (!isset(this.themePath)) getErrorConsole().throwError('Cả themePath option và themePath đều null. Đây là trường hợp không được phép');
    		themePath = this.themePath;
    	}

		return GFactory.getResourceManager().getThemeDataStorage().get(themePath + key);
	},

    getElement: function(tag){
		if (!tag){
			return this.domElement;
		}

		return this.domElement.getElement(tag);
	},

	getElementByTheme: function(themeVar){
		var value = this.getTheme(themeVar);
		if (!isset(value))
			getErrorConsole().throwError('Không tìm thấy giá trị ' + themeVar + ' của theme');

		var identifiedClassName = '';
		value.split(' ').each(function(className){
			identifiedClassName += '.' + className;
		});

		return this.getElement(identifiedClassName);
	},

	getElements: function(tag){
		return this.domElement.getElements(tag);
	},

	paint: /* abstract */ function(){
	},

	repaint: /* abstract */ function(){
	},

	createDomElement: /* abstract */ function(){
	},

	install: /* abstract */ function(){
		this.createDomElement();
	},

	/*
	Function: installGarbageCollector
		Hàm này dùng cho những trường hợp mà component này thường không được vẽ bên trong parentComponent nên không
	*/
	installGarbageCollector: function(){
		var gc = function(){
			// nếu đã bị hủy đối tượng cha hoặc đối tượng cha đã biến mất khỏi cây DOM
			// TODO: Kiểm tra kỹ performance của việc này
			if(!isset(this.getComponent().getParentComponent().getElement().getParent('body'))){
				this.getComponent().destroy();
				getTaskManager().removeProcess(gc, 'domModified');
			}
		}.bind(this);
		getTaskManager().addProcess(gc, 'domModified');
	},

	installSystemListener: function(){
		loadFile('light.G/Skin/DefaultListeners/SystemListener.js');
		var c = this.getComponent();
		this.returnFncs['systemMouse'] = c.addMouseListener(SystemListener);
		//this.returnFncs['systemChange'] = c.addChangeListener(SystemListener);
	},

	uninstall: /* abstract */ function(){
		this.destroyDomElement();
	},

	uninstallSystemListener: function(){
		var c = this.getComponent();
		c.removeMouseListener(this.returnFncs['systemMouse']);
		//c.removeChangeListener(this.returnFncs['systemChange']);
	},

    destroyDomElement: function(){
		this.domElement.destroy();
	},

    installTooltip: function(){
    	var c = this.getComponent();
    	if (isset(c.getTooltip())){
    		loadFile('light.G/Skin/DefaultListeners/TooltipListener.js');
    		this.returnFncs['tooltipMouseMotion'] = c.addMouseMotionListener(TooltipListener);
		}
	},

	uninstallTooltip: function(){
		var c = this.getComponent();
		if (isset(c.getTooltip())){
			c.removeMouseMotionListener(this.returnFncs['tooltipMouseMotion']);
		}
	},

	installPopup: function(){
		loadFile('light.G/Skin/DefaultListeners/PopupListener.js');
		var c = this.getComponent();
		this.returnFncs['popupMouse'] = c.addMouseListener(PopupListener);
		this.returnFncs['popupChange'] = c.addChangeListener(PopupListener);
	},

	uninstallPopup: function(){
		var c = this.getComponent();
		c.removeMouseListener(this.returnFncs['popupMouse']);
		c.removeChangeListener(this.returnFncs['popupChange']);
	},

	installDestroyOnBlur: function(){
		loadFile('light.G/Skin/DefaultListeners/DestroyOnBlurListener.js');
		var c = this.getComponent();
		this.returnFncs['destroyChange'] = c.addChangeListener(DestroyOnBlurListener);
	},

	uninstallDestroyOnBlur: function(){
        var c = this.getComponent();
		c.removeChangeListener(this.returnFncs['destroyChange']);
	},

	empty: function(){
		getErrorConsole().throwError('Phải nạp chồng lại hàm empty của ComponentView');
	},

	getTooltipTimer: function(){
		return this.tooltipTimer;
	},

	addSubComponent: function(component, index){
		//if (!isset(this.subComponents)) this.subComponents = new Hash();
		if (!isset(index)) index = this.subComponents.getLength() + 1;
		this.subComponents.include(index, component);
		return index;
	},

	getSubComponent: function(index){
		return this.subComponents.get(index);
	},

	getAllSubComponents: function(){
		return this.subComponents;
	}
});

};filesWrapper['light.G/Skin/DefaultListeners/DestroyOnBlurListener.js'] = function(){
	/*
Script: DestroyOnBlurListener
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/*
Class: DestroyOnBlurListener
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/

/* static class */ DestroyOnBlurListener /* implements ChangeListener */
= new Hash({

	stateChanged: function(aComponent, property, value){
		if (property == 'focus'){
			if (!value){
				aComponent.destroy();
			}
		}
	}

});
};filesWrapper['light.G/Skin/DefaultListeners/PopupListener.js'] = function(){
	/*
Class: PopupListener
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ PopupListener /* implements MouseListener, ChangeListener */
= new Hash({
    mouseDown: function(e, theComponent){
    	if (theComponent.isEnabled())
    		theComponent.setPopupVisible(!theComponent.isPopupVisible());
	},

	mouseUp: $empty,
    singleClick: $empty,
    doubleClick: $empty,

    stateChanged: function(theComponent, property, value){
		if (property == 'focus' && value == false){
			/* khi lost focus mà thôi */
			theComponent.setPopupVisible(false);
		}
	}
});
};filesWrapper['light.G/Skin/DefaultListeners/SystemListener.js'] = function(){
	/*
Class: SystemListener.js
	Các cách thức handle thông thường khi xảy ra các sự kiện phổ biến

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Implements:
	<MouseListener>
*/
/* static class */ SystemListener /* implements ChangeListener, MouseListener */
= new Hash({

    mouseDown: function(e, c){
    	if (c.isEnabled()){
    		GFactory.getComponentManager().makeFocus(c);
            if (isset(c.isPressed))
            	GFactory.getComponentManager().setLastPressedComponent(c);
		}
	},

    mouseUp: function(e, c){
    	var lastPressedComponent = GFactory.getComponentManager().getLastPressedComponent();
    	if (isset(lastPressedComponent)) lastPressedComponent.setPressed(false);
		GFactory.getComponentManager().setLastPressedComponent(null);
	},

    singleClick: $empty,
    doubleClick: $empty
});
};filesWrapper['light.G/Skin/DefaultListeners/TooltipListener.js'] = function(){
	/*
Class: TooltipListener
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ TooltipListener /* implements MouseMotionListener */
= new Hash({
    mouseEnter: function(e, theComponent){
        if (isset(theComponent.getTooltip())){
        	loadFile('core/IdleTimer.js');
        	loadFile('light.G/Components/GTooltip.js');

    		theComponent.setTooltipTimer(new IdleTimer(theComponent.getOption('tooltipIdleTime')));
    		theComponent.getTooltipTimer().addEvent('complete', function(){
    			theComponent.setTooltipComponent(new GTooltip({
    				text: theComponent.getTooltip(),
    				domEvent: e
    			}));
    			theComponent.getTooltipComponent().paint();
    		});

    		theComponent.getTooltipTimer().start();
    		theComponent.getTooltipTimer().idle();
    	}
	},

	mouseLeave: function(e, theComponent){
		if (isset(theComponent.getTooltipTimer())) theComponent.getTooltipTimer().stop();
		if (isset(theComponent.getTooltipComponent())) theComponent.getTooltipComponent().destroy();
	},

	mouseOver: $empty,
	mouseOut: $empty
});
};filesWrapper['light.G/Skin/DomButtonView.js'] = function(){
	loadFile('light.G/Skin/ComponentView.js');
/*
Class: DomButtonView


	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ DomButtonView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: 	'/Basic/Button/',
	buttonEl: null,

	initialize: function(buttonEl){
		if (isset(buttonEl)) this.buttonEl = buttonEl;
		this.parent();
	},

	paintBorder: function(){
		var c = this.getComponent();
		if (c.isEnabled())
			this.getElement().set('disabled', false);

		this.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));
		this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
		this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());
		if (!c.isEnabled())
			this.getElement().set('disabled', true);
	},

	paintInside: function(){
		var c = this.getComponent();
		if (!isset(c.getOption('text'))){
			if (isset(this.buttonEl))
				c.setOption('text', this.buttonEl.get('text'), false);

			return;
		}
		else {
	        if (this.compareState('text'))
        		this.getElement().set('html', c.getOption('text'));
		}
	},

	paintState: $empty,

	paint: function(){
    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), ['inject']);
    	var c = this.getComponent();
    	this.paintBorder();
    	this.paintInside();
        if (c.isEnabled()) this.paintState();
        GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
		this.saveState();
	},

    repaint: function(){
    	var c = this.getComponent();
    	this.paintBorder();
    	this.paintInside();
        if (c.isEnabled()) this.paintState();
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
		this.saveState();
	},

	install: function(){
		this.parent();
		this.installTooltip();
		this.returnFncs['change'] = this.getComponent().addChangeListener(DomButtonView.Listener);
	},

	uninstall: function(){
		this.getComponent().removeChangeListener(this.returnFncs['change']);
		this.uninstallTooltip();
		this.parent();
	},

	createDomElement: function(){
		var c = this.getComponent();
		if (!isset(this.buttonEl)){
	        this.domElement = new Element('button', {
	        	'type': 'button',
	        	'class': this.getTheme('main') + ' ' + c.getOption('baseCss'),
        		'id': c.getOption('id')
			});
		}
		else this.domElement = this.buttonEl;
		c.attachWithElement(this.domElement);
	}
});

/* static class */ DomButtonView.Listener /* implements ChangeListener*/
= new Hash({
    stateChanged: function(button){
    	button.repaint();
	}
});
};filesWrapper['light.G/Skin/DomCheckboxView.js'] = function(){
	loadFile('light.G/Skin/DomButtonView.js');
/*
Class: DomCheckboxView


	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ DomCheckboxView /* extends ComponentView */
= new Class({
	Extends: DomButtonView,
	themePath: 	'/Basic/Checkbox/',
	checkboxEl: null,

	initialize: function(checkboxEl){
		if (isset(checkboxEl)) this.checkboxEl = checkboxEl;
		//this.getComponent().setOption('busy', false, false); // định mức là không busy
		this.parent();
	},

	paintState: function(){
		var c = this.getComponent();
		if (!isset(c.getOption('busy')) || !c.getOption('busy')){ // nếu không busy, tức là không phải click từ checkbox
			//console.log(this.getElement(), c.isSelected());
			this.getElement().set('checked', c.isSelected());
		}

		c.setOption('busy', false, false); // không còn busy nữa
	},

	install: function(){
		this.parent();

		/* quay ngược state cho component từ element */
		this.returnFncs['elementMouse'] =
			this.getElement().addMouseListener(DomCheckboxView.ElementListener, this.getComponent());
	},

	uninstall: function(){
		this.getElement().removeMouseListener(this.returnFncs['elementMouse']);
		this.parent();
	},

	createDomElement: function(){
		var c = this.getComponent();
		if (!isset(this.checkboxEl)){
	        this.domElement = new Element('input', {
	        	'type': 'checkbox',
        		'id': c.getOption('id')
			});
		}
		else this.domElement = this.checkboxEl;
		c.attachWithElement(this.domElement);
	}
});

/* static class */ DomCheckboxView.ElementListener /* implements MouseListener */
= new Hash({
	mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, checkbox){
    	if (checkbox.isEnabled()){
			checkbox.setOption('busy', true, false);
			checkbox.toggleSelected();
		}
	},

    doubleClick: $empty
});

};filesWrapper['light.G/Skin/DomElementView.js'] = function(){
	/*
Class: DomElementView
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
loadFile('light.G/Skin/ComponentView.js');
/* class */ DomElementView /* extends ComponentView */
= new Class({
	Extends: ComponentView,

	getInsideContext: function(){
		return new Hash({
			'inject': {
				'target': this.getElement(),
				'position': 'bottom'
			}
		});
	},

    paint: function(){
    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
	},

	repaint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
	},

	createDomElement: function(){
		this.domElement = this.getComponent().getElement();
	},

	install: function(){
		this.parent();
		this.installTooltip();
	},

	uninstall: function(){
		this.uninstallTooltip();
		this.parent();
	}
});
};filesWrapper['light.G/Skin/DomLayerView.js'] = function(){
	loadFile('light.G/Skin/LayerView.js');
/* class */ DomLayerView /* extends LayerView */
= new Class({
	Extends: LayerView,

	getInsideContext: function(){
		return new Hash({
			'inject': {
				'target': this.getElement(),
				'position': 'bottom'
			}
		});
	},

    paint: function(){
    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
	},

	repaint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
	},

	createDomElement: function(){
		this.domElement = this.getComponent().getElement();
	},

	install: function(){
		this.parent();
		this.installTooltip();
	},

	uninstall: function(){
		this.uninstallTooltip();
		this.parent();
	}
});
};filesWrapper['light.G/Skin/LabelView.js'] = function(){
	loadFile('light.G/Skin/ComponentView.js');

/*
Class: LabelView
	Description cho class

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ LabelView /* extends ComponentView */
= new Class({
	Extends: ComponentView,

	getInsideContext: /* abstract */ function(){
		getErrorConsole().throwError('Phải nạp chồng lại hàm getInsideContext của LabelView');
	},

	createDomElement: /* abstract */ function(){
		getErrorConsole().throwError('Phải nạp chồng hàm createDomElement của LabelView');
	},

	paintInside: /*abstract */ function(){
		getErrorConsole().throwError('Phải nạp chồng hàm paintInside của LabelView');
	},

	paintState: /* abstract */ function(){
		getErrorConsole().throwError('Bạn phải override lại hàm paintState của ButtonView');
	},

	paint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), ['inject']);

    	this.paintBorder();
    	this.paintInside();

    	if (this.getComponent().isEnabled()){
        	this.paintState();
		}

    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);

    	this.saveState();
	},

	repaint: function(){
		this.paintBorder();
    	this.paintInside();

    	if (this.getComponent().isEnabled()){
        	this.paintState();
		}

    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);

		this.saveState();
	},

	paintBorder: function(){
		var c = this.getComponent();
        this.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));
    	this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());
	},

	install: function(){
    	this.parent();
		this.returnFncs['change'] = this.getComponent().addChangeListener(LabelView.Listener);
	},

	uninstall: function(){
		this.getComponent().removeChangeListener(this.returnFncs['change']);
		this.parent();
	}
});

/*
Class: LabelView.Listener
	Description cho class

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ LabelView.Listener /* implements ChangeListener */
= new Hash({
    stateChanged: function(label){
    	label.repaint();
	}
});
};filesWrapper['light.G/Skin/LayerView.js'] = function(){
	loadFile('light.G/Skin/ComponentView.js');
/*
Class: LayerView
	Lớp abstract cho view của một layer, các view khác cho component thừa kế từ layer thừa kế từ lớp này

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Todo:
	Viết thêm interface cho các view không thừa kế từ abstract này
*/
/* abstract class */ LayerView /* extends ComponentView */
= new Class({
	Extends: ComponentView,

	setIndex: function(zIndex){
		this.getElement().set('styles', {
			'position': 'absolute',
			'z-index': zIndex
		});
	}
});
};filesWrapper['light.G/Skin/ListView.js'] = function(){
	loadFile('light.G/Skin/ComponentView.js');
/* class */ ListView /* extends ComponentView */
= new Class({
	Extends: ComponentView,

	paint: function(){
    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
    	this.paintBorder();
    	this.paintChildren();
	},

	repaint: function(){
		this.paintBorder();
	},

	/*
	Function: paintBorder
		Hàm này có nhiệm vụ vẽ vỏ bao ngoài của List, là lớp vỏ mà các component tương ứng với từng cell sẽ được tạo và nhét vào trong
	*/
	paintBorder: function(){
		getErrorConsole().throwError('Phải nạp chồng hàm paintBorder của ListView');
	},

	/*
	Function: paintChildren
		Vẽ ruột của List, bao gồm tất cả component thể hiện cell tương ứng với dữ liệu đầu vào
	*/
	paintChildren: function(){
		getErrorConsole().throwError('Phải nạp chồng hàm paintChildren của ListView');
	}
});
};filesWrapper['light.G/Skin/Plastic/PlasticButtonView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicButtonView.js');

/* class */ PlasticButtonView /* extends BasicButtonView.WithFocus */
= new Class({
	Extends: BasicButtonView.WithFocus,

	paintInside: function(){
		var c = this.getComponent();
        if (this.compareState('text')){
        	this.getElementByTheme('inside-text').set('html', c.getOption('text'));
		}
	},

	createDomElement: function(){
		var c = this.getComponent();
        this.domElement = new Element('div', {
        	'id': c.getOption('id'),
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		}).set('html',
			'<div class="' + this.getTheme('inner') + '">' +
				'<div class="' + this.getTheme('inside') + '">' +
					'<div class="' + this.getTheme('inside-text') + '">' +
					'</div>' +
				'</div>' +
			'</div>'
		);
		c.attachWithElement(this.domElement);
	}
});
};filesWrapper['light.G/Skin/Plastic/PlasticCheckboxView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicCheckboxView.js');

/* class */ PlasticCheckboxView /* extends BasicCheckboxView */
= new Class({
	Extends: BasicCheckboxView,

	createDomElement: function(){
    	this.parent();
    	this.getElementByTheme('inside').grab(
			new Element('div', {
				'class': this.getTheme('inside-checkarrow')
			})
		);
	}
});
};filesWrapper['light.G/Skin/Plastic/PlasticComboBoxView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicComboBoxView.js');

/*
Class: PlasticComboBoxView
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ PlasticComboBoxView /* extends BasicComboBoxView */
= new Class({
	Extends: BasicComboBoxView,

	createDomElement: function(){
		var c = this.getComponent();
		this.domElement = new Element('div', {
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		}).set('html',
'<div class="' + this.getTheme('inner') + '">'+
	'<div class="' + this.getTheme('inside') + '">'+
		'<div class="' + this.getTheme('inside-text') + '">'+
		'</div>'+
		'<div class="' + this.getTheme('inside-arrow') + '">'+
		'</div>' +
	'</div>'+
'</div>'
		);

		c.attachWithElement(this.domElement);
	},

	paintInside: function(){
		var c = this.getComponent();
        if (this.compareState('text')){
        	this.getElementByTheme('inside-text').set('html', c.getOption('text'));
		}
	}
});
};filesWrapper['light.G/Skin/Plastic/PlasticToggleButtonView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicToggleButtonView.js');

/* class */ PlasticToggleButtonView /* extends BasicToggleButtonView */
= new Class({
	Extends: BasicToggleButtonView,

	paintInside: function(){
		var c = this.getComponent();
        if (this.compareState('text')){
        	this.getElementByTheme('inside-text').set('html', c.getOption('text'));
		}
	},

	createDomElement: function(){
		var c = this.getComponent();
        this.domElement = new Element('div', {
        	'id': c.getOption('id'),
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		}).set('html',
			'<div class="' + this.getTheme('inner') + '">' +
				'<div class="' + this.getTheme('inside') + '">' +
					'<div class="' + this.getTheme('inside-text') + '">' +
					'</div>' +
				'</div>' +
			'</div>'
		);
		c.attachWithElement(this.domElement);
	}
});
};filesWrapper['light.G/Skin/PopupMenuView.js'] = function(){
	loadFile('light.G/Skin/LayerView.js');
/* class */ PopupMenuView /* extends LayerView */
= new Class({
	Extends: LayerView,
	themePath: 	'/Basic/PopupMenu/',

	empty: function(){
		//this.getElement().empty();
	},

    getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElementByTheme('inner'),
				'position': 'bottom'
			}
		});
	},

    createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
        	'id': c.getOption('id'),
			'styles': {
				'-moz-user-select': 'none'
			}
		}).grab(
			new Element('div', {
				'id': c.getOption('innerId'),
				'class': this.getTheme('inner')
			})
		);
		c.attachWithElement(this.domElement);
	},

	paintLayer: function(){
		GFactory.getLayerManager().bringLayerToFront(this.getComponent());
	},

	paintBorder: function(){
        var c = this.getComponent();
        //-----------------------------------------
    	//	đưa hết về mặc định cho khỏi lắm chuyện về sau
    	//-----------------------------------------
    	c.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));
    	c.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	c.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());

    	GFactory.getPaint().setWidth(c.getElement(), c.getOption('width'));
    	GFactory.getPaint().setHeight(c.getElement(), c.getOption('height'));
	},

    paint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
		this.paintBorder();
		this.paintLayer();
	},

	repaint: function(){
		var c = this.getComponent();
		this.paintBorder();
		this.paintLayer();
        if (c.isVisible()){
			GFactory.getPaint().draw(c.getElement(), c.getGraphicsContext(), ['stackwidth', 'stackpos']);
		}
	},

	install: function(){
		this.parent();
		this.installGarbageCollector();
		this.returnFncs['change'] = this.getComponent().addChangeListener(PopupMenuView.Listener);
	},

	uninstall: function(){
		this.getComponent().removeChangeListener(this.returnFncs['change']);
		this.parent();
	}
});

/* static class */ PopupMenuView.Listener /* implements ChangeListener */
= new Hash({
    stateChanged: function(popupMenu){
    	popupMenu.repaint();
	}
});
};filesWrapper['light.G/Skin/ToolbarView.js'] = function(){
	/*
Script: ToolbarView
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/*
Class: ToolbarView
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Skin/ComponentView.js');
/* class */ ToolbarView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	builtToolbar: null,

	initialize: function(builtToolbar){
		this.builtToolbar = builtToolbar;
		this.parent();
	},

    getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement(),
				'position': 'bottom'
			}
		});
	},

    createDomElement: function(){
    	var c = this.getComponent();
    	if (!isset(this.builtToolbar)){
	        this.domElement = new Element('div', {
        		'class': 'toolbar' + ' ' + c.getOption('baseCss') + ' pkg'
	        });
		}
		else {
			this.domElement = this.builtToolbar;
		}

		this.getComponent().attachWithElement(this.domElement);
	},

	paint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
	},

	repaint: function(){
	},

    install: function(){
		this.parent();
	},

	uninstall: function(){
		this.parent();
	}
});
};filesWrapper['light.G/Skin/WindowView.js'] = function(){
	loadFile('light.G/Skin/LayerView.js');
loadFile('light.G/Workers/BlackHoleLayer.js');
loadFile('light.G/Components/GDomElement.js');
/*
Class: WindowView
	Cách thức vẽ window, được mô tả như sau, khi lần đầu vẽ, ta cần kiểm tra xem có cần vẽ blackHoleLayer ở dưới hay không, nếu có, vẽ trước, sau đó vẽ title, vẽ border và state, vì là lần đầu vẽ, ta kiểm tra xem window có được vẽ trong trạng thái activated không, nếu có đưa nó lên trên ngay. Window chỉ được vẽ lại khi đổi trạng thái, việc đưa window lên trước hay không sẽ được LayerManager thực hiện tự động thông qua listener.

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ WindowView /* extends LayerView */
= new Class({
	Extends: LayerView,
	themePath: '/Basic/Window/Layout/',
	blackHoleLayer: null,

	paint: function(){
		var c = this.getComponent();
		this.paintBlackHoleLayer();

		this.buildTitle();

		this.paintBorder();

		if (!isset(c.getGraphicsContext())){
			c.setGraphicsContext(this.getDefaultGraphicsContext());
		}

		GFactory.getPaint().draw(this.getElement(), c.getGraphicsContext());

		this.paintLayer();
		this.saveState();
	},

	repaint: function(){
		this.paintBlackHoleLayer();
		this.paintBorder();

		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
		this.paintLayer();
		this.saveState();
	},

	paintBlackHoleLayer: function(){
        var c = this.getComponent();
		if (c.getOption('stayOnTop')){
			if (!isset(this.blackHoleLayer)){
				if (c.getOption('useIframeBackground')){
					this.blackHoleLayer = new BlackHoleLayer({
						useIframe: true
					});
				}
				else {
					this.blackHoleLayer = new BlackHoleLayer();
				}
				this.blackHoleLayer.setParentComponent(this.getComponent());
				this.blackHoleLayer.paint();
			}
			else {
				/* cho trường hợp đã có black hole layer, set visible của black hole đồng bộ với visible của window */
				this.blackHoleLayer.setVisible(c.isVisible());
			}
		}
	},

	paintBorder: function(){
		var c = this.getComponent();
        this.getElement().set('class', this.getTheme('main') + ' ' + c.getOption('baseCss'));
    	this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());
    	this.getElement().stackClass(this.getTheme('activated'), c.isActivated());

    	GFactory.getPaint().setWidth(c.getElement(), c.getOption('width'));
    	GFactory.getPaint().setHeight(c.getElement(), c.getOption('height'));
	},

	getDefaultGraphicsContext: function(){
		var c = this.getComponent();
        var defaultContext = {
            'inject': {
    			'target': document.body,
    			'position': 'bottom'
    		}
		};

		return defaultContext;
	},

	paintLayer: function(){
		getErrorConsole().throwError('Phải nạp chồng hàm paintLayer của WindowView');
	},

	buildTitle: function(){
		getErrorConsole().throwError('Phải nạp chồng hàm buildTitle của WindowView');
	},

	getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement('.' + this.getTheme('content-inner')),
				'position': 'bottom'
			}
		});
	},

	install: function(){
        this.parent();
		this.installSystemListener();
		var c = this.getComponent();
		this.returnFncs['change'] = c.addChangeListener(WindowView.Listener);
		//this.returnFncs['mouse'] = c.addMouseListener(WindowView.Listener);
		this.returnFncs['window'] = c.addWindowListener(WindowView.Listener);
	},

	uninstall: function(){
		var c = this.getComponent();
		c.removeChangeListener(this.returnFncs['change']);
		//c.removeMouseListener(this.returnFncs['mouse']);
		c.removeWindowListener(this.returnFncs['window']);
        this.uninstallSystemListener();
		this.parent();

		getTaskManager().runProcesses('domModified');
	}
});

/* static class */ WindowView.Listener /* implements ChangeListener, MouseListener, WindowListener */
= new Hash({
	stateChanged: function(window, property, value){
		window.repaint();
	},

    wndBlur: $empty,
    wndFocus: $empty,
    wndLoad: $empty,

    wndResize: function(e, window){
    	window.repaint();
	},

    wndScroll: $empty,
    wndBeforeUnload: $empty,
    wndUnload: $empty
});

/* class */ WindowView.CloseButtonListener /* implements MouseListener */
= new Hash({
    mouseDown: $empty,

	mouseUp: $empty,

    singleClick: function(e, closeButton, window){
    	window.destroy();
	},

    doubleClick: $empty
});
};filesWrapper['light.G/WindowX.js'] = function(){
	/*
Class: WindowX
	Class này chỉ có tác dụng nhận lấy tất cả events của window, chủ yếu là event resize để đóng gói lại cho có cùng cách ứng xử trên FF và IE

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
var windowX = getClientStorage().get('windowX');
	(end)
*/
/* class */ WindowX /* */
= new Class({
	Implements: [Events]
});
};filesWrapper['light.G/Workers/BlackHoleLayer.js'] = function(){
	loadFile('light.G/Components/AbstractLayer.js');
/*
Class: BlackHoleLayer
	Một bộ component, model và view cùng các listener cần thiết để tạo một black hole layer hứng mọi tương tác của người dùng

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractLayer>
*/
/* class */ BlackHoleLayer /* extends AbstractLayer */
= new Class({
	Extends: AbstractLayer,
    initialize: function(options){
    	this.setModel(new BlackHoleLayer.Model());
    	this.setOptions(options);
	},

    createDefaultView: function(){
    	return new BlackHoleLayer.BasicView();
	},

    setLayer: function(theLayer){
		this.getModel().setLayer(theLayer);
	},

	getLayer: function(){
		return this.getModel().getLayer();
	}
});

loadFile('light.G/Model/DefaultLayerModel.js');
/*
Class: BlackHoleLayer.Model
	Model cho black hole layer component

Extends:
	<AbstractModel>
*/
/* class */ BlackHoleLayer.Model /* extends DefaultLayerModel */
= new Class({
	Extends: DefaultLayerModel,
	options: {
		useIframe: false
	}
});

loadFile('light.G/Skin/LayerView.js');
/* class */ BlackHoleLayer.BasicView /* extends LayerView */
= new Class({
	Extends: LayerView,
	themePath: '/Basic/BlackHoleLayer/',

	iframe: null,

    paint: function(){
        if (!isset(this.getComponent().getGraphicsContext())){
        	this.getComponent().setGraphicsContext({
                'inject': {
    				'target': document.body,
    				'position': 'bottom'
    			}
			});
		}
        this.getElement().setStyles({
			'position': 'absolute'
		});
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());

		this.paintLayer();
		GFactory.getLayerManager().bringLayerToFront(this.getComponent());
		//this.paintLayer();
		this.paintBorder();
	},

    paintBorder: function(){
		var c = this.getComponent();
		this.getElement().set('class', this.getTheme('main'));
    	this.getElement().stackClass(this.getTheme('disabled'), !c.isEnabled());
    	this.getElement().stackClass(this.getTheme('invisible'), !c.isVisible());
	},

    repaint: function(){
    	this.paintLayer();
    	this.paintBorder();
    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
	},

	paintLayer: function(size, scroll){
		var c = this.getComponent();

		if (!isset(size)){
			size = document.getSize();
		}

		if (!isset(scroll)){
			scroll = document.getScroll();
		}

		this.getElement().setStyles({
			left: scroll.x,
			top: scroll.y,
			width: size.x,
			height: size.y
		});

		if (c.getOption('useIframe')){
			if (this.iframe != null){
				this.iframe.destroy();
			}

        	this.iframe = new IFrame().inject(this.getElement(), 'bottom');
            this.iframe.setStyles({
            	margin: 0,
            	padding: 0,
				'border': 'none'
			});

			this.doc = this.iframe.contentWindow.document;
	        var documentTemplate = ''+
				'<html>'+
					'<head></head>'+
					'<body style="border: 0; margin: 0; padding: 0">'+
					'</body>'+
				'</html>'+
			'';
			this.doc.open();
			this.doc.write(documentTemplate);
			this.doc.close();

			this.iframe.set({
	            width: size.x - 16,
				height: size.y - 16
			});
		}
	},

    createDomElement: function(){
        this.domElement = new Element('div');
        this.getComponent().attachWithElement(this.domElement);
	},

    install: function(){
    	this.parent();
		this.returnFncs['window'] = this.getComponent().addWindowListener(BlackHoleLayer.BasicView.Listener);
		this.returnFncs['change'] = this.getComponent().addChangeListener(BlackHoleLayer.BasicView.Listener);

	},

	uninstall: function(){
		this.getComponent().removeChangeListener(this.returnFncs['change']);
        this.getComponent().removeWindowListener(this.returnFncs['window']);
		this.parent();
	}
});

/* static class */ BlackHoleLayer.BasicView.Listener /* implements ChangeListener, WindowListener */
= new Hash({
	stateChanged: function(layer, property, value){
		layer.repaint();
	},

    wndBlur: $empty,
    wndFocus: $empty,
    wndLoad: $empty,

    wndResize: function(e, blackHoleLayer){
    	blackHoleLayer.repaint();
	},

    wndScroll: function(e, blackHoleLayer){
    	blackHoleLayer.repaint();
	},
    wndBeforeUnload: $empty,
    wndUnload: $empty
});
};filesWrapper['light.G/Workers/ButtonGroup.js'] = function(){
	/* class */ ButtonGroup /* */
= new Class({
	buttonsList: new Array(),
	selectedButton: null,

	add: function(button){
		this.buttonsList.include(button);
		if (button.isSelected()){
			this.selectedButton = button;
		}

		button.setButtonGroup(this);
	},

	clearSelection: function(){
		if (this.selectedButton != null){
			this.selectedButton.setSelected(false);
		}
	},

	getButtonCount: function(){
		return this.buttonsList.length;
	},

	getElements: function(){
		return this.buttonsList;
	},

	remove: function(button){
		this.buttonsList.erase(button);
		button.setButtonGroup(null);
	},

	saveSelectionState: function(button){
		var index = this.buttonsList.indexOf(button);
		if (index == -1){
			getErrorConsole().throwError('Cant find button in this button group');
		}

		this.clearSelection();
		this.selectedButton = button;
	}
});
};filesWrapper['light.Controls/AutoCompleter/AutoCompleterModel.js'] = function(){
	/*
Interface: AutoCompleterModel
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ AutoCompleterModel /* */
= new Class({
});
};filesWrapper['light.Controls/AutoCompleter/BasicAutoCompleterView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicTextFieldView.js');

/* class */ BasicAutoCompleterView /* extends BasicTextFieldView */
= new Class({
	Extends: BasicTextFieldView,
	textInput: null,
	popup: null,

	paint: function(){
		this.parent();
		this.paintPopup();
	},

	getPopupGraphicsContext: function(){
		return {
			'inject': {
				'target': document.body,
				'position': 'bottom'
			},
			'stackwidth': {
				'target': this.getComponent().getElement()
			},
			'stackpos': {
				'target': this.getComponent().getElement(),
				'pop': 'bottom',
				'align': 'left'
			}
		};
	},

	processData: function(text){
		var data = JSON.decode(text);
		if (!isset(data) || data.length <= 0) return;
        var c = this.getComponent();
		c.setPopupVisible(true);
		this.popup.setVisible(true);
		this.popup.empty();

		/* lấy dữ liệu search và tạo list */
		loadFile('light.G/Components/GList.js');
		this.list = new GList({
			'maxRow': c.getOption('maxRow'),
			'rowHeight': c.getOption('rowHeight')
		}, data);

		var listObj = this.list;
		this.popup.add(this.list);

		listObj.getAllSubComponents().each(function(cell, index){
			cell.addChangeListener(new Hash({
				stateChanged: function(cell, property, value){
					if (property == 'armed'){
						if (value)
							listObj.lastArmed = index;
						else
							listObj.lastArmed = null;
					}
				}
			}), listObj);
		});

		listObj.addListSelectionListener(new Hash({
        	valueChanged: function(e, list){
        		this.selectItem(list.getLastSelectionIndex());
			}.bind(this)
		}));
	},

	displayList: function(){
		var c = this.getComponent();
		if (c.getText().length < 1) {
			c.setPopupVisible(false);
			return;
		}

		var currentText = c.getText();
		c.searchData(currentText, this.processData, this);
	},

	selectItem: function(index){
		var c = this.getComponent();
		c.setText(this.list.getDataElementAt(index));
		c.setPopupVisible(false);
	},

	getList: function(){
		return this.list;
	},

	paintPopup: function(){
		loadFile('light.G/Components/GPopupMenu.js');
		this.popup = new GPopupMenu();
		this.popup.setParentComponent(this.getComponent());
		this.popup.setGraphicsContext(this.getPopupGraphicsContext());
		this.popup.paint();
	},

	repaint: function(){
		this.parent();
		this.repaintPopup();
	},

	repaintPopup: function(){
		var c = this.getComponent();
		if (!c.isPopupVisible()) {
			this.popup.setVisible(false);
		}
	},

	install: function(){
		this.parent();
		this.returnFncs['autoState'] = this.getComponent().addChangeListener(BasicAutoCompleterView.TextInputListener);
		this.returnFncs['autoKeyboard'] = this.getComponent().addKeyboardListener(BasicAutoCompleterView.TextInputListener);
	},

	uninstall: function(){
		this.getComponent().removeChangeListener(this.returnFncs['autoState']);
		this.getComponent().removeKeyboardListener(this.returnFncs['autoKeyboard']);
		this.parent();
	}
});

/* class */ BasicAutoCompleterView.TextInputListener /* implements ChangeListener, KeyboardListener */
= new Hash({

	stateChanged: function(control, property, value){
		/* lose focus thì tắt popup và list đi */
		if (property == 'focus' && value == false){
			control.setPopupVisible(false);
		}
	},

    keyPress: function(e, control){
    	if (e.key == 'up' || e.key == 'down' || e.key == 'tab' || e.key == 'home' || e.key == 'end') return;
    	if (e.key == 'enter') {
    		control.selectCurrentItem();
    		e.preventDefault();
    		return;
		}

		if (e.key == 'esc') {
			control.setPopupVisible(false);
			return;
		}

    	/*
    	khi một chữ được gõ thì gọi IdleTimer và đếm lại time
    	đủ time thì tạo list
    	lấy dữ liệu từ hàm giao tiếp dữ liệu của component
    	*/
    	var timer = control.getTimer();
    	if (!isset(timer)) {
    		loadFile('core/IdleTimer.js');
			timer = new IdleTimer(400);
			timer.addEvent('complete', function(){
				control.displayList();
			});
			control.setTimer(timer);
		}
		timer.reset();
	},

	keyUp: function(e, control){
		if (e.key == 'backspace' && Browser.Engine.trident){
			var timer = control.getTimer();
    		if (!isset(timer)) {
    			loadFile('core/IdleTimer.js');
				timer = new IdleTimer(400);
				timer.addEvent('complete', function(){
					control.displayList();
				});
				control.setTimer(timer);
			}
			timer.reset();
		}
	},

    keyDown: function(e, control){
    	/*
    	nếu ký tự là nút lên xuống
    	khi ấn lên xuống, chuyển sang đối tượng tiếp theo đối tượng hiện tại được select
    	*/
    	if (e.key == 'up'){
    		control.hoverPrevious();
    		return;
		}

		if (e.key == 'down'){
			control.hoverNext();
			return;
		}
	}

});
};filesWrapper['light.Controls/AutoCompleter/CtrlAutoCompleter.js'] = function(){
	/*
Class: CtrlAutoCompleter
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

loadFile('light.G/Components/GTextField.js');
/* class */ CtrlAutoCompleter /* extends GTextField */
= new Class({
	Extends: GTextField,

	initialize: function(options, data){
		loadFile('light.Controls/AutoCompleter/DefaultAutoCompleterModel.js');
		this.setModel(new DefaultAutoCompleterModel());
		this.setOptions(options);
		if (isset(data)) this.getModel().setData(data);
	},

	createDefaultView: function(){
    	loadFile('light.Controls/AutoCompleter/BasicAutoCompleterView.js');
    	return new BasicAutoCompleterView();
	},

	displayList: function(){
		this.getView().displayList();
	},

	selectCurrentItem: function(){
		this.getView().selectItem(
			this.getView().getList().lastArmed
		);
	},

	hoverNext: function(){
		if (!this.isPopupVisible()){
			this.displayList();
			return;
		}

		var listObj = this.getView().getList();
		var nextArmed = null;
		var lastArmed = null;

		if(!isset(listObj.lastArmed)){
			nextArmed = 0;
		}
		else if (listObj.lastArmed < listObj.getModel().getSize() - 1){
			lastArmed = listObj.lastArmed;
			nextArmed = lastArmed + 1;
		}
		else {
			lastArmed = listObj.lastArmed;
			nextArmed = 0;
		}

		if (isset(lastArmed))
			listObj.getSubComponent(lastArmed).setArmed(false);

		listObj.getSubComponent(nextArmed).setArmed(true);

		var scrollTop = listObj.getElement().scrollTop;
		var nextPos = nextArmed * this.getOption('rowHeight');
		var maxHeight = this.getOption('maxRow') * this.getOption('rowHeight');
		if (nextPos < scrollTop){
			listObj.getElement().scrollTop = nextPos;
		}
		else if (nextPos >= scrollTop + maxHeight){
			listObj.getElement().scrollTop = nextPos - maxHeight + this.getOption('rowHeight');
		}
	},

	hoverPrevious: function(){
		if (!this.isPopupVisible()) return;
		var listObj = this.getView().getList();

		var nextArmed = null;
		var lastArmed = null;

		if(!isset(listObj.lastArmed)){
			nextArmed = listObj.getModel().getSize() - 1;
		}
		else if (listObj.lastArmed > 0){
			lastArmed = listObj.lastArmed;
			nextArmed = lastArmed - 1;
		}
		else {
			lastArmed = listObj.lastArmed;
			nextArmed = listObj.getModel().getSize() - 1;
		}

		if (isset(lastArmed))
			listObj.getSubComponent(lastArmed).setArmed(false);

		listObj.getSubComponent(nextArmed).setArmed(true);

		var scrollTop = listObj.getElement().scrollTop;
		var nextPos = nextArmed * this.getOption('rowHeight');
		var maxHeight = this.getOption('maxRow') * this.getOption('rowHeight');
		if (nextPos < scrollTop){
			listObj.getElement().scrollTop = nextPos;
		}
		else if (nextPos >= scrollTop + maxHeight){
			listObj.getElement().scrollTop = nextPos - maxHeight + this.getOption('rowHeight');
		}
	},

	getTimer: function(){
		return this.getModel().getTimer();
	},

	setTimer: function(timer){
		this.getModel().setTimer(timer);
	},

	searchData: function(text, fnc, view){
		return this.getModel().searchData(text, fnc, view);
	},

	isPopupVisible: function(){
		return this.getModel().getOption('popupVisible');
	},

	setPopupVisible: function(aFlag){
		this.getModel().setOption('popupVisible', aFlag);
	}
});
};filesWrapper['light.Controls/AutoCompleter/DefaultAutoCompleterModel.js'] = function(){
	/*
Class: DefaultAutoCompleterModel
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

loadFile('light.G/Model/DefaultTextFieldModel.js');
/* class */ DefaultAutoCompleterModel /* extends DefaultTextFieldModel implements AutoCompleterModel*/
= new Class({
	Extends: DefaultTextFieldModel,
	timer: null,
	data: null,

	options: {
		maxRow: 7,
		rowHeight: 13
	},

	setData: function(data){
		this.data = data;
	},

	getTimer: function(){
		return this.timer;
	},

	setTimer: function(timer){
		this.timer = timer;
	},

	searchData: function(text){
		var returnArr = new Array();
		this.data.each(function(word){
			if (word.toLowerCase().contains(text.toLowerCase()))
				returnArr.include(word);
		});
		return returnArr;
	}
});
};filesWrapper['light.Controls/AutoCompleter/JsonAutoCompleterModel.js'] = function(){
	/*
Class: JsonAutoCompleterModel
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

loadFile('light.Controls/AutoCompleter/DefaultAutoCompleterModel.js');
/* class */ JsonAutoCompleterModel /* extends DefaultAutoCompleterModel*/
= new Class({
	Extends: DefaultAutoCompleterModel,
	url: null,

	initialize: function(url){
		this.url = url;
	},

	searchData: function(text, fnc, view){
		loadFile('light.Ajax/json/Request.Light.Json.js');
		var request = new Request.Light.Json({
			url: this.url,
			async: true,
			data: {
				'key': text
			}
		});
		request.addEvent('success', fnc.bind(view));
		request.send();
		//return request.getResult();
	}
});
};filesWrapper['light.Controls/Balloon/BasicBalloonView.js'] = function(){
	loadFile('light.G/Skin/LayerView.js');
/*
Class: BasicBalloonView
	View mặc định cho <CtrlBalloon>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<LayerView>
*/
/* class */ BasicBalloonView /* extends LayerView */
= new Class({
	Extends: LayerView,
	themePath: '/More/Balloon/',
	fadeOutTimer: null,

    getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElementByTheme('content-inner'),
				'position': 'bottom'
			}
		});
	},

    paint: function(){
    	var c = this.getComponent();
        if (!isset(c.getGraphicsContext())) c.setGraphicsContext(this.getDefaultGraphicsContext());

		GFactory.getPaint().draw(this.getElement(), c.getGraphicsContext());

		GFactory.getPaint().setWidth(this.getElement(), c.getOption('width'));
    	GFactory.getPaint().setHeight(this.getElement(), c.getOption('height'));

		this.paintLayer();
		this.paintPosition.delay(getSystemConfig().get('/System/G/focusDelay/'), this);

		this.getElement().get('tween', {property: 'opacity'}).set(0);
		this.getElement().get('tween', {
			property: 'opacity',
			duration: c.getOption('fadeInDuration')
		}).start(1);

		if (!isset(c.getOption('fadeOutTime'))) return;
		loadFile('core/IdleTimer.js');
		this.fadeOutTimer = new IdleTimer(
			c.getOption('fadeOutTime')
		);
		this.fadeOutTimer.addEvent('complete', function(){
    		c.fadeOut();
    	}.bind(this));

    	this.fadeOutTimer.start();
    	this.fadeOutTimer.idle();
	},

	repaint: function(){
	},

    getDefaultGraphicsContext: function(){
		var c = this.getComponent();
        var defaultContext = {
            'inject': {
    			'target': document.body,
    			'position': 'bottom'
    		}
		};

		return defaultContext;
	},

	paintPosition: function(){
		var c = this.getComponent();
        if (c.hasLaunchedElement()){
        	var pos = GFactory.getPaint().stackPosition(
        		this.getElement(),
        		c.getLaunchedElement(),
        		c.getOption('popPos'),
        		c.getOption('alignPos'),
        		c.getOption('offsetX'),
        		c.getOption('offsetY')
        	);

        	this.domElement.addClass('balloon-tail-' + pos.pop + '-' + pos.align);
		}
		else {
			if (this.compareState('top') || this.compareState('left')){
				this.getElement().set('styles', {
					'top': c.getOption('top'),
					'left': c.getOption('left')
				});
			}
		}
	},

	paintLayer: function(){
		var c = this.getComponent();
		GFactory.getLayerManager().bringLayerToFront(c);
        this.getElement().set('styles', {
			'position': 'absolute',
			'top': 0,
			'left': 0
		});
	},

	createDomElement: function(){
		this.domElement = new Element('div', {
			'class': this.getTheme('main') + ' ' + this.getComponent().getOption('baseCss')
		}).set('html',
'<div class="' + this.getTheme('head') + '">' +
	'<div class="' + this.getTheme('head-inner') + '">' +
	'</div>' +
'</div>' +
'<div class="' + this.getTheme('content') + '">' +
	'<div class="' + this.getTheme('content-inner') + '">' +
	'</div>' +
'</div>' +
'<div class="' + this.getTheme('bottom') + '">' +
	'<div class="' + this.getTheme('bottom-inner') + '">' +
	'</div>' +
'</div>'
		);

		this.getComponent().attachWithElement(this.domElement);
	},

	install: function(){
		this.parent();
		//this.installSystemListener();
		//this.installDestroyOnBlur();
	},

	uninstall: function(){
		//this.uninstallDestroyOnBlur();
		//this.uninstallSystemListener();
		this.parent();
	},

	fadeOut: function(){
		this.getElement().get('tween', {
			property: 'opacity',
			duration: this.getComponent().getOption('fadeOutDuration')
		}).start(0);
	}

});
};filesWrapper['light.Controls/Balloon/CtrlBalloon.js'] = function(){
	loadFile('light.G/Components/AbstractLayer.js');
/*
Class: CtrlBalloon
	Balloon là một component dùng để hiển thị một khối nội dung được 'pop' ra từ một component khác có sẵn nào đó và thường là có một mũi tên trỏ đến vị trí mà từ đó nó pop ra. Balloon sẽ tự động biến mất sau một khoảng thời gian nhất định

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Syntax:
	(start code)
var balloonObj = new CtrlBalloon([options]);
	(end)

Options:
	popPos - (string) vị trí xuất hiện của balloon so với đối tượng launch nó, mặc định là 'bottom'
	alignPos - (string) vị trí bám lề của balloon so với đối tượng launch nó, mặc định là 'left'
	offsetX - (integer) di dời tọa độ x, mặc định là -8
	offsetY - (integer) di dời tọa độ y, mặc định là -8
	fadeOutTime - (string, integer) thời gian biến mất của balloon sau khi xuất hiện (tính theo ms), mặc định là 4000
	fadeInDuration - (string,integer) thời gian kéo dài hiệu ứng fade in, mặc định là 'normal'
	fadeOutDuration - (string, integer) thời gian kéo dài hiệu ứng fade out, mặc định là 'long'
	destroyDelay - (integer) thời gian delay trước khi destroy đối tượng, phải lớn hơn fadeOutDuration

See Also:
	<DefaultBalloonModel>, <BasicBalloonView>

Extends:
	<AbstractLayer>
*/
/* class */ CtrlBalloon /* extends AbstractLayer */
= new Class({
	Extends: AbstractLayer,

    initialize: function(options){
    	loadFile('light.Controls/Balloon/DefaultBalloonModel.js');
		this.setModel(new DefaultBalloonModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	loadFile('light.Controls/Balloon/BasicBalloonView.js');
    	return new BasicBalloonView();
	},

    getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	},

	getFadeOutTimer: function(){
		return this.getView().fadeOutTimer;
	},

	fadeOut: function(){
		this.getView().fadeOut();
		this.destroy.delay(
			this.getOption('destroyDelay')
			, this
		);
	}
});
};filesWrapper['light.Controls/Balloon/DefaultBalloonModel.js'] = function(){
	loadFile('light.G/Model/DefaultLayerModel.js');
/*
Class: DefaultBalloonModel
	Model mặc định cho <CtrlBalloon>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Options:
	popPos - (string) vị trí xuất hiện của balloon so với đối tượng launch nó, mặc định là 'bottom'
	alignPos - (string) vị trí bám lề của balloon so với đối tượng launch nó, mặc định là 'left'
	offsetX - (integer) di dời tọa độ x, mặc định là -8
	offsetY - (integer) di dời tọa độ y, mặc định là -8
	fadeOutTime - (string, integer) thời gian biến mất của balloon sau khi xuất hiện (tính theo ms), mặc định là 4000
	fadeInDuration - (string,integer) thời gian kéo dài hiệu ứng fade in, mặc định là 'normal'
	fadeOutDuration - (string, integer) thời gian kéo dài hiệu ứng fade out, mặc định là 'long'
	destroyDelay - (integer) thời gian delay trước khi destroy đối tượng, phải lớn hơn fadeOutDuration
*/
/* class */ DefaultBalloonModel /* extends DefaultLayerModel */
= new Class({
	Extends: DefaultLayerModel,

	options: {
		popPos: 'bottom',
		alignPos: 'left',
		offsetX: -8,
		offsetY: -8,
		fadeOutTime: 4000,
		fadeInDuration: 'normal',
		fadeOutDuration: 'long',
		destroyDelay: 1000
	}
});
};filesWrapper['light.Controls/bridge.js'] = function(){
	GFactory.getResourceManager().installTheme('More', 'light.Controls/resources/themes/More.js');
};filesWrapper['light.Controls/ColorChooser/ColorChangeListener.js'] = function(){
	/*
Interface: ColorChangeListener
	Mô tả dạng hàm mà một listener muốn lắng nghe sự thay đổi màu của các class sử dụng <ColorChooser> phải sử dụng

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ ColorChangeListener /* */
= new Hash({
	colorChanged: function(component, color){
	}
});
};filesWrapper['light.Controls/ColorChooser/ColorChooser.js'] = function(){
	/*
Class: ColorChooser
	Mô tả của một component có khả năng lưu trữ mầu sắc và thông báo sự thay đổi của nó

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ ColorChooser
= new Class({

    getColor: function(){
		return this.getModel().getColor();
	},

	setColor: function(color){
		this.getModel().setColor(color);
	},

	addColorChangeListener: function(){
		this.getModel().addColorChangeListener.run(arguments, this.getModel());
	},

	removeColorChangeListener: function(returnFncs){
		this.getModel().removeColorChangeListener(returnFncs);
	}
});
};filesWrapper['light.Controls/ColorChooser/ColorChooserModel.js'] = function(){
	/* class */ ColorChooserModel
= new Class({
	color: null,

	initialize: function(color){
		this.color = color;
	},

	getColor: function(){
		return this.color;
	},

	setColor: function(color){
		this.color = color;
		this.fireEvent('colorChange', [color]);
	},

	addColorChangeListener: function(){
		var colorChangeListenerHash = arguments[0];
        var realArguments = $A(arguments);
    	realArguments.erase(realArguments[0]);

        var returnFncs = new Hash({
			'colorChange': function(color){
				var newArguments = [this.getComponent(), color].extend(realArguments);
				colorChangeListenerHash.colorChanged.run(newArguments);
			}.bind(this)
		});

        returnFncs.each(function(value, key){
			this.addEvent(key, value);
		}.bind(this));

		return returnFncs;
	},

	removeColorChangeListener: function(returnFncs){
        returnFncs.each(function(value, key){
			this.removeEvent(key, value);
		}.bind(this));
	}
});
};filesWrapper['light.Controls/ColorChooser/CompColorBlock.js'] = function(){
	loadFile('light.Controls/ColorChooser/ColorChooser.js');
loadFile('light.G/Components/GButton.js');
/*
Class: CompColorBlock
	Một khối chứa màu, thường được sử dụng trong <CompColorBoard>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<GButton>
*/
/* class */ CompColorBlock /* extends GButton implements ColorChooser */
= new Class({
	Extends: GButton,
	Implements: ColorChooser,

	initialize: function(options, color){
		this.setModel(new CompColorBlock.Model(color));
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new CompColorBlock.View();
	}
});

loadFile('light.G/Model/DefaultButtonModel.js');
loadFile('light.Controls/ColorChooser/ColorChooserModel.js');
/*
Class: CompColorBlock.Model
	Model chịu trách nhiệm lưu trữ cho <CompColorBlock>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<DefaultButtonModel>
*/
/* class */ CompColorBlock.Model /* extends DefaultButtonModel implements ColorChooserModel */
= new Class({
	Extends: DefaultButtonModel,
	Implements: ColorChooserModel
});

loadFile('light.G/Skin/Basic/BasicButtonView.js');
/*
Class: CompColorBlock.View
	Thể hiện của một <CompColorBlock>. Không grab focus nên thừa kế từ WithoutFocus của <BasicButtonView>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ CompColorBlock.View /* extends BasicButtonView.WithoutFocus */
= new Class({
    Extends: BasicButtonView.WithoutFocus,
	themePath: 	'/More/ColorBlock/',

    paintInside: function(){
    	var c = this.getComponent();
		this.getElementByTheme('inside-color').set('styles', {
			'background-color': c.getColor()
		});
	},

	createDomElement: function(){
		this.parent();
		this.getElement().grab(
			new Element('div', {
				'class': this.getTheme('inside-color')
			})
		);
	}
});

};filesWrapper['light.Controls/ColorChooser/CompColorBoard.js'] = function(){
	loadFile('light.G/Components/GComponent.js');
loadFile('light.Controls/ColorChooser/ColorChooser.js');

/*
Class: CompColorBoard
	Dùng để tạo ra một bảng màu cho người dùng chọn

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ CompColorBoard /* implements ColorChooser */
= new Class({
	Extends: GComponent,
	Implements: ColorChooser,

	initialize: function(options){
		this.setModel(new CompColorBoard.Model());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new CompColorBoard.View();
	}
});

loadFile('light.G/Model/AbstractModel.js');
loadFile('light.Controls/ColorChooser/ColorChooserModel.js');
/* class */ CompColorBoard.Model /* extends AsbtractModel */
= new Class({
	Extends: AbstractModel,
	Implements: ColorChooserModel,
	options: {
		colors: {
			baseColor: ['ffff00', '00ff00', '00ffff', 'ff00ff', '0000ff']
		},
		css: {
			baseColor: 'base-colors'
		},
		context: {
			baseColor: 'inside'
		}
	}
});

loadFile('light.G/Skin/ComponentView.js');
/* class */ CompColorBoard.View /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: 	'/More/ColorBoard/',

	getDrawingContext: function(key){
		var context = this.getComponent().getOption('context');
		return new Hash({
			'inject': {
				'target': this.getElementByTheme(context[key]),
				'position': 'bottom'
			}
		});
	},

	paint: function(){
    	var c = this.getComponent();
    	GFactory.getPaint().draw(this.getElement(), c.getGraphicsContext());
    	var colors = c.getOption('colors');
    	$H(colors).each(function(data, key){
			data.each(function(color){
				this.paintColorBlock(color, key);
			}.bind(this))
    	}.bind(this));
	},

	repaint: function(){
		GFactory.getPaint().draw(this.getElement(), c.getGraphicsContext(), null, ['inject']);
	},

	paintColorBlock: function(color, key){
		var css = this.getComponent().getOption('css');
		var options = {
			baseCss: css[key]
		};

		loadFile('light.Controls/ColorChooser/CompColorBlock.js');
		var colorBlock = new CompColorBlock(options, '#' + color);
    	colorBlock.setGraphicsContext(this.getDrawingContext(key));
    	colorBlock.paint();
		this.setupColorBlock(colorBlock);
	},

	setupColorBlock: function(colorBlock){
		colorBlock.addMouseListener(CompColorBoard.View.ColorBlockListener, this.getComponent());
	},

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
			'class': this.getTheme('main')
		}).grab(
			new Element('div', {
				'class': this.getTheme('inner')
			}).grab(
				new Element('div', {
					'class': this.getTheme('inside') + ' pkg'
				})
			)
		);

		c.attachWithElement(this.domElement);
	},

	install: function(){
		this.createDomElement();
	},

    uninstall: function(){
		this.destroyDomElement();
	}
});

/* static class */ CompColorBoard.View.ColorBlockListener /* implements MouseListener */
= new Hash({
    mouseDown: $empty,
	mouseUp: $empty,

    singleClick: function(e, colorBlock, colorBoard){
    	colorBoard.setColor(colorBlock.getColor());
	},

    doubleClick: $empty
});
};filesWrapper['light.Controls/ColorChooser/CompColorPickerFromBoard.js'] = function(){
	loadFile('light.G/Components/GComponent.js');
loadFile('light.Controls/ColorChooser/ColorChooser.js');

/*
Class: CompColorPickerFromBoard
	Là một bộ button gồm button chính và arrow button. Khi ấn vào button chính sẽ thay đổi màu nền của chữ thành màu đang lưu trữ trong nó.	Còn khi ấn vào arrow button thì mở ra một <CompColorBoard> mà khi chọn một màu trong board thì sẽ set lại màu đang lưu trong button chính, đồng thời set lại màu chữ.

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ CompColorPickerFromBoard /* extends GComponent */
= new Class({
	Extends: GComponent,
	Implements: [ColorChooser],

	initialize: function(options){
		this.setModel(new CompColorPickerFromBoard.Model());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new CompColorPickerFromBoard.View();
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext))
            this.defaultChildGraphicsContext = this.getView().getInsideContext();

    	return this.defaultChildGraphicsContext;
	}
});

loadFile('light.Controls/ColorChooser/ColorChooserModel.js');
loadFile('light.G/Model/AbstractModel.js');
/* class */ CompColorPickerFromBoard.Model /* extends AbstractModel */
= new Class({
	Extends: AbstractModel,
	Implements: [ColorChooserModel],
	options: {
		boardColors: {
			baseColor: ['ffff00', '00ff00', '00ffff', 'ff00ff', '0000ff']
		},
		boardCss: {
			baseColor: 'base-colors'
		},
		boardContext: {
			baseColor: 'inside'
		}
	}
});

loadFile('light.G/Skin/ComponentView.js');
/* class */ CompColorPickerFromBoard.View /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	mainButton: null,
	arrowButton: null,
	popup: null,
	colorBoard: null,

	getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElementByTheme('inside'),
				'position': 'bottom'
			}
		});
	},

	paintMainButton: function(){
		var c = this.getComponent();
		loadFile('light.G/Components/GButton.js');
		this.button = new GButton({
			baseCss: this.getTheme('main-btn')
		});
		c.add(this.button);
	},

	paintArrowButton: function(){
		var c = this.getComponent();
		loadFile('light.G/Components/GButton.js');
		this.arrowButton = new GButton({
			baseCss: this.getTheme('arrow-btn')
		});
		c.add(this.arrowButton);
	},

	paintPopup: function(){
		loadFile('light.G/Components/GPopupMenu.js');
		var c = this.getComponent();
		this.popup = new GPopupMenu({
			baseCss: c.getOption('baseCss') + '-popup'
		});
    	this.popup.setParentComponent(c);
    	this.popup.setGraphicsContext({
    		'inject': {
    			'target': document.body,
    			'position': 'bottom'
    		},
    		'stackpos': {
    			'target': this.getElement(),
    			'pop': 'bottom',
    			'align': 'left'
    		}
    	});
    	this.popup.paint();
    	this.paintColorBoard();
    	this.popup.add(this.getColorBoard());
	},

	paintColorBoard: function(){
		var c = this.getComponent();
		loadFile('light.Controls/ColorChooser/CompColorBoard.js');
		this.colorBoard = new CompColorBoard({
			themePath: c.getOption('boardThemePath'),
			colors: c.getOption('boardColors'),
			css: c.getOption('boardCss'),
			context: c.getOption('boardContext')
    	});
	},

	getMainButton: function(){
		return this.button;
	},

	getArrowButton: function(){
		return this.arrowButton;
	},

	getPopup: function(){
		return this.popup;
	},

	getColorBoard: function(){
		return this.colorBoard;
	},

	paint: function(){
		// chỉ vẽ inject
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), ['inject']);
		var c = this.getComponent();

		this.paintMainButton();
		this.paintArrowButton();
		this.paintPopup();

    	this.getArrowButton().addChangeListener(CompColorPickerFromBoard.ArrowButtonListener, c);
    	this.getArrowButton().addMouseListener(CompColorPickerFromBoard.ArrowButtonListener, c);
		this.getColorBoard().addColorChangeListener(CompColorPickerFromBoard.ColorBoardListener, c);

    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext(), null, ['inject']);
		this.saveState();
	},

	repaint: function(){
		var c = this.getComponent();
        this.getPopup().setVisible(c.isPopupVisible());
        this.getArrowButton().setEnabled(c.isEnabled());
        this.getMainButton().setEnabled(c.isEnabled());
        this.getColorBoard().setEnabled(c.isEnabled());
        this.saveState();
	},

	createDomElement: function(){
		var c = this.getComponent();
        this.domElement = new Element('div', {
        	'id': c.getOption('id'),
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		}).set('html',
'<div class="' + this.getTheme('inside') + '">' +
'</div>' + ''
		);
		c.attachWithElement(this.domElement);
	},

	install: function(){
		this.parent();
		var c = this.getComponent();
		this.returnFncs['change'] = c.addChangeListener(CompColorPickerFromBoard.Listener);
		this.returnFncs['colorChange'] = c.addColorChangeListener(CompColorPickerFromBoard.Listener);
	},

	uninstall: function(){
		var c = this.getComponent();
		c.removeColorChangeListener(this.returnFncs['colorChange']);
		c.removeChangeListener(this.returnFncs['change']);
		this.parent();
	}
});

/* class */ CompColorPickerFromBoard.Listener /* implements ChangeListener, ColorChangeListener */
= new Hash({
	stateChanged: function(colorPicker, property, value){
		colorPicker.repaint();
	},

	colorChanged: function(colorPicker, color){
		colorPicker.getView().getMainButton().setColor(color);
	}
});

/* class */ CompColorPickerFromBoard.ArrowButtonListener /* implements ChangeListener */
= new Hash({
    mouseDown: function(e, arrowButton, backColorPicker){
    	if (arrowButton.isEnabled())
    		backColorPicker.setPopupVisible(!backColorPicker.isPopupVisible());
	},

	mouseUp: $empty,
    singleClick: $empty,
    doubleClick: $empty,

    stateChanged: function(arrowButton, property, value, backColorPicker){
		if (property == 'focus' && value == false){
			/* khi lost focus mà thôi */
			backColorPicker.setPopupVisible(false);
		}
	}
});

/* static class */ CompColorPickerFromBoard.ColorBoardListener /* implements ColorChangeListener */
= new Hash({
    colorChanged: function(colorBoard, color, colorPicker){
    	colorPicker.setColor(colorBoard.getColor());
    	colorPicker.setPopupVisible(false);
	}
});

};filesWrapper['light.Controls/ColorChooser/CompInputColorWithBoard.js'] = function(){
	loadFile('light.Controls/ColorChooser/CompColorPickerFromBoard.js');

/*
Class: CompInputColorWithBoard
	Là một bộ gồm một input và arrow button. Còn khi ấn vào arrow button thì mở ra một <CompColorBoard> mà khi chọn một màu trong board thì sẽ set lại giá trị của input

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ CompInputColorWithBoard /* extends CompColorPickerFromBoard */
= new Class({
	Extends: CompColorPickerFromBoard,

    createDefaultView: function(){
    	return new CompInputColorWithBoard.View();
	}
});

/* class */ CompInputColorWithBoard.View /* extends CompColorPickerFromBoard.View */
= new Class({
	Extends: CompColorPickerFromBoard.View,
	textField: null,

	paintMainButton: function(){
		var c = this.getComponent();
		loadFile('light.G/Components/GTextField.js');
		this.textField = new GTextField({
			'name': c.getOption('tf-name')
		});
		this.textField.setText(c.getOption('tf-value'));
		c.add(this.textField);
	},

	getMainButton: function(){
		return this.textField;
	},

	install: function(){
		this.createDomElement();
		var c = this.getComponent();
		this.returnFncs['change'] = c.addChangeListener(CompInputColorWithBoard.Listener);
		this.returnFncs['colorChange'] = c.addColorChangeListener(CompInputColorWithBoard.Listener);
	}
});

/* class */ CompInputColorWithBoard.Listener /* implements ChangeListener, ColorChangeListener */
= new Hash({
	stateChanged: function(colorPicker, property, value){
		colorPicker.repaint();
	},

	colorChanged: function(colorPicker, color){
		colorPicker.getView().getMainButton().setText(color);
	}
});
};filesWrapper['light.Controls/FU/CtrlFu.js'] = function(){
	loadFile('light.G/Components/GComponent.js');
/*
Class: CtrlFu
	Component thực hiện việc upload một file. Việc upload được thực hiện bằng cách sử dụng một file swf, gửi request thông qua file này lên server

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<GComponent>

See Also:
	- <DefaultFuModel>, <BasicFuView>, <MiniFuView>
	- <FuSwfConnector>
*/
/* class */ CtrlFu /* extends GComponent */
= new Class({
	Extends: GComponent,

    initialize: function(options){
    	loadFile('light.Controls/FU/DefaultFuModel.js');
		this.setModel(new DefaultFuModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	loadFile('light.Controls/FU/MiniFuView.js');
    	return new MiniFuView();
	},

    getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	},

	upload: function(){
		this.getView().getConnector().upload();
	},

	empty: function(){
		this.getView().getConnector().empty();
	},

	cancel: function(){
		this.getView().getConnector().cancel();
	},

	remove: function(index){
		this.getView().getConnector().remove(index);
	},

	getQueueSize: function(){
		return this.getView().getConnector().getQueueSize();
	},

	getConnector: function(){
		return this.getView().getConnector();
	}
});
};filesWrapper['light.Controls/FU/DefaultFuModel.js'] = function(){
	loadFile('light.G/Model/AbstractModel.js');
/*
Class: DefaultFuModel
	Model mặc định dùng để lưu trữ thuộc tính của component FU

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<AbstractModel>

Options:
	id - (string,integer) ID của component
	swfPath - (string) Đường dẫn đến file swf của flash
	uploadProcessor - (string) Đường dẫn thực hiện upload
	limitFiles - (integer) Số lượng file giới hạn trong danh sách
	maxFileSize - (integer) Số MB tối đa
	uploadFieldName - (string) Tên trường HTML được sử dụng để upload
	limitExt - (string) Danh sách các định dạng file có thể hỗ trợ, ngăn cách nhau bởi dấu chấm phẩy. Ví dụ: *.jpg;*.png
	browseDesc - (string) Xâu mô tả định dạng file hỗ trợ trong ô browse
	browseMode - (string) Chế độ browse, 'single' hoặc 'multiple'
	extraData - (mixed) Dữ liệu dạng hash gửi kèm HTTP lên
	uploadAfterSelect - (boolean) Upload ngay sau khi select hay không
*/
/* class */ DefaultFuModel /* extends AbstractModel */
= new Class({
   	Extends: AbstractModel,

    options: {
    	id: $time(),
    	swfPath: null,
    	uploadProcessor: null,
    	limitFiles: 2,
    	maxFileSize: 3,
    	uploadFieldName: 'filedata',
    	ext: '*.*',
    	extDesc: 'Chọn file ảnh bạn muốn upload',
    	browseMode: 'single', // hoặc 'multiple'
    	extraData: null,
    	uploadAfterSelect: false,
    	debugMode: false
	}
});
};filesWrapper['light.Controls/FU/Event/FuConnectorListener.js'] = function(){
	/*
Interface: FuConnectorListener
	Interface sử dụng cho các Listener muốn lắng nghe sự kiện của <FuSwfConnector>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ FuConnectorListener /**/
= new Hash({

    onProgress: function(obj, connector){
    },

    onRemove: function(obj, connector){
    },

	onSelect: function(obj, connector){
	},

	onComplete: function(obj, connector){
	},

	onFinish: function(connector){
	},

	onCdata: function(obj, connector){
	},

	onBeforeUpload: function(connector){
	},

	onUpload: function(obj, connector){
	},

	onHover: function(connector){
	},

	onOut: function(connector){
	},

	onCancel: function(connector){
	},

	onEmpty: function(connector){
	},

    onBrowse: function(connector){
	},

	onError: function(obj, connector){
	}
});
};filesWrapper['light.Controls/FU/FuSwfConnector.js'] = function(){
	/*
Class: FuSwfConnector
	Có nhiệm vụ kết nối với Flash thông qua việc quản lý các sự kiện

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ FuSwfConnector /* extends Swiff */
= new Class({
	Extends: Swiff,
    Implements: [Events,Options],

    options: {
    	uploadAfterSelect: false,
    	extraData: null
    },

    initialize: function(options){
        this.setOptions(options);
        var path = this.options.path;
        if (!path.contains('?')) path += '?noCache=' + $time();
		this.setupCallBacks();
        this.parent(path);
    },

    upload: function(){
    	this.onBeforeUpload();

        var data = new Hash({
        	'dcookie': HelpersFactory.getBase64Helper().encode(
        					JSON.encode(
        						HelpersFactory.getCookiesHelper().getAll()
        					)
        				)
		});

		if (isset(this.options.extraData)) data = data.extend(this.options.extraData);

		var newData = {};
		var keys = data.getKeys();
		var values = data.getValues();

		values.each(function(item, index){
		    newData[keys[index]] = item;
		});

        if(this.objFu.getQueue() > 0) this.objFu.sendEvent('UPLOAD', data);
    },

    getQueueSize: function(){
		return this.objFu.getQueue();
    },

    cancel: function() {
        this.objFu.sendEvent('CANCEL');
    },

    remove: function(index) {
        this.objFu.sendEvent('REMOVE', index);
    },

    empty: function(){
        this.objFu.sendEvent('EMPTY');
    },

    setupCallBacks: function(){
    	// danh sách các hàm có thể gọi callBacks từ Swf
    	var toCallBacks = ['onReady', 'onError', 'onHover', 'onOut', 'onBrowse', 'onStart', 'onProgress', 'onSelect', 'onComplete', 'onCdata', 'onFinish', 'onCancelf', 'onRemovef', 'onEmptyf'];
    	toCallBacks.each(function(fncName){
            // cho hàm của object này vào danh sách callBacks với key
        	this.options.callBacks[fncName] = this[fncName].create({delay: 10, bind:this});
    	}.bind(this));
    },

    onReady: function(obj){
        this.objFu = $(obj.id);
        var fnstr = 'Swiff.CallBacks.'+this.instance+'.on';
        this.busy = false;
        var swfEvents = ['Progress', 'Browse', 'Select', 'Complete', 'Cdata', 'Start', 'Error', 'Hover', 'Out', 'Finish', 'Cancelf', 'Removef', 'Emptyf'];
        // lưu ý các hàm ở đây phải được setupCallBacks rồi mới chạy được
        swfEvents.each(function(fn){
            this.objFu.addControlListener(fn, fnstr+fn);
        }.bind(this));
    },

    onProgress: function(obj){
    	this.fireEvent('progress', [obj, this]);
    },

    onSelect: function(obj){
    	this.fireEvent('select', [obj, this]);
    	if (this.options.uploadAfterSelect){
    		this.upload();
    	}
    },

    onComplete: function(obj){
        this.fireEvent('complete', [obj, this]);
    },

    onFinish: function(){
        this.fireEvent('finish', [this]);
    },

    onBrowse: function(){
    	this.fireEvent('browse', [this]);
    },

    onStart: function(obj){
    	this.fireEvent('upload', [obj, this]);
    },

    onCdata: function(obj){
    	/*
    	cấu trúc dữ liệu trả về:
    	- paintCommands // raw array
    	- continueStatus // stop, error, clear, continue
    	- cookies
    		cookieName =>
    			cookieData =>
    				value
    				options	=>	duration
    							domain
    							path
    							secure
    	*/

    	if (getSystemConfig().get('/System/debugMode')){
    		getErrorConsole().log(obj.data);
    		/*getErrorConsole().log(obj.data.charCodeAt(0));
    		getErrorConsole().log(obj.data.charCodeAt(1));
    		getErrorConsole().log(obj.data.charCodeAt(2));
    		getErrorConsole().log(obj.data.charCodeAt(3));*/
		}
        var data = JSON.decode(
        	HelpersFactory.getBase64Helper().decode(obj.data)
        );

        if (getSystemConfig().get('/System/debugMode')){
        	getErrorConsole().log(data);
		}

        HelpersFactory.getLadHelper().execute(data.paintCommands);
        HelpersFactory.getCookiesHelper().setAll(data.cookies);

        /*
    	*	bổ sung các hàm gọi TaskManager ở đây
    	*/
    	getTaskManager().runProcesses('afterLadExecute');
    	getTaskManager().runProcesses('finishLadExecute');

        var continueStatus = data.continueStatus.toLowerCase();
        switch(continueStatus) {
            case 'stop':
                //this.fireEvent('cdata', [obj, this]);
                this.onError(obj);
                break;
            case 'error':
                this.onError(obj);
                this.upload();
                break;
            case 'clear':
                this.empty();
                break;
            case 'continue':
            default:
                this.fireEvent('cdata', [obj, this]);
            	this.upload();
                break;
        }
    },

    onError: function(obj){
        this.fireEvent('error',[obj,this]);
    },

    onHover: function(){
    	this.fireEvent('hover', [this]);
    },

    onOut: function(){
    	this.fireEvent('out', [this]);
    },

    onCancelf: function(){
    	this.fireEvent('cancel', [this]);
    },

    onRemovef: function(obj){
    	this.fireEvent('remove', [obj, this]);
    },

    onEmptyf: function(){
    	this.fireEvent('empty', [this]);
    },

    onBeforeUpload: function(){
		this.fireEvent('beforeUpload', [this]);
    },

    /*
    Function:
    	Decode the string we get to get a decoded data that is excuteable

    Arguments:
    	fuSwfListenerHash - (array) Static class chứa các hàm lắng nghe sự kiện

    Returns:
    	Decoded data that is executeable
    */
    addFuConnectorListener: function(){
    	var fuSwfListenerHash = arguments[0];
    	var realArguments = $A(arguments);
        realArguments.erase(realArguments[0]);

        var returnFncs = new Hash({
			'progress': function(obj, connector){
				var newArguments = [obj, connector].extend(realArguments);
				fuSwfListenerHash.onProgress.run(newArguments);
			},

			'select': function(obj, connector){
				var newArguments = [obj, connector].extend(realArguments);
				fuSwfListenerHash.onSelect.run(newArguments);
			},

			'complete': function(obj, connector){
				var newArguments = [obj, connector].extend(realArguments);
				fuSwfListenerHash.onComplete.run(newArguments);
			},

			'finish': function(connector){
				var newArguments = [connector].extend(realArguments);
				fuSwfListenerHash.onFinish.run(newArguments);
			},

            'cancel': function(connector){
				var newArguments = [connector].extend(realArguments);
				fuSwfListenerHash.onCancel.run(newArguments);
			},

            'browse': function(connector){
				var newArguments = [connector].extend(realArguments);
				fuSwfListenerHash.onBrowse.run(newArguments);
			},

            'empty': function(connector){
				var newArguments = [connector].extend(realArguments);
				fuSwfListenerHash.onEmpty.run(newArguments);
			},

            'remove': function(obj, connector){
            	var newArguments = [obj, connector].extend(realArguments);
				fuSwfListenerHash.onRemove.run(newArguments);
			},

			'cdata': function(obj, connector){
				var newArguments = [obj, connector].extend(realArguments);
				fuSwfListenerHash.onCdata.run(newArguments);
			},

			'beforeUpload': function(connector){
				var newArguments = [connector].extend(realArguments);
				fuSwfListenerHash.onBeforeUpload.run(newArguments);
			},

            'upload': function(obj, connector){
				var newArguments = [obj, connector].extend(realArguments);
				fuSwfListenerHash.onUpload.run(newArguments);
			},

            'error': function(obj,connector) {
                var newArguments = [obj, connector].extend(realArguments);
                fuSwfListenerHash.onError.run(newArguments);
            },

			'hover': function(connector){
				var newArguments = [connector].extend(realArguments);
				fuSwfListenerHash.onHover.run(newArguments);
			},

			'out': function(connector){
				var newArguments = [connector].extend(realArguments);
				fuSwfListenerHash.onOut.run(newArguments);
			}
		});

		returnFncs.each(function(value, key){
			this.addEvent(key, value);
		}.bind(this));
    }
});
};filesWrapper['light.Controls/FU/FuView.js'] = function(){
	loadFile('light.G/Skin/ComponentView.js');
loadFile('light.G/Components/GButton.js');
loadFile('light.Controls/FU/FuSwfConnector.js');
loadFile('light.G/Components/GPopupMenu.js');

/*
Class: FuView
	Định nghĩa cách thức vẽ một view dành cho <CtrlFu>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* abstract class */ FuView /* extends ComponentView */
= new Class({
	Extends: ComponentView,

	fuContainer: null,
    fuConnector: null,
    browseButton: null,

    createBrowseButton: /* abstract */ function(){
    	this.browseButton = new GButton({
            text: 'Thêm file'
        });
    },

    getBrowseButton: function(){
		return this.browseButton;
    },

    getConnector: function(){
    	if (!isset(this.fuConnector)) getErrorConsole().throwError('Không tìm thấy connector cho FU');
    	return this.fuConnector;
    },

    getContainer: function(){
		return this.fuContainer;
    },

    createConnector: function(){
    	/* tạo một container bằng popupmenu chứa connector nằm ở trên nút browse */
    	var c = this.getComponent();

        var containerElement = $(c.getOption('id') + 'FuContainer');
        if (isset(containerElement)) containerElement.destroy();

    	this.fuContainer = new GPopupMenu({
			'id': c.getOption('id') + 'FuContainer',
			'innerId': c.getOption('id') + 'FuInnerContainer',
			'baseCss': this.getTheme('fu-container')
    	});
    	this.fuContainer.setParentComponent(c);
    	this.fuContainer.setVisible(true);

    	/* được chèn vào document.body vì là layer, cùng chiều rộng và cao với browseButton và cùng vị trí với browseButton */
    	this.fuContainer.setGraphicsContext({
			'inject': {
				'target': document.body,
				'position': 'bottom'
			},
			'stackwidth': {
				'target': this.getBrowseButton().getElement()
			},
			'stackheight': {
				'target': this.getBrowseButton().getElement()
			},
			'samepos': {
				'target': this.getBrowseButton().getElement()
			}
    	});
    	this.fuContainer.paint();

		this.fuConnector = new FuSwfConnector({
            path: c.getOption('swfPath'),
            extraData: c.getOption('extraData'),
            uploadAfterSelect: c.getOption('uploadAfterSelect'),
	        container: c.getOption('id') + 'FuInnerContainer',
	        id: c.getOption('id')+'SwfUploader',
	        height: this.getBrowseButton().getElement().getSize().y,
	        width: this.getBrowseButton().getElement().getSize().x,
	        params: {
	            quality: 'high',
	            allowScriptAccess: 'always',
	            wMode: 'transparent',
	            swLiveConnect: true
	        },
	        properties: {
	            name: c.getOption('id')+'SwfUploader'
	        },
	        vars: {
	        	width: this.browseButton.getElement().getSize().x,
	        	height: this.browseButton.getElement().getSize().y,
	            processor: c.getOption('uploadProcessor'),
	            limit: c.getOption('limitFiles'),
	            maxSize: c.getOption('maxFileSize') * 1024 * 1024,
	            fieldName: c.getOption('uploadFieldName'),
	            ext: c.getOption('ext'),
	            extDesc: c.getOption('extDesc'),
	            select: c.getOption('browseMode'),
	            debugMode: c.getOption('debugMode')
			}
		});
    },

    install: function(){
        this.createDomElement();
    },

    uninstall: function(){
        this.destroyDomElement();
    }
});

};filesWrapper['light.Controls/FU/InForm/InFormFuView.js'] = function(){
	loadFile('light.Controls/FU/FuView.js');

/*
Class: InFormFuView
	Upload nhiều file thay thế cho nút Browse ở trong một form

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Cấu trúc HTML
	(start code)
<div class='pkg'>
	<div class='default-row'>
		{browseButton}
		{fileCount}
		{emptyButton}
	</div>
	<div class='sub-row'>
		{overallProgressBar}
	</div>
</div>
	(end)
*/
/* class */ InFormFuView /* extends FuView */
= new Class({
	Extends: FuView,

	fileCountLabel: null,
	emptyButton: null,
	progressBar: null,

	themePath: '/More/InFormFU/',

	bindEvents: function(){
        this.fuConnector.addFuConnectorListener(
            InFormFuView.ConnectorListener,
            this.getComponent()
        );
    },

	setup: function(){
		this.createBrowseButton();
		this.getComponent().add(this.getBrowseButton());

		loadFile('light.G/Components/GLabel.js');
		this.fileCountLabel = new GLabel({
			baseCss: this.getTheme('fileCountLabel'),
			text: '0 file'
		});
		this.getComponent().add(this.fileCountLabel);

		loadFile('light.G/Components/GDomElement.js');
		this.emptyButton = new GDomElement(null, new Element('span', {
			'class': this.getTheme('clearButton'),
			'text': 'Dọn dẹp'
		}));

		// tạo wrapper chứa empty button
		this.emptyButton.addEvent('click', function(){
			this.fuConnector.empty();
		}.bind(this));
		this.getComponent().add(this.emptyButton);

		loadFile('light.Controls/ProgressBar/CtrlProgressBar.js');
		this.progressBar = new CtrlProgressBar();
		this.progressBar.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('sub'),
				'position': 'bottom'
			}
		});
		this.progressBar.paint();

		this.createConnector();
		this.bindEvents();
	},

	paint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
		this.setup();
	},

	repaint: function(){
	},

	getInsideContext: function(){
        return new Hash({
            'inject': {
                'target': this.getElementByTheme('default'),
                'position': 'bottom'
            }
        });
    },

    createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
            'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
        }).set('html',
'<div class=' + this.getTheme('default') + '>' +
'</div>'+
'<div class=' + this.getTheme('sub') + '>' +
'</div>'
        );
        c.attachWithElement(this.domElement);
    }
});

/* static class */ InFormFuView.ConnectorListener /* implements FuConnectorListener */
= new Hash({

	onProgress: function(obj, connector, fu){
		fu.getView().progressBar.setProgress(obj.tpercent);
    },

    onRemove: $empty,

	onSelect: function(obj, connector, fu){
		fu.getView().fileCountLabel.setOption('text', connector.getQueueSize() + ' file');
		// tạo nút empty
	},

	onComplete: function(obj, connector, fu){
		fu.getView().progressBar.setProgress(obj.tpercent);
	},

	onFinish: $empty,
	onCdata: $empty,
	onUpload: function(){
		// tạo progress bar
	},
	onHover: $empty,
	onOut: $empty,
	onCancel: $empty,

	onEmpty: function(connector, fu){
		fu.getView().progressBar.setProgress(0);
		fu.getView().fileCountLabel.setOption('text', connector.getQueueSize() + ' file');
		// xóa nút empty
	},

    onBrowse: $empty,

	onError: function(obj, connector){
		//console.log('some error appears');
	}

});

};filesWrapper['light.Controls/FU/Multi/MultiFuFileRow.js'] = function(){
	loadFile('light.G/Components/GComponent.js');
/* class */ MultiFuFileRow /* extends GComponent */
= new Class({
    Extends: GComponent,
    fuControl: null,

    initialize: function(options, fuControl){
        this.setModel(new MultiFuFileRowModel());
        this.setOptions(options);
        this.fuControl = fuControl;
    },

    getFuControl: function(){
		return this.fuControl;
    },

    createDefaultView: function(){
        return new MultiFuFileRowView();
    }
});

loadFile('light.G/Model/AbstractModel.js');
/* class */ MultiFuFileRowModel /* extracts AbstractModel */
= new Class({
    Extends: AbstractModel,
    options: {
        currentState: null,
        fileName: null,
        fileSize: null,
        fileType: null,
        progress: null
    }
});

loadFile('light.G/Skin/ComponentView.js');
loadFile('light.G/Components/GButton.js');
loadFile('light.Controls/ProgressBar/CtrlProgressBar.js');
loadFile('light.G/Components/GDomElement.js');
/* class */ MultiFuFileRowView /* extends ComponentView */
= new Class({
    Extends: ComponentView,
    themePath: '/More/MultiFU/FileRow/',

    status: null,
    statusMsg: null,
    progressBar: null,
    deleteBtn: null,
    cancelBtn: null,
    name: null,

    paint: function(){
        GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
        this.paintInside();
        this.paintButtons();
        this.paintState();
        this.saveState();
    },

    repaint: function(){
    	this.paintState();
        this.saveState();
    },

    paintState: function(){
		var c = this.getComponent();
        if (this.compareState('currentState')){
            this.getElement().set('class',
                this.getTheme('main') + ' ' + this.getTheme(c.getOption('currentState'))
            );

            switch(c.getOption('currentState')){
	            case 'begin':
	            	this.onBegin();
	                break;
	            case 'complete':
	            	this.onComplete();
	                break;
	            case 'error':
	            	this.onError();
	                break;
	            case 'cancel':
	            	this.onCancel();
	            	break;
	        }
        }

        if (this.compareState('progress')){
        	if (isset(this.progressBar)) this.progressBar.setProgress(c.getOption('progress'));
        }
    },

    onBegin: function(){
    	// vẽ progressbar
    	this.progressBar = new CtrlProgressBar();
		this.progressBar.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('progress-bar'),
				'position': 'bottom'
			}
		});
		this.progressBar.paint();

        // vẽ nút cancel
        this.cancelButton = new GDomElement(null, new Element('span', {
			'class': this.getTheme('empty-button'),
			'text': 'Cancel'
		}));

		this.cancelButton.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('buttons-wrapper'),
				'position': 'bottom'
			}
		});

		this.cancelButton.addEvent('click', function(){
			this.getComponent().getFuControl().cancel();
		}.bind(this));

		this.cancelButton.paint();

        // hủy nút xóa
        this.deleteButton.destroy();
    },

    onComplete: function(){
    	// hủy progressbar
    	this.progressBar.destroy();
        // hủy nút cancel
        this.cancelButton.destroy();
        // set status
        this.getElementByTheme('status-bar').set('html', 'File upload thành công');
    },

    onError: function(){
		// hủy progressbar
		if (isset(this.progressBar)) this.progressBar.destroy();
        // hủy nút cancel
        if (isset(this.cancelButton)) this.cancelButton.destroy();
        // set status
        this.getElementByTheme('status-bar').set('html', 'Có lỗi trong quá trình upload');
        // xóa nút delete
        if (isset(this.deleteButton)) this.deleteButton.destroy();
    },

    onCancel: function(){
		// hủy progressbar
		this.progressBar.destroy();
        // hủy nút cancel
        this.cancelButton.destroy();
        // set status
        this.getElementByTheme('status-bar').set('html', 'Đã ngừng');
    },

    paintButtons: function(){
		// vẽ button xóa
		this.deleteButton = new GDomElement(null, new Element('span', {
			'class': this.getTheme('delete-button'),
			'text': 'Xóa'
		}));

		this.deleteButton.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('buttons-wrapper'),
				'position': 'bottom'
			}
		});

		this.deleteButton.addEvent('click', function(){
			this.getComponent().getFuControl().remove(
				this.getComponent().getIndex()
			);
		}.bind(this));

		this.deleteButton.paint();
    },

    paintInside: function(){
        var c = this.getComponent();
        if (this.compareState('fileName'))
        	this.getElementByTheme('file-name').set('html', c.getOption('fileName'));

        if (this.compareState('fileSize'))
        	this.getElementByTheme('file-size').set('html', c.getOption('fileSize'));
    },

    createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div',{
        	'class': this.getTheme('main')
        }).grab(
        	new Element('div', {
        		'class': this.getTheme('inner') + ' pkg'
        	}).set('html',
'<div class="' + this.getTheme('file-icon') + ' ' + c.getOption('fileType') + '">' +
'</div>' +
'<div class="' + this.getTheme('main-content') + '">' +
	'<div class="' + this.getTheme('first-row') + '">' +
		'<div class="' + this.getTheme('file-name') + '">' +
		'</div>' +
		'<div class="' + this.getTheme('file-size') + '">' +
		'</div>' +
	'</div>' +
	'<div class="' + this.getTheme('second-row') + '">' +
		'<div class="' + this.getTheme('status-bar') + '">' +
		'</div>' +
		'<div class="' + this.getTheme('progress-bar') + '">' +
		'</div>' +
		'<div class="' + this.getTheme('buttons-wrapper') + '">' +
		'</div>' +
	'</div>' +
'</div>'
        	)
        );
		c.attachWithElement(this.domElement);
    },

    install: function(){
        this.parent();
        this.returnFncs['change'] = this.getComponent().addChangeListener(MultiFuFileRowView.Listener);
    },

    uninstall: function(){
    	this.getComponent().removeChangeListener(this.returnFncs['change']);
        this.parent();
    }
});

/* class */ MultiFuFileRowView.Listener /* implements ChangeListener */
= new Hash({
	stateChanged: function(fileRow, property, value){
		fileRow.repaint();
	}
});
};filesWrapper['light.Controls/FU/Multi/MultiFuFilesList.js'] = function(){
	loadFile('light.G/Components/GComponent.js');

/* class */ MultiFuFilesList /* extends GComponent */
= new Class({
	Extends: GComponent,
	componentItems: new Array(),

    initialize: function(options){
		this.setModel(new MultiFuFilesListModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new MultiFuFilesListView();
	},

    getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	}
});

loadFile('light.G/Model/AbstractModel.js');
/* class */ MultiFuFilesListModel /* extends AbstractModel */
= new Class({
	Extends: AbstractModel
});

loadFile('light.G/Skin/ComponentView.js');
/* class */ MultiFuFilesListView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: '/More/MultiFU/FilesList/',

    paint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
	},

	repaint: function(){
	},

    getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElementByTheme('inner'),
				'position': 'bottom'
			}
		});
	},

	empty: function(){
		this.getElementByTheme('inner').empty();
	},

    createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		}).grab(
			new Element('div', {
				'class': this.getTheme('inner')
			})
		);

		c.attachWithElement(this.domElement);
	}
});
};filesWrapper['light.Controls/FU/Multi/MultiFuView.js'] = function(){
	loadFile('light.Controls/FU/FuView.js');
loadFile('light.Controls/FU/Multi/MultiFuFilesList.js');

/*
Class: MultiFuView
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ MultiFuView /* extends BasicFuView */
= new Class({
	Extends: FuView,
	themePath: '/More/MultiFU/MainCtrl/',
	emptyButton: null,

	bindEvents: function(){
        this.fuConnector.addFuConnectorListener(
            MultiFuView.ConnectorListener,
            this.getComponent()
        );
    },

	setup: function(){
		// tạo nút browse
		this.createBrowseButton();
		this.getComponent().add(this.getBrowseButton());

		// tạo nút upload
		this.uploadButton = new GButton({
            text: 'Tải lên'
        });
        this.getComponent().add(this.uploadButton);

        this.uploadButton.addEvent('click', function(){
			this.fuConnector.upload();
        }.bind(this));

		// tạo file list
		this.filesList = new MultiFuFilesList();
		this.filesList.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('files-list-wrapper'),
				'position': 'bottom'
			}
		});
		this.filesList.paint();

		this.createConnector();
		this.bindEvents();
	},

	getFilesList: function(){
		return this.filesList;
	},

	paint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
		this.setup();
	},

	repaint: function(){
	},

	getInsideContext: function(){
        return new Hash({
            'inject': {
                'target': this.getElementByTheme('buttons-wrapper'),
                'position': 'bottom'
            }
        });
    },

    hasEmptyButton: function(){
		return isset(this.emptyButton);
    },

    createEmptyButton: function(){
		this.emptyButton = new GDomElement(null, new Element('a', {
			'class': this.getTheme('empty-button'),
			'text': 'Xóa sạch sẽ'
		}));
		this.emptyButton.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('empty-button-wrapper'),
				'position': 'bottom'
			}
		});
		this.emptyButton.paint();
		this.emptyButton.addEvent('click', function(){
			this.fuConnector.empty();
		}.bind(this));
    },

    deleteEmptyButton: function(){
		this.emptyButton.destroy();
		this.emptyButton = null;
    },

    createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
            'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
        }).set('html',
'<div class=' + this.getTheme('buttons-wrapper') + '>' +
'</div>'+
'<div class=' + this.getTheme('files-list-wrapper') + '>' +
'</div>'+
'<div class=' + this.getTheme('empty-button-wrapper') + '>' +
'</div>'
        );
        c.attachWithElement(this.domElement);
    }
});

/* static class */ MultiFuView.ConnectorListener /* implements FuConnectorListener */
= new Hash({
	onProgress: function(obj, connector, fu){
		var filesList = fu.getView().getFilesList();
		filesList.getSubComponent(obj.fid).setOption('progress', obj.percent);
    },

    onRemove: function(obj, connector, fu){
    	// xóa file row có id tương ứng
    	var filesList = fu.getView().getFilesList();
    	var fileId = obj.fid;
    	filesList.getSubComponent(fileId).destroy();
    	if (fu.getQueueSize() <= 0) fu.getView().deleteEmptyButton();
    },

	onSelect: function(obj, connector, fu){
		// tạo filerow và add vào filelist với id tương ứng
		var addFiles = obj.afile;
		var filesList = fu.getView().getFilesList();
		addFiles.each(function(fileData){
			loadFile('light.Controls/FU/Multi/MultiFuFileRow.js');
            var fileRow = new MultiFuFileRow({
				fileName: fileData.file.name,
				fileSize: HelpersFactory.getFileHelper().calculateFileSize(fileData.file.size),
                fileType: fileData.file.type.split(".")[1],
				currentState: 'default'
			}, fu);
			filesList.add(fileRow);
			filesList.addSubComponent(fileRow, fileData.id);
			fileRow.setIndex(fileData.id);
		});

		var removeFiles = obj.rfile;
		removeFiles.each(function(fileData){
			filesList.getSubComponent(fileData.id).destroy();
		});

		if (!fu.getView().hasEmptyButton()){
			fu.getView().createEmptyButton();
		}
	},

	onComplete: $empty,
	onFinish: $empty,

	onCdata: function(obj, connector, fu){
		var filesList = fu.getView().getFilesList();
		var fileRow =  filesList.getSubComponent(obj.fid);
        fileRow.setOption( 'currentState', 'complete' );
	},

	onUpload: function(obj, connector, fu){
		// đổi nút xóa thành nút cancel trong file row
		// đổi trạng thái của file row
		var filesList = fu.getView().getFilesList();
		var fileRow =  filesList.getSubComponent(obj.fid);
        fileRow.setOption( 'currentState', 'begin' );
	},

	onHover: $empty,
	onOut: $empty,
	onCancel: $empty,

	onEmpty: function(connector, fu){
		var filesList = fu.getView().getFilesList();
		filesList.empty();
		fu.getView().deleteEmptyButton();
	},

    onBrowse: $empty,

	onError: function(obj, connector, fu){
		var filesList = fu.getView().getFilesList();
		var fileRow =  filesList.getSubComponent(obj.fid);
        fileRow.setOption( 'currentState', 'error' );
	}
});
};filesWrapper['light.Controls/HtmlEditor/CtrlHtmlEditor.js'] = function(){
	loadFile('light.G/Components/GComponent.js');

/*
Class: CtrlHtmlEditor
	HtmlEditor được tạo ra bằng cách sử dụng <GHtmlDocument> và <GTextArea>, một sử dụng để soạn thảo dưới dạng WYSIWYG, một sử dụng để lưu trữ source code HTML. HtmlEditor sử dụng <HtmlEditor.View> kết hợp với một renderer tuân theo interface <HtmlEditor.SubComponentRenderer> để điều khiển việc hiển thị giao diện, trong đó renderer chịu hoàn toàn trách nhiệm việc vẽ các component con để cho vào toolbar của editor.

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<GComponent>
*/
/* class */ CtrlHtmlEditor /* extends GComponent */
= new Class({
	Extends: GComponent,
	textAreaComponent: null,

    initialize: function(options, textAreaComponent){
    	loadFile('light.Controls/HtmlEditor/DefaultModel.js');
		this.setModel(new HtmlEditor.DefaultModel());
		this.setOptions(options);

		if (isset(textAreaComponent))
			this.textAreaComponent = textAreaComponent;

		getClientStorage().set('editor' + this.getOption('id') + 'Inst', this);
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext))
            this.defaultChildGraphicsContext = this.getView().getInsideContext();

    	return this.defaultChildGraphicsContext;
	},

    createDefaultView: function(){
    	loadFile('light.Controls/HtmlEditor/View.js');
    	return new HtmlEditor.View(this.textAreaComponent);
	},

	execute: function(command, value){
		this.getView().getDocument().execute(command, value);
	},

	insertContent: function(content){
		this.getView().getDocument().insertContent(content);
	},

	getSelectedText: function(){
		return this.getView().getDocument().getSelectedText();
	},

	getContent: function(){
		return this.getView().getDocument().getContent();
	},

	getMode: function(){
		return this.getModel().getMode();
	},

	setMode: function(mode){
		this.synchronize();
		this.getModel().setMode(mode);
	},

	toggleMode: function(){
		this.synchronize();
		this.getModel().toggleMode();
	},

	synchronize: function(){
		this.getView().synchronize();
	},

	repaint: function(){
		/* chúng ta nạp chồng vì không muốn sử dụng graphics driver */
		this.getView().repaint();
	},

	getToolbar: function(){
		return this.getView().getToolbar();
	},

	/*
	Function: simpleAction
		Thực thi một hành động đơn giản lên document của editor

	Arguments:
		cpName - (string) Tên lệnh cần thực hiện
	*/
	simpleAction: function(cpName){
        this.grabFocus();
    	this.execute(cpName);
	},

	/*
	Function: changeFontColor
		Thực thi việc đổi màu chữ của đoạn text được select trong editor

	Arguments:
		color - (string) Màu chữ cần đổi
	*/
	changeFontColor: function(color){
		this.grabFocus();
		this.execute('forecolor', color)
	},

	/*
	Function: changeBackColor
		Thực thi việc đổi màu nền chữ của đoạn text được select trong editor

	Arguments:
		color - (string) Màu nền chữ cần đổi
	*/
	changeBackColor: function(color){
		this.grabFocus();
		this.execute('hilitecolor', color);
	},

	setSubComponentsRenderer: function(renderer){
		this.setOption('subComponentsRenderer', renderer);
	},

	getSubComponentsRenderer: function(){
		return this.getOption('subComponentsRenderer');
	}
});
};filesWrapper['light.Controls/HtmlEditor/DefaultModel.js'] = function(){
	loadFile('light.G/Model/AbstractModel.js');
namespace('HtmlEditor');

/*
Class: HtmlEditor.DefaultModel
	Model này chủ yếu dùng để lưu các trạng thái mặc định kế thừa từ AbstractModel và state đặc biệt là mode của HtmlEditor. Mode này sẽ được Editor gửi cho Document

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Options:
	mode - (string) mode của editor, giá trị cho phép là 'textarea' và 'iframe', mặc định là 'iframe'
	subComponents - (string) xâu config các component ở trong toolbar, chỉ được phép là các component đã config ở <BasicHtmlEditorView.SubComponents>
	insertImageUrl - (string) url dùng để gửi <Request.Light.Lad> yêu cầu trả về cửa sổ chèn ảnh,
    cssPath - (string) đường dẫn CSS apply cho document bên trong editor,
	cssClass - (string) tên class của node ngoài cùng trong document của editor,
	styleWithCss - (boolean) style các command bằng CSS
*/
/* class */ HtmlEditor.DefaultModel /* extends AbstractModel */
= new Class({
	Extends: AbstractModel,

	options: {
		mode: 'iframe',
		subComponents: 'fontface|fontsize|bold,italic,strikethrough|fontcolor,backcolor|unlink|alignleft,aligncenter,alignright|removeformat|toggle',
		insertImageUrl: null,
        cssPath: null,
		cssClass: null,
		styleWithCss: true
	},

	getMode: function(){
		return this.getOption('mode');
	},

	setMode: function(mode){
		this.setOption('mode', HelpersFactory.getTypeHelper().getValueWithLimited(mode, ['iframe', 'textarea']));
	},

	toggleMode: function(){
		if (this.getOption('mode') == 'iframe'){
			this.setOption('mode', 'textarea');
		}
		else {
			this.setOption('mode', 'iframe');
		}
	}
});
};filesWrapper['light.Controls/HtmlEditor/DefaultRenderer/ButtonView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicButtonView.js');
namespace('HtmlEditor');

/*
Class: ButtonView
	View thiết kế dành riêng cho button trong <CtrlHtmlEditor>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Extends:
	<BasicButtonView.WithFocus>
*/
/* class */ HtmlEditor.ButtonView /* extends BasicButtonView.WithFocus */
= new Class({
	Extends: BasicButtonView.WithFocus,
	themePath: '/More/Editor/Button/',

	paintBorder: function(){
		this.parent();
		var c = this.getComponent();
		if (!c.isEnabled())
			this.getElement().set('disabled', true);
		else
			this.getElement().set('disabled', false);
	},


	createDomElement: function(){
		var c = this.getComponent();
        this.domElement = new Element('button', {
        	'id': c.getOption('id'),
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss'),
			'type': 'button'
		}).set('html',
'<span class="' + this.getTheme('inside') + '">' + c.getOption('text') +
'</span>' + ''
		);
		//console.log(this.domElement);
		c.attachWithElement(this.domElement);
	}
});
};filesWrapper['light.Controls/HtmlEditor/DefaultRenderer/DefaultRenderer.js'] = function(){
	namespace('HtmlEditor');

/*
Class: HtmlEditor.DefaultRenderer
	Renderer mặc định của editor

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ HtmlEditor.DefaultRenderer /* implements EditorSubComponentsRenderer */
= new Hash({

	simpleComponents: $A(['bold', 'italic', 'underline', 'strikethrough', 'subscript', 'superscript', 'alignleft', 'aligncenter', 'alignright', 'alignjustify', 'listorder', 'listunorder', 'removeformat', 'unlink']),
	components: $A(['fontface','fontsize','image','toggle','fontcolor','backcolor', 'link']),

	textConfig: new Registry({
		bold: { baseCss: 'bold', text: 'Đậm', tooltip: 'Ctrl+B' },
		italic: { baseCss: 'italic', text: 'Nghiêng', tooltip: 'Ctrl+I' },
		underline: { baseCss: 'underline', text: 'Gạch dưới', tooltip: 'Ctrl+U' },
		strikethrough: { baseCss: 'strike', text: 'Gạch ngang chữ' },
		link: { baseCss: 'link', text: 'Thêm liên kết' },
		unlink: { baseCss: 'unlink', text: 'Bỏ liên kết' },
		image: { baseCss: 'image', text: 'Chèn ảnh' },
		alignleft: { baseCss: 'align-left', text: 'Căn lề trái' },
		aligncenter: { baseCss: 'align-center', text: 'Căn lề giữa' },
		alignright: { baseCss: 'align-right', text: 'Căn lề phải' },
		alignjustify: { baseCss: 'align-justify', text: 'Căn lề đều' },
		listorder: { baseCss: 'list-order', text: 'Đánh số' },
		listunorder: { baseCss: 'list-unorder', text: 'Đánh chỉ mục' },
		removeformat: { baseCss: 'unformat', text: 'Xóa style' },
		toggle: { baseCss: 'toggle', text: 'Bật/Tắt HTML' }
	}),

	createComponent: function(cpName, editor, toolbar, group){
		if (inArray(cpName, this.simpleComponents))
			return this.createSimpleButton(cpName, editor, toolbar, group);

		if (inArray(cpName, this.components))
			return this[cpName].run([cpName, editor, toolbar, group], this);
	},

	/*
	Function: createSimpleEditorButton
		Tạo một nút đơn giản cho editor

	Arguments:
		cpName - (string) tên key của button cần tạo

	Returns:
		- <GButton> sử dụng view <BasicEditorButtonView>
	*/
	createSimpleButton: function(cpName, editor, toolbar, group){
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/ButtonView.js');
		var ourCp = new GButton({
			themePath: '/More/Editor/Button/',
			baseCss: this.textConfig.get('/' + cpName + '/baseCss/'),
	        text: this.textConfig.get('/' + cpName + '/text/'),
	        tooltip: this.textConfig.get('/' + cpName + '/tooltip/')
		});
		ourCp.setView(new HtmlEditor.ButtonView());
		this.matchWithToolbar(ourCp, cpName, toolbar, group);

		loadFile('light.Controls/HtmlEditor/DefaultRenderer/Listeners.js');
		ourCp.addMouseListener(HtmlEditor.DefaultRenderer.SimpleButtonListener, editor);
		return ourCp;
	},

	afterDocCreated: function(editor){
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/Listeners.js');
		editor.getView().returnFncs['docKeyboard']
			= editor.getView().getDocument().addKeyboardListener(HtmlEditor.DefaultRenderer.ShortcutsListener, editor);
	},

	beforeComponentDestroyed: function(editor){
		editor.getView().getDocument().removeKeyboardListener(editor.getView().returnFncs['docKeyboard']);
	},

	matchWithToolbar: function(ourCp, cpName, toolbar, group){
		if (isset(group))
			group.add(ourCp);
		else toolbar.add(ourCp);
		toolbar.addSubComponent(ourCp, cpName);
		ourCp.setIndex(cpName); // lưu index cho component để toolbar track lại sau này
	},

	link: function(cpName, editor, toolbar, group){
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/ButtonView.js');
		var ourCp = new GButton({
			themePath: '/More/Editor/Button/',
			baseCss: this.textConfig.get('/' + cpName + '/baseCss/'),
	        text: this.textConfig.get('/' + cpName + '/text/'),
	        tooltip: this.textConfig.get('/' + cpName + '/tooltip/')
		});
		ourCp.setView(new HtmlEditor.ButtonView());
		this.matchWithToolbar(ourCp, cpName, toolbar, group);

		loadFile('light.Controls/HtmlEditor/DefaultRenderer/Listeners.js');
		ourCp.addMouseListener(HtmlEditor.DefaultRenderer.LinkButtonListener, editor);
		return ourCp;
	},

	image: function(cpName, editor, toolbar, group){
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/ButtonView.js');
		var ourCp = new GButton({
			themePath: '/More/Editor/Button/',
			baseCss: this.textConfig.get('/' + cpName + '/baseCss/'),
	        text: this.textConfig.get('/' + cpName + '/text/'),
	        tooltip: this.textConfig.get('/' + cpName + '/tooltip/')
		});
		ourCp.setView(new HtmlEditor.ButtonView());
		this.matchWithToolbar(ourCp, cpName, toolbar, group);
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/Listeners.js');
		ourCp.addMouseListener(HtmlEditor.DefaultRenderer.ImageButtonListener, editor);
		return ourCp;
	},

	toggle: function(cpName, editor, toolbar, group){
		var ourCp = new GButton({
        	themePath: '/More/Editor/Button/',
			baseCss: this.textConfig.get('/' + cpName + '/baseCss/'),
        	text: this.textConfig.get('/' + cpName + '/text/'),
			tooltip: this.textConfig.get('/' + cpName + '/tooltip/')
		});
		ourCp.setView(new HtmlEditor.ButtonView());
		this.matchWithToolbar(ourCp, cpName, toolbar, group);
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/Listeners.js');
        ourCp.addMouseListener(HtmlEditor.DefaultRenderer.ToggleButtonListener, editor);
		return ourCp;
	},

	fontcolor: function(cpName, editor, toolbar, group){
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/SubComponents/FontColorPicker.js');
        var ourCp = new HtmlEditor.FontColorPicker({
        	baseCss: 'fontcolor'
        });
        this.matchWithToolbar(ourCp, cpName, toolbar, group);
		ourCp.addColorChangeListener(HtmlEditor.DefaultRenderer.FontColorButtonListener, editor);
        ourCp.getView().getMainButton().addMouseListener(HtmlEditor.DefaultRenderer.FontColorButtonListener, editor);
		return ourCp;
	},

	backcolor: function(cpName, editor, toolbar, group){
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/SubComponents/BackColorPicker.js');
        var ourCp = new HtmlEditor.BackColorPicker({
        	baseCss: 'backcolor'
        });
        this.matchWithToolbar(ourCp, cpName, toolbar, group);
		ourCp.addColorChangeListener(HtmlEditor.DefaultRenderer.BackColorButtonListener, editor);
        ourCp.getView().getMainButton().addMouseListener(HtmlEditor.DefaultRenderer.BackColorButtonListener, editor);
		return ourCp;
	},

	fontface: function(cpName, editor, toolbar, group){
		loadFile('light.G/Components/GList.js');
		var fontsList = $A(['Arial','Tahoma']);
		var simpleList = new GList({
			baseCss: 'editor-ff-list'
		}, fontsList, 0, 'single');
		loadFile('light.G/Components/GComboBox.js');
		var ourCp = new GComboBox({
			baseCss: 'editor-ff-combo',
			width: 60
		}, simpleList);
		this.matchWithToolbar(ourCp, cpName, toolbar, group);
		simpleList.addListSelectionListener(HtmlEditor.DefaultRenderer.FontFamilyListListener, editor);
		return ourCp;
	},

	fontsize: function(cpName, editor, toolbar, group){
		loadFile('light.G/Components/GList.js');
		var fontsList = $A(['1','2','3','4','5']);
		var simpleList = new GList({
			baseCss: 'editor-fs-list'
		}, fontsList, 0, 'single');
		loadFile('light.G/Components/GComboBox.js');
		var ourCp = new GComboBox({
			baseCss: 'editor-fs-combo'
		}, simpleList);
		this.matchWithToolbar(ourCp, cpName, toolbar, group);
		simpleList.addListSelectionListener(HtmlEditor.DefaultRenderer.FontSizeListListener, editor);
		return ourCp;
	}
});

/* static class */ HtmlEditor.DefaultRenderer.ToggleButtonListener /* implements MouseListener */
= new Hash({
    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
    	editor.toggleMode();
	},

    doubleClick: $empty
});

/* static class */ HtmlEditor.DefaultRenderer.FontColorButtonListener /* implements ColorChangeListener, MouseListener */
= new Hash({
    colorChanged: function(button, color, editor){
    	editor.changeFontColor(color);
	},

    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
    	editor.changeFontColor(button.getColor());
	},

    doubleClick: $empty
});

/* static class */ HtmlEditor.DefaultRenderer.BackColorButtonListener /* implements ColorChangeListener, MouseListener */
= new Hash({
    colorChanged: function(button, color, editor){
    	editor.changeBackColor(color);
	},

    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
    	editor.changeBackColor(button.getColor());
	},

    doubleClick: $empty
});

HtmlEditor.DefaultRenderer.FontFamilyListListener /* */
= new Hash({
	valueChanged: function(e, list, editor){
		var value = list.getDataElementAt(list.getLastSelectionIndex());
		editor.execute('fontname', value);
	}
});

HtmlEditor.DefaultRenderer.FontSizeListListener
= new Hash ({
	valueChanged: function(e, list, editor){
		var text = editor.getSelectedText();
        var value = list.getDataElementAt(list.getLastSelectionIndex());
        editor.insertContent('<span style="font-size:'+(value*2+6)+'pt;">'+text+'</span>');
	}
});
};filesWrapper['light.Controls/HtmlEditor/DefaultRenderer/FloatColorButton.js'] = function(){
	namespace('HtmlEditor');

loadFile('light.Controls/ColorChooser/CompColorBlock.js');
/* class */ HtmlEditor.FloatColorButton /* extends CompColorBlock */
= new Class({
	Extends: CompColorBlock,
    createDefaultView: function(){
    	return new HtmlEditor.FloatColorButton.View();
	}
});

/* class */ HtmlEditor.FloatColorButton.View /* extends CompColorBlock.View */
= new Class({
	Extends: CompColorBlock.View,
	themePath: '/More/Editor/FloatColorButton/',

	paintInside: function(){
    	var c = this.getComponent();
		this.getElementByTheme('float-color').set('styles', {
			'background-color': c.getColor()
		});
	},

	paintBorder: function(){
		this.parent();
		var c = this.getComponent();
		if (!c.isEnabled())
			this.getElement().set('disabled', true);
		else
			this.getElement().set('disabled', false);
	},

	createDomElement: function(){
		var c = this.getComponent();
        this.domElement = new Element('button', {
        	'id': c.getOption('id'),
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss'),
			'type': 'button'
		}).set('html',
'<div class="' + this.getTheme('inside') + '">' +
	'<div class="' + this.getTheme('float-space') + '">' +
	'</div>' +
	'<div class="' + this.getTheme('float-color') + '">' +
	'</div>' +
'</div>' + ''
		);
		c.attachWithElement(this.domElement);
	},

	install: function(){
		this.returnFncs['floatButtonColorChange'] = this.getComponent().addColorChangeListener(HtmlEditor.FloatColorButton.Listener);
		this.parent();
	},

	uninstall: function(){
		this.getComponent().removeColorChangeListener(this.returnFncs['floatButtonColorChange']);
		this.parent();
	}
});

/* static class */ HtmlEditor.FloatColorButton.Listener /* implements ColorChangeListener */
= new Hash({
	colorChanged: function(floatColorButton, color){
		floatColorButton.repaint();
	}
});
};filesWrapper['light.Controls/HtmlEditor/DefaultRenderer/Listeners.js'] = function(){
	namespace('HtmlEditor.DefaultRenderer');

/* static class */ HtmlEditor.DefaultRenderer.Shortcuts /* */
= new Hash({
	'b': 'bold',
	'i': 'italic',
	'u': 'underline'
});

/* static class */ HtmlEditor.DefaultRenderer.ShortcutsListener /* implements KeyBoardListener */
= new Hash({
    keyPress: function(e, document, editor){
        if (e.control){
        	// shortcut
        	var buttonName = HtmlEditor.DefaultRenderer.Shortcuts[e.key];
        	if (isset(buttonName)){
				e.stop();
				var button = editor.getView().getToolbar().getSubComponent(buttonName);
				button.getElement().fireEvent('click');
			}
		}
	},

	keyUp: $empty,
    keyDown: $empty
});

HtmlEditor.SimpleActionsMap = new Hash({
    'alignleft': 		'justifyleft',
    'alignright': 		'justifyright',
    'aligncenter': 		'justifycenter',
    'alignjustify': 	'justifyfull',
    'listorder': 		'insertorderedlist',
    'listunorder': 		'insertunorderedlist'
});

/* static class */ HtmlEditor.DefaultRenderer.SimpleButtonListener /* implements MouseListener */
= new Hash({
    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
        var buttonName = button.getIndex();
        var simpleActionName = !inArray(buttonName, $A(HtmlEditor.SimpleActionsMap.getKeys())) ? buttonName : HtmlEditor.SimpleActionsMap.get(buttonName);
    	editor.simpleAction(simpleActionName);
	},

    doubleClick: $empty
});

HtmlEditor.DefaultRenderer.LinkButtonListener
= new Hash({
	mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
    	loadFile('light.G/Components/GWindow.js');
		var insertLinkWnd = new GWindow({
			width: 350,
			height: 175,
			/*left: GFactory.getPaint().getMiddleLeft(350),
			top: GFactory.getPaint().getMiddleTop(175),*/
			text: 'Chèn liên kết',
			draggable: false,
			useIframeBackground: false,
			stayOnTop: true
		});

        insertLinkWnd.setLaunchedElement(button.getElement());
        insertLinkWnd.paint();

        var formEl = new Element('div', {
            'class': 'link-wnd-content win-content-pad'
        }).set('html',
'<div class="simple-link-form">' +
    '<div class="ipt-row pkg">' +
        '<div class="label"><label class="first">' +
            'Đường dẫn liên kết' +
        '</label></div>' +
        '<div class="txtfld">' +
            '<input type="text" name="url" value="http://acc.vn"/>' +
        '</div>' +
    '</div>' +
    '<div class="ipt-row pkg">' +
        '<div class="label"><label>' +
            'Chữ' +
        '</label></div>' +
        '<div class="txtfld">' +
            '<input type="text" name="text" value="' + editor.getSelectedText() + '"/>' +
        '</div>' +
    '</div>' +
    '<div class="the-submit-row pkg">' +
        '<button type="button" class="submitBtn" name="insertBtn">Chèn</button>' +
        '<button type="button" class="cancelBtn" name="cancelBtn">Hủy bỏ</button>' +
    '</div>' +
'</div>'
        );

        loadFile('light.G/Components/GDomElement.js');
        insertLinkWnd.add(new GDomElement(null, formEl));
        insertLinkWnd.grabFocus();

        formEl.getElements('.the-submit-row button').each(function(buttonEl){
            if (buttonEl.get('name') == 'insertBtn'){
                buttonEl.addEvent('click', function(){
                    editor.grabFocus();
                    var url = formEl.getElement('input[name=url]').get('value');
                    var text = formEl.getElement('input[name=text]').get('value');
                    editor.insertContent("<a href='" + url + "'>" + text + "</a>");
                    insertLinkWnd.destroy();
                });
            }

            if (buttonEl.get('name') == 'cancelBtn'){
                buttonEl.addEvent('click', function(){
                    insertLinkWnd.destroy();
                });
            }
        });
	},

    doubleClick: $empty
});

HtmlEditor.DefaultRenderer.ImageButtonListener
= new Hash({
	mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
    	loadFile('light.G/Components/GWindow.js');
		var insertImageWnd = new GWindow({
			width: 350,
			height: 175,
			/*left: GFactory.getPaint().getMiddleLeft(350),
			top: GFactory.getPaint().getMiddleTop(175),*/
			text: 'Chèn ảnh',
			draggable: false,
			useIframeBackground: false,
			stayOnTop: true
		});

        insertImageWnd.setLaunchedElement(button.getElement());
        insertImageWnd.paint();

        var formEl = new Element('div', {
            'class': 'link-wnd-content win-content-pad'
        }).set('html',
'<div class="simple-link-form">' +
    '<div class="ipt-row pkg">' +
        '<div class="label"><label class="first">' +
            'Đường dẫn đến ảnh' +
        '</label></div>' +
        '<div class="txtfld">' +
            '<input type="text" name="imageurl" value=""/>' +
        '</div>' +
    '</div>' +
    '<div class="the-submit-row pkg">' +
        '<button type="button" class="submitBtn" name="insertBtn">Chèn</button>' +
        '<button type="button" class="cancelBtn" name="cancelBtn">Hủy bỏ</button>' +
    '</div>' +
'</div>'
        );

        loadFile('light.G/Components/GDomElement.js');
        insertImageWnd.add(new GDomElement(null, formEl));
        insertImageWnd.grabFocus();

        formEl.getElements('.the-submit-row button').each(function(buttonEl){
            if (buttonEl.get('name') == 'insertBtn'){
                buttonEl.addEvent('click', function(){
                    editor.grabFocus();
                    var imageUrl = formEl.getElement('input[name=imageurl]').get('value');
                    editor.insertContent("<img src='" + imageUrl + "'/>");
                    insertImageWnd.destroy();
                });
            }

            if (buttonEl.get('name') == 'cancelBtn'){
                buttonEl.addEvent('click', function(){
                    insertImageWnd.destroy();
                });
            }
        });
	},

    doubleClick: $empty
});
};filesWrapper['light.Controls/HtmlEditor/DefaultRenderer/SubComponents/BackColorPicker.js'] = function(){
	loadFile('light.Controls/ColorChooser/CompColorPickerFromBoard.js');
namespace('HtmlEditor');

/*
Class: HtmlEditor.BackColorPicker
	Thừa kế từ <CompColorPickerFromBoard>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ HtmlEditor.BackColorPicker /* extends CompColorPickerFromBoard */
= new Class({
	Extends: CompColorPickerFromBoard,

	initialize: function(options){
		this.setModel(new HtmlEditor.BackColorPicker.Model());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new HtmlEditor.BackColorPicker.View();
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext))
            this.defaultChildGraphicsContext = this.getView().getInsideContext();

    	return this.defaultChildGraphicsContext;
	}
});

/* class */ HtmlEditor.BackColorPicker.Model /* extends CompColorPickerFromBoard.Model */
= new Class({
	Extends: CompColorPickerFromBoard.Model,
	options: {
		boardColors: {
			baseColor: ['ffff00', '00ff00', '00ffff', 'ff00ff', '0000ff', 'ff0000', '000080', '008080', '008000', '800080', '800000', '808000', '808080', 'c0c0c0', '000000']
		},
		boardCss: {
			baseColor: 'base-colors'
		},
		boardContext: {
			baseColor: 'inside'
		}
	}
});

/* class */ HtmlEditor.BackColorPicker.View /* extends CompColorPickerFromBoard.View */
= new Class({
	Extends: CompColorPickerFromBoard.View,
	themePath: '/More/Editor/BackColorPicker/',

	paintMainButton: function(){
		var c = this.getComponent();
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/FloatColorButton.js');
		this.button = new HtmlEditor.FloatColorButton({
			baseCss: this.getTheme('main-btn')
		}, '#000000');
		c.add(this.button);
	},

	paintArrowButton: function(){
		var c = this.getComponent();
		loadFile('light.G/Components/GButton.js');
		this.arrowButton = new GButton({
			baseCss: this.getTheme('arrow-btn')
		});
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/ButtonView.js');
		this.arrowButton.setView(new HtmlEditor.ButtonView());
		c.add(this.arrowButton);
	}
});
};filesWrapper['light.Controls/HtmlEditor/DefaultRenderer/SubComponents/FontColorPicker.js'] = function(){
	loadFile('light.Controls/ColorChooser/CompColorPickerFromBoard.js');
namespace('HtmlEditor');

/*
Class: HtmlEditor.FontColorPicker
	Thừa kế từ <CompColorPickerFromBoard>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ HtmlEditor.FontColorPicker /* extends CompColorPickerFromBoard */
= new Class({
	Extends: CompColorPickerFromBoard,

	initialize: function(options){
		this.setModel(new HtmlEditor.FontColorPicker.Model());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new HtmlEditor.FontColorPicker.View();
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext))
            this.defaultChildGraphicsContext = this.getView().getInsideContext();

    	return this.defaultChildGraphicsContext;
	}
});

/* class */ HtmlEditor.FontColorPicker.Model /* extends CompColorPickerFromBoard.Model */
= new Class({
	Extends: CompColorPickerFromBoard.Model,
	options: {
		boardColors: {
			baseColor: ['ffffff', '000000', 'eeece1', '1f497d', '4f81bd', 'c0504d', '9bbb59', '8064a2', '4bacc6', 'f79646'],
			firstRow: 	['f2f2f2', '7f7f7f', 'ddd9c3', 'c6d9f0', 'dbe5f1', 'f2dcdb', 'ebf1dd', 'e5e0ec', 'dbeef3', 'fdeada'],
			secondRow: 	['d8d8d8', '595959', 'c4bd97', '8db3e2', 'b8cce4', 'e5b9b7', 'd7e3bc', 'ccc1d9', 'b7dde8', 'fbd5b5'],
			thirdRow: 	['bfbfbf', '3f3f3f', '938953', '548dd4', '95b3d7', 'd99694', 'c3d69b', 'b2a2c7', '92cddc', 'fac08f'],
			fourthRow: 	['a5a5a5', '262626', '494429', '17365d', '366092', '953734', '76923c', '5f497a', '31859b', 'e36c09'],
			fifthRow: 	['7f7f7f', '0c0c0c', '1d1b10', '0f243e', '244061', '632423', '4f6128', '3f3151', '205867', '974806'],
			standardColors:	['c00000', 'ff0000', 'ffc000', 'ffff00', '92d050', '00b050', '00b0f0', '0070c0', '002060', '7030a0']
		},
		boardCss: {
			baseColor: 'base-colors',
			firstRow: 'first-row',
			secondRow: 'second-row',
			thirdRow: 'third-row',
			fourthRow: 'fourth-row',
			fifthRow: 'fifth-row',
			standardColors: 'standard-colors'
		},
		boardContext: {
			baseColor: 'theme-color-content-main',
			firstRow: 'theme-color-content-sub',
			secondRow: 'theme-color-content-sub',
			thirdRow: 'theme-color-content-sub',
			fourthRow: 'theme-color-content-sub',
			fifthRow: 'theme-color-content-sub',
			standardColors: 'standard-color-content'
		}
	}
});

/* class */ HtmlEditor.FontColorPicker.View /* extends CompColorPickerFromBoard.View */
= new Class({
	Extends: CompColorPickerFromBoard.View,
	themePath: '/More/Editor/FontColorPicker/',

	paintMainButton: function(){
		var c = this.getComponent();
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/FloatColorButton.js');
		this.button = new HtmlEditor.FloatColorButton({
			baseCss: this.getTheme('main-btn')
		}, '#000000');
		c.add(this.button);
	},

	paintArrowButton: function(){
		var c = this.getComponent();
		loadFile('light.G/Components/GButton.js');
		this.arrowButton = new GButton({
			baseCss: this.getTheme('arrow-btn')
		});
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/ButtonView.js');
		this.arrowButton.setView(new HtmlEditor.ButtonView());
		c.add(this.arrowButton);
	},

	paintColorBoard: function(){
		var c = this.getComponent();
		loadFile('light.Controls/ColorChooser/CompColorBoard.js');
		this.colorBoard = new CompColorBoard({
			colors: c.getOption('boardColors'),
			css: c.getOption('boardCss'),
			context: c.getOption('boardContext')
    	});
		this.colorBoard.setView(new HtmlEditor.FontColorPicker.ColorBoardView());
	}
});

loadFile('light.Controls/ColorChooser/CompColorBoard.js');
/* class */ HtmlEditor.FontColorPicker.ColorBoardView /* extends CompColorBoard.View */
= new Class({
	Extends: CompColorBoard.View,
	themePath: '/More/Editor/FontColorPickerBoard/',

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
			'class': this.getTheme('main')
		}).grab(
			new Element('div', {
				'class': this.getTheme('inner')
			}).grab(
				new Element('div', {
					'class': this.getTheme('theme-color-content-main') + ' pkg'
				})
			).grab(
				new Element('div', {
					'class': this.getTheme('theme-color-content-sub') + ' pkg'
				})
			).grab(
				new Element('div', {
					'class': this.getTheme('standard-color-content') + ' pkg'
				})
			)
		);

		c.attachWithElement(this.domElement);
	}
});
};filesWrapper['light.Controls/HtmlEditor/DefaultRenderer/SubComponents/_BackColorPicker.js'] = function(){
	loadFile('light.G/Components/AbstractColorPicker.js');
/* class */ BackColorPicker /* extends AbstractColorPicker */
= new Class({
	Extends: AbstractColorPicker,

    initialize: function(options){
		this.setModel(new BackColorPicker.Model('#ffffff'));
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new BackColorPicker.BasicView();
	},

    isPopupVisible: function(){
    	return this.getModel().isPopupVisible();
    },

    setPopupVisible: function(aFlag){
    	this.getModel().setPopupVisible(aFlag);
    }
});

loadFile('light.G/Model/DefaultColorPickerModel.js');

/* class */ BackColorPicker.Model /* extends DefaultColorPickerModel */
= new Class({
	Extends: DefaultColorPickerModel,
    options: {
	    popupVisible: false
	},

    isPopupVisible: function(){
    	return this.getOption('popupVisible');
    },

    setPopupVisible: function(aFlag){
    	this.setOption('popupVisible', aFlag);
    }
});

loadFile('light.G/Skin/Basic/BasicButtonView.js');
loadFile('light.G/Components/GPopupMenu.js');
loadFile('light.G/Components/GButton.js');
loadFile('light.Controls/HtmlEditor/SubComponents/FontColorPicker.js');
loadFile('light.Controls/HtmlEditor/BasicEditorButtonView.js');
/* class */ BackColorPicker.BasicView /* extends BasicEditorButtonView */
= new Class({
	Extends: BasicEditorButtonView,
	popup: null,
	colorBoard: null,
	arrowButton: null,

	themePath: '/Default/ColorPickerButton/',

	paint: function(){
		this.parent();

		var c = this.getComponent();
		this.popup = new GPopupMenu();
    	this.popup.setParentComponent(c);
    	this.popup.setGraphicsContext({
    		'inject': {
    			'target': document.body,
    			'position': 'bottom'
    		},
    		'stackpos': {
    			'target': this.getElement(),
    			'pop': 'bottom',
    			'align': 'left'
    		}
    	});
    	this.popup.paint();

    	this.colorBoard = new BackColorPicker.ColorBoard();
    	this.popup.add(this.colorBoard);
    	this.colorBoard.addColorChangeListener(BackColorPicker.ColorBoard.Listener, c);

        this.arrowButton = new GButton({
        	baseCss: 'backcolor-arrow'
        });
        this.arrowButton.setView(new BasicEditorButtonView());
        this.arrowButton.setGraphicsContext({
    		'inject': {
    			'target': c.getElement(),
    			'position': 'after'
    		}
    	});
    	this.arrowButton.paint();
        this.arrowButton.addChangeListener(BackColorPicker.ArrowButtonListener, c);
	},

	repaint: function(){
		this.parent();
		var c = this.getComponent();
        this.popup.setVisible(c.isPopupVisible());
	},

	paintInside: function(){
		this.parent();
		var c = this.getComponent();
		this.getElementByTheme('float-color').set('styles', {
			'background-color': c.getColor()
		});
	},

	createDomElement: function(){
        this.parent();
    	this.getElementByTheme('inside').grab(
			new Element('div', {
				'class': this.getTheme('float-color')
			})
		);
	},

	install: function(){
		this.parent();
		var c = this.getComponent();
		this.returnFncs['colorChange'] = c.addColorChangeListener(FontColorPicker.BasicView.Listener);
	},

	uninstall: function(){
		var c = this.getComponent();
		c.removeColorChangeListener(this.returnFncs['colorChange']);
		this.parent();
	}
});

/* class */ BackColorPicker.ArrowButtonListener /* implements ChangeListener */
= new Hash({
    stateChanged: function(button, property, value, colorPickerButton){
		if (property == 'pressed'){
			if (value == true){
				/* khi mà button được ấn thì mới show, không làm gì khi nhả ra */
    			colorPickerButton.setPopupVisible(!colorPickerButton.isPopupVisible());
			}
		}
		else if (property == 'focus'){
			if (value == false){
				/* khi lost focus mà thôi */
				colorPickerButton.setPopupVisible(false);
			}
		}
	}
});

/* class */ BackColorPicker.BasicView.Listener /* implements ColorChangeListener */
= new Hash({
    colorChanged: function(button, color, rootComponent){
    	button.repaint();
	}
});

loadFile('light.G/Components/AbstractColorPicker.js');
/* class */ BackColorPicker.ColorBoard /* extends GComponent */
= new Class({
	Extends: AbstractColorPicker,

    initialize: function(options){
    	loadFile('light.G/Model/DefaultColorPickerModel.js');
		this.setModel(new DefaultColorPickerModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new BackColorPicker.ColorBoardView();
	},

    getDefaultChildGraphicsContext: function(){
    	if (this.defaultChildGraphicsContext == null){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	}
});

loadFile('light.G/Skin/ComponentView.js');
loadFile('light.G/Components/GColorBlock.js');
loadFile('light.Controls/HtmlEditor/BasicEditorColorBlockView.js');

/* class */ BackColorPicker.ColorBoardView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: 	'/Default/BackColorBoard/',
	baseColors: [
		'ffff00', '00ff00', '00ffff', 'ff00ff', '0000ff',
		'ff0000', '000080', '008080', '008000', '800080',
		'800000', '808000', '808080', 'c0c0c0', '000000'
	],

    getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement('.' + this.getTheme('inside')),
				'position': 'bottom'
			}
		});
	},

    paint: function(){
    	var c = this.getComponent();
    	GFactory.getPaint().draw(this.getElement(), c.getGraphicsContext());
    	this.paintChildren();
	},

	paintChildren: function(){
		var c = this.getComponent();
        this.baseColors.each(function(color){
    		var colorBlock = new GColorBlock(null, '#' + color);
    		colorBlock.setView(new BasicEditorColorBlockView());
    		c.add(colorBlock);
    		colorBlock.addMouseListener(BackColorPicker.ColorBlockListener, c);
    	});
	},

	repaint: function(){
		GFactory.getPaint().draw(this.getElement(), c.getGraphicsContext(), null, ['inject']);
	},

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
			'class': this.getTheme('main')
		}).grab(
			new Element('div', {
				'class': this.getTheme('inner')
			}).grab(
				new Element('div', {
					'class': this.getTheme('inside') + ' pkg'
				})
			)
		);

		c.attachWithElement(this.domElement);
	},

	install: function(){
		this.createDomElement();
	},

    uninstall: function(){
		this.destroyDomElement();
	}
});

/* static class */ BackColorPicker.ColorBlockListener /* implements MouseListener */
= new Hash({
    mouseDown: $empty,

	mouseUp: $empty,

    singleClick: function(e, colorBlock, colorBoard){
    	colorBoard.setColor(colorBlock.getColor());
	},

    doubleClick: $empty
});

/* static class */ BackColorPicker.ColorBoard.Listener /* implements ColorChangeListener */
= new Hash({
    colorChanged: function(colorBoard, color, colorPickerButton){
    	colorPickerButton.setColor(colorBoard.getColor());
    	colorPickerButton.setPopupVisible(false);
	}
});
};filesWrapper['light.Controls/HtmlEditor/DefaultRenderer/SubComponents/_FontColorPicker.js'] = function(){
	loadFile('light.G/Components/AbstractColorPicker.js');
/* class */ FontColorPicker /* extends AbstractColorPicker */
= new Class({
	Extends: AbstractColorPicker,

    initialize: function(options){
		this.setModel(new FontColorPicker.Model('#000000'));
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new FontColorPicker.BasicView();
	},

    isPopupVisible: function(){
    	return this.getModel().isPopupVisible();
    },

    setPopupVisible: function(aFlag){
    	this.getModel().setPopupVisible(aFlag);
    }
});

loadFile('light.G/Model/DefaultColorPickerModel.js');
/* class */ FontColorPicker.Model /* extends DefaultColorPickerModel */
= new Class({
	Extends: DefaultColorPickerModel,
    options: {
	    popupVisible: false
	},

    isPopupVisible: function(){
    	return this.getOption('popupVisible');
    },

    setPopupVisible: function(aFlag){
    	this.setOption('popupVisible', aFlag);
    }
});

loadFile('light.G/Skin/Basic/BasicButtonView.js');
loadFile('light.G/Components/GPopupMenu.js');
loadFile('light.G/Components/GButton.js');
loadFile('light.Controls/HtmlEditor/BasicEditorButtonView.js');
/* class */ FontColorPicker.BasicView /* extends BasicEditorButtonView */
= new Class({
	Extends: BasicEditorButtonView,
	popup: null,
	colorBoard: null,
	arrowButton: null,

	themePath: '/Default/ColorPickerButton/',

	paint: function(){
		this.parent();

		var c = this.getComponent();
		this.popup = new GPopupMenu();
    	this.popup.setParentComponent(c);
    	this.popup.setGraphicsContext({
    		'inject': {
    			'target': document.body,
    			'position': 'bottom'
    		},
    		'stackpos': {
    			'target': this.getElement(),
    			'pop': 'bottom',
    			'align': 'left'
    		}
    	});
    	this.popup.paint();

    	this.colorBoard = new FontColorPicker.ColorBoard();
    	this.popup.add(this.colorBoard);
    	this.colorBoard.addColorChangeListener(FontColorPicker.ColorBoard.Listener, c);

        this.arrowButton = new GButton({
        	baseCss: 'fontcolor-arrow'
        });
        this.arrowButton.setView(new BasicEditorButtonView());
        this.arrowButton.setGraphicsContext({
    		'inject': {
    			'target': c.getElement(),
    			'position': 'after'
    		}
    	});
    	this.arrowButton.paint();
        this.arrowButton.addChangeListener(FontColorPicker.ArrowButtonListener, c);
	},

	repaint: function(){
		this.parent();
		var c = this.getComponent();
        this.popup.setVisible(c.isPopupVisible());
	},

	paintInside: function(){
		this.parent();
		var c = this.getComponent();
		this.getElement('.' + this.getTheme('float-color')).set('styles', {
			'background-color': c.getColor()
		});
	},

	createDomElement: function(){
        this.parent();
    	this.getElement('.' + this.getTheme('inside')).grab(
			new Element('div', {
				'class': this.getTheme('float-color')
			})
		);
	},

	install: function(){
		this.parent();
		var c = this.getComponent();
		this.returnFncs['colorChange'] = c.addColorChangeListener(FontColorPicker.BasicView.Listener);
	},

	uninstall: function(){
		var c = this.getComponent();
		c.removeColorChangeListener(this.returnFncs['colorChange']);
		this.parent();
	}
});


/*
Class: FontColorPicker.ArrowButtonListener
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
/* class */ FontColorPicker.ArrowButtonListener /* implements ChangeListener */
= new Hash({
    stateChanged: function(button, property, value, colorPickerButton){
		if (property == 'pressed'){
			if (value == true){
				/* khi mà button được ấn thì mới show, không làm gì khi nhả ra */
    			colorPickerButton.setPopupVisible(!colorPickerButton.isPopupVisible());
			}
		}
		else if (property == 'focus'){
			if (value == false){
				/* khi lost focus mà thôi */
				colorPickerButton.setPopupVisible(false);
			}
		}
	}
});

/*
Class: FontColorPicker.BasicView.Listener
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
/* class */ FontColorPicker.BasicView.Listener /* implements ColorChangeListener */
= new Hash({
    colorChanged: function(button, color, rootComponent){
    	button.repaint();
	}
});

/*
Class: FontColorPicker.ColorBoard
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Components/AbstractColorPicker.js');
/* class */ FontColorPicker.ColorBoard /* extends AbstractColorPicker */
= new Class({
	Extends: AbstractColorPicker,

    initialize: function(options){
    	loadFile('light.G/Model/DefaultColorPickerModel.js');
		this.setModel(new DefaultColorPickerModel());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new FontColorPicker.ColorBoardView();
	},

    addMoreColorsInside: function(childComponent){
		childComponent.setParentComponent(this);
		childComponent.setGraphicsContext(
			this.getView().getMoreColorsInsideContext()
		);
		childComponent.paint();
	},

    addThemeColorContent: function(childComponent){
		childComponent.setParentComponent(this);
		childComponent.setGraphicsContext(
			this.getView().getThemeColorContentContext()
		);
		childComponent.paint();
	},

    addThemeColorContentSub: function(childComponent){
		childComponent.setParentComponent(this);
		childComponent.setGraphicsContext(
			this.getView().getThemeColorContentSubContext()
		);
		childComponent.paint();
	},

    addStandardColorContent: function(childComponent){
		childComponent.setParentComponent(this);
		childComponent.setGraphicsContext(
			this.getView().getStandardColorContentContext()
		);
		childComponent.paint();
	}
});

/*
Class: FontColorPicker.ColorBoardView
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
loadFile('light.G/Skin/ComponentView.js');
loadFile('light.G/Components/GColorBlock.js');
loadFile('light.Controls/HtmlEditor/BasicEditorColorBlockView.js');

/* class */ FontColorPicker.ColorBoardView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: 	'/More/FontColorBoard/',
	colors: {
		baseColors: ['ffffff', '000000', 'eeece1', '1f497d', '4f81bd', 'c0504d', '9bbb59', '8064a2', '4bacc6', 'f79646'],
		firstRow: 	['f2f2f2', '7f7f7f', 'ddd9c3', 'c6d9f0', 'dbe5f1', 'f2dcdb', 'ebf1dd', 'e5e0ec', 'dbeef3', 'fdeada'],
		secondRow: 	['d8d8d8', '595959', 'c4bd97', '8db3e2', 'b8cce4', 'e5b9b7', 'd7e3bc', 'ccc1d9', 'b7dde8', 'fbd5b5'],
		thirdRow: 	['bfbfbf', '3f3f3f', '938953', '548dd4', '95b3d7', 'd99694', 'c3d69b', 'b2a2c7', '92cddc', 'fac08f'],
		fourthRow: 	['a5a5a5', '262626', '494429', '17365d', '366092', '953734', '76923c', '5f497a', '31859b', 'e36c09'],
		fifthRow: 	['7f7f7f', '0c0c0c', '1d1b10', '0f243e', '244061', '632423', '4f6128', '3f3151', '205867', '974806'],
		standardColors:	['c00000', 'ff0000', 'ffc000', 'ffff00', '92d050', '00b050', '00b0f0', '0070c0', '002060', '7030a0']
	},

	css: {
		baseColors: 'base-colors',
		firstRow: 'first-row',
		secondRow: 'second-row',
		thirdRow: 'third-row',
		fourthRow: 'fourth-row',
		fifthRow: 'fifth-row',
		standardColors: 'standard-colors'
	},

	context: {
		baseColors: 'theme-color-content-main',
		firstRow: 'theme-color-content-sub',
		secondRow: 'theme-color-content-sub',
		thirdRow: 'theme-color-content-sub',
		fourthRow: 'theme-color-content-sub',
		fifthRow: 'theme-color-content-sub',
		standardColors: 'standard-color-content'
	},

	getDrawingContext: function(key){
		return new Hash({
			'inject': {
				'target': this.getElementByTheme(this.context[key]),
				'position': 'bottom'
			}
		});
	},

	paintColorBlock: function(color, key){
		var options = {
			baseCss: this.css[key]
		};

		var colorBlock = new GColorBlock(options, '#' + color);
    	colorBlock.setView(new BasicEditorColorBlockView());
    	colorBlock.setGraphicsContext(this.getDrawingContext(key));
    	colorBlock.paint();
		this.setupColorBlock(colorBlock);
	},

    paint: function(){
    	var c = this.getComponent();
    	GFactory.getPaint().draw(this.getElement(), c.getGraphicsContext());

    	this.colors.each(function(data, key){
			data.each(function(color){
				this.paintColorBlock(color, key);
			}.bind(this))
    	}.bind(this));
	},

	repaint: function(){
		GFactory.getPaint().draw(this.getElement(), c.getGraphicsContext(), null, ['inject']);
	},

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
			'class': this.getTheme('main')
		}).grab(
			new Element('div', {
				'class': this.getTheme('inner')
			}).grab(
	            new Element('div', {
					'class': this.getTheme('theme-color-title'),
					'html': 'Màu mặc định'
				})
			).grab(
				new Element('div', {
					'class': this.getTheme('theme-color-content-main') + ' pkg'
				})
			).grab(
				new Element('div', {
					'class': this.getTheme('theme-color-content-sub') + ' pkg'
				})
			).grab(
                new Element('div', {
					'class': this.getTheme('standard-color-title'),
					'html': 'Màu phổ biến'
				})
			).grab(
                new Element('div', {
					'class': this.getTheme('standard-color-content') + ' pkg'
				})
			).grab(
                new Element('div', {
					'class': this.getTheme('more-colors-inside')
				})
			)
		);

		c.attachWithElement(this.domElement);
	},

	install: function(){
		this.createDomElement();
	},

    uninstall: function(){
		this.destroyDomElement();
	}
});

/*
Class: FontColorPicker.ColorBoard.Listener
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/
/* static class */ FontColorPicker.ColorBoard.Listener /* implements ColorChangeListener */
= new Hash({
    colorChanged: function(colorBoard, color, colorPickerButton){
    	colorPickerButton.setColor(colorBoard.getColor());
    	colorPickerButton.setPopupVisible(false);
	}
});
};filesWrapper['light.Controls/HtmlEditor/DefaultRenderer/_DefaultRenderer.js'] = function(){
	loadFile('light.Controls/HtmlEditor/CtrlHtmlEditor.Actions.js');
loadFile('light.Controls/HtmlEditor/BasicEditorButtonView.js');
/*
Class: BasicHtmlEditorView.SubComponents
	Mảng config hỗ trợ cho <BasicHtmlEditorView>, mỗi lần view đọc config subComponents của <CtrlHtmlEditor>, view sẽ kiểm tra xem key đó có trong mảng này không, nếu key có giá trị là null, view sẽ dùng hàm <BasicHtmlEditorView::createSimpleEditorButton> để tạo, nếu key có createComponent, hàm này của key sẽ trả về component cần thiết. Mảng config này có thể được mở rộng hoặc sửa đổi bất kỳ lúc nào thông qua phương thức extend thông thường của Hash.

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Một số key phổ biến:
	image - Nút chèn ảnh vào bài viết, khi ấn vào nút này, sẽ gửi một request kiểu LAD đến cho url có trong config insertImageUrl của <CtrlHtmlEditor>
	fontcolor - Trả về button được tạo ra bởi <FontColorPicker>, mỗi khi button này thay đổi màu, editor sẽ thay đổi màu chữ theo
	backcolor - Trả về button được tạo ra bởi <BackColorPicker>, mỗi khi button này thay đổi màu, editor sẽ thay đổi màu nền chữ theo

Các key mặc định:
	bold, italic, underline, strikethrough, subscript, superscript, alignleft, aligncenter, alignright, alignjustify, listorder, listunorder, removeformat, unlink, image, fontcolor, backcolor, toggle
*/
/* static class */ BasicHtmlEditorView.SubComponents /* */
= new Hash({
	bold: null,
	italic: null,
	underline: null,
	strikethrough: null,
    subscript: null,
    superscript: null,
    alignleft: null,
	aligncenter: null,
	alignright: null,
	alignjustify: null,
    listorder: null,
    listunorder: null,
    removeformat: null,
    unlink: null,
    image: {
        createComponent: function(cpName, editor, toolbar){
            var ourCp = new GButton({
            	themePath: '/More/Editor/Button/',
                text: 'Chèn ảnh',
                baseCss: 'image'
            });
            ourCp.setView(new BasicEditorButtonView());
            toolbar.add(ourCp);
            toolbar.addSubComponent(ourCp, cpName);
            ourCp.setIndex(cpName); // lưu index cho component để toolbar track lại sau này
            ourCp.addMouseListener(BasicHtmlEditorView.InsertImageButtonListener, editor);
            return ourCp;
        }
    },
	toggle: {
		createComponent: function(cpName, editor, toolbar){
            var ourCp = new GButton({
            	themePath: '/More/Editor/Button/',
				baseCss: BasicHtmlEditorView.TextConfig.get('/' + cpName + '/baseCss/'),
	        	text: BasicHtmlEditorView.TextConfig.get('/' + cpName + '/text/')
			});
			ourCp.setView(new BasicEditorButtonView());
			toolbar.add(ourCp);
			toolbar.addSubComponent(ourCp, cpName);
            ourCp.setIndex(cpName); // lưu index cho component để toolbar track lại sau này
            ourCp.addMouseListener(BasicHtmlEditorView.ToggleButtonListener, editor);
			return ourCp;
		}
	},
    fontcolor: {
        createComponent: function(cpName, editor, toolbar){
        	loadFile('light.Controls/HtmlEditor/SubComponents/FontColorPicker.js');
            var ourCp = new FontColorPicker({
            	baseCss: 'fontcolor'
            });
            toolbar.add(ourCp);
            toolbar.addSubComponent(ourCp, cpName);
            ourCp.setIndex(cpName); // lưu index cho component để toolbar track lại sau này
            ourCp.addColorChangeListener(BasicHtmlEditorView.FontColorButtonListener, editor);
            ourCp.addMouseListener(BasicHtmlEditorView.FontColorButtonListener, editor);
            return ourCp;
        }
    },
    backcolor: {
        createComponent: function(cpName, editor, toolbar){
        	loadFile('light.Controls/HtmlEditor/SubComponents/BackColorPicker.js');
            var ourCp = new BackColorPicker({
            	baseCss: 'backcolor'
            });
            toolbar.add(ourCp);
            toolbar.addSubComponent(ourCp, cpName);
            ourCp.setIndex(cpName); // lưu index cho component để toolbar track lại sau này
            ourCp.addColorChangeListener(BasicHtmlEditorView.BackColorButtonListener, editor);
            ourCp.addMouseListener(BasicHtmlEditorView.BackColorButtonListener, editor);
            return ourCp;
        }
    }
});

/* static class */ BasicHtmlEditorView.FontColorButtonListener /* implements ColorChangeListener, MouseListener */
= new Hash({
    colorChanged: function(button, color, editor){
    	CtrlHtmlEditor.Actions.changeFontColor(editor, color);
	},

    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
    	CtrlHtmlEditor.Actions.changeFontColor(editor, button.getColor());
	},

    doubleClick: $empty
});

/* static class */ BasicHtmlEditorView.BackColorButtonListener /* implements ColorChangeListener, MouseListener */
= new Hash({
    colorChanged: function(button, color, editor){
    	CtrlHtmlEditor.Actions.changeBackColor(editor, color);
	},

    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
    	CtrlHtmlEditor.Actions.changeBackColor(editor, button.getColor());
	},

    doubleClick: $empty
});

/* static class */ BasicHtmlEditorView.ToggleButtonListener /* implements MouseListener */
= new Hash({
    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
    	editor.toggleMode();
	},

    doubleClick: $empty
});

/* static class */ BasicHtmlEditorView.InsertImageButtonListener /* implements MouseListener */
= new Hash({
    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
        /*
		*	lưu lại object gửi lad request cuối cùng
		*/
		getClientStorage().set('lastLadRequestObject', button.getElement());

		//editor.setMode('textarea');
		loadFile('light.Ajax/lad/Request.Light.Lad.js');
	    new Request.Light.Lad({
			method: 'post',
			url: editor.getOption('insertImageUrl'),
			data: new Hash({
				'editorid': editor.getOption('id')
			})
		}).send();
	},

    doubleClick: $empty
});
};filesWrapper['light.Controls/HtmlEditor/SubComponentRenderer.js'] = function(){
	/*
Interface: HtmlEditor.SubComponentRenderer
	Renderer cho editor có nhiệm vụ vẽ các vẽ các components cho editor bổ sung vào toolbar.

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ HtmlEditor.SubComponentRenderer /* */
= new Hash({
	createComponent: function(componentName, editor, toolbar){
	},

	afterDocCreated: function(editor){},

	beforeComponentDestroyed: function(editor){}
});
};filesWrapper['light.Controls/HtmlEditor/View.js'] = function(){
	loadFile('light.G/Skin/ComponentView.js');
loadFile('light.G/Components/GHtmlDocument.js');
loadFile('light.G/Components/GTextArea.js');
loadFile('light.G/Components/GToolbar.js');
loadFile('light.G/Components/GButton.js');
namespace('HtmlEditor');

/*
Class: HtmlEditor.View
	View của HtmlEditor được vẽ bằng cách tạo các components: <GHtmlDocument> và <GToolbar> sau đó đọc config và tạo ra các component bên trong tương ứng. Config của các component bên trong này được lưu trong <BasicHtmlEditorView.SubComponents>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ HtmlEditor.View /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	currentMode: 'iframe',
	textArea: null,
	document: null,
	toolbar: null,

	getDocument: function(){
		return this.document;
	},

	getToolbar: function(){
		return this.toolbar;
	},

	initialize: function(textArea){
		this.textArea = textArea;
		this.parent();
	},

	synchronize: function(){
		var c = this.getComponent();
        if (c.getMode() == 'iframe'){
        	/*console.log(HelpersFactory.getHtmlHelper().cleanup(
					this.document.getContent()
				));*/

			this.textArea.setText(
				HelpersFactory.getHtmlHelper().cleanup(
					this.document.getContent()
				)
			);

			this.getToolbar().disableAll();
    		this.getToolbar().enableComponent('toggle');
		}
		else {
			this.document.setContent(
				this.textArea.getText()
			);

			this.getToolbar().enableAll();
		};
	},

    getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement(),
				'position': 'bottom'
			}
		});
	},

    paint: function(){
    	var c = this.getComponent();
    	GFactory.getPaint().draw(this.getElement(), c.getGraphicsContext());

		this.buildToolbar();

		loadFile('light.G/Components/GDomElement.js');
		var wrapper = new GDomElement(null, new Element('div', {
			'class': 'editor-wrapper'
		}));
		c.add(wrapper);

    	this.document = new GHtmlDocument({
            'width': c.getOption('width'),
			'height': c.getOption('height'),
    		text: c.getOption('text'),
            cssPath: c.getOption('cssPath'),
			cssClass: c.getOption('cssClass'),
			styleWithCss: c.getOption('styleWithCss')
    	});
    	wrapper.add(this.document);

        var subComponentsRenderer = c.getSubComponentsRenderer();
		if (!isset(subComponentsRenderer)){
			loadFile('light.Controls/HtmlEditor/DefaultRenderer/DefaultRenderer.js');
			subComponentsRenderer = HtmlEditor.DefaultRenderer;
		}
		subComponentsRenderer.afterDocCreated(c);

    	if (!isset(this.textArea)){
    		loadFile('light.G/Components/GTextArea.js');
    		this.textArea = new GTextArea({
    			width: c.getOption('width'),
    			height: c.getOption('height')
    		});
    	}
    	wrapper.add(this.textArea);

    	this.paintMode();
    	this.saveState();
	},

	paintSize: function(){
		var c = this.getComponent();
		this.document.setNewOptions({
			'width': c.getOption('width'),
			'height': c.getOption('height')
		});
	},

	paintMode: function(){
		var c = this.getComponent();
		if (c.getMode() == 'iframe'){
			this.document.setVisible(true);
			this.textArea.setVisible(false);
		}
		else {
            this.document.setVisible(false);
			this.textArea.setVisible(true);
		}
	},

	getToolbar: function(){
		return this.toolbar;
	},

	buildToolbar: function(){
		var c = this.getComponent();
		this.toolbar = new GToolbar({
			baseCss: 'editor-toolbar'
		});
		c.add(this.toolbar);

        //-----------------------------------------
		//	tạo các button
		//-----------------------------------------
		var subComponentsRenderer = c.getSubComponentsRenderer();
		if (!isset(subComponentsRenderer)){
			loadFile('light.Controls/HtmlEditor/DefaultRenderer/DefaultRenderer.js');
			subComponentsRenderer = HtmlEditor.DefaultRenderer;
		}

        var toolbarGroups = c.getOption('subComponents').split('|');
        $each(toolbarGroups, function(groupData){
        	var groupCp = new GToolbar({
				baseCss: 'btn-group'
	        });
	        this.toolbar.add(groupCp);
        	var toolbarCps = groupData.split(',');
        	$each(toolbarCps, function(cpName) {
        		subComponentsRenderer.createComponent(cpName, c, this.toolbar, groupCp);
			}.bind(this));
        }.bind(this));
	},

	repaint: function(){
		var c = this.getComponent();
		if (c.isFocus()){
			this.document.grabFocus();
		}

		this.paintMode();
		this.paintSize();
		this.saveState();
	},

	createDomElement: function(){
		this.domElement = new Element('div', {
			'class': 'editor-container'
		});
		this.getComponent().attachWithElement(this.domElement);
	},

	getDocument: function(){
		return this.document;
	},

	install: function(){
		this.createDomElement();
		this.installSystemListener();
        this.returnFncs['change'] = this.getComponent().addChangeListener(HtmlEditor.View.Listener);
	},

	uninstall: function(){
        var subComponentsRenderer = c.getSubComponentsRenderer();
		if (!isset(subComponentsRenderer)){
			loadFile('light.Controls/HtmlEditor/DefaultRenderer/DefaultRenderer.js');
			subComponentsRenderer = HtmlEditor.DefaultRenderer;
		}
		subComponentsRenderer.beforeComponentDestroyed(this.getComponent());

		this.getComponent().removeChangeListener(this.returnFncs['change']);
		this.uninstallSystemListener();
		this.destroyDomElement();
	}
});

/* class */ HtmlEditor.View.Listener /* implements ChangeListener */
= new Hash({
	stateChanged: function(htmlEditor){
		htmlEditor.repaint();
	}
});
};filesWrapper['light.Controls/InputField/BasicInputFieldView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicTextFieldView.js');

/*
Class: BasicInputFieldView
	Bản nâng cấp dành cho view của một text field thông thường. Bổ sung hỗ trợ balloon thông báo lỗi để validate dữ liệu thông qua <BasicInputFieldView.Listener>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicInputFieldView /* extends BasicTextFieldView */
= new Class({
	Extends: BasicTextFieldView,
	balloon: null,

	install: function(){
		this.parent();
		this.returnFncs['valChange'] = this.getComponent().addChangeListener(BasicInputFieldView.Listener);
	},

	uninstall: function(){
		this.getComponent().removeChangeListener(this.returnFncs['valChange']);
		this.parent();
	},

	/*
	Function: displayErrorBalloon
		Được component yêu cầu khi có lỗi xảy ra ở <CtrlInputField::validateRules>
	*/
	displayErrorBalloon: function(){
		var c = this.getComponent();
		c.setBalloonComponent(
			c.getErrorBalloonRenderer().getComponent()
		);
		c.getBalloonComponent().setLaunchedComponent(c);
		c.getBalloonComponent().setOption('width', c.getOption('balloonWidth'));
		c.getBalloonComponent().paint();

		c.getBalloonComponent().add(
			c.getErrorTemplateRenderer().getComponent(
				c.getOption('mainInstruction'),
				c.getOption('suppInstruction'),
				c.getOption('errorIcon')
			)
		);
	},

	/*
	Function: displayTooltipBalloon
		Thể hiện ra một tooltip balloon
	*/
	displayTooltipBalloon: function(){
		var inputField = this.getComponent();
		if (inputField.getOption('tooltip') != null && inputField.getOption('tooltip') != ''){
			inputField.setBalloonComponent(
				inputField.getTooltipBalloonRenderer().getComponent()
			);
			inputField.getBalloonComponent().setLaunchedComponent(inputField);
			inputField.getBalloonComponent().setOption('width', inputField.getOption('balloonWidth'));
			inputField.getBalloonComponent().paint();
			inputField.getBalloonComponent().add(
				inputField.getTooltipTemplateRenderer().getComponent(
					inputField.getOption('tooltip'),
					inputField.getOption('tooltipIcon')
				)
			);
		}
	}
});

/*
Class: BasicInputFieldView.Listener
	Listener này có nhiệm vụ lắng nghe thay đổi trạng thái focus của component, hủy balloon cũ đi và yêu cầu component hiện tooltipBalloon hay kiểm tra dữ liệu đúng hay sai

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicInputFieldView.Listener /* implements ChangeListener */
= new Hash({
    stateChanged: function(inputField, property, value){
		if (property == 'focus'){
			if (inputField.getBalloonComponent() != null){
				inputField.getBalloonComponent().destroy();
			}

			if (value == true){
				inputField.getView().displayTooltipBalloon();
			}
			else {
				inputField.validateRules();
			}
		}

		inputField.repaint();
	}
});

/*
Class: BasicInputFieldView.DefaultTooltipBalloonRenderer

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicInputFieldView.DefaultTooltipBalloonRenderer /* */
= new Hash({
	/*
	Function: getComponent
		Trả về balloon thể hiện bao ngoài của tooltip

	Returns:
		<CtrlBalloon> với options như sau
		(start code)
return new CtrlBalloon({
	popPos: 'top',
	alignPos: 'left',
	offsetX: -12,
	offsetY: 0,
	fadeOutTime: 4000
});
		(end)
	*/
	getComponent: function(){
		loadFile('light.Controls/Balloon/CtrlBalloon.js');
		return new CtrlBalloon({
			popPos: 'top',
			alignPos: 'left',
			offsetX: -4,
			offsetY: -10,
			fadeOutTime: 4000
		});
	}
});

/*
Class: BasicInputFieldView.DefaultErrorBalloonRenderer

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicInputFieldView.DefaultErrorBalloonRenderer /* */
= new Hash({
	/*
	Function: getComponent
		Trả về balloon thể hiện bao ngoài của error

	Returns:
		<CtrlBalloon> với options như sau
		(start code)
return new CtrlBalloon({
	popPos: 'right',
	alignPos: 'bottom',
	offsetX: -28,
	offsetY: 0,
	fadeOutTime: 4000
});
		(end)
	*/
	getComponent: function(){
		loadFile('light.Controls/Balloon/CtrlBalloon.js');
		return new CtrlBalloon({
			popPos: 'right',
			alignPos: 'bottom',
			offsetX: -28,
			offsetY: -6,
			fadeOutTime: 4000
		});
	}
});

/*
Class: BasicInputFieldView.DefaultTooltipTemplateRenderer

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicInputFieldView.DefaultTooltipTemplateRenderer /* implements TooltipTemplateRenderer */
= new Hash({
	/*
	Function: getComponent
		Trả về component tương ứng với dữ liệu trả về để thể hiện nội dung tooltip

	Arguments:
		simpleMessage - (string) Message thể hiện tooltip
		tooltipIcon - (<IconResourceConfig>) Mảng chứa dữ liệu icon
	Returns:
		<SimpleMessageTemplate>
	*/
	getComponent: function(simpleMessage, tooltipIcon){
		loadFile('light.Controls/resources/templates/SimpleMessage.js');
		return new SimpleMessageTemplate({
			message: simpleMessage,
			iconResource: tooltipIcon
		});
	}
});

/*
Class: BasicInputFieldView.DefaultErrorTemplateRenderer

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicInputFieldView.DefaultErrorTemplateRenderer /* implements ErrorTemplateRenderer */
= new Hash({
	/*
	Function: getComponent
		Trả về component tương ứng với dữ liệu trả về để thể hiện nội dung báo lỗi

	Arguments:
		mainInstruction - (string) Lời thể hiện chính của lỗi
		suppInstruction - (string) Lời thể hiện bổ sung của lỗi
		tooltipIcon - (<IconResourceConfig>) Mảng chứa dữ liệu icon
	Returns:
		<DetailMessageTemplate>
	*/
	getComponent: function(mainInstruction, suppInstruction, errorIcon){
		loadFile('light.Controls/resources/templates/DetailMessage.js');
		return new DetailMessageTemplate({
			mainInstruction: mainInstruction,
			suppInstruction: suppInstruction,
			iconResource: errorIcon
		});
	}
});
};filesWrapper['light.Controls/InputField/CtrlInputField.js'] = function(){
	loadFile('light.G/Components/GTextField.js');

/*
Class: CtrlInputField
	Là component nâng cấp của <GTextField> để hỗ trợ thêm một số chức năng như
	- Hiện tooltip dưới dạng balloon
	- Bổ sung validator khi rời focus khỏi input
	- Kết hợp với <FormValidator>

	Để customize thể hiện balloon và thể hiện nội dung tooltip và error message của control này, customize thông qua các hàm set renderer

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Mặc định sử dụng các renderer:
	- <BasicInputFieldView.DefaultTooltipBalloonRenderer>
	- <BasicInputFieldView.DefaultErrorBalloonRenderer>
	- <BasicInputFieldView.DefaultTooltipTemplateRenderer>
	- <BasicInputFieldView.DefaultErrorTemplateRenderer>

See Also:
	<DefaultInputFieldModel>, <BasicInputFieldView>
*/
/* class */ CtrlInputField /* extends GTextField */
= new Class({
	Extends: GTextField,

	errorBalloonRenderer: null,
	errorTemplateRenderer: null,
	tooltipBalloonRenderer: null,
	tooltipTemplateRenderer: null,

    initialize: function(options, builtTextField){
    	this.parent(options, builtTextField);
    	loadFile('light.Controls/InputField/DefaultInputFieldModel.js');
		this.setModel(new DefaultInputFieldModel());
	},

    createDefaultView: function(){
    	loadFile('light.Controls/InputField/BasicInputFieldView.js');
    	return new BasicInputFieldView(this.builtTextField);
	},

	getBalloonComponent: function(){
		return this.getView().balloon;
	},

	setBalloonComponent: function(inst){
		this.getView().balloon = inst;
	},

	/*
	Function: validateRules
		Kiểm tra dữ liệu đang có có hợp lệ với rules yêu cầu không. Nếu có lỗi, gọi <BasicInputFieldView::displayErrorBalloon>
	*/
	validateRules: function(){
		// lấy dữ liệu
		var data = this.getText();

		// kiểm tra
		var result = HelpersFactory.getTypeHelper().verifyDataByRules(data, this.getOption('valRules'));
		if (!result){
			this.getView().displayErrorBalloon();
		}

		return result;
	},

	getClassName: function(){
		return 'CtrlInputField';
	},

	/*
	Function: setTooltipBalloonRenderer
		Đặt lại obj sẽ render ra tooltip balloon

	Arguments:
		renderer - (<LayoutRenderer>) Renderer sẽ render ra balloon
	*/
	setTooltipBalloonRenderer: function(renderer){
		this.tooltipBalloonRenderer = renderer;
	},

	getTooltipBalloonRenderer: function(){
		if (!isset(this.tooltipBalloonRenderer)){
			loadFile('light.Controls/InputField/BasicInputFieldView.js');
			this.tooltipBalloonRenderer =  BasicInputFieldView.DefaultTooltipBalloonRenderer;
		}

		return this.tooltipBalloonRenderer;
	},

	/*
	Function: setErrorBalloonRenderer
		Đặt lại obj sẽ render ra ballooon khi có lỗi

	Arguments:
		renderer - (<LayoutRenderer>) Renderer sẽ render ra balloon
	*/
	setErrorBalloonRenderer: function(renderer){
		this.errorBalloonRenderer = renderer;
	},

	getErrorBalloonRenderer: function(){
		if (!isset(this.errorBalloonRenderer)){
			loadFile('light.Controls/InputField/BasicInputFieldView.js');
			this.errorBalloonRenderer =  BasicInputFieldView.DefaultErrorBalloonRenderer;
		}

		return this.errorBalloonRenderer;
	},

	/*
	Function: setTooltipTemplateRenderer
		Đặt lại obj sẽ render ra nội dung tooltip

	Arguments:
		renderer - (<TooltipTemplateRenderer>) Renderer render ra nội dung tooltip
	*/
	setTooltipTemplateRenderer: function(renderer){
		this.tooltipTemplateRenderer = renderer;
	},

	getTooltipTemplateRenderer: function(){
		if (!isset(this.tooltipTemplateRenderer)){
			loadFile('light.Controls/InputField/BasicInputFieldView.js');
			this.tooltipTemplateRenderer =  BasicInputFieldView.DefaultTooltipTemplateRenderer;
		}

		return this.tooltipTemplateRenderer;
	},

	/*
	Function: setErrorTemplateRenderer
		Đặt lại obj sẽ render ra nội dung của error

	Arguments:
		renderer - (<ErrorTemplateRenderer>) Renderer render ra nội dung báo lỗi
	*/
	setErrorTemplateRenderer: function(renderer){
		this.errorTemplateRenderer = renderer;
	},

	getErrorTemplateRenderer: function(){
		if (!isset(this.errorTemplateRenderer)){
			loadFile('light.Controls/InputField/BasicInputFieldView.js');
			this.errorTemplateRenderer =  BasicInputFieldView.DefaultErrorTemplateRenderer;
		}

		return this.errorTemplateRenderer;
	}
});
};filesWrapper['light.Controls/InputField/DefaultInputFieldModel.js'] = function(){
	loadFile('light.G/Model/DefaultTextFieldModel.js');

/*
Class: DefaultInputFieldModel
	Model cho <CtrlInputField>, bổ sung chức năng lưu trữ thêm dữ liệu liên quan đến các luật validate

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Options:
	valRules - (mixed) Danh sách luật, sẽ được truyền vào <TypeHelper::verifyDataByRules>
	mainInstruction - (string) Hướng dẫn chính khi xuất hiện lỗi
	suppInstruction - (string) Hướng dẫn bổ sung khi có lỗi
	errorIcon - (<IconResourceConfig>) Icon khi có lỗi
	tooltipIcon - (<IconResourceConfig>) Icon khi thể hiện tooltip
*/
/* class */ DefaultInputFieldModel /* extends DefaultTextFieldModel  */
= new Class({
	Extends: DefaultTextFieldModel,
	options: {
		valRules: null,
		mainInstruction: 'Dữ liệu không đúng',
		suppInstruction: 'Dữ liệu này không đúng như yêu cầu, xin hãy nhập lại',
		balloonWidth: 300,
		errorIcon: null,
		tooltipIcon: null
	}
});
};filesWrapper['light.Controls/InputField/ErrorTemplateRenderer.js'] = function(){
	/*
Interface: ErrorTemplateRenderer
	Interface cho renderer muốn thay thế ErrorTemplateRenderer thông qua hàm <CtrlInputField::setErrorTemplateRenderer>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ ErrorTemplateRenderer /* */
= new Hash({
	/*
	Function: getComponent
		Trả về component tương ứng với dữ liệu trả về để thể hiện tooltip

	Arguments:
		mainInstruction - (string) Lời thể hiện chính của lỗi
		suppInstruction - (string) Lời thể hiện bổ sung của lỗi
		tooltipIcon - (<IconResourceConfig>) Mảng chứa dữ liệu icon
	*/
	getComponent: function(mainInstruction, suppInstruction, errorIcon){
	}
});
};filesWrapper['light.Controls/InputField/TooltipTemplateRenderer.js'] = function(){
	/*
Interface: TooltipTemplateRenderer
	Interface cho renderer muốn thay thế TooltipTemplateRenderer thông qua hàm <CtrlInputField::setTooltipTemplateRenderer>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ TooltipTemplateRenderer /* */
= new Hash({
	/*
	Function: getComponent
		Trả về component tương ứng với dữ liệu trả về để thể hiện tooltip

	Arguments:
		simpleMessage - (string) Message thể hiện tooltip
		tooltipIcon - (<IconResourceConfig>) Mảng chứa dữ liệu icon
	*/
	getComponent: function(simpleMessage, tooltipIcon){
	}
});
};filesWrapper['light.Controls/MenuGroup/BarMenuGroup.js'] = function(){
	loadFile('light.G/Components/GComponent.js');

/*
Class: BarMenuGroup
	Là một container có khả năng chứa các <MenuItem>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BarMenuGroup /* implements MenuGroup */
= new Class({
	Extends: GComponent,
	initialize: function(options, input){
		loadFile('light.Controls/MenuGroup/DefaultMenuGroupModel.js');
		this.setModel(new DefaultMenuGroupModel(input));
		this.setOptions(options);
	},

	setMenuItemRenderer: function(renderer){
		this.setOption('menuItemRenderer', renderer);
	},

	getMenuItemRenderer: function(){
		return this.getOption('menuItemRenderer');
	},

	setInsideMenuItemRenderer: function(renderer){
		return this.setOption('insideMenuItemRenderer', renderer);
	},

	getInsideMenuItemRenderer: function(){
		return this.getOption('insideMenuItemRenderer');
	},

	createDefaultView: function(){
    	return new BarMenuGroupView();
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	},

	getAllData: function(){
		return this.getModel().getAllData();
	}
});

/* class */ BarMenuGroupView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: '/More/BarMenuGroup/',

	paintChildren: function(){
		var c = this.getComponent();
		var data = c.getAllData();
		data.each(function(item, index){
			/* Gọi renderer để lấy component */
			var renderer = c.getMenuItemRenderer();
			if (!isset(renderer)) {
				loadFile('light.Controls/MenuGroup/DefaultMenuItemRenderer.js');
				renderer = DefaultMenuItemRenderer;
			}

			var menuItem = renderer.getComponent(c, item, index);
		}.bind(this));
	},

	paint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
		this.paintChildren();
	},

	repaint: function(){
	},

	getInsideContext: function(){
        return new Hash({
            'inject': {
                'target': this.getElementByTheme('inner'),
                'position': 'bottom'
            }
        });
    },

    createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
            'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
        }).set('html',
'<div class=' + this.getTheme('inner') + '>' +
'</div>'
        );
        c.attachWithElement(this.domElement);
    }
});

// tạo ra 1 wrapper
// với từng key, gọi renderer tạo ra MenuItem có text
// và có khả năng hiện ra các MenuGroup có đầu vào là children
};filesWrapper['light.Controls/MenuGroup/DefaultMenuGroupModel.js'] = function(){
	loadFile('light.G/Model/AbstractModel.js');

/*
Class: DefaultMenuGroupModel
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ DefaultMenuGroupModel /* */
= new Class({
	Extends: AbstractModel,
	data: null,
	initialize: function(data){
		this.data = data;
	},

	getAllData: function(){
		return this.data;
	},

	getSize: function(){
		return this.data.length;
	}
});
};filesWrapper['light.Controls/MenuGroup/DefaultMenuItemRenderer.js'] = function(){
	/*
Class: DefaultMenuItemRenderer
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ DefaultMenuItemRenderer /* implements MenuItemRenderer */
= new Hash({
	createMenuItem: function(data){
		loadFile('light.G/Components/GButton.js');
		// nếu tồn tại item.children
		var menuItem = new GButton({
			'baseCss': isset(data.baseCss) ? data.baseCss : '',
			'text': data.text
		});
		return menuItem;
	},

	createPopup: function(menuItem, data, c){
		loadFile('light.Controls/MenuGroup/PopupMenuGroup.js');
    	var popup = new PopupMenuGroup({
			'baseCss': isset(data.puCss) ? data.puCss : ''
    	}, data.children);

    	var insideRenderer = c.getInsideMenuItemRenderer()
    	if (isset(insideRenderer)){
    		popup.setMenuItemRenderer(insideRenderer);
    		popup.setInsideMenuItemRenderer(insideRenderer);
		}

    	popup.setVisible(false);
    	popup.setGraphicsContext({
			'inject': {
				'target': document.body,
				'position': 'bottom'
			},
			'stackpos': {
				'target': menuItem.getElement(),
				'pop': isset(data.puPop) ? data.puPop : 'right',
				'align': isset(data.puAlign) ? data.puAlign : 'top'
			}
		});
    	popup.paint();
    	return popup;
	},

	getComponent: function(c, data, index){
		var menuItem = this.createMenuItem(data);
		menuItem.setIndex(index);
		c.add(menuItem);
		c.addSubComponent(menuItem, index);

		if (isset(data.children)){
			var popup = this.createPopup(menuItem, data, c);
			menuItem.popup = popup;
			popup.setParentComponent(menuItem);
			popup.addMouseMotionListener(DefaultMenuItemRenderer.PopupListener, menuItem);
		}

		menuItem.addMouseMotionListener(DefaultMenuItemRenderer.Listener);

		return menuItem;
	}
});

DefaultMenuItemRenderer.PopupListener = new Hash({
	mouseLeave: function(e, popup, menuItem){
		if (isset(menuItem.timer))
			menuItem.timer.reset();

	},

	mouseOver: $empty,
	mouseOut: $empty,

    mouseEnter: function(e, popup, menuItem){
    	if (isset(menuItem.timer))
			menuItem.timer.stop();
	}
});

DefaultMenuItemRenderer.Listener = new Hash({
	mouseLeave: function(e, menuItem){
		if (isset(menuItem.popup)) {
			loadFile('core/IdleTimer.js');
			menuItem.timer = new IdleTimer(50);
			menuItem.timer.addEvent('complete', function(){
				menuItem.popup.setVisible(false);
			});
			menuItem.timer.addEvent('stop', function(){
				var parentMenuItem = menuItem.getParentComponent().getParentComponent();
				if (isset(parentMenuItem))
					if (isset(parentMenuItem.timer))
						parentMenuItem.timer.stop();
			});
			menuItem.timer.addEvent('reset', function(){
				var parentMenuItem = menuItem.getParentComponent().getParentComponent();
				if (isset(parentMenuItem))
					if (isset(parentMenuItem.timer))
						parentMenuItem.timer.reset();
			});
			menuItem.timer.start();
			menuItem.timer.idle();
		}
	},

	mouseOver: $empty,
	mouseOut: $empty,

    mouseEnter: function(e, menuItem){
    	if (isset(menuItem.timer))
    		menuItem.timer.stop();

    	if (isset(menuItem.popup))
    		menuItem.popup.setVisible(true);
	}
});
};filesWrapper['light.Controls/MenuGroup/MenuGroup.js'] = function(){
	/*
Interface: MenuGroup
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ MenuGroup /* */
= new Class({
	initialize: function(options, input){},
	setMenuItemRenderer: function(){}
});
};filesWrapper['light.Controls/MenuGroup/MenuItemRenderer.js'] = function(){
	/*
Interface: MenuItemRenderer
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* interface */ MenuItemRenderer /* extends LayoutRenderer */
= new Hash({
	getComponent: function(){
	}
});

};filesWrapper['light.Controls/MenuGroup/PopupMenuGroup.js'] = function(){
	loadFile('light.G/Components/GPopupMenu.js');
/*
Class: PopupMenuGroup
	Description

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ PopupMenuGroup /* extends GPopupMenu */
= new Class({
	Extends: GPopupMenu,

	initialize: function(options, input){
		this.setModel(new DefaultPopupMenuGroupModel(input));
		this.setOptions(options);
	},

	setMenuItemRenderer: function(renderer){
		this.setOption('menuItemRenderer', renderer);
	},

	getMenuItemRenderer: function(){
		return this.getOption('menuItemRenderer');
	},

	setInsideMenuItemRenderer: function(renderer){
		return this.setOption('insideMenuItemRenderer', renderer);
	},

	getInsideMenuItemRenderer: function(){
		return this.getOption('insideMenuItemRenderer');
	},

	createDefaultView: function(){
    	return new PopupMenuGroupView();
	},

	getDefaultChildGraphicsContext: function(){
    	if (!isset(this.defaultChildGraphicsContext)){
            this.defaultChildGraphicsContext = this.getView().getInsideContext()
    	}

    	return this.defaultChildGraphicsContext;
	},

	getAllData: function(){
		return this.getModel().getAllData();
	}
});

loadFile('light.G/Model/DefaultPopupMenuModel.js');
/* class */ DefaultPopupMenuGroupModel /* implements MenuGroupModel */
= new Class({
	Extends: DefaultPopupMenuModel,

	data: null,
	initialize: function(data){
		this.data = data;
	},

	getAllData: function(){
		return this.data;
	},

	getSize: function(){
		return this.data.length;
	}
});

loadFile('light.G/Skin/PopupMenuView.js');
/* class */ PopupMenuGroupView /* extends PopupMenuView */
= new Class({
	Extends: PopupMenuView,
	themePath: '/More/PopupMenuGroup/',

	paintChildren: function(){
		var c = this.getComponent();
		var data = $H(c.getAllData());
		data.each(function(item, index){
			/* Gọi renderer để lấy component */
			var renderer = c.getMenuItemRenderer();
			if (!isset(renderer)) {
				loadFile('light.Controls/MenuGroup/DefaultMenuItemRenderer.js');
				renderer = DefaultMenuItemRenderer;
			}

			var menuItem = renderer.getComponent(c, item, index);
		}.bind(this));
	},

	paint: function(){
		this.parent();
		this.paintChildren();
	},

	getInsideContext: function(){
        return new Hash({
            'inject': {
                'target': this.getElementByTheme('inner'),
                'position': 'bottom'
            }
        });
    },

    createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
            'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
        }).set('html',
'<div class=' + this.getTheme('inner') + '>' +
'</div>'
        );
        c.attachWithElement(this.domElement);
    }
});
};filesWrapper['light.Controls/ProgressBar/BasicProgressBarView.js'] = function(){
	loadFile('light.G/Skin/ComponentView.js');
/* class */ BasicProgressBarView /* extends ComponentView */
= new Class({
	Extends: ComponentView,
	themePath: '/More/ProgressBar/',

    paint: function(){
    	GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
    	this.paintProgress();
    	this.saveState();
	},

	repaint: function(){
		this.paintProgress();
		this.saveState();
	},

	paintProgress: function(){
        var c = this.getComponent();
        if (this.compareState('progress')){
        	this.getElementByTheme('bar').setStyles({
        		'background-position': (100 - c.getOption('progress')) + '% 0px'
        	});
		}
	},

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		}).grab(
			new Element('div', {
				'class': this.getTheme('inner')
			}).grab(
	            new Element('div', {
					'class': this.getTheme('bar')
				})
			)
		);

		c.attachWithElement(this.domElement);
	},

	install: function(){
		var c = this.getComponent();
		this.createDomElement();
		this.returnFncs['change'] = c.addChangeListener(BasicProgressBarView.ChangeListener);
	},

	uninstall: function(){
		var c = this.getComponent();
		c.removeChangeListener(this.returnFncs['change']);
		this.destroyDomElement();
	}
});

/* static class */ BasicProgressBarView.ChangeListener /* implements ChangeListener */
= new Hash({
	stateChanged: function(progressBar, property, value){
		progressBar.repaint();
	}
});
};filesWrapper['light.Controls/ProgressBar/CtrlProgressBar.js'] = function(){
	loadFile('light.G/Components/GComponent.js');
/* class */ CtrlProgressBar /* extends GComponent */
= new Class({
	Extends: GComponent,

	initialize: function(options){
		loadFile('light.Controls/ProgressBar/DefaultProgressBarModel.js');
		this.setModel(new DefaultProgressBarModel());
		this.setOptions(options);
	},

	createDefaultView: function(){
		loadFile('light.Controls/ProgressBar/BasicProgressBarView.js');
		return new BasicProgressBarView();
	},

	setProgress: function(value){
		this.getModel().setProgress(value);
	},

	getProgress: function(){
		return this.getModel().getProgress();
	}
});
};filesWrapper['light.Controls/ProgressBar/DefaultProgressBarModel.js'] = function(){
	loadFile('light.G/Model/AbstractModel.js');
/* class */ DefaultProgressBarModel /* extends AbstractModel */
= new Class({
	Extends: AbstractModel,

	options: {
		baseCss: '',
		progress: 0
	},

	setProgress: function(value){
		if (value < 0){
			value = 0;
		}

		if (value > 100){
			value = 100;
		}

		value = Math.round(value);
		this.setOption('progress', value);
	},

	getProgress: function(){
		return this.getOption('progress');
	}
});
};filesWrapper['light.Controls/resources/templates/DetailMessage.js'] = function(){
	loadFile('light.G/Components/GComponent.js');
/* class */ DetailMessageTemplate /* extends GComponent */
= new Class({
	Extends: GComponent,

	initialize: function(options){
        this.setModel(new DetailMessageTemplate.Model());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new DetailMessageTemplate.View();
	}
});

loadFile('light.G/Model/DefaultDomElementModel.js');
/* class */ DetailMessageTemplate.Model /* extends DefaultDomElementModel */
= new Class({
	Extends: DefaultDomElementModel,

	options: {
		mainInstruction: 'Main Instruction',
		suppInstruction: 'Supplemental Instruction',
		iconResource: null
	}
});

loadFile('light.G/Skin/DomElementView.js');
/* class */ DetailMessageTemplate.View /* extends DomElementView */
= new Class({
	Extends: DomElementView,
	themePath: '/More/Templates/DetailMessage/',

	createDomElement: function(){
		var c = this.getComponent();
		this.domElement = new Element('div', {
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		}).set('html',
'<div class="' + this.getTheme('inner') + '">'+
	'<div class="left">'+
		'<div class="left-inner">'+
			'<div class="' + this.getTheme('icon') + '">'+
			'</div>'+
		'</div>'+
	'</div>'+
	'<div class="right">'+
		'<div class="right-inner">'+
(c.getOption('mainInstruction') != null ? (
		    '<div class="' + this.getTheme('main-instruction') + '">'+
				c.getOption('mainInstruction') +
			'</div>'
) : '' ) +
(c.getOption('suppInstruction') != null ? (
			'<div class="' + this.getTheme('supp-instruction') + '">'+
				c.getOption('suppInstruction') +
			'</div>'
) : '' ) +
		'</div>'+
	'</div>'+
'</div>'
		);

		if (c.getOption('iconResource') != null){
			var iconResource = c.getOption('iconResource');
			GFactory.getResourceManager().getIconResource(
				iconResource.resourceName
			).get(
				iconResource.iconIndex,
				iconResource.iconSize
			).inject(
				this.getElementByTheme('icon'),
				'bottom'
			);
		}
	}
});
};filesWrapper['light.Controls/resources/templates/SimpleMessage.js'] = function(){
	/*
Script: SimpleMessageTemplate
	Define how a request will exist in the Light Environment

Copyright:
	Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/*
Class: SimpleMessageTemplate
	Define how a request will exist in the Light Environment

Author:
	hitori_vodanh <nhanvc@vsmc.vn>
*/

loadFile('light.G/Components/GComponent.js');
/* class */ SimpleMessageTemplate /* extends GComponent */
= new Class({
	Extends: GComponent,

	initialize: function(options){
        this.setModel(new SimpleMessageTemplate.Model());
		this.setOptions(options);
	},

    createDefaultView: function(){
    	return new SimpleMessageTemplate.View();
	}
});

loadFile('light.G/Model/DefaultDomElementModel.js');
/* class */ SimpleMessageTemplate.Model /* extends DefaultDomElementModel */
= new Class({
	Extends: DefaultDomElementModel,

	options: {
		message: 'Some Simple Message',
		iconResource: null
	}
});

loadFile('light.G/Skin/DomElementView.js');
/* class */ SimpleMessageTemplate.View /* extends DomElementView */
= new Class({
	Extends: DomElementView,
	themePath: '/More/Templates/SimpleMessage/',

	createDomElement: function(){
		var c = this.getComponent();
		this.domElement = new Element('div', {
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		}).set('html',
'<div class="' + this.getTheme('inner') + '">'+
	'<div class="left">'+
		'<div class="left-inner">'+
			'<div class="' + this.getTheme('icon') + '">'+
			'</div>'+
		'</div>'+
	'</div>'+
	'<div class="right">'+
		'<div class="right-inner">'+
		    '<div class="' + this.getTheme('message') + '">'+
				c.getOption('message') +
			'</div>'+
		'</div>'+
	'</div>'+
'</div>'
		);

		if (c.getOption('iconResource') != null){
			var iconResource = c.getOption('iconResource');
			GFactory.getResourceManager().getIconResource(
				iconResource.resourceName
			).get(
				iconResource.iconIndex,
				iconResource.iconSize
			).inject(
				this.getElementByTheme('icon'),
				'bottom'
			);
		}
	}
});
};filesWrapper['light.Controls/resources/themes/More.js'] = function(){
	ThemeData = {
	'Balloon': {
		main:			'balloon',
		head:			'balloon-head',
		'head-inner':	'balloon-head-inner',
		bottom:			'balloon-bottom',
		'bottom-inner':	'balloon-bottom-inner',
		content:		'balloon-content',
		'content-inner':	'balloon-content-inner'
	},

	'InFormFU': {
		'main':				'flash-uploader',
		'default':			'default-row',
		'sub':				'sub-row',
		'clearButton':		'clear-button',
		'fileCountLabel':	'file-count-label',
		'fu-container':		'fu-popup-container'
	},

	'MultiFU': {
		'MainCtrl': {
			'main':					'multi-fu',
			'buttons-wrapper':		'buttons-wrapper',
			'files-list-wrapper':	'files-list-wrapper',
			'empty-button-wrapper':	'empty-button-wrapper',
			'fu-container':		'fu-popup-container'
		},
		'FileRow': {
			'main': 				'file-row',
			'inner': 				'file-row-inner',
			'file-icon': 			'file-icon',
			'main-content': 		'main-content',
			'first-row': 			'first-row pkg',
			'file-name': 			'file-name',
			'file-size': 			'file-size',
			'second-row': 			'second-row pkg',
			'status-bar': 			'status-bar',
			'progress-bar': 		'progress-bar',
			'buttons-wrapper': 		'buttons-wrapper',
			'delete-button':		'delete-btn',

			'default': 				'default-state',
			'begin':				'begin-state',
			'complete':				'complete-state',
			'error':				'error-state',
			'cancel':				'cancel-state'
		},
		'FilesList': {
			'main':					'files-list',
			'inner':				'files-list-inner'
		}
	},

	'ProgressBar': {
		'main': 'cpb',
		'inner': 'cpb-inner',
		'bar': 'cpb-bar'
	},

	'BarMenuGroup': {
		'main':		'bar-menu pkg',
		'inner':	'bar-menu-inner'
	},

	'PopupMenuGroup': {
		'main':		'popup-menu pkg',
		'inner':	'popup-menu-inner',
		'disabled':			'popup-menu-disabled',
		'invisible':		'popup-menu-invisible'
	}
};

ThemeData.Templates = {
	'DetailMessage': {
		'main': 'detail-message',
		'inner': 'main-content pkg',
		'icon': 'instruction-error pkg',
		'main-instruction': 'main-instruction pkg',
		'supp-instruction': 'supp-instruction pkg'
	},

	'SimpleMessage': {
		'main': 'simple-message',
		'inner': 'main-content pkg',
		'icon': 'instruction-error pkg',
		'message': 'message pkg'
	}
};

ThemeData.Editor = {
	'Button': {
        main:						'editor-btn',
		inner:						'editor-btn-inner',
		inside:						'editor-btn-inside',
		disabled:					'editor-btn-disabled',
		invisible:					'editor-btn-invisible',
		'inside-color':				'',
		'inside-text':				'editor-btn-inside-text',

		armedPressed:				'editor-btn-armed',
		focus:						'',
		armedFocus:					'editor-btn-armed',
		armed:						'editor-btn-armed',

	    'flat-left':				'',
		'flat-right':				'',
		'no-left-border':			'',
		'no-right-border':			''
	},
	'Window': {
		'wnd-title':				'editor-wnd-title',
		'wnd-content':				'editor-wnd-content'
	},
	'BackColorPicker': {
		'main':			'editor-bcp-main',
		'inside':		'editor-bcp-inside pkg',
		'main-btn':		'editor-bcp-main-btn',
		'arrow-btn':	'editor-bcp-arrow-btn'
	},
	'FontColorPicker': {
		'main':			'editor-fcp-main',
		'inside':		'editor-fcp-inside pkg',
		'main-btn':		'editor-fcp-main-btn',
		'arrow-btn':	'editor-fcp-arrow-btn'
	},
	'FloatColorButton': {
		'main':			'editor-fcb-main',
		'inside':		'editor-fcb-inside',
		'float-space':	'editor-fcb-fs',
		'float-color':	'editor-fcb-fc',

		disabled:					'editor-fcb-disabled',
		invisible:					'editor-fcb-invisible',

		armedPressed:				'editor-fcb-armed',
		armed:						'editor-fcb-armed'
	},
	'FontColorPickerBoard': {
		'main':			'editor-fcp-board-main',
		'inner':		'editor-fcp-board-inner',
		'theme-color-content-main':		'editor-fcp-board-color-content-main',
		'theme-color-content-sub':		'editor-fcp-board-color-content-sub',
		'standard-color-content':		'editor-fcp-board-standard-color-content'
	}
};

ThemeData.ColorBlock = {
	main:						'cblock',
	inner:						'cblock-inner',
	inside:						'cblock-inside',
	disabled:					'cblock-disabled',
	invisible:					'cblock-invisible',
	'inside-color':				'cblock-inside-color',

	armedPressed:				'cblock-armed',
	focus:						'',
	armedFocus:					'cblock-armed',
	armed:						'cblock-armed'
};

ThemeData.ColorBoard = {
	main:		'cboard',
	inner:		'cboard-inner',
	inside: 	'cboard-inside'
};
};filesWrapper['light.PE/Clothes/Components/ReGenTable.js'] = function(){
	loadFile('light.G/Components/GTable.js');
/*
Class: ReGenTable
	Component này thay thế cho <GTable> để tạo ra một component giống như table nhưng dựa trên cấu trúc html của table element có sẵn nhằm tránh phải vẽ lại quá nhiều

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ ReGenTable /* extends GTable */
= new Class({
	Extends: GTable,
	/*
	Function: initialize

	Arguments:
		options - (array) options đầu vào phù hợp với DefaultTableModel
		tableEl - (element) table element được dùng để base lên
		input - (mixed) Đầu vào của list, nếu là object thì phải là một Model tuân theo chuẩn <ListModel>, nếu không thì phải là một array chứa danh sách các giá trị dữ liệu của list. Không được phép null. Trong trường hợp thông thường dùng các view phổ biến đi kèm thường là truyền vào danh sách các dòng tr
		defaultIndices - (midex) Các giá trị được "select" mặc định
		selectionMode - (string) Chế độ select, có thể là: 'single', 'multiple'

	Return:
		(type) result
	*/
	initialize: function(options, tableEl, input, defaultIndices, selectionMode){
		if (!isset(tableEl)) getErrorConsole().throwError('Table element không thể là null');

		loadFile('light.PE/Clothes/Model/DefaultReGenTableModel.js');
		if ($type(input) == 'array') this.setModel(new DefaultReGenTableModel(input));
		else if ($type(input) == 'object') this.setModel(input);
		else if (!isset(input)) getErrorConsole().throwError('Không thể tạo được một List nếu không có dữ liệu đầu vào');

		this.setOptions(options);
		this.setTableEl(tableEl);
		loadFile('light.G/Model/DefaultListSelectionModel.js');
		this.setSelectionModel(new DefaultListSelectionModel());
		this.setSelectionMode(selectionMode);
		if (defaultIndices != null){
			if ($type(defaultIndices) == 'array') this.getSelectionModel().setSelectionIndices(defaultIndices);
			else if ($type(defaultIndices) == 'number') this.getSelectionModel().setSelectionIndices(new Array().include(defaultIndices));
			else getErrorConsole().throwError('Giá trị index mặc định của List không đúng');
		}
	},

	createDefaultView: function(){
		loadFile('light.PE/Clothes/Skin/BasicReGenTableView.js');
		return new BasicReGenTableView();
	},

	setTableEl: function(tableEl){
		this.getModel().setTableEl(tableEl);
	},

	getTableEl: function(){
		return this.getModel().getTableEl();
	}
});
};filesWrapper['light.PE/Clothes/Components/ReGenTable.SimpleVersion.js'] = function(){
	loadFile('light.PE/Clothes/Components/ReGenTable.js');
/* class */ ReGenTable.SimpleVersion /* extends ReGenTable */
= new Class({
	Extends: ReGenTable,
	createDefaultView: function(){
		loadFile('light.PE/Clothes/Skin/SimpleReGenTableView.js');
		return new SimpleReGenTableView();
	}
});
};filesWrapper['light.PE/Clothes/Components/ReGenTableRow.js'] = function(){
	loadFile('light.G/Comm/DefaultTableRowRenderer.js');
/*
Class: ReGenTableRow
	Dùng để vẽ row của <ReGenTable>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ ReGenTableRow /* extends DefaultTableRow */
= new Class({
	Extends: DefaultTableRow,
	initialize: function(options, rowEl){
		this.setModel(new ReGenTableRow.Model());
		this.setRowEl(rowEl);
		this.setOptions(options);
	},

	createDefaultView: function(){
		return new ReGenTableRow.View();
	},

	setRowEl: function(rowEl){
		this.getModel().setRowEl(rowEl);
	},

	getRowEl: function(){
		return this.getModel().getRowEl();
	}
});

/* class */ ReGenTableRow.Model /* extends DefaultTableRow.Model */
= new Class({
	Extends: DefaultTableRow.Model,
	rowEl: null,

	setRowEl: function(rowEl){
		this.rowEl = rowEl;
	},

	getRowEl: function(){
		return this.rowEl;
	}
});

/* class */ ReGenTableRow.View /* extends DefaultTableRow.View */
= new Class({
	Extends: DefaultTableRow.View,

	createDomElement: function(){
		this.domElement = this.getComponent().getRowEl();
		this.getComponent().attachWithElement(this.domElement);
	},

	getInsideContext: $empty,
	paintInside: $empty
});
};filesWrapper['light.PE/Clothes/Model/DefaultReGenTableModel.js'] = function(){
	loadFile('light.G/Model/DefaultListModel.js');
/* class */ DefaultReGenTableModel /* extends DefaultListModel */
= new Class({
	Extends: DefaultListModel,
	tableEl: null,

	setTableEl: function(tableEl){
		this.tableEl = tableEl;
	},

	getTableEl: function(){
		return this.tableEl;
	}
});
};filesWrapper['light.PE/Clothes/Skin/BasicReGenTableView.js'] = function(){
	loadFile('light.G/Skin/Basic/BasicCheckboxTableView.js');
/*
Class: BasicReGenTableView
	View mặc định dùng cho <ReGenTable> có nhiệm vụ chủ yếu là biến các checkbox element bình thường có trong table element thành <GCheckbox> sử dụng PE

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* class */ BasicReGenTableView /* extends BasicCheckboxTableView */
= new Class({
	Extends: BasicCheckboxTableView,
	checkboxPattern: null,

	initialize: function(checkboxPattern){
		this.parent();
		if (!isset(checkboxPattern)) this.checkboxPattern = 'input[type=checkbox]';
		else this.checkboxPattern = checkboxPattern;
	},

	createDomElement: function(){
        this.domElement = this.getComponent().getTableEl();
		this.getComponent().attachWithElement(this.domElement);
	},

	getInsideContext: $empty,

	paintRow: function(rowEl, index){
		var c = this.getComponent();
		loadFile('light.PE/Clothes/Components/ReGenTableRow.js');
		var row = new ReGenTableRow({
			baseCss: rowEl.get('class')
		}, rowEl);
		row.setIndex(index);
		row.setSelected(c.isSelectionIndex(index));
    	c.add(row);
    	c.addSubComponent(row, index);

    	rowEl.getElements(this.checkboxPattern).each(function(checkboxEl){
			var checkbox = GCheckbox.PE.createFromCheckboxEl(null, checkboxEl);
			checkbox.addChangeListener(BasicCheckboxTableView.CheckboxListener, row, c);
			row.addChangeListener(BasicCheckboxTableView.RowListener, c, checkbox);
    		row.addMouseListener(BasicCheckboxTableView.RowListener, c, checkbox);
    	});
	}
});
};filesWrapper['light.PE/Clothes/Skin/SimpleReGenTableView.js'] = function(){
	loadFile('light.PE/Clothes/Skin/BasicReGenTableView.js');
/* class */ SimpleReGenTableView /* extends BasicReGenTableView */
= new Class({
	Extends: BasicReGenTableView,

	paintRow: function(rowEl, index){
		var c = this.getComponent();
		loadFile('light.PE/Clothes/Components/ReGenTableRow.js');
		var row = new ReGenTableRow({
			baseCss: rowEl.get('class')
		}, rowEl);
		row.setIndex(index);
		row.setSelected(c.isSelectionIndex(index));
    	c.add(row);
    	c.addSubComponent(row, index);
    	rowEl.getElements(this.checkboxPattern).each(function(checkboxEl){
			loadFile('light.G/Components/GDomCheckbox.js');
			var checkbox = new GDomCheckbox(null, checkboxEl); // dùng DomCheckbox
			checkbox.paint();
			checkbox.addChangeListener(BasicCheckboxTableView.CheckboxListener, row, c);
			row.addChangeListener(BasicCheckboxTableView.RowListener, c, checkbox);
    		row.addMouseListener(BasicCheckboxTableView.RowListener, c, checkbox);
    	});
	}
});
};filesWrapper['light.PE/DomAdapters/Clothes/ReGenTable.PE.js'] = function(){
	loadFile('light.PE/Clothes/Components/ReGenTable.js');

/* static class */ ReGenTable.PE /* */
= new Hash({
	create: function(
		options, tableEl, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
		, checkboxPattern
	){
		tableEl = $(tableEl);
		var input = tableEl.getElements('tbody tr');
		var defaultIndices = new Array();
		if (!isset(checkboxPattern))
			checkboxPattern = 'input[type=checkbox]';

		input.each(function(rowEl, index){
			var checkboxEl = rowEl.getElement(checkboxPattern);
			if (checkboxEl != null)
				if (checkboxEl.get('checked')) defaultIndices.include(index);
		});

		if (!isset(options)) options = {};
		options.baseCss = tableEl.get('class');

		loadFile('light.PE/Clothes/Components/ReGenTable.js');
		var component = new ReGenTable(options, tableEl, input, defaultIndices, 'multiple');
		component.setView(new BasicReGenTableView(checkboxPattern));
		component.paint();
		return component;
	},

	setupSelectAllCheckbox: function(options, checkbox, table){
		if ($type(checkbox) == 'element'){
			loadFile('light.PE/DomAdapters/Components/GCheckbox.PE.js');
			var checkboxCpnt = GCheckbox.PE.createFromCheckbox(null, checkbox);
		}
		else
			var checkboxCpnt = checkbox;

		checkboxCpnt.addMouseListener(ReGenTable.PE.SelectAllCheckboxListener, table);
		checkboxCpnt.addChangeListener(ReGenTable.PE.SelectAllCheckboxListener, table);
		table.addListSelectionListener(ReGenTable.PE.SelectAllCheckboxTableListener, checkboxCpnt);
		return checkboxCpnt;
	},

	setupSelectAllCheckboxes: function(checkboxes, table){
		checkboxes.each(function(checkbox){
			this.setupSelectAllCheckbox(checkbox, table);
		});
	},

	setupTableComponent: function(component, table){
		if (table.getSelectionSize() == 0)
			component.setEnabled(false);

		table.addListSelectionListener(ReGenTable.PE.SingleComponentTableListener, component);
	},

	setupTableComponents: function(components, table){
		if (table.getSelectionSize() == 0)
			components.each(function(component){
				component.setEnabled(false);
			});

		table.addListSelectionListener(ReGenTable.PE.ComponentsTableListener, components);
	}
});

/* class */ ReGenTable.PE.SelectAllCheckboxListener /* implements MouseListener, ChangeListener */
= new Hash({
	mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, checkbox, table){
    	table.selectAll(checkbox.isSelected());
	},

    doubleClick: $empty,
	stateChanged: $empty
});

/* class */ ReGenTable.PE.SelectAllCheckboxTableListener /* implements ListSelectionListener */
= new Hash({
	valueChanged: function(e, table, checkbox){
		if (table.getDataSize() == table.getSelectionSize()) checkbox.setSelected(true);
		else checkbox.setSelected(false);
	}
});

/* class */ ReGenTable.PE.SingleComponentTableListener /* implements ListSelectionListener */
= new Hash({
	valueChanged: function(e, table, component){
		if (table.getSelectionSize() > 0) component.setEnabled(true);
		else component.setEnabled(false);
	}
});

/* class */ ReGenTable.PE.ComponentsTableListener /* implements ListSelectionListener */
= new Hash({
	valueChanged: function(e, table, components){
		var turnTo = (table.getSelectionSize() > 0) ? true : false;
		components.each(function(component){
			component.setEnabled(turnTo);
		});
	}
});
};filesWrapper['light.PE/DomAdapters/Clothes/ReGenTable.SimpleVersion.PE.js'] = function(){
	loadFile('light.PE/Clothes/Components/ReGenTable.SimpleVersion.js');
loadFile('light.PE/DomAdapters/Clothes/ReGenTable.PE.js');

/* static class */ ReGenTable.SimpleVersion.PE /*  */
= $H(ReGenTable.PE).extend({
	create: function(
		options, tableEl, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
		, rowPattern, checkboxPattern
	){
		tableEl = $(tableEl);
		if (!isset(rowPattern))
			rowPattern = 'tbody tr';

		var input = tableEl.getElements(rowPattern);

		var defaultIndices = new Array();
		if (!isset(checkboxPattern))
			checkboxPattern = 'input[type=checkbox]';

		input.each(function(rowEl, index){
			var checkboxEl = rowEl.getElement(checkboxPattern);
			if (isset(checkboxEl)) if (checkboxEl.get('checked')) defaultIndices.include(index);
		});

		if (!isset(options)) options = {};
		options.baseCss = tableEl.get('class');
		loadFile('light.PE/Clothes/Components/ReGenTable.SimpleVersion.js');
		var component = new ReGenTable.SimpleVersion(options, tableEl, input, defaultIndices, 'multiple');
		loadFile('light.PE/Clothes/Skin/SimpleReGenTableView.js');
		component.setView(new SimpleReGenTableView(checkboxPattern));
		component.paint();
		return component;
	},

	setupSelectAllCheckbox: function(options, checkboxEl, table){
		if ($type(checkboxEl) == 'element'){
			loadFile('light.G/Components/GDomCheckbox.js');
			var checkboxCpnt = new GDomCheckbox(null, checkboxEl);
			checkboxCpnt.paint();
		}
		else var checkboxCpnt = checkbox;

		checkboxCpnt.addMouseListener(ReGenTable.PE.SelectAllCheckboxListener, table);
		checkboxCpnt.addChangeListener(ReGenTable.PE.SelectAllCheckboxListener, table);
		table.addListSelectionListener(ReGenTable.PE.SelectAllCheckboxTableListener, checkboxCpnt);
		return checkboxCpnt;
	}
});

};filesWrapper['light.PE/DomAdapters/Components/GButton.PE.js'] = function(){
	loadFile('light.G/Components/GButton.js');
/*
Class: GButton.PE
	Class hỗ trợ để nhanh chóng tạo <GButton> theo cách PE

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ GButton.PE /* */
= new Hash({
	/*
	Function: create
		Tạo từ một button element có sẵn. Khi click vào component, coi như button thật được click. Text của component được lấy từ text của input. Nếu không set baseCss cho options, sẽ lấy class của input, nếu có, là kết hợp của cả hai. Tooltip là title của input element

	Arguments:
		options - (mixed) options của <GButton>
		buttonEl - (element) element của button cần tạo
	*/
	create: function(
		options, buttonEl, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
	){
		buttonEl = $(buttonEl);
		if (!isset(options)) options = {};
        if (isset(options.baseCss)) options.baseCss += ' ' + buttonEl.get('class');
        else options.baseCss = buttonEl.get('class');
        if (!isset(options.text)) options.text = buttonEl.get('text');
        if (!isset(options.id)) options.id = buttonEl.get('id');
		if (!isset(options.tooltip)) options.tooltip = buttonEl.get('title');
		buttonEl.set('title', null);
        var component = new GButton(options);
        component.setGraphicsContext({
			'inject': {
				'target': buttonEl,
				'position': 'before'
			}
		});
		component.paint();
		component.addMouseListener(GButton.PE.ButtonSynchronize, buttonEl);
		buttonEl.hide();
		return component;
	},

	createMany: function(
		options, components, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
	){
		var components = new Array();
		elements.each(function(element){
			var component = this.create(options, element, customModel, customView, customGraphicsContext);
			components.include(component);
		}.bind(this));

		return components;
	}
});

/* static class */ GButton.PE.ButtonSynchronize /* implements ChangeListener */
= new Hash({
	singleClick: function(e, button, buttonEl){
		if (button.isEnabled()){
			buttonEl.clickSimulate();
		}
	},

    mouseDown: $empty,
	mouseUp: $empty,
    doubleClick: $empty
});

};filesWrapper['light.PE/DomAdapters/Components/GCheckbox.PE.js'] = function(){
	loadFile('light.G/Components/GCheckbox.js');
/*
Class: GCheckbox.PE
	Class hỗ trợ việc tạo nhanh <GCheckbox> theo cách PE

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ GCheckbox.PE /* */
= new Hash({
	/*
	Function: create
		Tạo component từ một checkbox element có sẵn, lấy dữ liệu và thay thế vào vị trí của element này

	Arguments:
		options - (mixed) options của <GCheckbox>
		checkboxEl - (element) element của checkbox element cần tạo
	*/
	create: function(
		options, checkboxEl, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
	){
		checkboxEl = $(checkboxEl);
		if (!isset(options)) options = {};
        options.enabled = !checkboxEl.get('disabled');
        options.selected = checkboxEl.get('checked');
        var component = new GCheckbox(options);
        component.setGraphicsContext({
			'inject': {
				'target': checkboxEl,
				'position': 'before'
			}
		});
		component.paint();
		component.addChangeListener(GCheckbox.PE.Listener, checkboxEl);
		component.addMouseListener(GCheckbox.PE.Listener, checkboxEl);

        if (checkboxEl.get('id')){
			var checkboxLabel = $$('label[for=' + checkboxEl.get('id') + ']')[0];
			if (isset(checkboxLabel)){
				checkboxLabel.addEvent('click', function(e){
					e.preventDefault();
	                if (component.isEnabled()){
						component.toggleSelected();
					}
				});
			}
		}

		checkboxEl.hide();
		checkboxEl.setComponent(component);
		return component;
	}
});

/* static class */ GCheckbox.PE.Listener /* implements ChangeListener */
= new Hash({
	stateChanged: function(checkbox, property, value, checkboxEl){
		if (property == 'selected'){
			checkboxEl.set('checked', value);
		}
	},

	singleClick: function(e, checkbox, checkboxEl){
		checkboxEl.fireEvent('click');
	},

    mouseDown: $empty,
	mouseUp: $empty,
    doubleClick: $empty
});
};filesWrapper['light.PE/DomAdapters/Components/GComboBox.PE.js'] = function(){
	loadFile('light.G/Components/GComboBox.js');

/*
Class: GComboBox.PE
	Class hỗ trợ tạo nhanh một <GComboBox> theo cách PE

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ GComboBox.PE /* */
= new Hash({
	/*
	Function: create
		Tạo combo box thay thế cho một element select có sẵn, lấy dữ liệu từ options của element này và thay thế vào vị trí của nó. Nếu options không truyền chiều rộng, sẽ lấy chiều rộng là chiều rộng của element

	Arguments:
		options - (mixed) options của <GComboBox>
		selectEl - (element) element mà component sẽ lấy dữ liệu và thay thế
	*/
	create: function(options, selectEl){
		if (!isset(options)) options = {};
		selectEl = $(selectEl);
		var data = new Array();
		var currentKey = 0;
		var selectElOptions = $A(selectEl.options);
		$each(selectElOptions, function(singleOption, key){
			var tempOption = {
				'value': singleOption.value,
				'text': singleOption.text,
				'baseCss': isset(singleOption.className) ? singleOption.className : ''
			};
			data.include(tempOption);
			if (singleOption.selected && options.redrawText){
				currentKey = key;
			}
		});

		if (!isset(options.width)) options.width = selectEl.getSize().x;
		options.baseCss = selectEl.get('class');

		loadFile('light.G/Components/GList.js');
		var listBaseCss =
			!isset(selectEl.get('class')) ?
				'cbb-btn-list' :
				'cbb-btn-list' + ' ' + selectEl.get('class') + '-list';

		var simpleList = new GList({
			baseCss: listBaseCss
		}, data, currentKey, 'single');

        var component = new GComboBox(options, simpleList);
        component.setGraphicsContext({
			'inject': {
				'target': selectEl,
				'position': 'after'
			}
		});
		component.paint();
		component.getView().list.addListSelectionListener(GComboBox.PE.ListListener, selectEl);
		selectEl.hide();
		return component;
	}
});

/* static class */ GComboBox.PE.ListListener /* implements ListSelectionListener */
= new Hash({
    valueChanged: function(e, list, selectEl){
    	var firstIndex = e.getAddingIndices()[0];
		selectEl.selectedIndex = firstIndex;
		selectEl.fireEvent('change');
	}
});
};filesWrapper['light.PE/DomAdapters/Components/GDomButton.PE.js'] = function(){
	loadFile('light.G/Components/GDomButton.js');

/* static class */ GDomButton.PE /*  */
= new Hash({
	create: function(
		options, buttonEl, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
	){
		buttonEl = $(buttonEl);
		if (!isset(options)) options = {};
		options.enabled = !buttonEl.get('disabled');
		if (!isset(options.tooltip)) options.tooltip = buttonEl.get('title');
		if (!isset(options.baseCss)) options.baseCss = buttonEl.get('class');
		buttonEl.set('title', null); // xóa tooltip của inputEl
		var component = new GDomButton(options, buttonEl);
		component.paint();
		return component;
	},

	createMany: function(
		options, components, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
	){
		var components = new Array();
		elements.each(function(buttonEl){
			var btn = this.create(options, buttonEl, customModel, customView, customGraphicsContext);
			components.include(btn);
		}.bind(this));

		return components;
	}
});
};filesWrapper['light.PE/DomAdapters/Components/GDomCheckbox.PE.js'] = function(){
	loadFile('light.G/Components/GDomCheckbox.js');
/* static class */ GDomCheckbox.PE /* */
= new Hash({
	create: function(options, checkboxEl){
		checkboxEl = $(checkboxEl);
		if (!isset(options)) options = {};
		options.enabled = !checkboxEl.get('disabled');
        options.selected = checkboxEl.get('checked');
        if (!isset(options.tooltip)) options.tooltip = checkboxEl.get('title');

        var component = new GDomCheckbox(options, checkboxEl);
		component.paint();
		return component;
	}
});
};filesWrapper['light.PE/DomAdapters/Components/GRadioButton.PE.js'] = function(){
	loadFile('light.G/Components/GRadioButton.js');
loadFile('light.G/Workers/ButtonGroup.js');
/*
Class: GRadioButton.PE
	Class hỗ trợ cho việc tạo nhanh <GRadioButton> theo cách PE

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ GRadioButton.PE /* */
= new Hash({
	/*
	Function: createGroupByName
		Tạo ra một nhóm <GRadioButton> trong cùng một <ButtonGroup> thông qua tên của một nhóm input có cùng kiểu radio

	Arguments:
		options - (mixed) options sẽ được truyền vào cho <GRadioButton>
		name - (string) tên của nhóm input sẽ được dùng để lấy ra các element mà ta lấy dữ liệu và thay thế
	*/
	createGroupByName: function(options, name){
        if (!isset(options)) options = {};
        var thisBtnGrp = new ButtonGroup();
		$$('input[type=radio][name=' + name + ']').each(function(radioEl){
			options.enabled = !radioEl.get('disabled');
			options.selected = radioEl.get('checked');
			options.baseCss = radioEl.get('class');

            var ourCpnt = new GRadioButton(options);
	        ourCpnt.setGraphicsContext({
				'inject': {
					'target': radioEl,
					'position': 'before'
				}
			});
			thisBtnGrp.add(ourCpnt);
			ourCpnt.paint();

			if (isset(radioEl.get('id'))){
				var radioLabel = $$('label[for=' + radioEl.get('id') + ']')[0];
				if (isset(radioLabel)){
					radioLabel.addEvent('click', function(e){
						e.preventDefault();
	                    if (ourCpnt.isEnabled()){
							ourCpnt.setSelected(true);
						}
					});
				}
			}

			radioEl.hide();
			radioEl.setComponent(ourCpnt);

            ourCpnt.addChangeListener(GRadioButton.PE.Listener, radioEl);
			ourCpnt.addMouseListener(GRadioButton.PE.Listener, radioEl);
		});
	}
});

/* class */ GRadioButton.PE.Listener /* implements ChangeListener */
= new Hash({
	stateChanged: function(radioButton, property, value, radioEl){
		if (property == 'selected') radioEl.set('checked', value);
	},

	singleClick: function(e, radioButton, radioEl){
		radioEl.fireEvent('click');
	},

    mouseDown: $empty,
	mouseUp: $empty,
    doubleClick: $empty
});
};filesWrapper['light.PE/DomAdapters/Components/GTextArea.PE.js'] = function(){
	loadFile('light.G/Components/GTextArea.js');

/* static class */ GTextArea.PE /* */
= new Hash({
	createFromTextArea: function(
		options, textAreaEl, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
	){
		textAreaEl = $(textAreaEl);
		if (textAreaEl.get('tag') != 'textarea') return;
		if (!isset(options)) options = {};
        options.enabled = !textAreaEl.get('disabled');
		options.text = textAreaEl.get('value');
		if (!isset(options.tooltip)) options.tooltip = textAreaEl.get('title');
		textAreaEl.set('title', null); // xóa tooltip của inputEl
		var component = new GTextArea(options, textAreaEl);
		component.paint();
		return component;
	}
});
};filesWrapper['light.PE/DomAdapters/Controls/CtrlAutoCompleter.PE.js'] = function(){
	loadFile('light.Controls/AutoCompleter/CtrlAutoCompleter.js');

/* static class */ CtrlAutoCompleter.PE /* */
= new Hash({
	create: function(
		options, inputEl, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
	){
		inputEl = $(inputEl);
		if (inputEl.get('tag') != 'input' || (inputEl.get('type') != 'text' && inputEl.get('type') != 'password')){
			getErrorConsole().throwError('Không thể tạo CtrlInputField từ một input không phải text');
		}

		if (!isset(options)) options = {};
		options.enabled = !inputEl.get('disabled');
		options.text = inputEl.get('value');
		if (!isset(options.tooltip)) options.tooltip = inputEl.get('title');
		if (!isset(options.overText)) options.overText = inputEl.get('overtext');

		inputEl.set('title', null); // xóa tooltip của inputEl

		var component = new CtrlAutoCompleter(options, inputEl);
		if (isset(customModel)) component.setModel(customModel);
		if (isset(customGraphicsContext)) component.setGraphicsContext(customGraphicsContext);
		component.paint();
		return component;
	}
});
};filesWrapper['light.PE/DomAdapters/Controls/CtrlHtmlEditor.PE.js'] = function(){
	loadFile('light.Controls/HtmlEditor/CtrlHtmlEditor.js');

/* static class */ CtrlHtmlEditor.PE /* */
= new Hash({
	create: function(
		options, textAreaEl, customModel, customView, customGraphicsContext, customRenderer // các tham số mặc định cho các hàm PE
	){
		if (!isset(options)) options = {};
		options.enabled = !textAreaEl.get('disabled');
		options.text = textAreaEl.get('value');

		loadFile('light.G/Components/GTextArea.js');
		var textAreaCpnt = new GTextArea({
			text: textAreaEl.get('value')
		}, textAreaEl);

		var size = textAreaEl.getSize();
		var targetWidth = size.x;
		var targetHeight = size.y;
		options.width = targetWidth;
		options.height = targetHeight;

		//TODO -o NhanVC: Tính toán lại độ rộng

		var editor = new CtrlHtmlEditor(options, textAreaCpnt);
		if (isset(customRenderer)) editor.setSubComponentsRenderer(customRenderer);

		//if (isset(customView)) editor.setView(customView);

		editor.setOption('text', textAreaCpnt.getText());
		editor.setGraphicsContext({
			'inject': {
				'target': textAreaEl,
				'position': 'before'
			}
		});
		editor.paint();

		/*
        	Update & cleanup content trước khi submit
        */
		var form = textAreaEl.getParent('form');
		form.addEvent('submit', function(){
			if (editor.getMode() == 'iframe') editor.synchronize();
		});

		return editor;
	}
});
};filesWrapper['light.PE/DomAdapters/Controls/CtrlInputField.PE.js'] = function(){
	loadFile('light.Controls/InputField/CtrlInputField.js');

/* static class */ CtrlInputField.PE /* */
= new Hash({
	create: function(
		options, inputEl, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
	){
		inputEl = $(inputEl);
		if (inputEl.get('tag') != 'input' || (inputEl.get('type') != 'text' && inputEl.get('type') != 'password')){
			getErrorConsole().throwError('Không thể tạo CtrlInputField từ một input không phải text');
		}

		if (!isset(options)) options = {};
        options.enabled = !inputEl.get('disabled');
		options.text = inputEl.get('value');

		if (!isset(options.tooltip)) options.tooltip = inputEl.get('title');
		if (!isset(options.overText)) options.overText = inputEl.get('overtext');
		if (!isset(options.mainInstruction)) options.mainInstruction = inputEl.get('maininstruction');
		if (!isset(options.suppInstruction)) options.suppInstruction = inputEl.get('suppinstruction');
		if (isset(inputEl.get('valrules'))) options.valRules = JSON.decode(inputEl.get('valRules'));
		if (isset(inputEl.get('erroricon'))) options.errorIcon = JSON.decode(inputEl.get('erroricon'));
		if (isset(inputEl.get('tooltipicon'))) options.tooltipIcon = JSON.decode(inputEl.get('tooltipicon'));

		inputEl.set('title', null); // xóa tooltip của inputEl

		var component = new CtrlInputField(options, inputEl);
		var parentEl = inputEl.getParent();
		component.setGraphicsContext({
			'inject': {
				'target': parentEl,
				'position': 'top'
			}
		});
		component.paint();
		return component;
	}
});
};filesWrapper['light.PE/DomAdapters/Controls/CtrlMenuGroup.PE.js'] = function(){
	loadFile('light.Controls/MenuGroup/DefaultMenuItemRenderer.js');
/* class */ LinkMenuItemRenderer /* */
= $H(DefaultMenuItemRenderer).extend({
	createMenuItem: function(data){
		var link = data.link;
		loadFile('light.G/Components/GDomElement.js');
		var menuItem = new GDomElement(null, link);
		return menuItem;
	}
});

CtrlMenuGroup = {};

/* class */ CtrlMenuGroup.PE /* */
= new Hash({
	createFromList: function(options, list){
		if (!isset(options)) options = {};
		if (!isset(options.baseCss)) options.baseCss = list.get('class');
		
		var parseRow = function(row){
			var data = {};
			var link = row.getElement('a');

			data.link = link;
			var list = row.getElement('ul');
			if (list) {
				data.puCss = list.get('class');
				data.puPop = list.get('puPop');
				data.puAlign = list.get('puAlign');
				var subRows = list.getChildren('li');
				if (subRows.length){
					data.children = {};
					subRows.each(function(row, index){
						data.children[index] = parseRow(row);
					});
				}
			}

			return data;
		}
		var menuData = {};
		list.getChildren('li').each(function(row, index){
			var parsedData = parseRow(row);
			menuData[index] = parsedData;
		});

		menuData = $H(menuData);
		loadFile('light.Controls/MenuGroup/BarMenuGroup.js');
		var ctrl = new BarMenuGroup(options, menuData);
		ctrl.setMenuItemRenderer(LinkMenuItemRenderer);
		ctrl.setInsideMenuItemRenderer(LinkMenuItemRenderer);
		ctrl.setGraphicsContext({
			'inject': {
				'target': list,
				'position': 'after'
			}
		});
		ctrl.paint();
		list.destroy();
	}
});
};filesWrapper['light.PE/Forms/FormValidator.js'] = function(){
	/*
Class: FormValidator
	Có nhiệm vụ kết hợp với <CtrlInputField> để kiểm tra dữ liệu nhập vào của một form. Quá trình kiểm tra được thực hiện bằng cách lấy các input có trong form, lấy component tương ứng rồi gọi <CtrlInputField::validateRules>

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Options:
	stopOnFirstError - (boolean) Là true, chúng ta dừng ngay khi field đầu tiên có lỗi. Là false, chúng ta kiểm tra tất cả các lỗi của các field bên trong
*/
/* class */ FormValidator /* */
= new Class({
	Implements: [Options],
	formEl: null,
	options: {
		stopOnFirstError: true
	},

	initialize: function(formEl, options){
		this.setOptions(options);
		this.formEl = $(formEl);
		this.installEvents();
	},

	installEvents: function(){
		this.formEl.addEvent('submit', function(e){
			var passed = true;
			this.formEl.getElements('input[type=text],input[type=password]').each(function(inputEl){
				if (passed != false || !this.options.stopOnFirstError){
					var component = inputEl.getComponent();
					if (component){
						var result = component.validateRules();
						passed = passed && result;
					}
				}
			}.bind(this));

			return passed;
		}.bind(this));
	}
});
};filesWrapper['light.PE/Forms/Repeater.js'] = function(){
	/*
Class: Repeater
	Có nhiệm vụ làm cho một cấu trúc HTML lặp đi lặp để tiện cho các form gửi những thuộc tính có khả năng lặp lại nhiều lần

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.

Options:
	template - Element được dùng để làm template, không được null
	wrapper - Element được dùng để chứa các dòng mới
	round - Số lần lặp lại việc thêm dòng mới

Events:
	rowCreated - fire mỗi lần một row được tạo ra, đầu vào là newRow vừa tạo
	actionButtonClick - fire mỗi lần nút được ấn
*/
/* class */ Repeater /* */
= new Class({
	Implements: [Options,Events],
	/* private */ template: null,
	options: {
		template: null,
		wrapper: null,
		round: 3
	},

	initialize: function(options){
		this.setOptions(options);
		if (!isset(this.options.template)) getErrorConsole().throwError('Template phải là một element, không thể null');
		if (!isset(this.options.wrapper)) getErrorConsole().throwError('Wrapper phải là một element, không thể null');

		this.template = this.options.template.clone();
		this.template.getElements('input[type=text]').each(function(inputEl){
			inputEl.set('value', '');
		});

		this.template.getElements('select').each(function(selectEl){
			selectEl.selectedIndex = 0;
		});
	},

	/*
	Function: repeat
		Thực hiện việc thêm các dòng mới giống như template vào wrapper
	*/
	repeat: function(){
		for(var i=0;i < this.options.round;i++){
			var newRow = this.template.clone();
			newRow.inject(this.options.wrapper, 'bottom');
			this.fireEvent('rowCreated', [newRow]);
		}
		this.fireEvent('actionButtonClick');
	}
});
};filesWrapper['light.PE/Lifts/AutoGrowTextArea.js'] = function(){
	/*
* Flext - A Mootools Based Flexible TextArea Class
* version 1.1 - for mootools 1.2
* by Graham McNicoll
*
* Copyright 2008-2009 - Education.com
* License:	MIT-style license.
*
* Features:
*  - Grows text areas when needed
*  - Can set a max height to grow to
*  - Grows parents if they have a fixed height
*  - Ghost text replacement
*  - Text input emulation (enter can submit form, instead of new line)
*
* Usage:
*
*  include the source somewhere on your page. Textareas must have the class name: 'flext'
*  for the class to watch them. Use additional class names to trigger features.
*
*   'growme' -  grow the text area
*   'maxheight-[num]' - the max height to grow in pixels (replaces [num] )
*   'stopenter' - stop the enter key
*   'entersubmits' - submit the form when enter is pressed
*   'replaceghosttext' - tries to use the ghosted text features
*   'growparents' - grow the parent elements if needed
*
*  if replaceghosttext is on, then you need to add two more attributes to the textarea.
*  'ghosttext' contains a copy of the original ghost text (needed for matching initial conditions),
*  and 'ghostclass' which contains a class name to remove when the ghosting is removed (which
*  is used to remove ghosting color).
*
* Examples:
*
*  A simple growing text area: -
*
*    <textarea name='mytext' class='flext growme maxheight-200' ></textarea>
*
*   It will find this text area by the class name, 'flext', and the 'growme'
*   class will tell it to grow until the max size, as given by the 'maxheight-[num]'
*   class (integer, in pixels).
*
*  Textarea which will grow the parent elements (if needed) -
*
*    <textarea name='mytext' class='flext growme growparents maxheight-200' ></textarea>
*
*   This is the same as above, except it will also grow any parent elements which
*   have fixed heights when the textarea expands ('growparents').
*
*
* Adv. example:
*
*  <textarea name='mytext' class='flext growme stopenter entersubmits replaceghosttext ghost-text growparents maxheight-60' ghosttext='enter something here' ghostclass='ghost-text'>
*    enter something here
* </textarea>
*
*   This example not only grows, but simulates a text input, in that 'enter'
*   will not be passed to the textarea ('stopenter') instead it will submit
*   the form ('entersubmits'). It also has ghosted text replacement and class
*   changing. When this textarea receives focus, it will remove the default
*   text (ghosttext property), and remove the class as specified by the
*   ghostclass property. Use of these features as currently coded requires
*   non valid xhtml, so dont use it if you require valid markup. (its on my list to fix)
*
*  You can also instantiate this class manually, by leaving off the 'flext' class from
*  any textareas, and instantiate a new class usual with the first variable being the
*  textarea element, and the second the options object.
*/



AutoGrowTextArea = new Class({
	Implements: Options,
	options: {
		aniTime: 300, 					//int (ms) - grow animation time
		maxHeight: 0,					//int (pixels) - one way to set a max height, if you dont set it via the class.
		defaultMaxHeight: 1000,			//int (pixels) - if not otherwise set, this is the max height
		parentDepth: 6,				//int - how many levels up should to check the parent el's height.
		//trigger classes:
		growClass: 'growme',					//string (class name)- grow the text area
		enterStoppedClass: 'stopenter',			//string (class name)- stop the enter key
		enterSubmitsClass: 'entersubmits',			//string (class name)- submit the form when enter is pressed
		replaceGhostTextClass: 'replaceghosttext',	//string (class name)- tries to use the ghosted text features
		growParentsClass: 'growparents',			//string (class name)- grow the parent elements if needed
		//other attributes:
		ghostTextAttr: 'ghosttext',
		ghostClassAttr: 'ghostclass'
	},
	initialize: function(el, options) {
		this.setOptions(options);

		this.el = document.id(el); //the textarea element.

		//by default, we will do nothing to the text area unless it has the class...
		this.autoGrow = el.hasClass(this.options.growClass);
		this.stopEnter = el.hasClass(this.options.enterStoppedClass);
		this.enterSubmits = el.hasClass(this.options.enterSubmitsClass);
		this.useGhostText = el.hasClass(this.options.replaceGhostTextClass);
		this.growParents = el.hasClass(this.options.growParentsClass);

		//initialize, and add events:
		if(this.autoGrow) {
			this.resizer = new Fx.Tween(this.el, {duration: this.options.aniTime});
			this.getMaxSize();
			this.reachedMax = false;
			this.startSize = this.origSize = this.el.getSize().y;
			this.vertPadding = this.el.getStyle('padding-top').toInt()+this.el.getStyle('padding-bottom').toInt()+this.el.getStyle('border-top').toInt()+this.el.getStyle('border-bottom').toInt();
			this.el.setStyle('overflow', 'hidden');
			this.el.addEvents({
				'keyup': function(e) {
					this.checkSize(e);
				}.bind(this),
				'change': function(e) {
					this.checkSize(e);
				}.bind(this),
				'click': function(e) {
					this.checkSize(e);
				}.bind(this)
			});

			//get inital state:
			this.checkSize();
		}
		//watch this text area: keydown
		if(this.stopEnter) {
			this.el.addEvent('keydown', function(e) {
				if(e.key == 'enter') {
					e.stop();
					if(this.enterSubmits) {
						this.submitForm();
					}
				}
			}.bind(this));
		}
		//replace ghost text:
		if(this.useGhostText) {
			this.ghostText = this.el.get(this.options.ghostTextAttr);
			this.ghostClass = this.el.get(this.options.ghostClassAttr);
			if(this.ghostText) {
				//initial states: if populated with something else, remove the class:
				if(this.el.value != this.ghostText) {
					this.el.removeClass(this.ghostClass);
				}
				//add events to watch for ghosting:
				this.el.addEvents({
					//remove the ghosted text when the text area receives focus
					'focus': function(e) {
						if(this.el.value == this.ghostText) {
							this.el.set('value', '');
							if(this.ghostClass) {
								this.el.removeClass(this.ghostClass);
							}
						}
					}.bind(this),
					//put the ghost text back if blur'ed and its empty
					'blur': function(e) {
						if(this.el.value == '') {
							this.el.set('value', this.ghostText);
							if(this.ghostClass) {
								this.el.addClass(this.ghostClass);
							}
						}
					}.bind(this)
				});
			}
		}

	},
	getMaxSize: function() {
		this.maxSize = this.options.maxHeight;
		if(this.maxSize == 0) {
			var testmax = this.el.className.match(/maxheight-(\d*)/);
			if(testmax) {
				this.maxSize = testmax[1];
			}
			else {
				this.maxSize = this.options.defaultMaxHeight; //if one forgets to set a max height via options or class, use a reasonable number.
			}
		}
	},
	checkSize: function(e) {
		var theSize = this.el.getSize();
		var theScrollSize = this.el.getScrollSize();
		if(navigator.userAgent.toLowerCase().indexOf('chrome') > -1) { var checksize = (theScrollSize.y); }
		else var checksize = (theScrollSize.y+this.vertPadding);

		if(checksize > theSize.y) {
			//we are scrolling, so grow:
			this.resizeIt(theSize, theScrollSize);
		}
	},
	resizeIt: function(theSize, scrollSize) {
		var newSize = scrollSize.y;
		if((scrollSize.y+this.vertPadding) > this.maxSize && !this.reachedMax) {
			//we've reached the max size, grow to max size and make textarea scrollable again:
			newSize = this.maxSize;
			this.el.setStyle('overflow', '');
			this.resizer.start('height', newSize);
			if(this.growParents) {
				var increasedSize = newSize - this.startSize;
				this.resizeParents(this.el, 0, increasedSize);
			}
			//remember that we've reached the max size:
			this.reachedMax = true;
		}
		if(!this.reachedMax) {
			//grow the text area:
			var increasedSize = newSize - this.startSize;
			if(increasedSize < 0) increasedSize = 0;
			this.startSize = newSize;
			this.resizer.start('height', newSize);
			//resize parent objects if needed:
			if(this.growParents) {
				this.resizeParents(this.el, 0, increasedSize);
			}
		}
	},
	resizeParents: function(el, num, incSize) {
		if(num < this.options.parentDepth) {
			var newel = el.getParent();
			if(newel) {
				if(newel.style.height && newel.style.height != '' ) {
					if(newel.retrieve('flextAdjusted')) {
						var newheight = (newel.getStyle('height').toInt()+incSize);
					} else {
						newel.store('flextAdjusted', true); //when resizing parents, the first time we enlarge them we have to include vertical padding
						var newheight = (newel.getStyle('height').toInt()+incSize+this.vertPadding);
					}
					newel.setStyle('height', newheight);
				}
				return this.resizeParents(newel, (num+1), incSize);
			}
			return true;
		} else {
			return true;
		}
	},
	submitForm: function() {
		var thisForm = this.el.getParent('form');
		if(thisForm) {
			var formName = thisForm.get('name');
			document[formName].submit();

		}
	}
});
};filesWrapper['light.PE/Lifts/MiniGallery.js'] = function(){
	MiniGallery = new Class({
	Implements: [Events, Options],
	options: {
		id: 'DefaultMiniGallery',
		autoPlay: true,
		useButtons: true
	},

	singleContainer: false,
	alreadySetup: new Array(),

	// truyền vào nhiều containers nếu mỗi button sử dụng 1 container khác nhau
	// nếu truyền vào 1, tất cả button sẽ sử dụng chung container đó
	initialize: function(containers, buttons, options){
		this.setOptions(options);

		this.containers = containers;
		if ($type(containers) == 'array') this.singleContainer = false;
		else this.singleContainer = true;

		this.buttons = buttons;
		return this;
	},

	start: function(){
		if (this.options.useButtons)
			this.buttons.each(function(button, index){
				button.addEvent('click', function(e){
					e.preventDefault();
					this.show(index);
				}.bind(this));
			}.bind(this));

		if (this.options.autoPlay) this.show(0);
	},

	getContainer: function(index){
		if (!this.singleContainer)
			return this.containers[index];
		else return this.containers;
	},

	// hiển thị ảnh tương ứng với button có index đưa vào
	show: function(index){
		// nếu chỉ dùng 1 container
		if (this.singleContainer){
			this.getContainer(index).set('html', this.getHtml(index));
		}
		else {
			var bigImgLocation = this.buttons[index].get('href');
			// nếu đã setup rồi
			if (!this.alreadySetup[index]){
				this.getContainer(index).set('html', this.getHtml(index));
				this.alreadySetup[index] = true;
			}
		}
	},

	getClientStorageKey: function(index){
		return 'mgData__' + this.options.id + '__' + index;
	},

	getButton: function(index){
		return this.buttons[index];
	},

	getHtml: function(index){
		this.fireEvent('getHtml', [index]);

		if (isset(getClientStorage().get( this.getClientStorageKey(index) ))){
			return getClientStorage().get( this.getClientStorageKey(index) );
		}
		else {
			var bigImgLocation = this.buttons[index].get('href');
			return '<img src="' + bigImgLocation + '"/>';
		}
	}
});
};filesWrapper['light.PE/Lifts/SimpleCarousel.js'] = function(){
	/* Clientcide Copyright (c) 2006-2009, http://www.clientcide.com/wiki/cnet-libraries#license*/

//Contents: SimpleCarousel

//This lib: http://www.clientcide.com/js/build.php?excludeLibs[]=mootools-core&excludeLibs[]=mootools-more&require[]=SimpleCarousel&compression=none

/*
Script: SimpleCarousel.js

Builds a carousel object that manages the basic functions of a generic carousel (a carousel	here being a collection of "slides" that play from one to the next, with a collection of "buttons" that reference each slide).

License:
	http://www.clientcide.com/wiki/cnet-libraries#license

Document:
	http://www.clientcide.com/docs/Layout/SimpleCarousel
*/
SimpleCarousel = new Class({
	Implements: [Options, Events],
	options: {
//		onRotate: $empty,
//		onStop: $empty,
//		onAutoPlay: $empty,
//		onShowSlide: $empty,
		slideInterval: 4000,
		transitionDuration: 700,
		startIndex: 0,
		buttonOnClass: "selected",
		buttonOffClass: "off",
		rotateAction: "none",
		rotateActionDuration: 100,
		autoplay: true
	},
	initialize: function(container, slides, buttons, options){
		this.container = document.id(container);
		var instance = this.container.retrieve('SimpleCarouselInstance');
		if (instance) return instance;
		this.container.store('SimpleCarouselInstance', this);
		this.setOptions(options);
		this.container.addClass('hasCarousel');
		this.slides = $$(slides);
		this.buttons = $$(buttons);
		this.createFx();
		this.showSlide(this.options.startIndex);
		if (this.options.autoplay) this.autoplay();
		if (this.options.rotateAction != 'none') this.setupAction(this.options.rotateAction);
		return this;
	},
	toElement: function(){
		return this.container;
	},
	setupAction: function(action) {
		this.buttons.each(function(el, idx){
			document.id(el).addEvent(action, function() {
				this.slideFx.setOptions(this.slideFx.options, {duration: this.options.rotateActionDuration});
				if (this.currentSlide != idx) this.showSlide(idx);
				this.stop();
			}.bind(this));
		}, this);
	},
	createFx: function(){
		if (!this.slideFx) this.slideFx = new Fx.Elements(this.slides, {duration: this.options.transitionDuration});
		this.slides.each(function(slide){
			slide.setStyle('opacity',0);
		});
	},
	showSlide: function(slideIndex){
		var action = {};
		this.slides.each(function(slide, index){
			if (index == slideIndex && index != this.currentSlide){ //show
				if (document.id(this.buttons[index])) document.id(this.buttons[index]).swapClass(this.options.buttonOffClass, this.options.buttonOnClass);
				action[index.toString()] = {
					opacity: 1
				};
			} else {
				if (document.id(this.buttons[index])) document.id(this.buttons[index]).swapClass(this.options.buttonOnClass, this.options.buttonOffClass);
				action[index.toString()] = {
					opacity:0
				};
			}
		}, this);
		this.fireEvent('onShowSlide', slideIndex);
		this.currentSlide = slideIndex;
		this.slideFx.start(action);
		return this;
	},
	autoplay: function(){
		this.slideshowInt = this.rotate.periodical(this.options.slideInterval, this);
		this.fireEvent('onAutoPlay');
		return this;
	},
	stop: function(){
		$clear(this.slideshowInt);
		this.fireEvent('onStop');
		return this;
	},
	rotate: function(){
		var current = this.currentSlide;
		var next = (current+1 >= this.slides.length) ? 0 : current+1;
		this.showSlide(next);
		this.fireEvent('onRotate', next);
		return this;
	}
});
};filesWrapper['light.PE/Lifts/SimplePopUnder.js'] = function(){
	/*
Class: SimplePopUnder
	Một custom đơn giản để biến một element có liên kết với một popup element khác, sẽ xuất hiện tại vị trí của element khi di chuột qua

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/

/* static class */ SimplePopUnder /*  */
= new Hash({
	setup: function(el, popup, delayTime, align, pop, offsetX, offsetY){
		if (!isset(delayTime)) delayTime = 300;
		if (!isset(align)) align = 'left';
		if (!isset(pop)) pop = 'bottom';

		loadFile('light.G/Components/GDomLayer.js');
		var popupObj = new GDomLayer(null, popup);
		popupObj.setGraphicsContext({
			'inject': {
				'target': document.body,
				'position': 'bottom'
			},
			'stackpos': {
				'target': el,
				'pop': pop,
				'align': align,
				'offsetX': offsetX,
				'offsetY': offsetY
			}
		});
		popupObj.paint();
		GFactory.getLayerManager().bringLayerToFront(popupObj);
		popupObj.getElement().setStyle('display', 'none');

		el.store('popupObj', popupObj);
		popupObj.btn = el;

		el.addEvents({
			'mouseenter': function(e){
				var timer = el.retrieve('timer');
				if (isset(timer)) timer.stop();

				loadFile('core/IdleTimer.js');
				timer = new IdleTimer(delayTime);
				timer.addEvent('complete', function(){
					var popupObj = el.retrieve('popupObj');
					if (isset(popupObj)){
						popupObj.repaint();
						popupObj.getElement().setStyle('display', 'block');
						GFactory.getLayerManager().bringLayerToFront(popupObj);
						el.setStyles({
							'z-index': GFactory.getLayerManager().getNextIndex()
						});
					}

					el.setStyle('position', 'relative');
					el.addClass('popup-showing');
					var theClass = el.get('class').split(' ')[0];
					el.addClass(theClass + '-popup-showing');
				});
				timer.start();
				timer.idle();
			},
			'mouseleave': function(e){
				var popupObj = el.retrieve('popupObj');
				if (!isset(popupObj)) return;

				var timer = el.retrieve('timer');
				if (!isset(timer)){
					loadFile('core/IdleTimer.js');
					timer = new IdleTimer(delayTime);
					timer.addEvent('complete', function(){
						popupObj.getElement().setStyle('display', 'none');
						el.setStyle('position', null);
						el.removeClass('popup-showing');
						var theClass = el.get('class').split(' ')[0];
						el.removeClass(theClass + '-popup-showing');
					});
					el.store('timer', timer);
				}

				timer.start();
				timer.idle();
			}
		});

		popupObj.getElement().addEvents({
			'mouseenter': function(e){
				var el = popupObj.btn;
				var timer = el.retrieve('timer');
				if (isset(timer)) timer.stop();
			},
			'mouseleave': function(e){
				var el = popupObj.btn;
				var timer = el.retrieve('timer');
				if (isset(timer)) timer.reset();
			}
		})
	}
});
};filesWrapper['light.PE/Lifts/SimpleTabs.js'] = function(){
	/* static class */ SimpleTabs /*  */
= new Hash({
	setCurrent: function(tabs, contents, currentKey){
		$each(tabs, function(value, key){
			if (key == currentKey) {
				value.addClass('current');
				contents[key].show();
			}
			else {
				value.removeClass('current');
				contents[key].hide();
			}
		});
	},

	setup: function(tabs, contents){
		$each(tabs, function(value, key){
			if (key == 0){
				value.addClass('current');
				contents[key].show();
			}
			else {
				value.removeClass('current');
				contents[key].hide();
			}
			
			value.addEvent('click', function(){
				SimpleTabs.setCurrent(tabs, contents, key);
			});
		})
	}
});
};filesWrapper['light.PE/_deprecated/CtrlHtmlEditor.PE.js'] = function(){
	loadFile('light.G/Controls/HtmlEditor/CtrlHtmlEditor.js');
/*
Class: CtrlHtmlEditor.PE
	Class hỗ trợ việc tạo <CtrlHtmlEditor> theo cách PE

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ CtrlHtmlEditor.PE /* */
= new Hash({
	/*
	Function: createFromTextArea
		Tạo control từ một textarea HTML có sẵn và chèn control vào trước textarea. Tất cả dữ liệu của control sẽ được đồng bộ với textarea, kể cả khi submit form đi

	Arguments:
		options - (mixed) options dành cho <CtrlHtmlEditor>
		textArea - (element) element của textarea trong form HTML thông thường
	*/
	createFromTextArea: function(options, textArea){
		if (options == null){
			options = {};
		}

		loadFile('light.G/Components/GTextArea.js');
		var textAreaCpnt = new GTextArea({
			text: textArea.get('value')
		},textArea);

		var size = textArea.getSize();
		var targetWidth = size.x;
		var targetHeight = size.y;
		options.width = targetWidth;
		options.height = targetHeight;

		var ourCtrl = new CtrlHtmlEditor(
			options,
			textAreaCpnt
		);
		ourCtrl.setOption('text', textAreaCpnt.getText());
		ourCtrl.setGraphicsContext({
			'inject': {
				'target': textArea,
				'position': 'before'
			}
		});
		ourCtrl.paint();

		/*
			Bổ sung WindowListener cho ourCtrl để lắng nghe window resize
			để đảm bảo khi window resize thì editor được resize theo
		*/
		ourCtrl.addWindowListener(new Hash({
            wndBlur: $empty,
			wndFocus: $empty,
			wndLoad: $empty,

			wndResize: function(e, editor){
		        if (editor.getMode() == 'iframe'){
		            editor.toggleMode();
		            var size = textArea.getSize();
					var targetWidth = size.x;
					var targetHeight = size.y;
		            editor.setNewOptions({
		                'width': targetWidth,
		                'height': targetHeight
					});
		            editor.toggleMode();
		        }
		        else {
		            var size = textArea.getSize();
					var targetWidth = size.x;
					var targetHeight = size.y;
		            editor.setNewOptions({
		                'width': targetWidth,
		                'height': targetHeight
					});
		        }
			},

			wndScroll: $empty,
			wndBeforeUnload: $empty,
			wndUnload: $empty
		}));

        /*
        	Update & cleanup content trước khi submit
        */
		var form = textArea.getParent('form');
		form.addEvent('submit', function(){
			if (ourCtrl.getMode() == 'iframe') ourCtrl.synchronize();
		});

		return ourCtrl;
	}
});
};filesWrapper['light.PE/_deprecated/GRadioButton.PE.js'] = function(){
	loadFile('light.G/Components/GRadioButton.js');
loadFile('light.G/Workers/ButtonGroup.js');
/*
Class: GRadioButton.PE
	Class hỗ trợ cho việc tạo nhanh <GRadioButton> theo cách PE

	Author - hitori_vodanh (<nhanvc@vsmc.vn>)
	Copyright - Copyright (c) 2008-2009 Vietnam Social Media Corporation, http://vsmc.vn.
*/
/* static class */ GRadioButton.PE /* */
= new Hash({
	/*
	Function: createGroupByName
		Tạo ra một nhóm <GRadioButton> trong cùng một <ButtonGroup> thông qua tên của một nhóm input có cùng kiểu radio

	Arguments:
		options - (mixed) options sẽ được truyền vào cho <GRadioButton>
		name - (string) tên của nhóm input sẽ được dùng để lấy ra các element mà ta lấy dữ liệu và thay thế
	*/
	createGroupByName: function(options, name){
        if (options == null){
        	options = {}
        }

        var thisBtnGrp = new ButtonGroup();

		$$('input[type=radio][name=' + name + ']').each(function(radioEl){
			options.enabled = !radioEl.get('disabled');
			options.selected = radioEl.get('checked');
            var ourCpnt = new GRadioButton(options);
	        ourCpnt.setGraphicsContext({
				'inject': {
					'target': radioEl,
					'position': 'before'
				}
			});
			thisBtnGrp.add(ourCpnt);
			ourCpnt.paint();

			if (radioEl.get('id')){
				var radioLabel = $$('label[for=' + radioEl.get('id') + ']')[0];
				if (isset(radioLabel)){
					radioLabel.addEvent('click', function(e){
						e.preventDefault();
	                    if (ourCpnt.isEnabled()){
							ourCpnt.setSelected(true);
						}
					});
				}
			}

			radioEl.hide();
			radioEl.setComponent(ourCpnt);

            ourCpnt.addChangeListener(GRadioButton.PE.Listener, radioEl);
			ourCpnt.addMouseListener(GRadioButton.PE.Listener, radioEl);
		});
	}
});

/* class */ GRadioButton.PE.Listener /* implements ChangeListener */
= new Hash({
	stateChanged: function(radioButton, property, value, radioEl){
		if (property == 'selected'){
			radioEl.set('checked', value);
		}
	},

	singleClick: function(e, radioButton, radioEl){
		radioEl.fireEvent('click');
	},

    mouseDown: $empty,
	mouseUp: $empty,
    doubleClick: $empty
});
};filesWrapper['light.PE/_deprecated/GTable.PE.js'] = function(){
	GTable.BasicReGenTable = {};

/* static class */ GTable.BasicReGenTable.PE /* */
= new Hash({
	createFromTable: function(
		options, tableEl, customModel, customView, customGraphicsContext // các tham số mặc định cho các hàm PE
		, checkboxPattern
	){
		tableEl = $(tableEl);
		var input = tableEl.getElements('tbody tr');
		var defaultIndices = new Array();
		if (!isset(checkboxPattern))
			checkboxPattern = 'input[type=checkbox]';

		input.each(function(rowEl, index){
			var checkboxEl = rowEl.getElement(checkboxPattern);
			if (checkboxEl != null)
				if (checkboxEl.get('checked')) defaultIndices.include(index);
		});

		if (!isset(options)) options = {};
		options.baseCss = tableEl.get('class');

		loadFile('light.PE/Clothes/Components/ReGenTable.js');
		var component = new ReGenTable(options, tableEl, input, defaultIndices, 'multiple');
		component.setView(new BasicReGenTableView(checkboxPattern));
		component.paint();
		return component;
	},

	setupSelectAllCheckbox: function(options, checkbox, table){
		if ($type(checkbox) == 'element'){
			loadFile('light.PE/Components/GCheckbox.PE.js');
			var checkboxCpnt = GCheckbox.PE.createFromCheckbox(null, checkbox);
		}
		else
			var checkboxCpnt = checkbox;

		checkboxCpnt.addMouseListener(GTable.PE.SelectAllCheckboxListener, table);
		checkboxCpnt.addChangeListener(GTable.PE.SelectAllCheckboxListener, table);
		table.addListSelectionListener(GTable.PE.SelectAllCheckboxTableListener, checkboxCpnt);
		return checkboxCpnt;
	},

	setupSelectAllCheckboxes: function(checkboxes, table){
		checkboxes.each(function(checkbox){
			GTable.PE.setupSelectAllCheckbox(checkbox, table);
		});
	},

	setupTableComponent: function(component, table){
		if (table.getSelectionSize() == 0){
			component.setEnabled(false);
		}

		table.addListSelectionListener(GTable.PE.ComponentTableListener, component);
	},

	setupTableComponents: function(components, table){
		components.each(function(component){
			GTable.PE.setupTableComponent(component, table);
		});
	}
});

/* class */ GTable.PE.SelectAllCheckboxListener /* implements MouseListener, ChangeListener */
= new Hash({
	mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, checkbox, table){
    	table.selectAll(checkbox.isSelected());
	},

    doubleClick: $empty,
	stateChanged: $empty
});

/* class */ GTable.PE.SelectAllCheckboxTableListener /* implements ListSelectionListener */
= new Hash({
	valueChanged: function(e, table, checkbox){
		if (table.getDataSize() == table.getSelectionSize()) checkbox.setSelected(true);
		else checkbox.setSelected(false);
	}
});

/* class */ GTable.PE.ComponentTableListener /* implements ListSelectionListener */
= new Hash({
	valueChanged: function(e, table, component){
		if (table.getSelectionSize() > 0) component.setEnabled(true);
		else component.setEnabled(false);
	}
});
};filesWrapper['light.PE/_deprecated/GTextField.PE.js'] = function(){
	loadFile('light.G/Components/GTextField.js');

/* static class */ GTextField.PE /* */
= new Hash({
	createFromInputEl: function(options, inputEl){
		inputEl = $(inputEl);
		if (inputEl.get('type') != 'text'){
			return;
		}

        if (options == null){
        	options = {}
        }

        options.enabled = !inputEl.get('disabled');

		options.text = inputEl.get('value');

		if (options.tooltip == null){
			options.tooltip = inputEl.get('title');
		}

		if (options.overText == null){
			options.overText = inputEl.get('overtext');
		}

		inputEl.set('title', null); // xóa tooltip của inputEl

		var textFieldCpnt = new GTextField(options, inputEl);
		textFieldCpnt.paint();
		return textFieldCpnt;
	}
});
};filesWrapper['light.PE/_deprecated/GToggleButton.PE.js'] = function(){
	loadFile('light.G/Components/GToggleButton.js');
loadFile('light.G/Workers/ButtonGroup.js');

/* static class */ GToggleButton.PE /* */
= new Hash({
	createFromElement: function(options, element, optionalView){
		element = $(element);

		if (!['a', 'button'].contains(element.get('tag'))){
			getErrorConsole().throwError('Element loại này không được support bởi GToggleButton.PE');
		}

        if (options == null) options = {};
        if (options.baseCss != null) options.baseCss += ' ' + element.get('class');
        else options.baseCss = element.get('class');

        if (options.text == null) options.text = element.get('text');
        if (options.id == null) options.id = element.get('id');
		if (options.tooltip == null) options.tooltip = element.get('title');

        var ourCpnt = new GToggleButton(options);
        if (optionalView != null){
			ourCpnt.setView(optionalView);
        }

        ourCpnt.setGraphicsContext({
			'inject': {
				'target': element,
				'position': 'before'
			}
		});
		ourCpnt.paint();
		ourCpnt.addMouseListener(GToggleButton.PE.SimulateClickListener, element);

		element.hide();
		return ourCpnt;
	},

	createGroupUsingSelector: function(options, selector, selectedElement, optionalView){
		if ($type(selector) == 'string'){
			var elements = $$(selector);
		}
		else if ($type(selector) == 'array'){
			var elements = selector;
		}
		else if ($type(selector) == 'element'){
			var elements = new Array();
			elements.include(selector);
		}

		var buttons = new Array();
		var buttonGroup = new ButtonGroup();

		elements.each(function(element, index){
			if (options != null) var realOptions = $merge(options); else var realOptions = null;
			if (optionalView != null) var realOptionalView = $merge(optionalView); else var realOptionalView = null;

			var button = this.createFromElement(realOptions, element, realOptionalView);
			buttons.include(button);
			buttonGroup.add(button);

			if (element == selectedElement){
				button.setSelected(true);
			}
		}.bind(this))
	}
});

/* class */ GToggleButton.PE.SimulateClickListener /* implements MouseListener */
= new Hash({
	singleClick: function(e, button, element){
		if (button.isEnabled()){
			element.clickSimulate();
		}
	},

    mouseDown: $empty,
	mouseUp: $empty,
    doubleClick: $empty
});
};filesWrapper['acc/bridge.js'] = function(){
	GFactory.getResourceManager().installTheme('Acc', 'acc/resources/themes/Acc.js');
};filesWrapper['acc/custom/AccBalloonView.js'] = function(){
	loadFile('light.Controls/Balloon/BasicBalloonView.js');
/* class */ AccBalloonView /* extends BasicBalloonView */
= new Class({
	Extends: BasicBalloonView,
	themePath: '/Acc/Balloon/',

	getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElementByTheme('layer6'),
				'position': 'bottom'
			}
		});
	},

	createDomElement: function(){
		this.domElement = new Element('div', {
			'class': this.getTheme('main') + ' ' + this.getComponent().getOption('baseCss')
		}).set('html',
'<div class="' + this.getTheme('layer2') + '">' +
	'<div class="' + this.getTheme('layer3') + '">' +
		'<div class="' + this.getTheme('layer4') + '">' +
			'<div class="' + this.getTheme('layer5') + '">' +
				'<div class="' + this.getTheme('layer6') + '">' +
				'</div>' +
			'</div>' +
		'</div>' +
	'</div>' +
'</div>'
		);

		this.getComponent().attachWithElement(this.domElement);
	}
});
};filesWrapper['acc/custom/AccConfirm.js'] = function(){
	AccConfirm = new Class({
	Implements: [Options, Events],
	Binds: ['yesClicked', 'noClicked'],
	options: {
		id: 'askforfun',
		message: 	'Message gì đó ha',
		lang_yes: 	'Có',
		lang_no:	'Không',
		lang_save: 	'Ghi nhớ lựa chọn này'
	},
	balloonContent: null,
	balloonObj: null,

	initialize: function(options){
		this.setOptions(options);

		if (HelpersFactory.getCookiesHelper().read('save_' + this.options.id)){
			this.doYesClicked();
			return;
		}

		loadFile('light.Controls/Balloon/CtrlBalloon.js');
		this.balloonObj = new CtrlBalloon({
			fadeOutTime: null,
			baseCss: 'confirm',
			left: GFactory.getPaint().getMiddleLeft(300),
			top: GFactory.getPaint().getMiddleTop(100)
		});
		loadFile('acc/custom/AccDialogView.js');
		this.balloonObj.setView(new AccDialogView());
		loadFile('light.G/Components/GDomElement.js');
		this.balloonContent = new Element('div').set('html',
'<div class="message">' + this.options.message + '</div>' +
'<div class="submit-row pkg">' +
	'<button type="button" class="ok">' + this.options.lang_yes + '</button>' +
	'<button type="button" class="cancel">' + this.options.lang_no + '</button>' +
	'<div class="remember pkg">' +
		'<input type="checkbox" class="save"/><label>' + this.options.lang_save  + '</label>' +
	'</div>' +
'</div>'
		);

		this.balloonContent.getElement('button.ok').addEvent('click', this.yesClicked);
		this.balloonContent.getElement('button.cancel').addEvent('click', this.noClicked);
		this.balloonObj.add(new GDomElement(null, this.balloonContent));
		this.balloonObj.paint();
	},

	noClicked: function(){
		this.balloonObj.destroy();
	},

	yesClicked: function(){
		var saveChoice = this.balloonContent.getElement('input[type=checkbox]').get('checked');
		if (saveChoice) HelpersFactory.getCookiesHelper().write('save_' + this.options.id, true);
		else HelpersFactory.getCookiesHelper().dispose('save_' + this.options.id);
		this.doYesClicked();
	},

	doYesClicked: function(){
		if (isset(this.balloonObj))
			this.balloonObj.destroy();
	}
});

AccConfirm.Link = new Class({
	Extends: AccConfirm,
	linkEl: null,
	options: {
		type: 'lad'
	},

	initialize: function(options, linkEl){
		if (!isset(linkEl))
			getErrorConsole().throwNew('Không tồn tại link');

		this.linkEl = linkEl;
		this.parent(options);
	},

	doYesClicked: function(){
		if (this.options.type == 'lad'){
			loadFile('light.Ajax/lad/Request.Light.Lad.js');
			new Request.Light.Lad({
				url: this.linkEl.get('href')
			}).send();
		}
		else {
			document.location = linkEl.get('href');
		}

		this.parent();
	}
});

AccConfirm.Form = new Class({
	Extends: AccConfirm,
	formEl: null,
	options: {
		type: 'lad'
	},

	initialize: function(options, formEl){
		if (!isset(formEl))
			getErrorConsole().throwNew('Không tồn tại link');
		this.formEl = formEl;
		this.parent(options);
	},

	doYesClicked: function(){
		if (this.options.type == 'lad'){
			AjaxFactory.getLadFormPool().push(this.formEl);
			this.formEl.submitLad();
		}
		else this.formEl.submit();
		this.parent();
	}
});
};filesWrapper['acc/custom/AccDialogView.js'] = function(){
	loadFile('acc/custom/AccBalloonView.js');
/* class */ AccDialogView /* extends AccBalloonView */
= new Class({
	Extends: AccBalloonView,
	themePath: '/Acc/Dialog/',

	install: function(){
		this.parent();
		this.getElementByTheme('close').addEvent('click', function(){
			this.getComponent().destroy();
		}.bind(this));
	},

	getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElementByTheme('layer5'),
				'position': 'bottom'
			}
		});
	},

/*
<div class='main baseCss'>
	<div class='layer2'>
		<div class='layer3'>
			<div class='layer4'>
				<button class='close'>Đóng</button>
				<div class='layer5'>
				</div>
			</div>
		</div>
	</div>
</div>
*/
	createDomElement: function(){
		this.domElement = new Element('div', {
			'class': this.getTheme('main') + ' ' + this.getComponent().getOption('baseCss')
		}).set('html',
'<div class="' + this.getTheme('layer2') + '">' +
	'<div class="' + this.getTheme('layer3') + '">' +
		'<div class="' + this.getTheme('layer4') + '">' +
			'<button class="' + this.getTheme('close') + '">' +
			'Đóng</button>' +
			'<div class="' + this.getTheme('layer5') + '">' +
			'</div>' +
		'</div>' +
	'</div>' +
'</div>'
		);

		this.getComponent().attachWithElement(this.domElement);
	}
});
};filesWrapper['acc/custom/AccInputColorWithBoard.js'] = function(){
	loadFile('light.Controls/ColorChooser/CompInputColorWithBoard.js');

/* class */ AccInputColorWithBoard /* extends CompInputColorWithBoard */
= new Class({
	Extends: CompInputColorWithBoard,

	initialize: function(options){
		this.setModel(new AccInputColorWithBoard.Model());
		this.setOptions(options);
	},

	createDefaultView: function(){
    	return new AccInputColorWithBoard.View();
	}
});

/* class */ AccInputColorWithBoard.View /* extends CompInputColorWithBoard.View */
= new Class({
	Extends: CompInputColorWithBoard.View,
	themePath: '/Acc/InputColorWithBoard/',

	paintColorBoard: function(){
		var c = this.getComponent();
		loadFile('light.Controls/ColorChooser/CompColorBoard.js');
		this.colorBoard = new CompColorBoard({
			colors: c.getOption('boardColors'),
			css: c.getOption('boardCss'),
			context: c.getOption('boardContext')
    	});
		this.colorBoard.setView(new AccInputColorWithBoard.ColorBoardView());
	}
});

/* class */ AccInputColorWithBoard.Model /* extends CompColorPickerFromBoard.Model */
= new Class({
	Extends: CompColorPickerFromBoard.Model,
	options: {
		boardColors: {
			baseColor: ['ffffff', '000000', 'eeece1', '1f497d', '4f81bd', 'c0504d', '9bbb59', '8064a2', '4bacc6', 'f79646'],
			firstRow: 	['f2f2f2', '7f7f7f', 'ddd9c3', 'c6d9f0', 'dbe5f1', 'f2dcdb', 'ebf1dd', 'e5e0ec', 'dbeef3', 'fdeada'],
			secondRow: 	['d8d8d8', '595959', 'c4bd97', '8db3e2', 'b8cce4', 'e5b9b7', 'd7e3bc', 'ccc1d9', 'b7dde8', 'fbd5b5'],
			thirdRow: 	['bfbfbf', '3f3f3f', '938953', '548dd4', '95b3d7', 'd99694', 'c3d69b', 'b2a2c7', '92cddc', 'fac08f'],
			fourthRow: 	['a5a5a5', '262626', '494429', '17365d', '366092', '953734', '76923c', '5f497a', '31859b', 'e36c09'],
			fifthRow: 	['7f7f7f', '0c0c0c', '1d1b10', '0f243e', '244061', '632423', '4f6128', '3f3151', '205867', '974806'],
			standardColors:	['c00000', 'ff0000', 'ffc000', 'ffff00', '92d050', '00b050', '00b0f0', '0070c0', '002060', '7030a0']
		},
		boardCss: {
			baseColor: 'base-colors',
			firstRow: 'first-row',
			secondRow: 'second-row',
			thirdRow: 'third-row',
			fourthRow: 'fourth-row',
			fifthRow: 'fifth-row',
			standardColors: 'standard-colors'
		},
		boardContext: {
			baseColor: 'theme-color-content-main',
			firstRow: 'theme-color-content-sub',
			secondRow: 'theme-color-content-sub',
			thirdRow: 'theme-color-content-sub',
			fourthRow: 'theme-color-content-sub',
			fifthRow: 'theme-color-content-sub',
			standardColors: 'standard-color-content'
		}
	}
});

loadFile('light.Controls/ColorChooser/CompColorBoard.js');
/* class */ AccInputColorWithBoard.ColorBoardView /* extends CompColorBoard.View */
= new Class({
	Extends: CompColorBoard.View,
	themePath: '/Acc/InputColorBoard/',

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
			'class': this.getTheme('main')
		}).grab(
			new Element('div', {
				'class': this.getTheme('inner')
			}).grab(
				new Element('div', {
					'class': this.getTheme('theme-color-content-main') + ' pkg'
				})
			).grab(
				new Element('div', {
					'class': this.getTheme('theme-color-content-sub') + ' pkg'
				})
			).grab(
				new Element('div', {
					'class': this.getTheme('standard-color-content') + ' pkg'
				})
			)
		);

		c.attachWithElement(this.domElement);
	}
});
};filesWrapper['acc/custom/AccSimpleProgressBarView.js'] = function(){
	loadFile('light.Controls/ProgressBar/BasicProgressBarView.js');

AccSimpleProgressBarView = new Class({
	Extends: BasicProgressBarView,
	themePath: '/Acc/SimpleProgressBar/',

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		});
		c.attachWithElement(this.domElement);
	},

	paintProgress: function(){
        var c = this.getComponent();
        if (this.compareState('progress')){
        	this.getElement().setStyles({
        		'width': c.getOption('progress') + '%'
        	});
		}
	}
});
};filesWrapper['acc/custom/AccSingleUploaderView.js'] = function(){
	loadFile('light.Controls/FU/FuView.js');

/* class */ AccSingleUploaderView /* extends FuView */
= new Class({
	Extends: FuView,
	progressBar: null,
	themePath: '/Acc/SingleUploader/',

	createBrowseButton: function(){
		loadFile('light.G/Components/GDomElement.js');
    	this.browseButton = new GDomElement(null, new Element('button', {
    		'type': 'button',
			'id':		'browseBtn',
			'class': 	'browse',
			'text': 	'Chọn ảnh'
		}));
    },

	setup: function(){
		loadFile('light.G/Components/GDomElement.js');

		// tạo nút browse
		this.createBrowseButton();
		this.getBrowseButton().setGraphicsContext({
			'inject': {
				'target': this.getElement(),
				'position': 'top'
			}
		});
		this.getBrowseButton().paint();

		// tạo progress bar
		loadFile('light.Controls/ProgressBar/CtrlProgressBar.js');
		this.progressBar = new CtrlProgressBar();
		loadFile('acc/custom/AccSimpleProgressBarView.js');
		this.progressBar.setView(new AccSimpleProgressBarView());
		this.progressBar.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('progress-bar'),
				'position': 'bottom'
			}
		});
		this.progressBar.paint();

		// tạo các sự kiện
		this.createConnector();
		this.bindEvents();
	},

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
            'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
        }).set('html',
'<div class="' + this.getTheme('progress') + '">0%' +
'</div>'+
'<div class="' + this.getTheme('progress-bar') + '">' +
'</div>' +
'<div class="' + this.getTheme('note') + '">' +
'</div>'
        );
        c.attachWithElement(this.domElement);
    },

    bindEvents: function(){
        this.fuConnector.addFuConnectorListener(
            AccSingleUploaderView.ConnectorListener,
            this.getComponent()
        );
    },

    paint: function(){
		GFactory.getPaint().draw(this.getElement(), this.getComponent().getGraphicsContext());
		this.setup();
	},

	repaint: function(){
	}
});

/* static class */ AccSingleUploaderView.ConnectorListener /* implements FuConnectorListener */
= new Hash({

	onProgress: function(obj, connector, fu){
		fu.getView().progressBar.setProgress(obj.tpercent);
		fu.getView().getElementByTheme('progress').set('text', fu.getView().progressBar.getProgress() + '%');
    },

    onRemove: $empty,
	onSelect: function(obj, connector, fu){
		fu.getView().getElementByTheme('progress').set('text', '0%');
	},

	onComplete: function(obj, connector, fu){
		fu.getView().progressBar.setProgress(obj.tpercent);
		fu.getView().getElementByTheme('progress').set('text', fu.getView().progressBar.getProgress() + '%');
	},

	onFinish: $empty,
	onCdata: $empty,
	onUpload: $empty,
	onHover: $empty,
	onOut: $empty,
	onCancel: $empty,
	onBeforeUpload: $empty,

	onEmpty: function(connector, fu){
		fu.getView().progressBar.setProgress(0);
	},

    onBrowse: $empty,
	onError: $empty
});

};filesWrapper['acc/custom/ForumEditorRenderer.js'] = function(){
	loadFile('light.Controls/HtmlEditor/DefaultRenderer/DefaultRenderer.js');

ForumEditorRenderer = $H(HtmlEditor.DefaultRenderer).extend({
	simpleComponents: $A(['bold', 'italic', 'underline', 'strikethrough', 'subscript', 'superscript', 'alignleft', 'aligncenter', 'alignright', 'alignjustify', 'listorder', 'listunorder', 'removeformat', 'unlink']),
	components: $A(['fontface','fontsize','image','toggle','fontcolor','backcolor', 'link', 'quote', 'spoiler']),

	textConfig: new Registry({
		bold: { baseCss: 'bold', text: 'Đậm', tooltip: 'Ctrl+B' },
		italic: { baseCss: 'italic', text: 'Nghiêng', tooltip: 'Ctrl+I' },
		underline: { baseCss: 'underline', text: 'Gạch dưới', tooltip: 'Ctrl+U' },
		strikethrough: { baseCss: 'strike', text: 'Gạch ngang chữ' },
		link: { baseCss: 'link', text: 'Thêm liên kết' },
		unlink: { baseCss: 'unlink', text: 'Bỏ liên kết' },
		image: { baseCss: 'image', text: 'Chèn ảnh' },
		alignleft: { baseCss: 'align-left', text: 'Căn lề trái' },
		aligncenter: { baseCss: 'align-center', text: 'Căn lề giữa' },
		alignright: { baseCss: 'align-right', text: 'Căn lề phải' },
		alignjustify: { baseCss: 'align-justify', text: 'Căn lề đều' },
		listorder: { baseCss: 'list-order', text: 'Đánh số' },
		listunorder: { baseCss: 'list-unorder', text: 'Đánh chỉ mục' },
		removeformat: { baseCss: 'unformat', text: 'Xóa style' },
		toggle: { baseCss: 'toggle', text: 'Bật/Tắt HTML' },
		quote: { baseCss: 'quote', text: 'Trích dẫn' },
		spoiler: { baseCss: 'spoiler', text: 'Ẩn nội dung' }
	}),

	quote: function(cpName, editor, toolbar, group){
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/ButtonView.js');
		var ourCp = new GButton({
			themePath: '/More/Editor/Button/',
			baseCss: this.textConfig.get('/' + cpName + '/baseCss/'),
	        text: this.textConfig.get('/' + cpName + '/text/'),
	        tooltip: this.textConfig.get('/' + cpName + '/tooltip/')
		});
		ourCp.setView(new HtmlEditor.ButtonView());
		this.matchWithToolbar(ourCp, cpName, toolbar, group);
		ourCp.addMouseListener(ForumEditorRenderer.QuoteButtonListener, editor);
		return ourCp;
	},

	spoiler: function(cpName, editor, toolbar, group){
		loadFile('light.Controls/HtmlEditor/DefaultRenderer/ButtonView.js');
		var ourCp = new GButton({
			themePath: '/More/Editor/Button/',
			baseCss: this.textConfig.get('/' + cpName + '/baseCss/'),
	        text: this.textConfig.get('/' + cpName + '/text/'),
	        tooltip: this.textConfig.get('/' + cpName + '/tooltip/')
		});
		ourCp.setView(new HtmlEditor.ButtonView());
		this.matchWithToolbar(ourCp, cpName, toolbar, group);
		ourCp.addMouseListener(ForumEditorRenderer.SpoilerButtonListener, editor);
		return ourCp;
	}
});

/* static class */ ForumEditorRenderer.QuoteButtonListener /* implements ColorChangeListener, MouseListener */
= new Hash({
    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
    	var text = editor.getContent();
    	editor.insertContent('<div class="quotemain pkg">'+text+'</div>');
	}
});

/* static class */ ForumEditorRenderer.SpoilerButtonListener /* implements ColorChangeListener, MouseListener */
= new Hash({
    mouseDown: $empty,
	mouseUp: $empty,
    singleClick: function(e, button, editor){
    	var text = editor.getContent();
    	editor.insertContent('<div class="thespoiler pkg">'+text+'</div>');
	}
});
};filesWrapper['acc/custom/WikiFuFileRowView.js'] = function(){
	loadFile('light.Controls/FU/Multi/MultiFuFileRow.js');

WikiFuFileRowView = new Class({
	Extends: MultiFuFileRowView,
	themePath: '/Acc/WikiFuFileRow/',

	paintState: function(){
		this.parent();

		var c = this.getComponent();
		if (this.compareState('progress'))
			this.getElement('.progress').set('text', c.getOption('progress'));
	},

	paintButtons: function(){
		// vẽ button xóa
		this.deleteButton = new GDomElement(null, new Element('div', {
			'class': 'btn',
			'text': 'Waiting Icon'
		}));

		this.deleteButton.setGraphicsContext({
			'inject': {
				'target': this.getElement(),
				'position': 'top'
			}
		});

		this.deleteButton.addEvent('click', function(){
			this.getComponent().getFuControl().remove(
				this.getComponent().getIndex()
			);
		}.bind(this));

		this.deleteButton.paint();
    },

    onBegin: function(){
    	// vẽ progressbar
    	loadFile('light.Controls/ProgressBar/CtrlProgressBar.js');
    	this.progressBar = new CtrlProgressBar();
    	loadFile('acc/custom/AccSimpleProgressBarView.js');
    	this.progressBar.setView(new AccSimpleProgressBarView());
		this.progressBar.setGraphicsContext({
			'inject': {
				'target': this.getElement(),
				'position': 'bottom'
			}
		});
		this.progressBar.paint();

        // vẽ nút cancel
        this.cancelButton = new GDomElement(null, new Element('div', {
			'class': 'btn',
			'text': 'Uploading Icon'
		}));

		this.cancelButton.setGraphicsContext({
			'inject': {
				'target': this.getElement(),
				'position': 'top'
			}
		});

		this.cancelButton.addEvent('click', function(){
			this.getComponent().getFuControl().cancel();
		}.bind(this));

		this.cancelButton.paint();

        // hủy nút xóa
        this.deleteButton.destroy();
    },

    onComplete: function(){
        // hủy nút cancel
        this.cancelButton.destroy();
        // set status
        this.getElementByTheme('status-bar').set('html', 'File upload thành công');
    },

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('li',{
        	'class': this.getTheme('main')
        }).set('html',

        '<div class="' + this.getTheme('status-bar') + '"></div>' +
        '<div class="progress"></div>' +
        '<div class="' + this.getTheme('file-size') + '"></div>' +
        '<div class="' + this.getTheme('file-name') + '"></div>'

        );

		c.attachWithElement(this.domElement);
    }
});
};filesWrapper['acc/custom/WikiFuFilesListView.js'] = function(){
	loadFile('light.Controls/FU/Multi/MultiFuFilesList.js');

WikiFuFilesListView = new Class({
	Extends: MultiFuFilesListView,
	themePath: '/Acc/WikiFuFileslist/',

	empty: function(){
		this.getElement().empty();
	},

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('ol', {
        	'id': 'uploadImgList',
			'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
		});
		c.attachWithElement(this.domElement);
	},

	getInsideContext: function(){
        return new Hash({
			'inject': {
				'target': this.getElement(),
				'position': 'bottom'
			}
		});
	}
});
};filesWrapper['acc/custom/WikiFuView.js'] = function(){
	loadFile('light.Controls/FU/Multi/MultiFuView.js');

/* class */ WikiFuView /* extends BasicFuView */
= new Class({
	Extends: MultiFuView,
	themePath: '/Acc/WikiFu/',

	createBrowseButton: function(){
		loadFile('light.G/Components/GDomElement.js');
    	this.browseButton = new GDomElement(null, new Element('button', {
    		'type': 'button',
			'id':		'uploadImgBrowseBtn',
			'class': 	'browseBtn'
		}).grab(
			new Element('span', {
				'text': 	'Chọn ảnh'
			})
		));
    },

    setup: function(){
    	loadFile('light.G/Components/GDomElement.js');

		// tạo nút browse
		this.createBrowseButton();
		this.getBrowseButton().setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('toolbar'),
				'position': 'bottom'
			}
		});
		this.getBrowseButton().paint();

		// tạo nút upload
		this.uploadButton = new GDomElement(null, new Element('button', {
			'type': 'button',
			'id':		'uploadImgUploadBtn',
			'class': 	'uploadBtn',
			'text': 	'Tải lên'
		}));
        this.uploadButton.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('upload-foot'),
				'position': 'bottom'
			}
        });
        this.uploadButton.paint();
        this.uploadButton.addEvent('click', function(){
			this.fuConnector.upload();
        }.bind(this));

		// tạo file list
		this.filesList = new MultiFuFilesList();

		loadFile('acc/custom/WikiFuFilesListView.js');
		this.filesList.setView(new WikiFuFilesListView());
		this.filesList.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('upload-cnt'),
				'position': 'bottom'
			}
		});
		this.filesList.paint();

		this.createConnector();
		this.bindEvents();
	},

	createEmptyButton: function(){
		loadFile('light.G/Components/GDomElement.js');

		this.emptyButton = new GDomElement(null, new Element('button', {
			'type': 'button',
			'id':		'uploadImgClearAll',
			'class': 'removeAllBtn',
			'text': 'Xóa toàn bộ danh sách'
		}));
		this.emptyButton.setGraphicsContext({
			'inject': {
				'target': this.getElementByTheme('upload-foot'),
				'position': 'top'
			}
		});
		this.emptyButton.paint();
		this.emptyButton.addEvent('click', function(){
			this.fuConnector.empty();
		}.bind(this));
    },

	createDomElement: function(){
        var c = this.getComponent();
        this.domElement = new Element('div', {
            'class': this.getTheme('main') + ' ' + c.getOption('baseCss')
        }).set('html',
'<div class="' + this.getTheme('toolbar') + '">' +
'</div>'+
'<div class="' + this.getTheme('upload-head') + '">' +
	'<label class="no">STT</label>' +
	'<label class="name">Tên ảnh</label>' +
	'<label class="size">Dung lượng</label>' +
	'<label class="progress">%</label>' +
	'<label class="status">Tình trạng</label>' +
	'<label class="btn"/>' +
'</div>'+
'<div class="' + this.getTheme('upload-cnt') + '">' +
'</div>' +
'<div class="' + this.getTheme('upload-foot') + '">' +
'</div>'
        );
        c.attachWithElement(this.domElement);
    },

    bindEvents: function(){
        this.fuConnector.addFuConnectorListener(
            WikiFuView.ConnectorListener,
            this.getComponent()
        );
    }
});

/* static class */ WikiFuView.ConnectorListener /* implements FuConnectorListener */
= $H(MultiFuView.ConnectorListener).extend({
	onSelect: function(obj, connector, fu){
		// tạo filerow và add vào filelist với id tương ứng
		var addFiles = obj.afile;
		var filesList = fu.getView().getFilesList();
		addFiles.each(function(fileData){
			loadFile('acc/custom/WikiFuFileRowView.js');
            var fileRow = new MultiFuFileRow({
				fileName: fileData.file.name,
				fileSize: HelpersFactory.getFileHelper().calculateFileSize(fileData.file.size),
                fileType: fileData.file.type.split(".")[1],
				currentState: 'default'
			}, fu);
			fileRow.setView(new WikiFuFileRowView());
			filesList.add(fileRow);
			filesList.addSubComponent(fileRow, fileData.id);
			fileRow.setIndex(fileData.id);
		});

		var removeFiles = obj.rfile;
		removeFiles.each(function(fileData){
			filesList.getSubComponent(fileData.id).destroy();
		});

		if (!fu.getView().hasEmptyButton()){
			fu.getView().createEmptyButton();
		}
	},

	onBeforeUpload: function(connector){
		var selectEl = $$('#imageUploaderGroups select')[0];
		connector.options.extraData = {
			'grp': selectEl.options[selectEl.selectedIndex].value
		};
	}
});
};filesWrapper['acc/resources/themes/Acc.js'] = function(){
	ThemeData = {
	'Balloon': {
		main:			'balloon',
		layer2:			'balloon-2',
		layer3:			'balloon-3',
		layer4:			'balloon-4',
		layer5:			'balloon-5',
		layer6:			'balloon-6'
	},
	'Dialog': {
		main:			'dialog',
		layer2:			'dialog-2',
		layer3:			'dialog-3',
		layer4:			'dialog-4',
		layer5:			'dialog-5',
		close:			'dialog-close'
	},
	'WikiFu': {
		'main':	'port-cnt uploader pkg',
		'toolbar': 'toolbar pkg',
		'upload-head': 'upload-head pkg',
		'upload-cnt': 'upload-cnt pkg',
		'upload-foot': 'upload-foot pkg',
		'fu-container':	'fu-popup-container'
	},
	'WikiFuFileslist': {
		'main':					'files-list'
	},
	'WikiFuFileRow': {
		'main': 				'file-row',
		'file-name': 			'name',
		'file-size': 			'size',
		'status-bar': 			'status',

		'default': 				'queue',
		'begin':				'uploading',
		'complete':				'finished',
		'error':				'error',
		'cancel':				'canceled'
	},
	'SimpleProgressBar': {
		'main': 				'progress-bar'
	},
	'InputColorWithBoard': {
		'main':			'icp-main',
		'inside':		'icp-inside pkg',
		'arrow-btn':	'icp-arrow-btn',
		'theme-color-content-main':		'editor-fcp-board-color-content-main',
		'theme-color-content-sub':		'editor-fcp-board-color-content-sub',
		'standard-color-content':		'editor-fcp-board-standard-color-content'
	},

	'InputColorBoard': {
		'main':		'icp-board-main',
		'inner':	'icp-board-inner',
		'theme-color-content-main':		'icp-board-color-content-main',
		'theme-color-content-sub':		'icp-board-color-content-sub',
		'standard-color-content':		'icp-board-standard-color-content'
	},
	'SingleUploader': {
		'main': 		'uploader single pkg',
		'progress':		'progress',
		'progress-bar': 'progress-bar-wrp pkg',
		'note': 		'note pkg',
		'submit-row':	'submit-row pkg',
		'fu-container':	'fu-popup-container'
	}
}
};