$.browser.ie6 = $.browser.msie && (parseInt($.browser.version) < 7);
ReadyObject = {
	isReady: false,
	init:function()
	{
		this.isReady = true;
	},
	ready:function(func)
	{
		VHV.ExecQueue.add(func, function(){return this.isReady;}, this);
	}
};
VHV = $.extend({
	cache:{},
	debug:1,
	frameworkCache:false,
	publish:false,
	noGroupService:true,
	publishPages:false,
	async:true,
	allLinks:{},
	xmlCache:{},
	serviceCache: {},
	domain:location.host,
	home: 'http://'+location.host,
	defaultLanguage:'vi',
	language:'vi',
	version:1.21,
	rootURL:'/',
	innerText:$.browser.msie?($.browser.ie6?'nodeValue':'innerText'):'textContent',
	allOrderedLinks:[],
	xml:function(fn, path)
	{
		if(VHV.xmlCache[fn])
		{
			return VHV.xmlCache[fn];
		}
		
		//VHV.xmlCache[fn] = VHV.xmlToJson($(path?path:'*',VHV.read(fn, {dataType:'xml', async:false})));
		return VHV.xmlToJson($(path?path:'*',VHV.read(fn, {dataType:'xml', async:false})));
	},
	xmlTemplate: function(xml)
	{
		for(var i in xml)
		{
			if(typeof(xml[i]) == 'string')
			{
				if(xml[i].indexOf('(*=') != -1)
				{
					xml[i] = VHV.template(xml[i], this, true);
				}
			}
			else if(typeof(xml[i]) == 'array' || typeof(xml[i]) == 'object')
			{
				VHV.xmlTemplate(xml[i]);
			}
		}
		return xml;
	},
	xmlToJson:function(xmlNode, parentNode)
	{
		var result = {}, count = 0, isArray = false;
		if(xmlNode.children)
		{
			xmlNode.children().each(function(){
				var children = $(this).children(), key;
				if(count == 0 && typeof(result[this.tagName]) == 'undefined' && !isArray)
				{
					if(typeof(parentNode) != 'undefined' && parentNode == this.tagName+'s')
					{
						key = 0;
						isArray = true;
						result = [];
					}
					else
					{
						key = this.tagName;
					}
				}
				else
				{
					if(count == 0 && typeof(result[this.tagName]) != 'undefined')
					{
						result = [result[this.tagName]];
					}
					key = ++count;
				}
				if(children.length > 0)
				{
					result[key] = VHV.xmlToJson($(this), key);
				}
				else
				{
					result[key] = $.trim($(this).text());
				}
				children = null;
				//result[key]._index = count;
			});
		}
		else
		{
			return xmlNode;
		}
		return result;
	},
	jsonToXml: function(json, root)
	{
		function _jsonToXml(json, parentNode)
		{
			if(json)
			{
				if(typeof(json) != 'object' && typeof(json) != 'array') 
				{
					json = json.toString();
					return (/[<>&'"]/.test(json))?'<![CDATA['+json+']]>':json;
				}
				var code = '', childNode = (parentNode.charAt(parentNode.length-1) == 's')?parentNode.substr(0, parentNode.length - 1):parentNode;
				for(var i in json)
				{
					if(i != 'id' || parseInt(json[i]) != json[i])
					{
						var node = (i == parseInt(i))?childNode:i;
						code += '<'+node+'>'+_jsonToXml(json[i], node)+'</'+node+'>';
					}
				}
				return code;
			}
			return '';
		}
		if(!root)root = 'root';
		return '<?xml version="1.0" encoding="utf-8"?><'+root+'>'+_jsonToXml(json, root)+'</'+root+'>';
	},
	createXMLDocument : function(string) //Copy from http://plugins.jquery.com/project/createXMLDocument
	{
		var doc;
		if ($.browser.msie)
		{
			doc = new ActiveXObject('Microsoft.XMLDOM');
			doc.async = 'false'
			doc.loadXML(string);
		} else {
			doc = (new DOMParser()).parseFromString(string, 'text/xml');
		}
		return doc;
	},
	template:function(id, data, parseText)
	{
		return $.fn.pureJSTemplate({
			id:id, 
			data:data,
			parseText:parseText
		});
	},
	layoutBound: function(code, context)
	{
		if(context && context.skin && (context.layout || context.name))
		{
			var layoutName;
			if(context.layout)
			{
				var layoutParts = context.layout.replace(/\./g, '/').split('/');
				layoutName = layoutParts[layoutParts.length - 2];
			}
			else
			{
				layoutName = context.name.split('.').pop();
			}
			var skinParts = context.skin.replace(/\./g, '/').split('/'),
				skinName = skinParts.pop();
			var classPart = ' class="'+layoutName+'-'+skinName+'"';
			VHV.load(skinParts.join('/')+'/'+skinName+'.css');
			return '<div id="module-'+context.id+'"'+classPart+'>'+code+'</div>';
		}
		return (context?'<div id="module-'+context.id+'">':'')+code+(context?'</div>':'');
	},
	templateEscape:function(st)
	{
		return st.replace(/\(\*/g,'((~~x~~=\'*\'~~x~~)').replace(/\*\)/g,'(*=\'*\'*))').replace(/~~x~~/g,'*');
	},
	request: function(param, defaultValue) {
		if(typeof(defaultValue) == 'undefined')
		{
			defaultValue = '';
		}
		var regex = '[?&]' + param + '=([^&#]*)';
		var results = (new RegExp(regex)).exec(location.href);
		if(results)
		{
			return decodeURIComponent(results[1]);
		}
		else
		{
			var regex = '[?&]'+param+'\\[(\\w*)\\]=([^&#]*)', regExpObj = new RegExp(regex, 'g');
			var matches = location.href.toString().replace(/\%5B/g, '[').replace(/\%5D/g, ']').match(regExpObj);
			if(matches)
			{
				var items = {};
				for(var i = 0; i < matches.length; i++)
				{
					var results = (new RegExp(regex)).exec(matches[i]);
					if(results)
					{
						if(results[1] !== '')
						{
							items[results[1]] = decodeURIComponent(results[2]);
						}
						else
						{
							items[VHV.sizeof(items)] = decodeURIComponent(results[2]);
						}
					}
				}
				return items;
			}
		}
		return defaultValue;
	},
	buildURL:function(options, urlMode){
		var url = '?';
		for(var i in options)
		{
			url += '&'+i+'='+encodeURI(options[i]);
		}
		return url;
	},
	setAllLinks: function(fileName, value){
		VHV.allLinks[fileName] = value;
		if(VHV.publishModule && fileName.indexOf('3rdparty')==-1 && fileName.indexOf('languages')==-1)
		{
			var rootURL = VHV.rootURL.replace(/\//g, '__');
			VHV.allLinks[fileName.replace(/\//g, '__').replace(rootURL, VHV.rootURL)] = value;
		}
	},
	read:function(fileName, options, func)
	{
		if(!fileName)return;
		
		if(typeof(options) == 'function')
		{
			func = options;
			options = {};
		}
		if(VHV.allLinks[fileName] == 2)
		{
			if(func) func.call(this, VHV.cache[fileName]?VHV.cache[fileName]:'');
			else return VHV.cache[fileName]?VHV.cache[fileName]:'';
			return;
		}
		else
		if(parseInt(VHV.allLinks[fileName]) == 1 && (!options || typeof(options.async)=='undefined' || options.async))
		{
			if(1 || !options || options.async)
			{
				VHV.ExecQueue.add(func, function(){return VHV.allLinks[fileName] == 2}, null, {fileName:fileName});
			}
			else
			{
				/*while(VHV.allLinks[fileName] == 1)
				{
					
				}*/
				func.call(this, VHV.cache[fileName]?VHV.cache[fileName]:'');
			}
			return;
		}
		VHV.setAllLinks(fileName, 1);
		if(!options)
		{
			options = {};
		}
		if(!options.dataType)
		{
			options.dataType = 'html';
		}
		if(typeof(options.async) == 'undefined')
		{
			options.async = VHV.async;
		}
		if(fileName.indexOf('http://') != -1)
		{
			$('body').append('<'+'script src="'+fileName+'"><'+'/script>');
			VHV.setAllLinks(fileName, 2);
			VHV.allOrderedLinks.push(fileName);
		}
		else
		{
			if(fileName.indexOf('.css') != -1)
			{
//				if(fileName.indexOf('detail.css') != -1)
//				{
//					alert($.toJSON(VHV.allLinks));
//					alert(fileName);
//				}
				var fn = fileName;
				if(fn.charAt(0) == '/')
				{
					fn = 'http://'+location.host+fn;
				}
				$('body').append('<link rel="stylesheet" type="text/css" href="'+fn+'" />');
				VHV.setAllLinks(fileName, 2);
				VHV.allOrderedLinks.push(fileName);
				return;
			}
			//&& options.async != false
			if(fileName.indexOf('.js') != -1 && navigator.userAgent.toLowerCase().indexOf('chrome')==-1 )
			{
				var node = document.createElement('SCRIPT');
				node.src = fileName;
				if($.browser.msie)
				{
					node.onreadystatechange= function () {
						if ((this.readyState == 'complete' || this.readyState == 'loaded') && (VHV.allLinks[fileName] != 2)){
							VHV.setAllLinks(fileName, 2);
							VHV.allOrderedLinks.push(fileName);
							if(func) func.call(this);
						}
					}
				}
				else
				//if($.browser.webkit || $.browser.safari)
				{
					
					node.onload = function(){
						VHV.setAllLinks(fileName, 2);
						VHV.allOrderedLinks.push(fileName);
						if(func) func.call(this);
					};
					
				}
				
				document.body.appendChild(node);
				/*if($.browser.webkit || $.browser.safari)
				{
				
				}
				else
				if($.browser.msie)
				{
					VHV.ExecQueue.add(function(){
						VHV.setAllLinks(fileName, 2);
						VHV.allOrderedLinks.push(fileName);
						if(func) func.call(this);
					}, function(){
						return node.readyState == 'complete' || node.readyState == 'loaded';
					}, null, {fileName:fileName});
				}
				else
				{
					var node2 = document.createElement('SCRIPT');
					node2.text = 'VHV.setAllLinks("'+fileName+'", 2); VHV.allOrderedLinks.push("'+fileName+'");';
					document.body.appendChild(node2);
					if(func) 
						VHV.ExecQueue.add(function(){
							func.call(this);
						}, function(){
							return VHV.allLinks[fileName] >= 2;
						}, null, {fileName:fileName});
				}*/
				return;
			}
			var returnValue = '';
			var success = function(data)
				{
					if(fileName.indexOf('.js') == -1 && fileName.indexOf('.css') == -1)
					{
						if (data)					
							VHV.cache[fileName] = data;
					}
					if(options.dataType == 'html')
					{
						if(fileName.indexOf('.css') != -1)
						{
							var parts = fileName.split('/');
							parts.splice(parts.length - 1, 1);
							parts = parts.join('/')+'/';
							data = data.replace(/url\s*\(\s*(["']?)/gi, 'url($1'+parts);
							$('body').append('<style>'+data+'</style>');
						}
						else
						if(fileName.indexOf('.js') != -1)
						{
							//alert(fileName + ' ' + data);
							eval(data);
						}
					}
					else
					{
						returnValue = data;
					}

					VHV.setAllLinks(fileName, 2);

					VHV.allOrderedLinks.push(fileName);
					if(func)
					{
						func.call(this, data);
					}
				};
			/*if(fileName.indexOf('.xml') == -1 && (typeof(options.async)=='undefined' || options.async))
			{
				VHV.Model.CallingServices.add(fileName, success);
			}
			else*/
			{
				$.ajax($.extend({
					url: fileName+(/\?/.test(fileName)?'&':'?')+'v='+VHV.version,
					cache:true,
					success:success
				}, options));
			}
			return returnValue;
		}
	},
	getComponentURL:function(url)
	{
		
		var values = {name:url, path : '', type : ''};
		if(url.indexOf('http://') != -1)
		{
			values.path = VHV.rootURL + 'get.php?url='+ encodeURI(url);
			values.type = 'cross-domain';
		}
		else if(url.indexOf('3rdparty') != -1 || url.indexOf('languages') != -1 || url.indexOf('.js') != -1 || url.indexOf('.css') != -1)
		{
			values.path = VHV.rootURL+url;
			values.type = '3rdparty';
		}
		else if(url.indexOf('.') != -1)
		{
			var parts = url.split('.'), module = parts.splice(parts.length-1, 1);
			values.package = parts.join('.');
			if(module && module != '')
			{
				if(VHV.publishCode)
				{
					values.path = VHV.rootURL+'publish/modules/'+parts.join('__')+'__'+module+'.js';
				}
				else
				{
					values.path = VHV.rootURL+parts.join('/')+'/'+module+'.js';
				}
				
				values.type = 'module';
			}
			else
			{
				if(VHV.publishCode)
				{
					values.packagePath = VHV.rootURL+parts.join('/')+'/';
					values.path = VHV.rootURL+parts.join('__')+'__'+'Model.js';
				}
				else
				{
					values.packagePath = VHV.rootURL+parts.join('/')+'/';
					values.path = VHV.frameworkCache?VHV.rootURL+'cache/'+parts.join('_')+'.js':values.packagePath+'Model.js';
				}
				values.name = values.package;
				values.type = 'package';
			}
		}
		else
		{
			values.packagePath = VHV.rootURL+url+'/';
			values.package = url;
			values.path = VHV.frameworkCache?VHV.rootURL+url.replace(/\//g, '_')+'.js':values.packagePath+'Model.js';
			values.type = 'package';
		}
		return values;
	},
	load:function()
	{
		var args = [];
		if(arguments.length>0)
		{
			if(typeof(arguments[0]) == 'function')
			{
				arguments[0].call(this);
			}
			else
			{
				var length = arguments.length;
				if(typeof(arguments[arguments.length - 1]) == 'function')
				{
					length--;
				}
				if(typeof(arguments[0]) == 'object' && arguments[0].length && typeof(arguments[0][0]) == 'object' && arguments[0][0].length)
				{
					var args = arguments;
					var newArgs = args[0].splice(0,1)[0];
					if(args[0].length > 0)
					{
						newArgs.push(function(){
							VHV.load(args[0], args[1]);
						});
					}
					else
					{
						newArgs.push(args[1]);
					}
					VHV.load.apply(this, newArgs);
					return;
				}
				for(var i = 0; i < length; i++)
				{
					
					if(typeof(arguments[i]) == 'string' && arguments[i])
					{
						args[i] = VHV.getComponentURL(arguments[i]);

						if(!VHV.allLinks[args[i].path])
						{
							var currentArg = args[i];
							if(args[i].type == 'module' || args[i].type == 'package')
							{
								
								var parts = arguments[i].split('.');
								if(args[i].type == 'package' && parts[parts.length-1] == ''){
									parts.pop();
								}
								var files = [];
								
								for(var j = 0; j < parts.length - 1; j++)
								{
									
									var file = parts.slice(0, j+1).join('.')+'.';
									if(file && file != 'VHV.')
									{
										var url2 = VHV.getComponentURL(file);
										if(!VHV.allLinks[url2.path] || VHV.allLinks[url2.path]<2)
										{
											files.push(file);
										}
									}
								}
								if(files.length > 0)
								{
									var thisPath = arguments[i];
									files.push(function(){VHV.load(thisPath)});
									var lastAsync = VHV.async;
									VHV.async = false;
									VHV.load.apply(this, files);
									VHV.async = lastAsync;
									continue;
								}
							}
							VHV.read(args[i].path, function(){
								switch(currentArg.type)
								{
									case 'package':
										VHV.ExecQueue.add(function(){
											eval('var model = VHV.'+currentArg.name+';');
											if(model && typeof(model.init) == 'function')
											{
												model.init();
											}
										}, function(){eval('var model = VHV.'+currentArg.name+';');return model;}, null, {fileName:currentArg.name});
										break;
								}
							});
						}
					}
				}
				if(typeof(arguments[length]) == 'function')
				{
					var oldArgs = arguments;
					
					VHV.ExecQueue.add(function(){
						oldArgs[length].call(this);
					},function(){
						for(var i = 0; i < length; i ++)
						{
							if(args[i])
							{
								if(!VHV.allLinks[args[i].path] || VHV.allLinks[args[i].path] < 2)
								{
									return false;
								}
								else if(args[i].type == 'module' || args[i].type == 'package')
								{
									var ok = true;
									try{

										eval('ok = (typeof(VHV.'+args[i].name+') != "undefined");');
									}
									catch(e)
									{
										ok = false;
									};
									if(!ok)
									{
										return false;
									}
									if(args[i].type == 'package')
									{
										eval('var package = VHV.'+args[i].name+';');
										if(typeof(package.isReady) != 'undefined')
										{
											if(!package.isReady)return false;
										}
									}
								}
							}
						}
						return true;
					}, arguments, {caller:'load', args:args});
				}
			}
		}
	},
	run:function()
	{
		VHV.ready(function(){
			
			if(VHV.packageName)
			{
				VHV.read(VHV.frameworkCache?VHV.rootURL+(VHV.packageName?VHV.packageName.replace(/[\.\/]/g, '_')+'/':'')+'cache.js':VHV.path+'Model.js', function(){
					VHV.App.run();
				});
			}
			else
			{
				
				VHV.App.run();
			}
		});
	},
	using:function(moduleName, options, success)
	{
		var currentModule = VHV.App.currentModule;
		var moduleId = ++VHV.App.maxModuleId;
		//alert(moduleName)
		if(moduleName.indexOf('Marketplace.') == 0)
		{
			VHV.Model.register('Core.File', {getApplication:['id']}, function(){
				VHV.Model.Core.File.getApplication({id:moduleName}, function(response){
					eval('var code = '+response+';');
					if(code.appCode && code.layout)
					{
						eval(code.appCode);
						eval('var moduleDefinition = VHV.'+moduleName+';');
						if(moduleDefinition)
						{
							moduleDefinition.prototype.layout = code.layout;
							VHV.runModule(moduleName, moduleId, options, success, currentModule);
						}
					}
				});
			});
		}
		else
		{
			VHV.load(moduleName, function(){
				VHV.runModule(moduleName, moduleId, options, success, currentModule);
			});
		}
	},
	runModule: function(moduleName, moduleId, options, success, currentModule)
	{
		var lastModule = VHV.App.currentModule;
		VHV.App.currentModule = currentModule;
		eval('var module = new VHV.'+moduleName+'('+moduleId+');');
		VHV.App.currentModule = lastModule;
		module.name = moduleName;
		$.extend(module, options);
		if(module.modules)
		{
			var modules = {};
			module.applyFunction(function(){
				for(var i in this.modules)
				{
					if(this.modules[i] && this.modules[i].name)
					{
						VHV.using(this.modules[i].name, $.extend({position:i},this.modules[i]), function(){
							modules[this.position] = 1;
						});
					}
				}
			});
			VHV.ExecQueue.add(function(){
				if(module.init)
				{
					module.applyFunction(module.init);
						
				}
				if(success)
				{
					success.call(module);
				}
			},function(){
				for(var i in module.modules)
				{
					if(!modules[i] && module.modules[i].name)
					{
						return false;
					}
				}
				return true;
			}, null, {caller:'runModule '+moduleName});
			return;
		}
		if(module.init)
		{
			module.applyFunction(module.init);
		}
		if(success)
		{
			success.call(module);
		}
	},
	extend:function(oldClass, properties)
	{
		var newClass = function()
		{
			if(typeof(oldClass) != 'undefined')
			{
				oldClass.apply(this,arguments);
			}
		}
		if(typeof(oldClass) != 'undefined')
		{
			$.extend(newClass.prototype, oldClass.prototype, properties);
		}
		return newClass;
	},
	sizeof:function(obj)
	{
		if(typeof(obj) == 'object')
		{
			var size = 0;
			for(var i in obj)
			{
				if(typeof(obj[i])!='function')
				{
					size ++;
				}
			}
			return parseInt(size);
		}
		else
		if(typeof(obj)!='undefined' && typeof(obj.length) != 'undefined')
		{
			return obj.length;
		}
		return 0;
	},
	Marketplace: {
	},
	ExecQueue: {
		queue:[],
		isRunning:false,
		interval:false,
		run:function()
		{
			if(!this.interval)
			{
				this.interval = setInterval(this.intervalFunction, 10);
			}
		},
		intervalFunction: function(){
			var that = VHV.ExecQueue;
			if(!that.isRunning)
			{
				that.isRunning = true;
				for(var i = 0; i < that.queue.length; i++)
				{
					if((!that.queue[i].isCalled) && that.queue[i].condition.call(that.queue[i].context))
					{
						that.queue[i].isCalled = true;
						that.queue[i].callback.call(that.queue[i].context);
					}
				}
				var i = 0; 
				while(i < that.queue.length)
				{
					if(that.queue[i].isCalled)
					{
						that.queue.splice(i, 1);
					}
					else
					{
						i ++;
					}
				}
				if(that.queue.length == 0)
				{
					clearInterval(that.interval);
					that.interval = false;
				}
				that.isRunning = false;
			}
		},
		add:function(callback, condition, context, data)
		{
			if(condition.call(context))
			{
				callback.call(context);
			}
			else
			{
				this.queue.push($.extend({
					callback : callback,
					condition : condition,
					context:context,
					isCalled : false
				}, data));
				if(!this.interval)
				{
					this.run();
				}
			}
		}
	},
	App: $.extend({
		portal: 'VHV',
		mainPackage: 'CMS/VHV',
		layout:'',
		skin:'',
		version:'1.0',
		modules:{},
		currentPage:false,
		maxModuleId:0,
		currentModule:null,
		languagePackages:{},
		run:function()
		{
			//this.configPath
			VHV.App.site = VHV.App.mainPackage;
			$.extend(VHV.App, VHV.xml(VHV.rootURL+VHV.App.mainPackage+'/config.xml','root:first'));
			VHV.App.init();
			this.languagePackages[VHV.App.mainPackage] = 1;
			this.pageName = this.getPageName();
			
			this.ready(function(){
				var languagePackages = [], language = VHV.cookie('language');
				if(!language) language = 'vi';
				for(var i in this.languagePackages)
				{
					languagePackages.push(i.replace(/\./g,'/')+'/languages/'+language+'.js');
				}
				if(languagePackages.length)
				{
					languagePackages.push(function(){
						VHV.App.loadPage(VHV.App.pageName);
					});
					VHV.load.apply(this, languagePackages);
				}
				else
				{
					VHV.App.loadPage(VHV.App.pageName);
				}
			});
		},
		importLanguage: function(packageName)
		{
			this.languagePackages[packageName] = 1;
		},
		getPageName: function(){
			if(VHV.request('page'))
			{
				return VHV.request('page');
			}
			if(VHV.request('module'))
			{
				return 'module';
			}
			var parts = location.pathname.split('/'), pageName = parts[parts.length-1].replace(/\.html/i, '').replace(/\.php/i, '');
			if(!pageName) pageName='index';
			return pageName;
		},
		loadPage:function(page)
		{
			this.currentPage = (typeof(page) == 'object')?page:VHV.xml(((VHV.path=='/')?'/'+VHV.App.mainPackage+'/':VHV.path)+'pages/'+page+'.xml', 'page:first');
			if(!(this.pageLayout = this.currentPage.layout))
			{
				this.pageLayout = 'Default';
			}
			var modules = {};
			if(this.currentPage['modules'])
			{
				for(var i in this.currentPage.modules)
				{
					if(typeof(this.currentPage.modules[i]) == 'object' && this.currentPage.modules[i].name)
					{
						VHV.using(this.currentPage.modules[i].name, $.extend({position:i},this.currentPage.modules[i]), function(){
							modules[this.position] = 1;
						});
					}
				}
			}
			VHV.ExecQueue.add(function(){
				VHV.App.isReady = true;
				$('body').append(VHV.template(VHV.App.pageLayout));
			},function(){
				if(VHV.App.currentPage['modules'])
				{
					for(var i in VHV.App.currentPage.modules)
					{
						if(typeof(VHV.App.currentPage.modules[i]) == 'object' && VHV.App.currentPage.modules[i].name && !modules[i])
						{
							
							return false;
						}
					}
				}
				return true;
			}, null, {caller:'loadPage '});
		},
		numberCompare: function(a,b){
			if(a == b)
			{
				return 0;
			}
			return (parseInt(a) < parseInt(b))?-1:1;
		},
		region:function(region)
		{
			if(this.currentModule)
			{
				var parent = this.currentModule;
			}
			else
			{
				var parent = null;
			}
			var st = '', orderedModules = [];
			for(var i in this.modules)
			{
				orderedModules.push(parseInt(i));
			}
			orderedModules.sort(this.numberCompare);
			for(var j = 0; j <  orderedModules.length; j++)
			{
				
				i = orderedModules[j];
				if(this.modules[i]){
					if(this.modules[i].region == region && ((parent==null && this.modules[i].parent == null) || (parent && this.modules[i].parent && parent.id == this.modules[i].parent.id)))
					{
						var moduleContent = this.modules[i].applyFunction('draw'), classPart = '';
						if(this.modules[i].skin && (this.modules[i].layout || this.modules[i].name))
						{
							var layoutName;
							if(this.modules[i].layout)
							{
								var layoutParts = this.modules[i].layout.replace(/\./g, '/').split('/');
								layoutName = layoutParts[layoutParts.length - 2];
							}
							else
							{
								layoutName = this.modules[i].name.split('.').pop();
							}
							var skinParts = this.modules[i].skin.replace(/\./g, '/').split('/'),
								skinName = skinParts.pop();
							classPart = ' class="'+layoutName+'-'+skinName+'"';
							VHV.load(skinParts.join('/')+'/'+skinName+'.css');
						}
						st += '<div id="module-'+this.modules[i].id+'"'+classPart+'>'+(moduleContent?moduleContent:'')+'</div>';
					}
				}
			}
			return st;
		},
		image: function(name)
		{
			return VHV.path+'skins/'+VHV.App.skin+'/images/'+name;
		},
		isChild: function(childId, parentId)
		{
			while(childId != -1)
			{
				if(childId == parentId)
				{
					return true;
				}
				if(VHV.App.modules[childId] && VHV.App.modules[childId].parent)
				{
					childId = VHV.App.modules[childId].parent.id;
				}
				else
				{
					return false;
				}
			}
			return false;
		},
		removeModule: function(id)
		{
			if(this.modules[id])
			{
				if(this.modules[id].modules)
				{
					for(var i = 0; i < this.modules[id].modules.length; i++)
					{
						this.removeModule(this.modules[id].modules[i].id);
					}
				}
				if(this.modules[id].destructor)
				{
					this.modules[id].destructor();
				}
				delete this.modules[id];
				this.modules[id] = null;
			}
		}
	}, ReadyObject),
	Module: function(id){
		if(!VHV.App.modules[this.id])
		{
			this.id = id?id:++VHV.App.maxModuleId;
			VHV.App.modules[this.id] = this;
			this.parent = VHV.App.currentModule;
		}
		else
		{
			return VHV.App.modules[this.id];
		}
	}
}, ReadyObject, {
	init:function()
	{
		var pathname = (typeof(applicationPath) != 'undefined')?applicationPath:(location.pathname.substr(VHV.rootURL.length));
		
		var path = pathname.split('/');
		VHV.path = (VHV.rootURL+path.slice(0, path.length-1).join('/')+(path.length>1?'/':'')).replace(/\/\//g, '/');
		
		VHV.packagePath = VHV.rootURL+path.slice(0, path.length-1).join('/')+'/';
		VHV.packageName = path.slice(0, path.length-1).join('.');
		if($.trim(VHV.packageName))
		{
			VHV.App.mainPackage = path.slice(0, path.length-1).join('/');
		}
		//VHV.appName = path[path.length - 2];
		VHV.App.layout = VHV.App.skin = 'Default';
		
		VHV.fileName = path[path.length - 1];
		//if(typeof(VHV.allLinks) == 'undefined')
		{
			
			VHV.allLinks[VHV.rootURL+'3rdparty/jQuery/jquery-1.4.2.min.js'] = 2;
			VHV.allLinks[VHV.rootURL+'VHV.js'] = 2;
			VHV.allOrderedLinks.push(VHV.rootURL+'3rdparty/jQuery/jquery-1.4.2.min.js');
			VHV.allOrderedLinks.push(VHV.rootURL+'VHV.js');
			var loader = jQuery('<div id="loader"><img src="'+VHV.rootURL+'3rdparty/loading.gif" alt="loading..." /></div>')
				.css({position: "absolute", top: "1em", left: "1em", 'z-index':10000})
				.appendTo("body")
				.hide();
			loader.ajaxStart(function() {
				loader.show();
			}).ajaxStop(function() {
				loader.hide();
			}).ajaxError(function(a, b, e) {
				//throw e;
			});
			if(!VHV.allLinks[VHV.rootURL+'3rdparty/jQuery/jquery.cookie.js'])
			{
				VHV.load(
					'3rdparty/jQuery/jquery.cookie.js',
					'3rdparty/jQuery/json/jquery.json.min.js',				
					'3rdparty/jQuery/pureJSTemplate.js', function(){
					VHV.load('Utils.js', function(){
						VHV.ExecQueue.add(function(){
												   
							$.fn.pureJSTemplate.setDelimiters("(*", "*)");
							VHV.load('Core.Workflow.', function(){
								if(VHV.packageName)
								{
									VHV.load(VHV.packageName+'.',function(){
										VHV.isReady = true;
									});
								}
								else
								{
									VHV.isReady = true;
								}
							});
						},function(){return typeof($.fn.pureJSTemplate) == 'function';});
					});
				});
			}
			
		}
		$(window).resize(function(){
			VHV.ExecQueue.add(function(){
				var oldWidth = VHV.oldClientWidth;
				var oldHeight = VHV.oldClientHeight;
				VHV.oldClientWidth = 0;
				VHV.oldClientHeight = 0;
				if(oldWidth != VHV.clientWidth() || oldHeight != VHV.clientHeight())
				{
					VHV.resize();
				}
			}, function (){return VHV.clientWidth;});
		});
	},
	Lang: function (word)
	{
		if(typeof(word) == 'string' && typeof(VHV.Lang[word]) == 'string')
		{
			return VHV.Lang[word];
		}
		return word?word:'';
	}
});
elem = VHV.elem;

$L = Lang = VHV.Lang;
$VHV = function(name, context)
{
	var modules = VHV.App.modules, parentId = -1, path = name.split(' ');
	if(path.length > 1)
	{
		var obj = $VHV(path.splice(0,1), context);
		if(obj) return $VHV(path.join(' '), obj);
		return null;
	}
	if(typeof(context) == 'object')
	{
		parentId = context.id;
	}
	else if(typeof(context) == 'number')
	{
		parentId = context;
	}
	for(var i in modules)
	{
		if(modules[i] && modules[i].name == name)
		{
			if(parentId == -1 || VHV.App.isChild(modules[i].id, parentId))
			{
				return modules[i];
			}
			
		}
	}
	return null;
};

VHV.Lang.keyword = function(word, lang){
	word = word.toString().replace(/\s/g, '_').replace(/[^\w]/g, '');
	return word?(lang?'(*=Lang.get(\''+word+'\');*)':word):'';
};
VHV.Lang.get = function(word){
	return VHV.Lang[word]?VHV.Lang[word]:word.replace(/\_/g, ' ');
};
$.extend(VHV.Module.prototype,{
	$cache:false,
	data:{},
	layout:'',
	applyFunction:function(func){
		var oldModule = VHV.App.currentModule;
		module = VHV.App.currentModule = this;
		if(typeof(func) == 'function')
		{
			var returnValue = func.call(this);
		}
		else
		{
			var returnValue = this[func]();
		}
		module = VHV.App.currentModule = oldModule;
		return returnValue;
	},
	object: function()
	{
		return 'VHV.App.modules['+this.id+']';
	},
	
	$id: function(id, index) {
		return $('#' + id + ((typeof(index) != 'undefined')?'-'+index:'') + '-' + this.id);
	},
	each: function(f)
	{
		for(var i in VHV.App.modules)
		{
			var module = VHV.App.modules[i];
			if(module && module.parent && module.parent.id == this.id)
			{
				if(f.call(module) === false)
				{
					return;
				}
			}
		}
	},
	draw: function(){
		this.ready(function(){
			this.reload();
		});
		if(this.boundLayout)
		{
			return VHV.template(this.boundLayout, this);
		}
		return '';
	},
	reload: function()
	{
		this.applyFunction(function(){
			if(this.layout)
			{
				if(this.boundLayout)
				{
					$('#moduleContent'+this.id).html(VHV.template(this.layout, this));
				}
				else
				{
					this.html(VHV.template(this.layout, this));
				}
				this.initEvents();
			}
		});
	},
	initEvents: function(){
	},
	$: function()
	{
		if(this.$cache && this.$cache.length > 0)
		{
			return this.$cache;
		}
		else
		{
			this.$cache = $('#module-'+this.id);
			return this.$cache;
		}
	},
	html: function(code)
	{
		return this.$().html(code);
	},
	append: function(code)
	{
		return this.$().append(code);
	},
	close:function()
	{
		$('#Dialog-'+this.name.replace(/\./ig,'-')).hide();
		if(typeof(this.onClose) == 'function')
		{
			this.onClose();
		}
	}
}, ReadyObject, {
	ready:function(callback)
	{
		VHV.ExecQueue.add(function(){this.applyFunction(callback);}, function(){return this.isReady && this.$().length;}, this, {caller:'ready'});
	}
});
VHV.Model = function(method)
{
	return VHV.Model.register(method);
}
$.extend(VHV.Model,
{
	CallingServices:{
		queue:[],
		successQueue:[],
		isRunning:false,
		interval:false,
		run:function()
		{
			if(!this.interval)
			{
				this.interval = setInterval(this.intervalFunction, 100);
			}
		},
		intervalFunction: function(){
			var that = VHV.Model.CallingServices;
			if(!that.isRunning)
			{
				clearInterval(that.interval);
				that.interval = false;
				that.isRunning = true;
				var queue = that.queue, successQueue = that.successQueue;
				that.queue = [];
				that.successQueue = [];
				VHV.Model.register('Core.Service', {callServices:[]});
				VHV.Model.Core.Service.callServices({
					services: $.toJSON(queue),
					immediate: true
				}, function(results){
					if(results)
					{
						eval('results = '+results+';');
						for(var i = 0; i < results.length; i++)
						{
							if(successQueue && successQueue[i])
							{
								successQueue[i].call(this, results[i]);
							}
						}
					}
					that.isRunning = false;
				});
			}
		},
		add:function(service, success)
		{
			this.queue.push(service);
			this.successQueue.push(success);
			if(!this.interval)
			{
				this.run();
			}
		}
	},
	engine: {
		serverPath:VHV.rootURL+'server/services.php',
		register:function(serviceModule, methods){
			var model = {};
			for(var i in methods)
			{
				model[i] = this.registerMethod(serviceModule, i);
				model[i].url = this.registerURLMethod(serviceModule, i);
			}
			return model;
		},
		registerMethod: function(serviceModule, method)
		{
			var engine = this;
			return function(options, success){
				return engine.call(serviceModule, method, options, success);
			};;
		},
		registerURLMethod: function(serviceModule, method)
		{
			var engine = this;
			return function(options){
				return engine.url(serviceModule, method, options);
			};;
		},
		call: function(serviceModule, serviceMethod, options, success)
		{
			if(!options)options = {};
			if(!options.portal) options.portal = VHV.App.portal;
			if(options.serviceCache && VHV.serviceCache[serviceModule+'.'+serviceMethod])
			{
				var startPos = options.serviceCache.indexOf('('), serviceCache = options.serviceCache;
				if(startPos != -1)
				{
					serviceCache = $.trim(options.serviceCache.substr(0, startPos))+'(';
					var settings = options.serviceCache.substr(startPos).replace('(','').replace(')','').split('|');
					for(var i = 0; i < settings.length; i++)
					{
						var settingName = $.trim(settings[i]+''), defaultValue = '';
						if(settingName.indexOf('==') != -1)
						{
							
							var exprs = settingName.split('==');
							if(options[exprs[0]] && options[exprs[0]]!=trim(exprs[1]))
							{
							
								serviceCache+=',error';
								break;
							}
						}
						else
						{
							if(i) serviceCache+=',';
							if(settingName.indexOf('=') != -1)
							{
								var values = settingName.split('=');
								settingName = values[0];
								defaultValue = values[1];
							}
							
							if(settingName && module && typeof(module[settingName]) != 'undefined')
							{
								
								serviceCache+=module[settingName];
							}
							else
							{
								serviceCache+=defaultValue;
							}
						}
					}
					serviceCache += ')';
				}
				//alert(serviceMethod+' '+serviceCache+' '+options.serviceCache);
				var response = VHV.serviceCache[serviceModule+'.'+serviceMethod][serviceCache];
				if(response)
				{
					//alert('OK');
					if(success){success.call(this, response);}
					return response;
				}
			}
			if(options.serviceCache){
				delete options.serviceCache;
			}
			if((typeof(options.async)!='undefined' && !options.async) || options.immediate || VHV.noGroupService){
				var data;
				$.ajax({
					url: this.serverPath, 
					data: $.extend({serviceModule:serviceModule, serviceMethod:serviceMethod},options), 
					async:options.async, 
					type:($.toJSON(options).length > 2048)?'POST':'GET',
					success: function(response){
						if(success){success.call(this, response);}
						data = response;
					}
				});
				return data;
			}
			else
			{
				VHV.Model.CallingServices.add({
					service:serviceModule,
					method:serviceMethod,
					params:$.extend({serviceModule:serviceModule, serviceMethod:serviceMethod},options)
				}, success);
				//$.post(this.serverPath, $.extend({serviceModule:serviceModule, serviceMethod:serviceMethod},options), success);
			}
		},
		url: function(serviceModule, serviceMethod, options)
		{
			if(!options)options = {};
			if(!options.portal) options.portal = VHV.App.portal;
			return this.serverPath+'?'+$.param($.extend({serviceModule:serviceModule, serviceMethod:serviceMethod},options));
		}
	},
	register: function(serviceModule, methods, engine){
		if(!engine)engine = VHV.Model.engine;
		
		var names = serviceModule.split('.'), methodName = '';
		names[names.length-1] = names[names.length-1];
		
		if(!methods){
			methods = {};
			methodName = names.pop();
			methods[methodName] = [];
		}
		
		var obj = VHV.Model;
		for(var i = 0; i < names.length; i++)
		{
			if(!obj[names[i]])
			{
				obj[names[i]] = {};
			}
			obj = obj[names[i]];
		}
		for(var i in methods)
		{
			if(obj[methods[i]])
			{
				delete methods[i];
			}
		}
		var model = VHV.Model.engine.register(names.join('.'), methods);
		$.extend(obj, model);
		if(methodName)
		{
			return obj[methodName];
		}
		return obj;
	}, 
	call: function(serviceModule, serviceMethod, options, success){return VHV.Model.engine.call(serviceModule, serviceMethod, options, success);}
});
module = false;
if(location.host.indexOf('about') != -1 || location.host.indexOf('vietnam') != -1)
{
	VHV.App.mainPackage = 'CMS/AboutVN';
}
if (VHV.publish){
	var map='/'+VHV.App.mainPackage+'/data/map-'+VHV.language+'.xml';	
	VHV.publishPages=VHV.xml(map,'root');	
	VHV.publish=parseInt(VHV.publishPages.publish);

}
VHV.init();
mainPackage = VHV.App.mainPackage;